diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index 90ca2005a2..35037d71fa 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -3024,9 +3024,9 @@ void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) { &if_true, &if_false, &fall_through); __ JumpIfSmi(eax, if_false); - __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); + __ CmpObjectType(eax, FIRST_FUNCTION_TYPE, ebx); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Split(equal, if_true, if_false, fall_through); + Split(above_equal, if_true, if_false, fall_through); context()->Plug(if_true, if_false); } diff --git a/src/x87/builtins-x87.cc b/src/x87/builtins-x87.cc old mode 100755 new mode 100644 index d5d5274aa1..88733e14dc --- a/src/x87/builtins-x87.cc +++ b/src/x87/builtins-x87.cc @@ -1773,6 +1773,117 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, } +namespace { + +void Generate_PushBoundArguments(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- edx : new.target (only in case of [[Construct]]) + // -- edi : target (checked to be a JSBoundFunction) + // ----------------------------------- + + // Load [[BoundArguments]] into ecx and length of that into ebx. + Label no_bound_arguments; + __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); + __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); + __ SmiUntag(ebx); + __ test(ebx, ebx); + __ j(zero, &no_bound_arguments); + { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- edx : new.target (only in case of [[Construct]]) + // -- edi : target (checked to be a JSBoundFunction) + // -- ecx : the [[BoundArguments]] (implemented as FixedArray) + // -- ebx : the number of [[BoundArguments]] + // ----------------------------------- + + // Reserve stack space for the [[BoundArguments]]. + { + Label done; + __ lea(ecx, Operand(ebx, times_pointer_size, 0)); + __ sub(esp, ecx); + // Check the stack for overflow. We are not trying to catch interruptions + // (i.e. debug break and preemption) here, so check the "real stack + // limit". + __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex); + __ j(greater, &done, Label::kNear); // Signed comparison. + // Restore the stack pointer. + __ lea(esp, Operand(esp, ebx, times_pointer_size, 0)); + { + FrameScope scope(masm, StackFrame::MANUAL); + __ EnterFrame(StackFrame::INTERNAL); + __ CallRuntime(Runtime::kThrowStackOverflow, 0); + } + __ bind(&done); + } + + // Adjust effective number of arguments to include return address. + __ inc(eax); + + // Relocate arguments and return address down the stack. + { + Label loop; + __ Set(ecx, 0); + __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0)); + __ bind(&loop); + __ fld_s(Operand(ebx, ecx, times_pointer_size, 0)); + __ fstp_s(Operand(esp, ecx, times_pointer_size, 0)); + __ inc(ecx); + __ cmp(ecx, eax); + __ j(less, &loop); + } + + // Copy [[BoundArguments]] to the stack (below the arguments). + { + Label loop; + __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); + __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); + __ SmiUntag(ebx); + __ bind(&loop); + __ dec(ebx); + __ fld_s( + FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize)); + __ fstp_s(Operand(esp, eax, times_pointer_size, 0)); + __ lea(eax, Operand(eax, 1)); + __ j(greater, &loop); + } + + // Adjust effective number of arguments (eax contains the number of + // arguments from the call plus return address plus the number of + // [[BoundArguments]]), so we need to subtract one for the return address. + __ dec(eax); + } + __ bind(&no_bound_arguments); +} + +} // namespace + + +// static +void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- edi : the function to call (checked to be a JSBoundFunction) + // ----------------------------------- + __ AssertBoundFunction(edi); + + // Patch the receiver to [[BoundThis]]. + __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset)); + __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx); + + // Push the [[BoundArguments]] onto the stack. + Generate_PushBoundArguments(masm); + + // Call the [[BoundTargetFunction]] via the Call builtin. + __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); + __ mov(ecx, Operand::StaticVariable(ExternalReference( + Builtins::kCall_ReceiverIsAny, masm->isolate()))); + __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); + __ jmp(ecx); +} + + // static void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { // ----------- S t a t e ------------- @@ -1786,6 +1897,9 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); __ j(equal, masm->isolate()->builtins()->CallFunction(mode), RelocInfo::CODE_TARGET); + __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); + __ j(equal, masm->isolate()->builtins()->CallBoundFunction(), + RelocInfo::CODE_TARGET); __ CmpInstanceType(ecx, JS_PROXY_TYPE); __ j(not_equal, &non_function); @@ -1846,6 +1960,36 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { } +// static +void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- eax : the number of arguments (not including the receiver) + // -- edx : the new target (checked to be a constructor) + // -- edi : the constructor to call (checked to be a JSBoundFunction) + // ----------------------------------- + __ AssertBoundFunction(edi); + + // Push the [[BoundArguments]] onto the stack. + Generate_PushBoundArguments(masm); + + // Patch new.target to [[BoundTargetFunction]] if new.target equals target. + { + Label done; + __ cmp(edi, edx); + __ j(not_equal, &done, Label::kNear); + __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); + __ bind(&done); + } + + // Construct the [[BoundTargetFunction]] via the Construct builtin. + __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); + __ mov(ecx, Operand::StaticVariable( + ExternalReference(Builtins::kConstruct, masm->isolate()))); + __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); + __ jmp(ecx); +} + + // static void Builtins::Generate_ConstructProxy(MacroAssembler* masm) { // ----------- S t a t e ------------- @@ -1890,6 +2034,12 @@ void Builtins::Generate_Construct(MacroAssembler* masm) { __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); __ j(zero, &non_constructor, Label::kNear); + // Only dispatch to bound functions after checking whether they are + // constructors. + __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); + __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(), + RelocInfo::CODE_TARGET); + // Only dispatch to proxies after checking whether they are constructors. __ CmpInstanceType(ecx, JS_PROXY_TYPE); __ j(equal, masm->isolate()->builtins()->ConstructProxy(), diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index fc10a9b995..cc5387a4ff 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -2269,14 +2269,6 @@ void InstanceOfStub::Generate(MacroAssembler* masm) { static_cast(1 << Map::kHasNonInstancePrototype)); __ j(not_zero, &slow_case); - // Ensure that {function} is not bound. - Register const shared_info = scratch; - __ mov(shared_info, - FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); - __ BooleanBitTest(shared_info, SharedFunctionInfo::kCompilerHintsOffset, - SharedFunctionInfo::kBoundFunction); - __ j(not_zero, &slow_case); - // Get the "prototype" (or initial map) of the {function}. __ mov(function_prototype, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); diff --git a/src/x87/macro-assembler-x87.cc b/src/x87/macro-assembler-x87.cc index b16d44bdc5..b297e316f2 100644 --- a/src/x87/macro-assembler-x87.cc +++ b/src/x87/macro-assembler-x87.cc @@ -793,6 +793,18 @@ void MacroAssembler::AssertFunction(Register object) { } +void MacroAssembler::AssertBoundFunction(Register object) { + if (emit_debug_code()) { + test(object, Immediate(kSmiTagMask)); + Check(not_equal, kOperandIsASmiAndNotABoundFunction); + Push(object); + CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); + Pop(object); + Check(equal, kOperandIsNotABoundFunction); + } +} + + void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) { if (emit_debug_code()) { Label done_checking; diff --git a/src/x87/macro-assembler-x87.h b/src/x87/macro-assembler-x87.h index dfd63a6e8a..5a6bc7abff 100644 --- a/src/x87/macro-assembler-x87.h +++ b/src/x87/macro-assembler-x87.h @@ -513,6 +513,10 @@ class MacroAssembler: public Assembler { // Abort execution if argument is not a JSFunction, enabled via --debug-code. void AssertFunction(Register object); + // Abort execution if argument is not a JSBoundFunction, + // enabled via --debug-code. + void AssertBoundFunction(Register object); + // Abort execution if argument is not undefined or an AllocationSite, enabled // via --debug-code. void AssertUndefinedOrAllocationSite(Register object);