if (arguments == NULL) return NULL;
// Allocate and initialize a new arguments object.
- Node* callee = GetFunctionClosure();
CreateArgumentsParameters::Type type =
is_strict(language_mode()) || !info()->has_simple_parameters()
? CreateArgumentsParameters::kUnmappedArguments
: CreateArgumentsParameters::kMappedArguments;
const Operator* op = javascript()->CreateArguments(type, 0);
- Node* object = NewNode(op, callee);
+ Node* object = NewNode(op, GetFunctionClosure());
+ PrepareFrameState(object, BailoutId::None());
- // Assign the object to the arguments variable.
+ // Assign the object to the {arguments} variable. This should never lazy
+ // deopt, so it is fine to send invalid bailout id.
DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
- // This should never lazy deopt, so it is fine to send invalid bailout id.
FrameStateBeforeAndAfter states(this, BailoutId::None());
BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
BailoutId::None(), states);
// Retrieve the closure we were called with.
Node* this_function = GetFunctionClosure();
- // Assign the object to the {.this_function} variable.
+ // Assign the object to the {.this_function} variable. This should never lazy
+ // deopt, so it is fine to send invalid bailout id.
FrameStateBeforeAndAfter states(this, BailoutId::None());
BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST,
VectorSlotPair(), BailoutId::None(), states);
javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0);
Node* object = NewNode(op);
- // Assign the object to the {new.target} variable.
+ // Assign the object to the {new.target} variable. This should never lazy
+ // deopt, so it is fine to send invalid bailout id.
FrameStateBeforeAndAfter states(this, BailoutId::None());
BuildVariableAssignment(new_target_var, object, Token::INIT_CONST,
VectorSlotPair(), BailoutId::None(), states);
ReplaceWithRuntimeCall(node, fun); \
}
REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort)
-REPLACE_RUNTIME_CALL(JSCreateArguments, Runtime::kNewArguments)
REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
}
+void JSGenericLowering::LowerJSCreateArguments(Node* node) {
+ const CreateArgumentsParameters& p = CreateArgumentsParametersOf(node->op());
+ switch (p.type()) {
+ case CreateArgumentsParameters::kMappedArguments:
+ ReplaceWithRuntimeCall(node, Runtime::kNewSloppyArguments_Generic);
+ break;
+ case CreateArgumentsParameters::kUnmappedArguments:
+ ReplaceWithRuntimeCall(node, Runtime::kNewStrictArguments_Generic);
+ break;
+ case CreateArgumentsParameters::kRestArray:
+ UNIMPLEMENTED();
+ break;
+ }
+}
+
+
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
CreateClosureParameters p = CreateClosureParametersOf(node->op());
node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.shared_info()));
switch (use->opcode()) {
case IrOpcode::kParameter: {
int index = 1 + ParameterIndexOf(use->op());
+ DCHECK_LE(index, inlinee_context_index);
if (index < inliner_inputs && index < inlinee_context_index) {
// There is an input from the call, and the index is a value
// projection but not the context, so rewire the input.
Replace(use, call->InputAt(index));
} else if (index == inlinee_context_index) {
+ // The projection is requesting the inlinee function context.
Replace(use, context);
- } else if (index < inlinee_context_index) {
+ } else {
// Call has fewer arguments than required, fill with undefined.
Replace(use, jsgraph_->UndefinedConstant());
- } else {
- // We got too many arguments, discard for now.
- // TODO(sigurds): Fix to treat arguments array correctly.
}
break;
}
return NoChange();
}
- if (info.scope()->arguments() != NULL && is_sloppy(info.language_mode())) {
- // For now do not inline functions that use their arguments array.
- TRACE("Not inlining %s into %s because inlinee uses arguments array\n",
- function->shared()->DebugName()->ToCString().get(),
- info_->shared_info()->DebugName()->ToCString().get());
- return NoChange();
- }
-
TRACE("Inlining %s into %s\n",
function->shared()->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());
}
+const CreateArgumentsParameters& CreateArgumentsParametersOf(
+ const Operator* op) {
+ DCHECK_EQ(IrOpcode::kJSCreateArguments, op->opcode());
+ return OpParameter<CreateArgumentsParameters>(op);
+}
+
+
bool operator==(CreateClosureParameters const& lhs,
CreateClosureParameters const& rhs) {
return lhs.pretenure() == rhs.pretenure() &&
std::ostream& operator<<(std::ostream&, CreateArgumentsParameters const&);
+const CreateArgumentsParameters& CreateArgumentsParametersOf(
+ const Operator* op);
+
// Defines shared information for the closure that should be created. This is
// used as a parameter by JSCreateClosure operators.
case Runtime::kForInDone:
case Runtime::kForInStep:
case Runtime::kGetOriginalConstructor:
- case Runtime::kNewArguments:
case Runtime::kNewClosure:
case Runtime::kNewClosure_Tenured:
case Runtime::kNewFunctionContext:
case IrOpcode::kJSInstanceOf:
// Object operations
+ case IrOpcode::kJSCreateArguments:
case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject:
}
-static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
- Handle<JSFunction> callee,
- Object** parameters,
- int argument_count) {
+namespace {
+
+template <typename T>
+Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
+ T parameters, int argument_count) {
CHECK(!IsSubclassConstructor(callee->shared()->kind()));
DCHECK(callee->has_simple_parameters());
Handle<JSObject> result =
while (index >= mapped_count) {
// These go directly in the arguments array and have no
// corresponding slot in the parameter map.
- arguments->set(index, *(parameters - index - 1));
+ arguments->set(index, parameters[index]);
--index;
}
if (duplicate) {
// This goes directly in the arguments array with a hole in the
// parameter map.
- arguments->set(index, *(parameters - index - 1));
+ arguments->set(index, parameters[index]);
parameter_map->set_the_hole(index + 2);
} else {
// The context index goes in the parameter map with a hole in the
isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
result->set_elements(*elements);
for (int i = 0; i < argument_count; ++i) {
- elements->set(i, *(parameters - i - 1));
+ elements->set(i, parameters[i]);
}
}
}
}
-static Handle<JSObject> NewStrictArguments(Isolate* isolate,
- Handle<JSFunction> callee,
- Object** parameters,
- int argument_count) {
+template <typename T>
+Handle<JSObject> NewStrictArguments(Isolate* isolate, Handle<JSFunction> callee,
+ T parameters, int argument_count) {
Handle<JSObject> result =
isolate->factory()->NewArgumentsObject(callee, argument_count);
DisallowHeapAllocation no_gc;
WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
for (int i = 0; i < argument_count; i++) {
- array->set(i, *--parameters, mode);
+ array->set(i, parameters[i], mode);
}
result->set_elements(*array);
}
}
-RUNTIME_FUNCTION(Runtime_NewArguments) {
+class HandleArguments BASE_EMBEDDED {
+ public:
+ explicit HandleArguments(Handle<Object>* array) : array_(array) {}
+ Object* operator[](int index) { return *array_[index]; }
+
+ private:
+ Handle<Object>* array_;
+};
+
+
+class ParameterArguments BASE_EMBEDDED {
+ public:
+ explicit ParameterArguments(Object** parameters) : parameters_(parameters) {}
+ Object*& operator[](int index) { return *(parameters_ - index - 1); }
+
+ private:
+ Object** parameters_;
+};
+
+} // namespace
+
+
+RUNTIME_FUNCTION(Runtime_NewSloppyArguments_Generic) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
- JavaScriptFrameIterator it(isolate);
-
- // Find the frame that holds the actual arguments passed to the function.
- it.AdvanceToArgumentsFrame();
- JavaScriptFrame* frame = it.frame();
+ // This generic runtime function can also be used when the caller has been
+ // inlined, we use the slow but accurate {Runtime::GetCallerArguments}.
+ int argument_count = 0;
+ base::SmartArrayPointer<Handle<Object>> arguments =
+ Runtime::GetCallerArguments(isolate, 0, &argument_count);
+ HandleArguments argument_getter(arguments.get());
+ return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
+}
- // Determine parameter location on the stack and dispatch on language mode.
- int argument_count = frame->GetArgumentsLength();
- Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
- return (is_strict(callee->shared()->language_mode()) ||
- !callee->has_simple_parameters())
- ? *NewStrictArguments(isolate, callee, parameters, argument_count)
- : *NewSloppyArguments(isolate, callee, parameters, argument_count);
+RUNTIME_FUNCTION(Runtime_NewStrictArguments_Generic) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
+ // This generic runtime function can also be used when the caller has been
+ // inlined, we use the slow but accurate {Runtime::GetCallerArguments}.
+ int argument_count = 0;
+ base::SmartArrayPointer<Handle<Object>> arguments =
+ Runtime::GetCallerArguments(isolate, 0, &argument_count);
+ HandleArguments argument_getter(arguments.get());
+ return *NewStrictArguments(isolate, callee, argument_getter, argument_count);
}
JavaScriptFrameIterator it(isolate);
DCHECK(!it.frame()->HasInlinedFrames());
#endif // DEBUG
- return *NewSloppyArguments(isolate, callee, parameters, argument_count);
+ ParameterArguments argument_getter(parameters);
+ return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
}
JavaScriptFrameIterator it(isolate);
DCHECK(!it.frame()->HasInlinedFrames());
#endif // DEBUG
- return *NewStrictArguments(isolate, callee, parameters, argument_count);
+ ParameterArguments argument_getter(parameters);
+ return *NewStrictArguments(isolate, callee, argument_getter, argument_count);
}
F(IsRegExp, 1, 1)
-#define FOR_EACH_INTRINSIC_SCOPES(F) \
- F(ThrowConstAssignError, 0, 1) \
- F(DeclareGlobals, 2, 1) \
- F(InitializeVarGlobal, 3, 1) \
- F(InitializeConstGlobal, 2, 1) \
- F(DeclareLookupSlot, 2, 1) \
- F(DeclareReadOnlyLookupSlot, 2, 1) \
- F(InitializeLegacyConstLookupSlot, 3, 1) \
- F(NewArguments, 1, 1) /* TODO(turbofan): Only temporary */ \
- F(NewSloppyArguments, 3, 1) \
- F(NewStrictArguments, 3, 1) \
- F(NewClosure, 1, 1) \
- F(NewClosure_Tenured, 1, 1) \
- F(NewScriptContext, 2, 1) \
- F(NewFunctionContext, 1, 1) \
- F(PushWithContext, 2, 1) \
- F(PushCatchContext, 3, 1) \
- F(PushBlockContext, 2, 1) \
- F(IsJSModule, 1, 1) \
- F(PushModuleContext, 2, 1) \
- F(DeclareModules, 1, 1) \
- F(DeleteLookupSlot, 2, 1) \
- F(StoreLookupSlot, 4, 1) \
- F(ArgumentsLength, 0, 1) \
+#define FOR_EACH_INTRINSIC_SCOPES(F) \
+ F(ThrowConstAssignError, 0, 1) \
+ F(DeclareGlobals, 2, 1) \
+ F(InitializeVarGlobal, 3, 1) \
+ F(InitializeConstGlobal, 2, 1) \
+ F(DeclareLookupSlot, 2, 1) \
+ F(DeclareReadOnlyLookupSlot, 2, 1) \
+ F(InitializeLegacyConstLookupSlot, 3, 1) \
+ F(NewSloppyArguments_Generic, 1, 1) \
+ F(NewStrictArguments_Generic, 1, 1) \
+ F(NewSloppyArguments, 3, 1) \
+ F(NewStrictArguments, 3, 1) \
+ F(NewClosure, 1, 1) \
+ F(NewClosure_Tenured, 1, 1) \
+ F(NewScriptContext, 2, 1) \
+ F(NewFunctionContext, 1, 1) \
+ F(PushWithContext, 2, 1) \
+ F(PushCatchContext, 3, 1) \
+ F(PushBlockContext, 2, 1) \
+ F(IsJSModule, 1, 1) \
+ F(PushModuleContext, 2, 1) \
+ F(DeclareModules, 1, 1) \
+ F(DeleteLookupSlot, 2, 1) \
+ F(StoreLookupSlot, 4, 1) \
+ F(ArgumentsLength, 0, 1) \
F(Arguments, 1, 1)
"(function () {"
" var x = 42;"
" function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
- " return (function (s,t) { return bar(s); });"
+ " function foo(s, t) { return bar(s); };"
+ " return foo;"
"})();",
kInlineFlags);
}
+TEST(InlineOmitArgumentsObject) {
+ FunctionTester T(
+ "(function () {"
+ " function bar(s, t, u, v) { AssertInlineCount(2); return arguments; };"
+ " function foo(s, t) { var args = bar(s);"
+ " return args.length == 1 &&"
+ " args[0] == 11; };"
+ " return foo;"
+ "})();",
+ kInlineFlags);
+
+ InstallAssertInlineCountHelper(CcTest::isolate());
+ T.CheckCall(T.true_value(), T.Val(11), T.undefined());
+}
+
+
TEST(InlineOmitArgumentsDeopt) {
FunctionTester T(
"(function () {"
"(function () {"
" var x = 42;"
" function foo(s) { AssertInlineCount(2); return x + s; };"
- " function bar(s,t) { return foo(s,t,13); };"
+ " function bar(s, t) { return foo(s, t, 13); };"
" return bar;"
"})();",
kInlineFlags);
}
+TEST(InlineSurplusArgumentsObject) {
+ FunctionTester T(
+ "(function () {"
+ " function foo(s) { AssertInlineCount(2); return arguments; };"
+ " function bar(s, t) { var args = foo(s, t, 13);"
+ " return args.length == 3 &&"
+ " args[0] == 11 &&"
+ " args[1] == 12 &&"
+ " args[2] == 13; };"
+ " return bar;"
+ "})();",
+ kInlineFlags);
+
+ InstallAssertInlineCountHelper(CcTest::isolate());
+ T.CheckCall(T.true_value(), T.Val(11), T.Val(12));
+}
+
+
TEST(InlineSurplusArgumentsDeopt) {
FunctionTester T(
"(function () {"