Support load function prototype in hydrogen/lithium.
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Dec 2010 15:43:32 +0000 (15:43 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Dec 2010 15:43:32 +0000 (15:43 +0000)
Review URL: http://codereview.chromium.org/6009005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/ast.cc
src/ast.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h

index e31d2e1..7807d8a 100644 (file)
@@ -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));
index 41209c6..a0b18a5 100644 (file)
@@ -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) { }
index dfc4891..6b75073 100644 (file)
@@ -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.");
 }
index 895ab67..1a6e768 100644 (file)
@@ -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());
index 0e821de..ba422fd 100644 (file)
--- 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<Map> monomorphic_receiver_type_;
 
index cbbe8fc..537e5c4 100644 (file)
@@ -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) {
index e34acd6..87cc43a 100644 (file)
@@ -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<String> name = expr->key()->AsLiteral()->AsPropertyName();
     ZoneMapList* types = expr->GetReceiverTypes();
index 2d5cd0f..194585e 100644 (file)
@@ -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());
index 3b272d0..dede470 100644 (file)
@@ -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));
index 3f48e50..efd4ab5 100644 (file)
@@ -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) { }