summaryrefslogtreecommitdiff
path: root/deps/v8/src/x64/builtins-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/x64/builtins-x64.cc')
-rw-r--r--deps/v8/src/x64/builtins-x64.cc314
1 files changed, 207 insertions, 107 deletions
diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc
index 38d7e5abeb..4efd3bfb23 100644
--- a/deps/v8/src/x64/builtins-x64.cc
+++ b/deps/v8/src/x64/builtins-x64.cc
@@ -21,12 +21,13 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
BuiltinExtraArguments extra_args) {
// ----------- S t a t e -------------
// -- rax : number of arguments excluding receiver
- // -- rdi : called function (only guaranteed when
- // extra_args requires it)
+ // (only guaranteed when the called function
+ // is not marked as DontAdaptArguments)
+ // -- rdi : called function
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -- ...
- // -- rsp[8 * argc] : first argument (argc == rax)
+ // -- rsp[8 * argc] : first argument
// -- rsp[8 * (argc + 1)] : receiver
// -----------------------------------
__ AssertFunction(rdi);
@@ -50,8 +51,21 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
}
// JumpToExternalReference expects rax to contain the number of arguments
- // including the receiver and the extra arguments.
+ // including the receiver and the extra arguments. But rax is only valid
+ // if the called function is marked as DontAdaptArguments, otherwise we
+ // need to load the argument count from the SharedFunctionInfo.
+ Label argc, done_argc;
+ __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ LoadSharedFunctionInfoSpecialField(
+ rbx, rdx, SharedFunctionInfo::kFormalParameterCountOffset);
+ __ cmpp(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
+ __ j(equal, &argc, Label::kNear);
+ __ leap(rax, Operand(rbx, num_extra_args + 1));
+ __ jmp(&done_argc, Label::kNear);
+ __ bind(&argc);
__ addp(rax, Immediate(num_extra_args + 1));
+ __ bind(&done_argc);
+
__ JumpToExternalReference(ExternalReference(id, masm->isolate()), 1);
}
@@ -135,14 +149,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ cmpp(Operand(kScratchRegister, 0), Immediate(0));
__ j(not_equal, &rt_call);
- // Fall back to runtime if the original constructor and function differ.
- __ cmpp(rdx, rdi);
+ // Verify that the original constructor is a JSFunction.
+ __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rbx);
__ j(not_equal, &rt_call);
- // Verified that the constructor is a JSFunction.
// Load the initial map and verify that it is in fact a map.
- // rdi: constructor
- __ movp(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
+ // rdx: original constructor
+ __ movp(rax, FieldOperand(rdx, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi
DCHECK(kSmiTag == 0);
__ JumpIfSmi(rax, &rt_call);
@@ -151,6 +164,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ CmpObjectType(rax, MAP_TYPE, rbx);
__ j(not_equal, &rt_call);
+ // Fall back to runtime if the expected base constructor and base
+ // constructor differ.
+ __ cmpp(rdi, FieldOperand(rax, Map::kConstructorOrBackPointerOffset));
+ __ j(not_equal, &rt_call);
+
// Check that the constructor is not constructing a JSFunction (see
// comments in Runtime_NewObject in runtime.cc). In which case the
// initial map's instance type would be JS_FUNCTION_TYPE.
@@ -178,7 +196,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Push(rdx);
__ Push(rdi);
- __ Push(rdi); // constructor
+ __ Push(rax); // initial map
__ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
__ Pop(rdi);
@@ -263,8 +281,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Must restore rsi (context) and rdi (constructor) before calling runtime.
__ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ movp(rdi, Operand(rsp, offset));
- __ Push(rdi); // argument 2/1: constructor function
- __ Push(rdx); // argument 3/2: original constructor
+ __ Push(rdi); // constructor function
+ __ Push(rdx); // original constructor
__ CallRuntime(Runtime::kNewObject, 2);
__ movp(rbx, rax); // store result in rbx
@@ -698,28 +716,16 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// - Support profiler (specifically profiling_counter).
// - Call ProfileEntryHookStub when isolate has a function_entry_hook.
// - Allow simulator stop operations if FLAG_stop_at is set.
- // - Deal with sloppy mode functions which need to replace the
- // receiver with the global proxy when called as functions (without an
- // explicit receiver object).
// - Code aging of the BytecodeArray object.
- // - Supporting FLAG_trace.
- //
- // The following items are also not done here, and will probably be done using
- // explicit bytecodes instead:
- // - Allocating a new local context if applicable.
- // - Setting up a local binding to the this function, which is used in
- // derived constructors with super calls.
- // - Setting new.target if required.
- // - Dealing with REST parameters (only if
- // https://codereview.chromium.org/1235153006 doesn't land by then).
- // - Dealing with argument objects.
// Perform stack guard check.
{
Label ok;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &ok, Label::kNear);
+ __ Push(kInterpreterBytecodeArrayRegister);
__ CallRuntime(Runtime::kStackGuard, 0);
+ __ Pop(kInterpreterBytecodeArrayRegister);
__ bind(&ok);
}
@@ -771,6 +777,86 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
}
+static void Generate_InterpreterPushArgs(MacroAssembler* masm,
+ bool push_receiver) {
+ // ----------- S t a t e -------------
+ // -- rax : the number of arguments (not including the receiver)
+ // -- rbx : the address of the first argument to be pushed. Subsequent
+ // arguments should be consecutive above this, in the same order as
+ // they are to be pushed onto the stack.
+ // -----------------------------------
+
+ // Find the address of the last argument.
+ __ movp(rcx, rax);
+ if (push_receiver) {
+ __ addp(rcx, Immediate(1)); // Add one for receiver.
+ }
+
+ __ shlp(rcx, Immediate(kPointerSizeLog2));
+ __ negp(rcx);
+ __ addp(rcx, rbx);
+
+ // Push the arguments.
+ Label loop_header, loop_check;
+ __ j(always, &loop_check);
+ __ bind(&loop_header);
+ __ Push(Operand(rbx, 0));
+ __ subp(rbx, Immediate(kPointerSize));
+ __ bind(&loop_check);
+ __ cmpp(rbx, rcx);
+ __ j(greater, &loop_header, Label::kNear);
+}
+
+
+// static
+void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : the number of arguments (not including the receiver)
+ // -- rbx : the address of the first argument to be pushed. Subsequent
+ // arguments should be consecutive above this, in the same order as
+ // they are to be pushed onto the stack.
+ // -- rdi : the target to call (can be any Object).
+ // -----------------------------------
+
+ // Pop return address to allow tail-call after pushing arguments.
+ __ PopReturnAddressTo(kScratchRegister);
+
+ Generate_InterpreterPushArgs(masm, true);
+
+ // Call the target.
+ __ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+}
+
+
+// static
+void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- rax : the number of arguments (not including the receiver)
+ // -- rdx : the original constructor (either the same as the constructor or
+ // the JSFunction on which new was invoked initially)
+ // -- rdi : the constructor to call (can be any Object)
+ // -- rbx : the address of the first argument to be pushed. Subsequent
+ // arguments should be consecutive above this, in the same order as
+ // they are to be pushed onto the stack.
+ // -----------------------------------
+
+ // Pop return address to allow tail-call after pushing arguments.
+ __ PopReturnAddressTo(kScratchRegister);
+
+ // Push slot for the receiver to be constructed.
+ __ Push(Immediate(0));
+
+ Generate_InterpreterPushArgs(masm, false);
+
+ // Push return address in preparation for the tail-call.
+ __ PushReturnAddressFrom(kScratchRegister);
+
+ // Call the constructor (rax, rdx, rdi passed on).
+ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CONSTRUCT_CALL);
+}
+
+
void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
CallRuntimePassFunction(masm, Runtime::kCompileLazy);
GenerateTailCallToReturnedCode(masm);
@@ -1338,6 +1424,7 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : number of arguments
// -- rdi : constructor function
+ // -- rdx : original constructor
// -- rsp[0] : return address
// -- rsp[(argc - n) * 8] : arg[n] (zero-based)
// -- rsp[(argc + 1) * 8] : receiver
@@ -1364,17 +1451,19 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
{
Label convert, done_convert;
__ JumpIfSmi(rbx, &convert, Label::kNear);
- __ CmpObjectType(rbx, FIRST_NONSTRING_TYPE, rdx);
+ __ CmpObjectType(rbx, FIRST_NONSTRING_TYPE, rcx);
__ j(below, &done_convert);
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
ToStringStub stub(masm->isolate());
+ __ Push(rdx);
__ Push(rdi);
__ Move(rax, rbx);
__ CallStub(&stub);
__ Move(rbx, rax);
__ Pop(rdi);
+ __ Pop(rdx);
}
__ bind(&done_convert);
}
@@ -1384,9 +1473,14 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rbx : the first argument
// -- rdi : constructor function
+ // -- rdx : original constructor
// -----------------------------------
+ Label allocate, done_allocate, rt_call;
+
+ // Fall back to runtime if the original constructor and constructor differ.
+ __ cmpp(rdx, rdi);
+ __ j(not_equal, &rt_call);
- Label allocate, done_allocate;
__ Allocate(JSValue::kSize, rax, rcx, no_reg, &allocate, TAG_OBJECT);
__ bind(&done_allocate);
@@ -1412,6 +1506,21 @@ void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
__ Pop(rbx);
}
__ jmp(&done_allocate);
+
+ // Fallback to the runtime to create new object.
+ __ bind(&rt_call);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(rbx);
+ __ Push(rdi);
+ __ Push(rdi); // constructor function
+ __ Push(rdx); // original constructor
+ __ CallRuntime(Runtime::kNewObject, 2);
+ __ Pop(rdi);
+ __ Pop(rbx);
+ }
+ __ movp(FieldOperand(rax, JSValue::kValueOffset), rbx);
+ __ Ret();
}
}
@@ -1612,75 +1721,92 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// static
-void Builtins::Generate_CallFunction(MacroAssembler* masm) {
+void Builtins::Generate_CallFunction(MacroAssembler* masm,
+ ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the function to call (checked to be a JSFunction)
// -----------------------------------
-
- Label convert, convert_global_proxy, convert_to_object, done_convert;
StackArgumentsAccessor args(rsp, rax);
__ AssertFunction(rdi);
- // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal
- // slot is "classConstructor".
+
+ // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
+ // Check that the function is not a "classConstructor".
+ Label class_constructor;
+ __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ testb(FieldOperand(rdx, SharedFunctionInfo::kFunctionKindByteOffset),
+ Immediate(SharedFunctionInfo::kClassConstructorBitsWithinByte));
+ __ j(not_zero, &class_constructor);
+
+ // ----------- S t a t e -------------
+ // -- rax : the number of arguments (not including the receiver)
+ // -- rdx : the shared function info.
+ // -- rdi : the function to call (checked to be a JSFunction)
+ // -----------------------------------
+
// Enter the context of the function; ToObject has to run in the function
// context, and we also need to take the global proxy from the function
// context in case of conversion.
- // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
SharedFunctionInfo::kStrictModeByteOffset);
__ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
- __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
// We need to convert the receiver for non-native sloppy mode functions.
+ Label done_convert;
__ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
Immediate((1 << SharedFunctionInfo::kNativeBitWithinByte) |
(1 << SharedFunctionInfo::kStrictModeBitWithinByte)));
__ j(not_zero, &done_convert);
{
- __ movp(rcx, args.GetReceiverOperand());
-
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
- // -- rcx : the receiver
// -- rdx : the shared function info.
// -- rdi : the function to call (checked to be a JSFunction)
// -- rsi : the function context.
// -----------------------------------
- Label convert_receiver;
- __ JumpIfSmi(rcx, &convert_to_object, Label::kNear);
- STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- __ CmpObjectType(rcx, FIRST_JS_RECEIVER_TYPE, rbx);
- __ j(above_equal, &done_convert);
- __ JumpIfRoot(rcx, Heap::kUndefinedValueRootIndex, &convert_global_proxy,
- Label::kNear);
- __ JumpIfNotRoot(rcx, Heap::kNullValueRootIndex, &convert_to_object,
- Label::kNear);
- __ bind(&convert_global_proxy);
- {
+ if (mode == ConvertReceiverMode::kNullOrUndefined) {
// Patch receiver to global proxy.
__ LoadGlobalProxy(rcx);
+ } else {
+ Label convert_to_object, convert_receiver;
+ __ movp(rcx, args.GetReceiverOperand());
+ __ JumpIfSmi(rcx, &convert_to_object, Label::kNear);
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
+ __ CmpObjectType(rcx, FIRST_JS_RECEIVER_TYPE, rbx);
+ __ j(above_equal, &done_convert);
+ if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
+ Label convert_global_proxy;
+ __ JumpIfRoot(rcx, Heap::kUndefinedValueRootIndex,
+ &convert_global_proxy, Label::kNear);
+ __ JumpIfNotRoot(rcx, Heap::kNullValueRootIndex, &convert_to_object,
+ Label::kNear);
+ __ bind(&convert_global_proxy);
+ {
+ // Patch receiver to global proxy.
+ __ LoadGlobalProxy(rcx);
+ }
+ __ jmp(&convert_receiver);
+ }
+ __ bind(&convert_to_object);
+ {
+ // Convert receiver using ToObject.
+ // TODO(bmeurer): Inline the allocation here to avoid building the frame
+ // in the fast case? (fall back to AllocateInNewSpace?)
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Integer32ToSmi(rax, rax);
+ __ Push(rax);
+ __ Push(rdi);
+ __ movp(rax, rcx);
+ ToObjectStub stub(masm->isolate());
+ __ CallStub(&stub);
+ __ movp(rcx, rax);
+ __ Pop(rdi);
+ __ Pop(rax);
+ __ SmiToInteger32(rax, rax);
+ }
+ __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ bind(&convert_receiver);
}
- __ jmp(&convert_receiver);
- __ bind(&convert_to_object);
- {
- // Convert receiver using ToObject.
- // TODO(bmeurer): Inline the allocation here to avoid building the frame
- // in the fast case? (fall back to AllocateInNewSpace?)
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ Integer32ToSmi(rax, rax);
- __ Push(rax);
- __ Push(rdi);
- __ movp(rax, rcx);
- ToObjectStub stub(masm->isolate());
- __ CallStub(&stub);
- __ movp(rcx, rax);
- __ Pop(rdi);
- __ Pop(rax);
- __ SmiToInteger32(rax, rax);
- }
- __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
- __ bind(&convert_receiver);
__ movp(args.GetReceiverOperand(), rcx);
}
__ bind(&done_convert);
@@ -1698,11 +1824,18 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm) {
ParameterCount actual(rax);
ParameterCount expected(rbx);
__ InvokeCode(rdx, expected, actual, JUMP_FUNCTION, NullCallWrapper());
+
+ // The function is a "classConstructor", need to raise an exception.
+ __ bind(&class_constructor);
+ {
+ FrameScope frame(masm, StackFrame::INTERNAL);
+ __ CallRuntime(Runtime::kThrowConstructorNonCallableError, 0);
+ }
}
// static
-void Builtins::Generate_Call(MacroAssembler* masm) {
+void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the target to call (can be any Object)
@@ -1713,7 +1846,7 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
__ JumpIfSmi(rdi, &non_callable);
__ bind(&non_smi);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
- __ j(equal, masm->isolate()->builtins()->CallFunction(),
+ __ j(equal, masm->isolate()->builtins()->CallFunction(mode),
RelocInfo::CODE_TARGET);
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
__ j(not_equal, &non_function);
@@ -1735,7 +1868,9 @@ void Builtins::Generate_Call(MacroAssembler* masm) {
__ movp(args.GetReceiverOperand(), rdi);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi);
- __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+ __ Jump(masm->isolate()->builtins()->CallFunction(
+ ConvertReceiverMode::kNotNullOrUndefined),
+ RelocInfo::CODE_TARGET);
// 3. Call to something that is not callable.
__ bind(&non_callable);
@@ -1832,41 +1967,6 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
}
-// static
-void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) {
- // ----------- S t a t e -------------
- // -- rax : the number of arguments (not including the receiver)
- // -- rbx : the address of the first argument to be pushed. Subsequent
- // arguments should be consecutive above this, in the same order as
- // they are to be pushed onto the stack.
- // -- rdi : the target to call (can be any Object).
-
- // Pop return address to allow tail-call after pushing arguments.
- __ Pop(rdx);
-
- // Find the address of the last argument.
- __ movp(rcx, rax);
- __ addp(rcx, Immediate(1)); // Add one for receiver.
- __ shlp(rcx, Immediate(kPointerSizeLog2));
- __ negp(rcx);
- __ addp(rcx, rbx);
-
- // Push the arguments.
- Label loop_header, loop_check;
- __ j(always, &loop_check);
- __ bind(&loop_header);
- __ Push(Operand(rbx, 0));
- __ subp(rbx, Immediate(kPointerSize));
- __ bind(&loop_check);
- __ cmpp(rbx, rcx);
- __ j(greater, &loop_header, Label::kNear);
-
- // Call the target.
- __ Push(rdx); // Re-push return address.
- __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
-}
-
-
void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
// Lookup the function in the JavaScript frame.
__ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));