| Index: src/x64/code-stubs-x64.cc
|
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
|
| index f7bd9b6a31005bfe6f879eab5a928ffaa6ede4bd..5025b644a943e2872ed0e438e6bda22e8e7bd419 100644
|
| --- a/src/x64/code-stubs-x64.cc
|
| +++ b/src/x64/code-stubs-x64.cc
|
| @@ -5025,6 +5025,170 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| +// Updates holder to the correct api holder. info is preserved.
|
| +static void SignatureCheck(MacroAssembler* masm, Register holder, Register info,
|
| + Register scratch_0, Register scratch_1,
|
| + Register scratch_2, Label* illegal_receiver) {
|
| + Register signature = scratch_0;
|
| + Register map = scratch_1;
|
| + __ movp(signature,
|
| + FieldOperand(info, FunctionTemplateInfo::kSignatureOffset));
|
| + __ movp(map, FieldOperand(holder, HeapObject::kMapOffset));
|
| +
|
| + // Loop over hidden prototype chain.
|
| + Label prototype_chain_loop, prototype_chain_loop_next, legal_receiver;
|
| + __ bind(&prototype_chain_loop);
|
| +
|
| + // Verify signature for current map.
|
| + Register cons = scratch_2;
|
| + // Requires a constructor of type jsfunction.
|
| + __ movp(cons, FieldOperand(map, Map::kConstructorOffset));
|
| + __ CompareRoot(cons, Heap::kNullValueRootIndex);
|
| + __ j(equal, &prototype_chain_loop_next, Label::kNear);
|
| +#ifdef DEBUG
|
| + {
|
| + Label expected;
|
| + // constructors should be null or js functions.
|
| + __ CmpObjectType(cons, JS_FUNCTION_TYPE, kScratchRegister);
|
| + __ j(equal, &expected);
|
| + __ int3(); // Can't call abort without a frame.
|
| + __ bind(&expected);
|
| + }
|
| +#endif
|
| + // Load shared function data for checked object.
|
| + Register type = cons;
|
| + __ movp(type, FieldOperand(cons, JSFunction::kSharedFunctionInfoOffset));
|
| + __ movp(type, FieldOperand(type, SharedFunctionInfo::kFunctionDataOffset));
|
| +
|
| + {
|
| + // Loop over function template info chain, hunting for signature.
|
| + Label function_template_loop;
|
| + __ bind(&function_template_loop);
|
| + __ cmpp(signature, type);
|
| + __ j(equal, &legal_receiver, Label::kNear);
|
| + // Requires a data of type FunctionTemplateInfo.
|
| + Condition is_smi = masm->CheckSmi(type);
|
| + __ j(is_smi, &prototype_chain_loop_next, Label::kNear);
|
| + __ CmpObjectType(type, FUNCTION_TEMPLATE_INFO_TYPE, kScratchRegister);
|
| + __ j(not_equal, &prototype_chain_loop_next, Label::kNear);
|
| + // Load parent and loop.
|
| + __ movp(type,
|
| + FieldOperand(type, FunctionTemplateInfo::kParentTemplateOffset));
|
| + __ jmp(&function_template_loop, Label::kNear);
|
| + }
|
| +
|
| + __ bind(&prototype_chain_loop_next);
|
| +
|
| + // Load next holder.
|
| + __ movp(holder, FieldOperand(map, Map::kPrototypeOffset));
|
| +
|
| + // End of prototype chain walk.
|
| + __ CompareRoot(holder, Heap::kNullValueRootIndex);
|
| + __ j(equal, illegal_receiver);
|
| +
|
| + // Load next map.
|
| + __ movp(map, FieldOperand(holder, HeapObject::kMapOffset));
|
| +
|
| + // End of prototype chain walk.
|
| + __ testb(FieldOperand(map, Map::kBitFieldOffset),
|
| + Immediate(1 << Map::kIsHiddenPrototype));
|
| + __ j(zero, illegal_receiver);
|
| +
|
| +#ifdef DEBUG
|
| + {
|
| + Label expected;
|
| + // Hidden prototypes should already be js objects.
|
| + __ CmpInstanceType(map, FIRST_JS_OBJECT_TYPE);
|
| + __ j(above_equal, &expected, Label::kNear);
|
| + __ int3(); // Can't call abort without a frame.
|
| + __ bind(&expected);
|
| + }
|
| +#endif
|
| +
|
| + // Jump up to start of signature check loop for this map.
|
| + __ jmp(&prototype_chain_loop, Label::kNear);
|
| +
|
| + // Successful exit.
|
| + __ bind(&legal_receiver);
|
| +}
|
| +
|
| +
|
| +void JSApiFunctionStub::Generate(MacroAssembler* masm) {
|
| + // ----------- S t a t e -------------
|
| + // -- rax : number of arguments excluding receiver
|
| + // -- rdi : callee
|
| + // -- rsi : context
|
| + // -- rsp[0] : return address
|
| + // -- rsp[8] : last argument
|
| + // -- ...
|
| + // -- rsp[8 * argc] : first argument (argc == rax)
|
| + // -- rsp[8 * (argc + 1)] : receiver
|
| + // -----------------------------------
|
| +
|
| + StackArgumentsAccessor args(rsp, rax);
|
| + __ movp(rcx, args.GetReceiverOperand());
|
| +
|
| + // Update receiver if this is a contextual call.
|
| + Label set_global_proxy, receiver_correct;
|
| + __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
|
| + __ j(equal, &set_global_proxy);
|
| + __ bind(&receiver_correct);
|
| +
|
| + // Load FunctionTemplateInfo.
|
| + __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
| + __ movp(rbx, FieldOperand(rbx, SharedFunctionInfo::kFunctionDataOffset));
|
| +
|
| + Label illegal_receiver;
|
| + if (has_signature()) {
|
| + // Typecheck. Update receiver with api holder.
|
| + SignatureCheck(masm, rcx, rbx, rdx, r8, r9, &illegal_receiver);
|
| + }
|
| +
|
| + if (!has_call_code()) {
|
| + // Return receiver for non c call. Pop arguments and receiver.
|
| + __ leap(rbx, Operand(rax, times_pointer_size, 1 * kPointerSize));
|
| + __ movp(rax, args.GetReceiverOperand());
|
| + __ PopReturnAddressTo(rcx);
|
| + __ addp(rsp, rbx);
|
| + __ jmp(rcx);
|
| + } else {
|
| + // c call.
|
| + __ movp(rbx, FieldOperand(rbx, FunctionTemplateInfo::kCallCodeOffset));
|
| + // Put call_data and function address in place.
|
| + __ movp(rdx, FieldOperand(rbx, CallHandlerInfo::kCallbackOffset));
|
| + __ movp(rdx, FieldOperand(rdx, Foreign::kForeignAddressOffset));
|
| + __ movp(rbx, FieldOperand(rbx, CallHandlerInfo::kDataOffset));
|
| + // Jump to stub.
|
| + // TODO(dcarney): fix abi for CallApiFunctionStub.
|
| + __ xchgp(rax, rdi); // Put callee in place. Put n_args in place.
|
| + CallApiFunctionStub stub(masm->isolate(), call_data_undefined());
|
| + __ TailCallStub(&stub);
|
| + }
|
| +
|
| + // Deferred code: Replace receiver on stack with global proxy for contextual
|
| + // calls.
|
| + __ bind(&set_global_proxy);
|
| + __ movp(rcx, GlobalObjectOperand());
|
| + __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalProxyOffset));
|
| + __ movp(args.GetReceiverOperand(), rcx);
|
| + __ jmp(&receiver_correct);
|
| +
|
| + if (!illegal_receiver.is_unused()) {
|
| + // Deferred code: Receiver does not match signature. Throw exception.
|
| + __ bind(&illegal_receiver);
|
| +
|
| + // Pop return address, arguments and receiver.
|
| + __ PopReturnAddressTo(rbx);
|
| + __ leap(rax, Operand(rax, times_pointer_size, 1 * kPointerSize));
|
| + __ addp(rsp, rax);
|
| + __ PushReturnAddressFrom(rbx);
|
| +
|
| + FrameScope frame(masm, StackFrame::INTERNAL);
|
| + __ Push(rdi);
|
| + __ TailCallRuntime(Runtime::kThrowIllegalInvocation, 1, 1);
|
| + }
|
| +}
|
| +
|
| #undef __
|
|
|
| } } // namespace v8::internal
|
|
|