Chromium Code Reviews| 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..0c8a27f29736d38f97c6ac07844ac190d2dbf6ee 100644 |
| --- a/src/x64/code-stubs-x64.cc |
| +++ b/src/x64/code-stubs-x64.cc |
| @@ -5025,6 +5025,144 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) { |
| } |
| +// Updates holder to the correct api holder. Map may be trashed. |
| +static void SignatureCheck(MacroAssembler* masm, Register map, Register holder, |
| + Register signature, Register scratch, |
| + Label* illegal_receiver) { |
| + // 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 type = scratch; |
| + // Requires a constructor of type jsfunction. |
| + __ movp(type, FieldOperand(map, Map::kConstructorOffset)); |
| + __ CmpObjectType(type, JS_FUNCTION_TYPE, kScratchRegister); |
| + __ j(not_equal, &prototype_chain_loop_next, Label::kNear); |
|
jochen (gone - plz use gerrit)
2015/01/21 12:01:39
I wonder whether we can here already jump to illeg
|
| + // Load shared function data. |
| + __ movp(type, FieldOperand(type, 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); |
| + // Requires a data of type FunctionTemplateInfo. |
| + __ CmpObjectType(type, FUNCTION_TEMPLATE_INFO_TYPE, kScratchRegister); |
| + __ j(not_equal, &prototype_chain_loop_next, Label::kNear); |
| + __ cmpp(signature, type); |
| + __ j(equal, &legal_receiver, Label::kNear); |
| + // Incorrect signature, load parent and loop. |
| + __ movp(type, |
| + FieldOperand(type, FunctionTemplateInfo::kParentTemplateOffset)); |
| + __ jmp(&function_template_loop, Label::kNear); |
| + } |
| + |
| + __ bind(&prototype_chain_loop_next); |
| + __ movp(holder, FieldOperand(map, Map::kPrototypeOffset)); |
| + |
| + // End of prototype chain walk. |
| + __ CompareRoot(holder, Heap::kNullValueRootIndex); |
| + __ j(equal, illegal_receiver); |
| + |
| + __ movp(map, FieldOperand(holder, HeapObject::kMapOffset)); |
| + // End of prototype chain walk. |
| + __ testb(FieldOperand(map, Map::kBitFieldOffset), |
| + Immediate(1 << Map::kIsHiddenPrototype)); |
| + __ j(zero, illegal_receiver); |
| + |
| + // TODO(dcarney): this check is probably unnecessary. |
| + // Requires a js object map. |
| + __ CmpInstanceType(map, FIRST_JS_OBJECT_TYPE); |
| + __ j(below, &prototype_chain_loop_next, Label::kNear); |
| + |
| + // 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)); |
| + |
| + // TODO(dcarney): CHECK that !has_call_code implies !has_signature. |
| + Label illegal_receiver; |
| + if (has_signature()) { |
| + // Typecheck. Update receiver with api holder. |
| + __ movp(r8, FieldOperand(rbx, FunctionTemplateInfo::kSignatureOffset)); |
| + __ movp(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| + SignatureCheck(masm, rdx, rcx, 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 |