diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 1a9262d025..29a176628e 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -549,6 +549,7 @@ class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 0> { } DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") + DECLARE_HYDROGEN_ACCESSOR(WrapReceiver) LOperand* receiver() { return inputs_[0]; } LOperand* function() { return inputs_[1]; } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 7a4893658f..0433a26200 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -3429,19 +3429,21 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { // passed unchanged to builtins and strict-mode functions. Label global_object, result_in_receiver; - // Do not transform the receiver to object for strict mode - // functions. - __ ldr(scratch, - FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(scratch, - FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset)); - __ tst(scratch, - Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize))); - __ b(ne, &result_in_receiver); + if (!instr->hydrogen()->known_function()) { + // Do not transform the receiver to object for strict mode + // functions. + __ ldr(scratch, + FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); + __ ldr(scratch, + FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset)); + int mask = 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize); + __ tst(scratch, Operand(mask)); + __ b(ne, &result_in_receiver); - // Do not transform the receiver to object for builtins. - __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); - __ b(ne, &result_in_receiver); + // Do not transform the receiver to object for builtins. + __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); + __ b(ne, &result_in_receiver); + } // Normal function. Replace undefined or null with global receiver. __ LoadRoot(scratch, Heap::kNullValueRootIndex); @@ -3456,8 +3458,8 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { DeoptimizeIf(eq, instr->environment()); __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE); DeoptimizeIf(lt, instr->environment()); - __ b(&result_in_receiver); + __ b(&result_in_receiver); __ bind(&global_object); __ ldr(result, FieldMemOperand(function, JSFunction::kContextOffset)); __ ldr(result, diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 64a1c0b75d..ebbd287fc4 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -3692,6 +3692,8 @@ class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> { public: DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); + virtual bool DataEquals(HValue* other) V8_OVERRIDE { return true; } + virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { return Representation::Tagged(); } @@ -3702,15 +3704,21 @@ class HWrapReceiver V8_FINAL : public HTemplateInstruction<2> { virtual HValue* Canonicalize() V8_OVERRIDE; virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; + bool known_function() const { return known_function_; } DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) private: HWrapReceiver(HValue* receiver, HValue* function) { + known_function_ = function->IsConstant() && + HConstant::cast(function)->handle(function->isolate())->IsJSFunction(); set_representation(Representation::Tagged()); SetOperandAt(0, receiver); SetOperandAt(1, function); + SetFlag(kUseGVN); } + + bool known_function_; }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 3c7bf5064b..78a703b565 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -1287,6 +1287,13 @@ HValue* HGraphBuilder::BuildCheckString(HValue* string) { HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { if (object->type().IsJSObject()) return object; + if (function->IsConstant() && + HConstant::cast(function)->handle(isolate())->IsJSFunction()) { + Handle f = Handle::cast( + HConstant::cast(function)->handle(isolate())); + SharedFunctionInfo* shared = f->shared(); + if (!shared->is_classic_mode() || shared->native()) return object; + } return Add(object, function); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 49e3da5639..552b4f586d 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -3581,26 +3581,28 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { Register receiver = ToRegister(instr->receiver()); Register function = ToRegister(instr->function()); - Register scratch = ToRegister(instr->temp()); // If the receiver is null or undefined, we have to pass the global // object as a receiver to normal functions. Values have to be // passed unchanged to builtins and strict-mode functions. Label receiver_ok, global_object; Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; + Register scratch = ToRegister(instr->temp()); - // Do not transform the receiver to object for strict mode - // functions. - __ mov(scratch, - FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); - __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), - 1 << SharedFunctionInfo::kStrictModeBitWithinByte); - __ j(not_equal, &receiver_ok, dist); + if (!instr->hydrogen()->known_function()) { + // Do not transform the receiver to object for strict mode + // functions. + __ mov(scratch, + FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); + __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), + 1 << SharedFunctionInfo::kStrictModeBitWithinByte); + __ j(not_equal, &receiver_ok, dist); - // Do not transform the receiver to object for builtins. - __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), - 1 << SharedFunctionInfo::kNativeBitWithinByte); - __ j(not_equal, &receiver_ok, dist); + // Do not transform the receiver to object for builtins. + __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), + 1 << SharedFunctionInfo::kNativeBitWithinByte); + __ j(not_equal, &receiver_ok, dist); + } // Normal function. Replace undefined or null with global receiver. __ cmp(receiver, factory()->null_value()); @@ -3613,14 +3615,14 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { DeoptimizeIf(equal, instr->environment()); __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch); DeoptimizeIf(below, instr->environment()); - __ jmp(&receiver_ok, Label::kNear); + __ jmp(&receiver_ok, Label::kNear); __ bind(&global_object); __ mov(receiver, FieldOperand(function, JSFunction::kContextOffset)); - __ mov(receiver, - Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ mov(receiver, FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset)); - + const int global_offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); + __ mov(receiver, Operand(receiver, global_offset)); + const int receiver_offset = GlobalObject::kGlobalReceiverOffset; + __ mov(receiver, FieldOperand(receiver, receiver_offset)); __ bind(&receiver_ok); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 8ec520321e..811700a544 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -565,6 +565,7 @@ class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 1> { LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") + DECLARE_HYDROGEN_ACCESSOR(WrapReceiver) }; diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 1cd2d75249..0c039c54ee 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3161,20 +3161,22 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { Label global_object, receiver_ok; Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; - // Do not transform the receiver to object for strict mode - // functions. - __ movp(kScratchRegister, - FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); - __ testb(FieldOperand(kScratchRegister, - SharedFunctionInfo::kStrictModeByteOffset), - Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); - __ j(not_equal, &receiver_ok, dist); + if (!instr->hydrogen()->known_function()) { + // Do not transform the receiver to object for strict mode + // functions. + __ movp(kScratchRegister, + FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); + __ testb(FieldOperand(kScratchRegister, + SharedFunctionInfo::kStrictModeByteOffset), + Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); + __ j(not_equal, &receiver_ok, dist); - // Do not transform the receiver to object for builtins. - __ testb(FieldOperand(kScratchRegister, - SharedFunctionInfo::kNativeByteOffset), - Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); - __ j(not_equal, &receiver_ok, dist); + // Do not transform the receiver to object for builtins. + __ testb(FieldOperand(kScratchRegister, + SharedFunctionInfo::kNativeByteOffset), + Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); + __ j(not_equal, &receiver_ok, dist); + } // Normal function. Replace undefined or null with global receiver. __ CompareRoot(receiver, Heap::kNullValueRootIndex); @@ -3187,14 +3189,16 @@ void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { DeoptimizeIf(is_smi, instr->environment()); __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); DeoptimizeIf(below, instr->environment()); - __ jmp(&receiver_ok, Label::kNear); + __ jmp(&receiver_ok, Label::kNear); __ bind(&global_object); __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset)); __ movp(receiver, - Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); + Operand(receiver, + Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); __ movp(receiver, FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset)); + __ bind(&receiver_ok); } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index ca187a183d..cfaed15077 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -552,6 +552,7 @@ class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 0> { LOperand* function() { return inputs_[1]; } DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver") + DECLARE_HYDROGEN_ACCESSOR(WrapReceiver) };