diff options
Diffstat (limited to 'deps/v8/src/x64/builtins-x64.cc')
-rw-r--r-- | deps/v8/src/x64/builtins-x64.cc | 314 |
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)); |