Commit ed17bab8 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Support inline allocation of mapped outer arguments.

This adds support for lowering {JSCreateArguments} within outermost
frames of type {CreateArgumentsType::kMappedArguments}. It will hence
enable escape analysis to work with such objects and allow for further
optimization.

This also adds a new {NewMappedArgumentsElements} simplfied operator.
Note that escape analysis support for this new operator will be done as
a follow-up.

R=tebbi@chromium.org

Change-Id: I0e2fac25c654f796433f57b116964053b6b68635
Reviewed-on: https://chromium-review.googlesource.com/641454
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47761}
parent a9f517e2
......@@ -410,11 +410,5 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
return result.value();
}
TF_BUILTIN(FastNewSloppyArguments, ArgumentsBuiltinsAssembler) {
Node* function = Parameter(FastNewArgumentsDescriptor::kFunction);
Node* context = Parameter(FastNewArgumentsDescriptor::kContext);
Return(EmitFastNewSloppyArguments(context, function));
}
} // namespace internal
} // namespace v8
......@@ -73,7 +73,6 @@ namespace internal {
TFC(FastNewClosure, FastNewClosure, 1) \
TFC(FastNewFunctionContextEval, FastNewFunctionContext, 1) \
TFC(FastNewFunctionContextFunction, FastNewFunctionContext, 1) \
TFC(FastNewSloppyArguments, FastNewArguments, 1) \
TFC(FastCloneRegExp, FastCloneRegExp, 1) \
TFC(FastCloneShallowArrayTrack, FastCloneShallowArray, 1) \
TFC(FastCloneShallowArrayDontTrack, FastCloneShallowArray, 1) \
......@@ -170,7 +169,7 @@ namespace internal {
TFS(CopyFastSmiOrObjectElements, kObject) \
TFC(GrowFastDoubleElements, GrowArrayElements, 1) \
TFC(GrowFastSmiOrObjectElements, GrowArrayElements, 1) \
TFC(NewUnmappedArgumentsElements, NewArgumentsElements, 1) \
TFC(NewArgumentsElements, NewArgumentsElements, 1) \
\
/* Debugger */ \
ASM(FrameDropperTrampoline) \
......
......@@ -168,9 +168,10 @@ TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
}
TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
Node* frame = Parameter(Descriptor::kFrame);
Node* length = SmiToWord(Parameter(Descriptor::kLength));
Node* mapped_count = SmiToWord(Parameter(Descriptor::kMappedCount));
// Check if we can allocate in new space.
ElementsKind kind = PACKED_ELEMENTS;
......@@ -195,21 +196,49 @@ TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
// Allocate a FixedArray in new space.
Node* result = AllocateFixedArray(kind, length);
// The elements might be used to back mapped arguments. In that case fill
// the mapped elements (i.e. the first {mapped_count}) with the hole, but
// make sure not to overshoot the {length} if some arguments are missing.
Node* number_of_holes =
SelectConstant(IntPtrLessThan(mapped_count, length), mapped_count,
length, MachineType::PointerRepresentation());
Node* the_hole = TheHoleConstant();
// Fill the first elements up to {number_of_holes} with the hole.
VARIABLE(var_index, MachineType::PointerRepresentation());
Label loop1(this, &var_index), done_loop1(this);
var_index.Bind(IntPtrConstant(0));
Goto(&loop1);
BIND(&loop1);
{
// Load the current {index}.
Node* index = var_index.value();
// Check if we are done.
GotoIf(WordEqual(index, number_of_holes), &done_loop1);
// Store the hole into the {result}.
StoreFixedArrayElement(result, index, the_hole, SKIP_WRITE_BARRIER);
// Continue with next {index}.
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
Goto(&loop1);
}
BIND(&done_loop1);
// Compute the effective {offset} into the {frame}.
Node* offset = IntPtrAdd(length, IntPtrConstant(1));
// Copy the parameters from {frame} (starting at {offset}) to {result}.
VARIABLE(var_index, MachineType::PointerRepresentation());
Label loop(this, &var_index), done_loop(this);
var_index.Bind(IntPtrConstant(0));
Goto(&loop);
BIND(&loop);
Label loop2(this, &var_index), done_loop2(this);
Goto(&loop2);
BIND(&loop2);
{
// Load the current {index}.
Node* index = var_index.value();
// Check if we are done.
GotoIf(WordEqual(index, length), &done_loop);
GotoIf(WordEqual(index, length), &done_loop2);
// Load the parameter at the given {index}.
Node* value = Load(MachineType::AnyTagged(), frame,
......@@ -220,10 +249,10 @@ TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
// Continue with next {index}.
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
Goto(&loop);
Goto(&loop2);
}
BIND(&done_loop2);
BIND(&done_loop);
Return(result);
}
}
......@@ -232,7 +261,8 @@ TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
{
// Allocate in old space (or large object space).
TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
BitcastWordToTagged(frame), SmiFromWord(length));
BitcastWordToTagged(frame), SmiFromWord(length),
SmiFromWord(mapped_count));
}
}
......
......@@ -751,6 +751,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kArgumentsLength:
result = LowerArgumentsLength(node);
break;
case IrOpcode::kNewMappedArgumentsElements:
result = LowerNewMappedArgumentsElements(node);
break;
case IrOpcode::kNewUnmappedArgumentsElements:
result = LowerNewUnmappedArgumentsElements(node);
break;
......@@ -2169,18 +2172,33 @@ Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerNewMappedArgumentsElements(Node* node) {
Node* frame = NodeProperties::GetValueInput(node, 0);
Node* length = NodeProperties::GetValueInput(node, 1);
int mapped_count = OpParameter<int>(node);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
Operator::Properties const properties = node->op()->properties();
CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(desc, __ HeapConstant(callable.code()), frame, length,
__ SmiConstant(mapped_count), __ NoContextConstant());
}
Node* EffectControlLinearizer::LowerNewUnmappedArgumentsElements(Node* node) {
Node* frame = NodeProperties::GetValueInput(node, 0);
Node* length = NodeProperties::GetValueInput(node, 1);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kNewUnmappedArgumentsElements);
Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
Operator::Properties const properties = node->op()->properties();
CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(desc, __ HeapConstant(callable.code()), frame, length,
__ NoContextConstant());
__ SmiConstant(0), __ NoContextConstant());
}
Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) {
......
......@@ -97,6 +97,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerObjectIsUndetectable(Node* node);
Node* LowerArgumentsFrame(Node* node);
Node* LowerArgumentsLength(Node* node);
Node* LowerNewMappedArgumentsElements(Node* node);
Node* LowerNewUnmappedArgumentsElements(Node* node);
Node* LowerArrayBufferWasNeutered(Node* node);
Node* LowerStringCharAt(Node* node);
......
......@@ -311,22 +311,26 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
case CreateArgumentsType::kMappedArguments: {
// TODO(mstarzinger): Duplicate parameters are not handled yet.
if (shared->has_duplicate_parameters()) return NoChange();
// If there is no aliasing, the arguments object elements are not
// special in any way, we can just return an unmapped backing store.
if (shared->internal_formal_parameter_count() == 0) {
Node* const callee = NodeProperties::GetValueInput(node, 0);
Node* const context = NodeProperties::GetContextInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* const arguments_frame =
graph()->NewNode(simplified()->ArgumentsFrame());
Node* const arguments_length = graph()->NewNode(
simplified()->ArgumentsLength(0, false), arguments_frame);
simplified()->ArgumentsLength(
shared->internal_formal_parameter_count(), false),
arguments_frame);
// Allocate the elements backing store.
Node* const elements = effect =
graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
arguments_frame, arguments_length, effect);
bool has_aliased_arguments = false;
Node* const elements = effect = AllocateAliasedArguments(
effect, control, context, arguments_frame, arguments_length, shared,
&has_aliased_arguments);
// Load the arguments object map.
Node* const arguments_map = jsgraph()->HeapConstant(
handle(native_context()->sloppy_arguments_map(), isolate()));
handle(has_aliased_arguments
? native_context()->fast_aliased_arguments_map()
: native_context()->sloppy_arguments_map(),
isolate()));
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
Node* properties = jsgraph()->EmptyFixedArrayConstant();
......@@ -339,19 +343,6 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
a.Store(AccessBuilder::ForArgumentsCallee(), callee);
RelaxControls(node);
a.FinishAndChange(node);
} else {
Callable callable = Builtins::CallableFor(
isolate(), Builtins::kFastNewSloppyArguments);
Operator::Properties properties = node->op()->properties();
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0,
CallDescriptor::kNoFlags, properties);
const Operator* new_op = common()->Call(desc);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->InsertInput(graph()->zone(), 0, stub_code);
node->RemoveInput(3); // Remove the frame state.
NodeProperties::ChangeOp(node, new_op);
}
return Changed(node);
}
case CreateArgumentsType::kUnmappedArguments: {
......@@ -386,9 +377,9 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* const arguments_frame =
graph()->NewNode(simplified()->ArgumentsFrame());
int formal_parameter_count = shared->internal_formal_parameter_count();
Node* const rest_length = graph()->NewNode(
simplified()->ArgumentsLength(formal_parameter_count, true),
simplified()->ArgumentsLength(
shared->internal_formal_parameter_count(), true),
arguments_frame);
// Allocate the elements backing store. Since
// NewUnmappedArgumentsElements copies from the end of the arguments
......@@ -1201,6 +1192,53 @@ Node* JSCreateLowering::AllocateAliasedArguments(
return a.Finish();
}
// Helper that allocates a FixedArray serving as a parameter map for values
// unknown at compile-time, the true {arguments_length} and {arguments_frame}
// values can only be determined dynamically at run-time and are provided.
// Serves as backing store for JSCreateArguments nodes.
Node* JSCreateLowering::AllocateAliasedArguments(
Node* effect, Node* control, Node* context, Node* arguments_frame,
Node* arguments_length, Handle<SharedFunctionInfo> shared,
bool* has_aliased_arguments) {
// If there is no aliasing, the arguments object elements are not
// special in any way, we can just return an unmapped backing store.
int parameter_count = shared->internal_formal_parameter_count();
if (parameter_count == 0) {
return graph()->NewNode(simplified()->NewUnmappedArgumentsElements(),
arguments_frame, arguments_length, effect);
}
// From here on we are going to allocate a mapped (aka. aliased) elements
// backing store. We do not statically know how many arguments exist, but
// dynamically selecting the hole for some of the "mapped" elements allows
// using a static shape for the parameter map.
int mapped_count = parameter_count;
*has_aliased_arguments = true;
// The unmapped argument values are stored yet another indirection away and
// then linked into the parameter map below, whereas mapped argument values
// (i.e. the first {mapped_count} elements) are replaced with a hole instead.
Node* arguments =
graph()->NewNode(simplified()->NewMappedArgumentsElements(mapped_count),
arguments_frame, arguments_length, effect);
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), arguments, control);
a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
a.Store(AccessBuilder::ForFixedArraySlot(0), context);
a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
for (int i = 0; i < mapped_count; ++i) {
int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
Node* value = graph()->NewNode(
common()->Select(MachineRepresentation::kTagged),
graph()->NewNode(simplified()->NumberLessThan(), jsgraph()->Constant(i),
arguments_length),
jsgraph()->Constant(idx), jsgraph()->TheHoleConstant());
a.Store(AccessBuilder::ForFixedArraySlot(i + 2), value);
}
return a.Finish();
}
Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind,
int capacity,
......
......@@ -74,6 +74,10 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Node* AllocateAliasedArguments(Node* effect, Node* control, Node* frame_state,
Node* context, Handle<SharedFunctionInfo>,
bool* has_aliased_arguments);
Node* AllocateAliasedArguments(Node* effect, Node* control, Node* context,
Node* arguments_frame, Node* arguments_length,
Handle<SharedFunctionInfo>,
bool* has_aliased_arguments);
Node* AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind, int capacity,
PretenureFlag pretenure);
......
......@@ -363,6 +363,7 @@
V(ObjectIsUndetectable) \
V(ArgumentsFrame) \
V(ArgumentsLength) \
V(NewMappedArgumentsElements) \
V(NewUnmappedArgumentsElements) \
V(ArrayBufferWasNeutered) \
V(EnsureWritableFastElements) \
......
......@@ -2734,6 +2734,7 @@ class RepresentationSelector {
MachineRepresentation::kTaggedSigned);
return;
}
case IrOpcode::kNewMappedArgumentsElements:
case IrOpcode::kNewUnmappedArgumentsElements: {
VisitBinop(node, UseInfo::PointerInt(), UseInfo::TaggedSigned(),
MachineRepresentation::kTaggedPointer);
......
......@@ -976,6 +976,16 @@ bool IsRestLengthOf(const Operator* op) {
return OpParameter<ArgumentsLengthParameters>(op).is_rest_length;
}
const Operator* SimplifiedOperatorBuilder::NewMappedArgumentsElements(
int mapped_count) {
return new (zone()) Operator1<int>( // --
IrOpcode::kNewMappedArgumentsElements, // opcode
Operator::kEliminatable, // flags
"NewMappedArgumentsElements", // name
2, 1, 0, 1, 1, 0, // counts
mapped_count); // parameter
}
const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
PretenureFlag pretenure) {
return new (zone()) Operator1<AllocateParameters>(
......
......@@ -451,7 +451,10 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ArgumentsLength(int formal_parameter_count,
bool is_rest_length);
// new-unmapped-arguments-elements
// new-mapped-arguments-elements arguments-frame, arguments-length
const Operator* NewMappedArgumentsElements(int mapped_count);
// new-unmapped-arguments-elements arguments-frame, arguments-length
const Operator* NewUnmappedArgumentsElements();
// array-buffer-was-neutered buffer
......
......@@ -2001,6 +2001,10 @@ Type* Typer::Visitor::TypeArgumentsFrame(Node* node) {
return Type::ExternalPointer();
}
Type* Typer::Visitor::TypeNewMappedArgumentsElements(Node* node) {
return Type::OtherInternal();
}
Type* Typer::Visitor::TypeNewUnmappedArgumentsElements(Node* node) {
return Type::OtherInternal();
}
......
......@@ -1029,6 +1029,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kArgumentsFrame:
CheckTypeIs(node, Type::ExternalPointer());
break;
case IrOpcode::kNewMappedArgumentsElements:
case IrOpcode::kNewUnmappedArgumentsElements:
CheckValueInputIs(node, 0, Type::ExternalPointer());
CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,
......
......@@ -157,8 +157,8 @@ DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
Handle<StringSet> non_locals = it.GetNonLocals();
MaterializeReceiver(materialized, local_context, local_function,
non_locals);
frame_inspector.MaterializeStackLocals(materialized, local_function);
MaterializeArgumentsObject(materialized, local_function);
frame_inspector.MaterializeStackLocals(materialized, local_function,
true);
ContextChainElement context_chain_element;
context_chain_element.scope_info = it.CurrentScopeInfo();
context_chain_element.materialized_object = materialized;
......@@ -223,24 +223,6 @@ void DebugEvaluate::ContextBuilder::UpdateValues() {
}
void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject(
Handle<JSObject> target, Handle<JSFunction> function) {
// Do not materialize the arguments object for eval or top-level code.
// Skip if "arguments" is already taken.
if (function->shared()->is_toplevel()) return;
Maybe<bool> maybe = JSReceiver::HasOwnProperty(
target, isolate_->factory()->arguments_string());
DCHECK(maybe.IsJust());
if (maybe.FromJust()) return;
// FunctionGetArguments can't throw an exception.
Handle<JSObject> arguments = Accessors::FunctionGetArguments(function);
Handle<String> arguments_str = isolate_->factory()->arguments_string();
JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
NONE)
.Check();
}
void DebugEvaluate::ContextBuilder::MaterializeReceiver(
Handle<JSObject> target, Handle<Context> local_context,
Handle<JSFunction> local_function, Handle<StringSet> non_locals) {
......
......@@ -66,11 +66,6 @@ class DebugEvaluate : public AllStatic {
Handle<StringSet> whitelist;
};
// Helper function to find or create the arguments object for
// Runtime_DebugEvaluate.
void MaterializeArgumentsObject(Handle<JSObject> target,
Handle<JSFunction> function);
void MaterializeReceiver(Handle<JSObject> target,
Handle<Context> local_context,
Handle<JSFunction> local_function,
......
......@@ -4,6 +4,7 @@
#include "src/debug/debug-frames.h"
#include "src/accessors.h"
#include "src/frames-inl.h"
#include "src/wasm/wasm-interpreter.h"
#include "src/wasm/wasm-objects-inl.h"
......@@ -108,7 +109,8 @@ void FrameInspector::SetArgumentsFrame(StandardFrame* frame) {
// Create a plain JSObject which materializes the local scope for the specified
// frame.
void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
Handle<ScopeInfo> scope_info) {
Handle<ScopeInfo> scope_info,
bool materialize_arguments_object) {
HandleScope scope(isolate_);
// First fill all parameters.
for (int i = 0; i < scope_info->ParameterCount(); ++i) {
......@@ -139,18 +141,41 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
value = isolate_->factory()->undefined_value();
}
if (value->IsOptimizedOut(isolate_)) {
if (materialize_arguments_object) {
Handle<String> arguments_str = isolate_->factory()->arguments_string();
if (String::Equals(name, arguments_str)) continue;
}
value = isolate_->factory()->undefined_value();
}
JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
}
}
void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
Handle<JSFunction> function) {
Handle<JSFunction> function,
bool materialize_arguments_object) {
// Do not materialize the arguments object for eval or top-level code.
if (function->shared()->is_toplevel()) materialize_arguments_object = false;
Handle<SharedFunctionInfo> shared(function->shared());
Handle<ScopeInfo> scope_info(shared->scope_info());
MaterializeStackLocals(target, scope_info);
MaterializeStackLocals(target, scope_info, materialize_arguments_object);
// Third materialize the arguments object.
if (materialize_arguments_object) {
// Skip if "arguments" is already taken and wasn't optimized out (which
// causes {MaterializeStackLocals} above to skip the local variable).
Handle<String> arguments_str = isolate_->factory()->arguments_string();
Maybe<bool> maybe = JSReceiver::HasOwnProperty(target, arguments_str);
DCHECK(maybe.IsJust());
if (maybe.FromJust()) return;
// FunctionGetArguments can't throw an exception.
Handle<JSObject> arguments = Accessors::FunctionGetArguments(function);
JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
NONE)
.Check();
}
}
......
......@@ -49,10 +49,12 @@ class FrameInspector {
void SetArgumentsFrame(StandardFrame* frame);
void MaterializeStackLocals(Handle<JSObject> target,
Handle<ScopeInfo> scope_info);
Handle<ScopeInfo> scope_info,
bool materialize_arguments_object = false);
void MaterializeStackLocals(Handle<JSObject> target,
Handle<JSFunction> function);
Handle<JSFunction> function,
bool materialize_arguments_object = false);
void UpdateStackLocalsFromMaterializedObject(Handle<JSObject> object,
Handle<ScopeInfo> scope_info);
......
......@@ -2361,7 +2361,7 @@ Handle<Object> GetValueForDebugger(TranslatedFrame::iterator it,
Isolate* isolate) {
if (it->GetRawValue() == isolate->heap()->arguments_marker()) {
if (!it->IsMaterializableByDebugger()) {
return isolate->factory()->undefined_value();
return isolate->factory()->optimized_out();
}
}
return it->GetValue();
......
......@@ -386,8 +386,9 @@ void GrowArrayElementsDescriptor::InitializePlatformSpecific(
void NewArgumentsElementsDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kFrame, kLength
// kFrame, kLength, kMappedCount
MachineType const kMachineTypes[] = {MachineType::Pointer(),
MachineType::TaggedSigned(),
MachineType::TaggedSigned()};
data->InitializePlatformIndependent(arraysize(kMachineTypes), 0,
kMachineTypes);
......@@ -395,7 +396,7 @@ void NewArgumentsElementsDescriptor::InitializePlatformIndependent(
void NewArgumentsElementsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, 2);
DefaultInitializePlatformSpecific(data, 3);
}
void FastCloneRegExpDescriptor::InitializePlatformIndependent(
......
......@@ -835,7 +835,7 @@ class GrowArrayElementsDescriptor : public CallInterfaceDescriptor {
class NewArgumentsElementsDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kFrame, kLength)
DEFINE_PARAMETERS(kFrame, kLength, kMappedCount)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(NewArgumentsElementsDescriptor,
CallInterfaceDescriptor)
};
......
......@@ -390,14 +390,14 @@ void PrintSloppyArgumentElements(std::ostream& os, ElementsKind kind,
SloppyArgumentsElements* elements) {
Isolate* isolate = elements->GetIsolate();
FixedArray* arguments_store = elements->arguments();
os << "\n 0: context= " << Brief(elements->context())
<< "\n 1: arguments_store= " << Brief(arguments_store)
os << "\n 0: context = " << Brief(elements->context())
<< "\n 1: arguments_store = " << Brief(arguments_store)
<< "\n parameter to context slot map:";
for (uint32_t i = 0; i < elements->parameter_map_length(); i++) {
uint32_t raw_index = i + SloppyArgumentsElements::kParameterMapStart;
Object* mapped_entry = elements->get_mapped_entry(i);
os << "\n " << raw_index << ": param(" << i
<< ")= " << Brief(mapped_entry);
<< ") = " << Brief(mapped_entry);
if (mapped_entry->IsTheHole(isolate)) {
os << " in the arguments_store[" << i << "]";
} else {
......@@ -414,7 +414,6 @@ void PrintSloppyArgumentElements(std::ostream& os, ElementsKind kind,
DCHECK_EQ(kind, SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
PrintDictionaryElements(os, arguments_store);
}
os << "\n }";
}
} // namespace
......@@ -422,7 +421,7 @@ void PrintSloppyArgumentElements(std::ostream& os, ElementsKind kind,
void JSObject::PrintElements(std::ostream& os) { // NOLINT
// Don't call GetElementsKind, its validation code can cause the printer to
// fail when debugging.
os << " - elements= " << Brief(elements()) << " {";
os << " - elements = " << Brief(elements()) << " {";
if (elements()->length() == 0) {
os << " }\n";
return;
......
......@@ -607,15 +607,20 @@ RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
DCHECK_EQ(3, args.length());
Object** frame = reinterpret_cast<Object**>(args[0]);
CONVERT_SMI_ARG_CHECKED(length, 1);
CONVERT_SMI_ARG_CHECKED(mapped_count, 2);
Handle<FixedArray> result =
isolate->factory()->NewUninitializedFixedArray(length);
int const offset = length + 1;
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int index = 0; index < length; ++index) {
int number_of_holes = Min(mapped_count, length);
for (int index = 0; index < number_of_holes; ++index) {
result->set_the_hole(isolate, index);
}
for (int index = number_of_holes; index < length; ++index) {
result->set(index, frame[offset - index], mode);
}
return *result;
......
......@@ -497,7 +497,7 @@ namespace internal {
F(NewStrictArguments, 1, 1) \
F(NewRestParameter, 1, 1) \
F(NewSloppyArguments, 3, 1) \
F(NewArgumentsElements, 2, 1) \
F(NewArgumentsElements, 3, 1) \
F(NewClosure, 3, 1) \
F(NewClosure_Tenured, 3, 1) \
F(NewScriptContext, 2, 1) \
......
......@@ -31,12 +31,12 @@ Debug = debug.Debug
var error = null;
var array = ["a", "b", "c"];
var result = null;
function listener(event, exec_state, event_data, data) {
try {
if (event == Debug.DebugEvent.Break) {
assertArrayEquals(array,
exec_state.frame(0).evaluate('arguments').value());
result = exec_state.frame(0).evaluate('arguments').value();
}
} catch (e) {
error = e;
......@@ -51,13 +51,35 @@ function f(a, b) {
debugger; // Arguments object is already materialized.
}
result = null;
f.apply(this, array);
assertArrayEquals(array, result);
result = null;
f("a", "b", "c");
assertArrayEquals(array, result);
assertNull(error);
function g(a, b) {
debugger; // Arguments object is not yet materialized.
}
result = null;
g.apply(this, array);
assertArrayEquals(array, result);
result = null;
g("a", "b", "c");
assertArrayEquals(array, result);
assertNull(error);
function h(a, b) {
var arguments = undefined;
debugger; // Arguments already used as local variable.
}
result = null;
h.apply(this, array);
assertEquals(undefined, result);
result = null;
h("a", "b", "c");
assertEquals(undefined, result);
assertNull(error);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment