diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index e31d2e1d8a..7807d8a31c 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1854,6 +1854,14 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { } +LInstruction* LChunkBuilder::DoLoadFunctionPrototype( + HLoadFunctionPrototype* instr) { + return AssignEnvironment(DefineAsRegister( + new LLoadFunctionPrototype(UseRegister(instr->function()), + TempRegister()))); +} + + LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); return DefineSameAsFirst(new LLoadElements(input)); diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 41209c67d5..a0b18a5db8 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -127,6 +127,7 @@ class Translation; // LIsSmiAndBranch // LLoadNamedField // LLoadNamedGeneric +// LLoadFunctionPrototype // LNumberTagD // LNumberTagI // LPushArgument @@ -223,6 +224,7 @@ class Translation; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -1256,6 +1258,22 @@ class LLoadNamedGeneric: public LUnaryOperation { }; +class LLoadFunctionPrototype: public LUnaryOperation { + public: + LLoadFunctionPrototype(LOperand* function, LOperand* temporary) + : LUnaryOperation(function), temporary_(temporary) { } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") + DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) + + LOperand* function() const { return input(); } + LOperand* temporary() const { return temporary_; } + + private: + LOperand* temporary_; +}; + + class LLoadElements: public LUnaryOperation { public: explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index dfc48917da..6b75073923 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1447,6 +1447,50 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { } +void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { + Register function = ToRegister(instr->function()); + Register temp = ToRegister(instr->temporary()); + Register result = ToRegister(instr->result()); + + // Check that the function really is a function. Load map into the + // result register. + __ CompareObjectType(function, result, temp, JS_FUNCTION_TYPE); + DeoptimizeIf(ne, instr->environment()); + + // Make sure that the function has an instance prototype. + Label non_instance; + __ ldrb(temp, FieldMemOperand(result, Map::kBitFieldOffset)); + __ tst(temp, Operand(1 << Map::kHasNonInstancePrototype)); + __ b(ne, &non_instance); + + // Get the prototype or initial map from the function. + __ ldr(result, + FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); + + // Check that the function has a prototype or an initial map. + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(result, ip); + DeoptimizeIf(eq, instr->environment()); + + // If the function does not have an initial map, we're done. + Label done; + __ CompareObjectType(result, temp, temp, MAP_TYPE); + __ b(ne, &done); + + // Get the prototype from the initial map. + __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); + __ jmp(&done); + + // Non-instance prototype: Fetch prototype from constructor field + // in initial map. + __ bind(&non_instance); + __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); + + // All done. + __ bind(&done); +} + + void LCodeGen::DoLoadElements(LLoadElements* instr) { Abort("DoLoadElements unimplemented."); } diff --git a/src/ast.cc b/src/ast.cc index 895ab67713..1a6e7681cf 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -517,6 +517,9 @@ void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { if (key()->IsPropertyName()) { if (oracle->LoadIsBuiltin(this, Builtins::LoadIC_ArrayLength)) { is_array_length_ = true; + } else if (oracle->LoadIsBuiltin(this, + Builtins::LoadIC_FunctionPrototype)) { + is_function_prototype_ = true; } else { Literal* lit_key = key()->AsLiteral(); ASSERT(lit_key != NULL && lit_key->handle()->IsString()); diff --git a/src/ast.h b/src/ast.h index 0e821de876..ba422fdaf3 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1208,6 +1208,7 @@ class Property: public Expression { is_monomorphic_(false), receiver_types_(NULL), is_array_length_(false), + is_function_prototype_(false), is_arguments_access_(false) { } DECLARE_NODE_TYPE(Property) @@ -1220,6 +1221,8 @@ class Property: public Expression { int position() const { return pos_; } bool is_synthetic() const { return type_ == SYNTHETIC; } + bool IsFunctionPrototype() const { return is_function_prototype_; } + // Marks that this is actually an argument rewritten to a keyed property // accessing the argument through the arguments shadow object. void set_is_arguments_access(bool is_arguments_access) { @@ -1249,6 +1252,7 @@ class Property: public Expression { bool is_monomorphic_; ZoneMapList* receiver_types_; bool is_array_length_; + bool is_function_prototype_; bool is_arguments_access_; Handle monomorphic_receiver_type_; diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index cbbe8fcc88..537e5c493a 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -76,7 +76,6 @@ class LChunkBuilder; // HLoadKeyed // HLoadKeyedFastElement // HLoadKeyedGeneric -// HLoadNamedGeneric // HPower // HStoreNamed // HStoreNamedField @@ -132,6 +131,8 @@ class LChunkBuilder; // HLoadElements // HTypeofIs // HLoadNamedField +// HLoadNamedGeneric +// HLoadFunctionPrototype // HPushArgument // HTypeof // HUnaryMathOperation @@ -221,6 +222,7 @@ class LChunkBuilder; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -256,6 +258,7 @@ class LChunkBuilder; V(GlobalVars) \ V(Maps) \ V(ArrayLengths) \ + V(FunctionPrototypes) \ V(OsrEntries) #define DECLARE_INSTRUCTION(type) \ @@ -2617,6 +2620,27 @@ class HLoadNamedGeneric: public HUnaryOperation { }; +class HLoadFunctionPrototype: public HUnaryOperation { + public: + explicit HLoadFunctionPrototype(HValue* function) + : HUnaryOperation(function) { + set_representation(Representation::Tagged()); + SetFlagMask(kDependsOnFunctionPrototypes); + } + + HValue* function() const { return OperandAt(0); } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load_function_prototype") + + protected: + virtual bool DataEquals(HValue* other) const { return true; } +}; + + class HLoadKeyed: public HBinaryOperation { public: HLoadKeyed(HValue* obj, HValue* key) : HBinaryOperation(obj, key) { diff --git a/src/hydrogen.cc b/src/hydrogen.cc index e34acd67d4..87cc43a05b 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -3722,6 +3722,11 @@ void HGraphBuilder::VisitProperty(Property* expr) { AddInstruction(new HCheckNonSmi(array)); instr = new HArrayLength(array); + } else if (expr->IsFunctionPrototype()) { + HValue* function = Pop(); + AddInstruction(new HCheckNonSmi(function)); + instr = new HLoadFunctionPrototype(function); + } else if (expr->key()->IsPropertyName()) { Handle name = expr->key()->AsLiteral()->AsPropertyName(); ZoneMapList* types = expr->GetReceiverTypes(); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 2d5cd0f197..194585ea31 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1837,6 +1837,48 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { } +void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { + Register function = ToRegister(instr->function()); + Register temp = ToRegister(instr->temporary()); + Register result = ToRegister(instr->result()); + + // Check that the function really is a function. + __ CmpObjectType(function, JS_FUNCTION_TYPE, result); + DeoptimizeIf(not_equal, instr->environment()); + + // Check whether the function has an instance prototype. + NearLabel non_instance; + __ test_b(FieldOperand(result, Map::kBitFieldOffset), + 1 << Map::kHasNonInstancePrototype); + __ j(not_zero, &non_instance); + + // Get the prototype or initial map from the function. + __ mov(result, + FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); + + // Check that the function has a prototype or an initial map. + __ cmp(Operand(result), Immediate(Factory::the_hole_value())); + DeoptimizeIf(equal, instr->environment()); + + // If the function does not have an initial map, we're done. + NearLabel done; + __ CmpObjectType(result, MAP_TYPE, temp); + __ j(not_equal, &done); + + // Get the prototype from the initial map. + __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); + __ jmp(&done); + + // Non-instance prototype: Fetch prototype from constructor field + // in the function's map. + __ bind(&non_instance); + __ mov(result, FieldOperand(result, Map::kConstructorOffset)); + + // All done. + __ bind(&done); +} + + void LCodeGen::DoLoadElements(LLoadElements* instr) { ASSERT(instr->result()->Equals(instr->input())); Register reg = ToRegister(instr->input()); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 3b272d0b02..dede470135 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1860,6 +1860,14 @@ LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { } +LInstruction* LChunkBuilder::DoLoadFunctionPrototype( + HLoadFunctionPrototype* instr) { + return AssignEnvironment(DefineAsRegister( + new LLoadFunctionPrototype(UseRegister(instr->function()), + TempRegister()))); +} + + LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { LOperand* input = UseRegisterAtStart(instr->value()); return DefineSameAsFirst(new LLoadElements(input)); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 3f48e50e22..efd4ab5513 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -130,6 +130,7 @@ class LGapNode; // LIsSmiAndBranch // LLoadNamedField // LLoadNamedGeneric +// LLoadFunctionPrototype // LNumberTagD // LNumberTagI // LPushArgument @@ -226,6 +227,7 @@ class LGapNode; V(LoadKeyedGeneric) \ V(LoadNamedField) \ V(LoadNamedGeneric) \ + V(LoadFunctionPrototype) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -1271,6 +1273,22 @@ class LLoadNamedGeneric: public LUnaryOperation { }; +class LLoadFunctionPrototype: public LUnaryOperation { + public: + LLoadFunctionPrototype(LOperand* function, LOperand* temporary) + : LUnaryOperation(function), temporary_(temporary) { } + + DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") + DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) + + LOperand* function() const { return input(); } + LOperand* temporary() const { return temporary_; } + + private: + LOperand* temporary_; +}; + + class LLoadElements: public LUnaryOperation { public: explicit LLoadElements(LOperand* obj) : LUnaryOperation(obj) { }