Introduce FieldIndex to unify and abstract property/field offset
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 6 Jun 2014 14:05:10 +0000 (14:05 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 6 Jun 2014 14:05:10 +0000 (14:05 +0000)
R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/300283002

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

30 files changed:
src/arm/stub-cache-arm.cc
src/arm64/stub-cache-arm64.cc
src/bootstrapper.cc
src/code-stubs-hydrogen.cc
src/code-stubs.h
src/deoptimizer.cc
src/field-index-inl.h [new file with mode: 0644]
src/field-index.cc [new file with mode: 0644]
src/field-index.h [new file with mode: 0644]
src/heap-snapshot-generator.cc
src/ia32/stub-cache-ia32.cc
src/ic.cc
src/ic.h
src/json-parser.h
src/json-stringifier.h
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.cc
src/objects.h
src/property.cc
src/property.h
src/runtime.cc
src/string-stream.cc
src/stub-cache.cc
src/stub-cache.h
src/utils.h
src/x64/stub-cache-x64.cc
test/cctest/test-heap.cc
tools/gyp/v8.gyp

index c0be0762504f7df846ea001908d25384e4d6584b..5f17c9f2d8461e3f6efd0561c7adf1db4a52d77f 100644 (file)
@@ -573,12 +573,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // checks.
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
-  int index = lookup->GetFieldIndex().field_index();
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= object->map()->inobject_properties();
+  FieldIndex index = lookup->GetFieldIndex();
 
   Representation representation = lookup->representation();
   ASSERT(!representation.IsNone());
@@ -604,14 +599,12 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.
-    if (index < 0) {
-      int offset = object->map()->instance_size() + (index * kPointerSize);
-      __ ldr(scratch1, FieldMemOperand(receiver_reg, offset));
+    if (index.is_inobject()) {
+      __ ldr(scratch1, FieldMemOperand(receiver_reg, index.offset()));
     } else {
       __ ldr(scratch1,
              FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-      int offset = index * kPointerSize + FixedArray::kHeaderSize;
-      __ ldr(scratch1, FieldMemOperand(scratch1, offset));
+      __ ldr(scratch1, FieldMemOperand(scratch1, index.offset()));
     }
 
     // Store the value into the storage.
@@ -638,10 +631,9 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // TODO(verwaest): Share this code as a code stub.
   SmiCheck smi_check = representation.IsTagged()
       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
+  if (index.is_inobject()) {
     // Set the property straight into the object.
-    int offset = object->map()->instance_size() + (index * kPointerSize);
-    __ str(value_reg, FieldMemOperand(receiver_reg, offset));
+    __ str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
 
     if (!representation.IsSmi()) {
       // Skip updating write barrier if storing a smi.
@@ -651,7 +643,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
       // Pass the now unused name_reg as a scratch register.
       __ mov(name_reg, value_reg);
       __ RecordWriteField(receiver_reg,
-                          offset,
+                          index.offset(),
                           name_reg,
                           scratch1,
                           kLRHasNotBeenSaved,
@@ -661,11 +653,10 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array
     __ ldr(scratch1,
            FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ str(value_reg, FieldMemOperand(scratch1, offset));
+    __ str(value_reg, FieldMemOperand(scratch1, index.offset()));
 
     if (!representation.IsSmi()) {
       // Skip updating write barrier if storing a smi.
@@ -675,7 +666,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
       // Ok to clobber receiver_reg and name_reg, since we return.
       __ mov(name_reg, value_reg);
       __ RecordWriteField(scratch1,
-                          offset,
+                          index.offset(),
                           name_reg,
                           receiver_reg,
                           kLRHasNotBeenSaved,
@@ -1006,20 +997,14 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
 
 void LoadStubCompiler::GenerateLoadField(Register reg,
                                          Handle<JSObject> holder,
-                                         PropertyIndex field,
+                                         FieldIndex field,
                                          Representation representation) {
   if (!reg.is(receiver())) __ mov(receiver(), reg);
   if (kind() == Code::LOAD_IC) {
-    LoadFieldStub stub(isolate(),
-                       field.is_inobject(holder),
-                       field.translate(holder),
-                       representation);
+    LoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   } else {
-    KeyedLoadFieldStub stub(isolate(),
-                            field.is_inobject(holder),
-                            field.translate(holder),
-                            representation);
+    KeyedLoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   }
 }
index ae597b2a0198584d6f2d953499fcad29520daff1..b933f65f44a8d5deaefea0002032a95c8245268d 100644 (file)
@@ -522,12 +522,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // checks.
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
-  int index = lookup->GetFieldIndex().field_index();
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= object->map()->inobject_properties();
+  FieldIndex index = lookup->GetFieldIndex();
 
   Representation representation = lookup->representation();
   ASSERT(!representation.IsNone());
@@ -558,14 +553,12 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag);
 
     // Load the double storage.
-    if (index < 0) {
-      int offset = (index * kPointerSize) + object->map()->instance_size();
-      __ Ldr(scratch1, FieldMemOperand(receiver_reg, offset));
+    if (index.is_inobject()) {
+      __ Ldr(scratch1, FieldMemOperand(receiver_reg, index.offset()));
     } else {
-      int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
       __ Ldr(scratch1,
              FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-      __ Ldr(scratch1, FieldMemOperand(scratch1, offset));
+      __ Ldr(scratch1, FieldMemOperand(scratch1, index.offset()));
     }
 
     // Store the value into the storage.
@@ -589,10 +582,9 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // TODO(verwaest): Share this code as a code stub.
   SmiCheck smi_check = representation.IsTagged()
       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
+  if (index.is_inobject()) {
     // Set the property straight into the object.
-    int offset = object->map()->instance_size() + (index * kPointerSize);
-    __ Str(value_reg, FieldMemOperand(receiver_reg, offset));
+    __ Str(value_reg, FieldMemOperand(receiver_reg, index.offset()));
 
     if (!representation.IsSmi()) {
       // Skip updating write barrier if storing a smi.
@@ -602,7 +594,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
       // Pass the now unused name_reg as a scratch register.
       __ Mov(name_reg, value_reg);
       __ RecordWriteField(receiver_reg,
-                          offset,
+                          index.offset(),
                           name_reg,
                           scratch1,
                           kLRHasNotBeenSaved,
@@ -612,11 +604,10 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array
     __ Ldr(scratch1,
            FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ Str(value_reg, FieldMemOperand(scratch1, offset));
+    __ Str(value_reg, FieldMemOperand(scratch1, index.offset()));
 
     if (!representation.IsSmi()) {
       // Skip updating write barrier if storing a smi.
@@ -626,7 +617,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
       // Ok to clobber receiver_reg and name_reg, since we return.
       __ Mov(name_reg, value_reg);
       __ RecordWriteField(scratch1,
-                          offset,
+                          index.offset(),
                           name_reg,
                           receiver_reg,
                           kLRHasNotBeenSaved,
@@ -967,20 +958,14 @@ Register LoadStubCompiler::CallbackHandlerFrontend(Handle<HeapType> type,
 
 void LoadStubCompiler::GenerateLoadField(Register reg,
                                          Handle<JSObject> holder,
-                                         PropertyIndex field,
+                                         FieldIndex field,
                                          Representation representation) {
   __ Mov(receiver(), reg);
   if (kind() == Code::LOAD_IC) {
-    LoadFieldStub stub(isolate(),
-                       field.is_inobject(holder),
-                       field.translate(holder),
-                       representation);
+    LoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   } else {
-    KeyedLoadFieldStub stub(isolate(),
-                            field.is_inobject(holder),
-                            field.translate(holder),
-                            representation);
+    KeyedLoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   }
 }
index 69aff083a3787d709261601c3415b922cfe293f3..cfef267892e7f7a8970927483dba35016cb52755 100644 (file)
@@ -1145,11 +1145,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     LookupResult lookup(isolate);
     result->LookupOwn(factory->callee_string(), &lookup);
     ASSERT(lookup.IsField());
-    ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsCalleeIndex);
+    ASSERT(lookup.GetFieldIndex().property_index() ==
+           Heap::kArgumentsCalleeIndex);
 
     result->LookupOwn(factory->length_string(), &lookup);
     ASSERT(lookup.IsField());
-    ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
+    ASSERT(lookup.GetFieldIndex().property_index() ==
+           Heap::kArgumentsLengthIndex);
 
     ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex);
     ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
@@ -1245,7 +1247,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     LookupResult lookup(isolate);
     result->LookupOwn(factory->length_string(), &lookup);
     ASSERT(lookup.IsField());
-    ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
+    ASSERT(lookup.GetFieldIndex().property_index() ==
+           Heap::kArgumentsLengthIndex);
 
     ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
 
@@ -2417,7 +2420,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
         case FIELD: {
           HandleScope inner(isolate());
           Handle<Name> key = Handle<Name>(descs->GetKey(i));
-          int index = descs->GetFieldIndex(i);
+          FieldIndex index = FieldIndex::ForDescriptor(from->map(), i);
           ASSERT(!descs->GetDetails(i).representation().IsDouble());
           Handle<Object> value = Handle<Object>(from->RawFastPropertyAt(index),
                                                 isolate());
index 9e974138926d711ee4f5033364152d836d3d60a1..88e71faca9ee9dca4db2991d81117fbb8568a147 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/v8.h"
 
 #include "src/code-stubs.h"
+#include "src/field-index.h"
 #include "src/hydrogen.h"
 #include "src/lithium.h"
 
@@ -59,9 +60,7 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
   Isolate* isolate() { return info_.isolate(); }
 
   HLoadNamedField* BuildLoadNamedField(HValue* object,
-                                       Representation representation,
-                                       int offset,
-                                       bool is_inobject);
+                                       FieldIndex index);
 
   enum ArgumentClass {
     NONE,
@@ -553,14 +552,15 @@ Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
 
 
 HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField(
-    HValue* object,
-    Representation representation,
-    int offset,
-    bool is_inobject) {
-  HObjectAccess access = is_inobject
+    HValue* object, FieldIndex index) {
+  Representation representation = index.is_double()
+      ? Representation::Double()
+      : Representation::Tagged();
+  int offset = index.offset();
+  HObjectAccess access = index.is_inobject()
       ? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
       : HObjectAccess::ForBackingStoreOffset(offset, representation);
-  if (representation.IsDouble()) {
+  if (index.is_double()) {
     // Load the heap number.
     object = Add<HLoadNamedField>(
         object, static_cast<HValue*>(NULL),
@@ -574,10 +574,7 @@ HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField(
 
 template<>
 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
-  return BuildLoadNamedField(GetParameter(0),
-                             casted_stub()->representation(),
-                             casted_stub()->offset(),
-                             casted_stub()->is_inobject());
+  return BuildLoadNamedField(GetParameter(0), casted_stub()->index());
 }
 
 
@@ -588,10 +585,10 @@ Handle<Code> LoadFieldStub::GenerateCode() {
 
 template<>
 HValue* CodeStubGraphBuilder<StringLengthStub>::BuildCodeStub() {
-  HValue* string = BuildLoadNamedField(
-      GetParameter(0), Representation::Tagged(), JSValue::kValueOffset, true);
-  return BuildLoadNamedField(
-      string, Representation::Tagged(), String::kLengthOffset, true);
+  HValue* string = BuildLoadNamedField(GetParameter(0),
+      FieldIndex::ForInObjectOffset(JSValue::kValueOffset));
+  return BuildLoadNamedField(string,
+      FieldIndex::ForInObjectOffset(String::kLengthOffset));
 }
 
 
index 4a93f9920ad7409b70448c216a789864264a6ada..55d8b885c842326f219eb816289bb42e3f36c965 100644 (file)
@@ -897,11 +897,9 @@ class HandlerStub: public HICStub {
 
 class LoadFieldStub: public HandlerStub {
  public:
-  LoadFieldStub(Isolate* isolate,
-                bool inobject,
-                int index, Representation representation)
-      : HandlerStub(isolate) {
-    Initialize(Code::LOAD_IC, inobject, index, representation);
+  LoadFieldStub(Isolate* isolate, FieldIndex index)
+    : HandlerStub(isolate), index_(index) {
+    Initialize(Code::LOAD_IC);
   }
 
   virtual Handle<Code> GenerateCode() V8_OVERRIDE;
@@ -918,42 +916,30 @@ class LoadFieldStub: public HandlerStub {
     return KindBits::decode(bit_field_);
   }
 
-  bool is_inobject() {
-    return InobjectBits::decode(bit_field_);
-  }
-
-  int offset() {
-    int index = IndexBits::decode(bit_field_);
-    int offset = index * kPointerSize;
-    if (is_inobject()) return offset;
-    return FixedArray::kHeaderSize + offset;
-  }
+  FieldIndex index() const { return index_; }
 
   bool unboxed_double() {
-    return UnboxedDoubleBits::decode(bit_field_);
+    return index_.is_double();
   }
 
   virtual Code::StubType GetStubType() { return Code::FAST; }
 
  protected:
-  explicit LoadFieldStub(Isolate* isolate) : HandlerStub(isolate) { }
+  explicit LoadFieldStub(Isolate* isolate);
 
-  void Initialize(Code::Kind kind,
-                  bool inobject,
-                  int index,
-                  Representation representation) {
-    bit_field_ = KindBits::encode(kind)
-        | InobjectBits::encode(inobject)
-        | IndexBits::encode(index)
-        | UnboxedDoubleBits::encode(representation.IsDouble());
+  void Initialize(Code::Kind kind) {
+    int property_index_key = index_.GetLoadFieldStubKey();
+    // Save a copy of the essence of the property index into the bit field to
+    // make sure that hashing of unique stubs works correctly..
+    bit_field_ = KindBits::encode(kind) |
+        EncodedLoadFieldByIndexBits::encode(property_index_key);
   }
 
  private:
   STATIC_ASSERT(KindBits::kSize == 4);
-  class InobjectBits: public BitField<bool, 4, 1> {};
-  class IndexBits: public BitField<int, 5, 11> {};
-  class UnboxedDoubleBits: public BitField<bool, 16, 1> {};
+  class EncodedLoadFieldByIndexBits: public BitField<int, 4, 13> {};
   virtual CodeStub::Major MajorKey() { return LoadField; }
+  FieldIndex index_;
 };
 
 
@@ -1098,11 +1084,9 @@ class CallApiGetterStub : public PlatformCodeStub {
 
 class KeyedLoadFieldStub: public LoadFieldStub {
  public:
-  KeyedLoadFieldStub(Isolate* isolate,
-                     bool inobject,
-                     int index, Representation representation)
-      : LoadFieldStub(isolate) {
-    Initialize(Code::KEYED_LOAD_IC, inobject, index, representation);
+  KeyedLoadFieldStub(Isolate* isolate, FieldIndex index)
+      : LoadFieldStub(isolate, index) {
+    Initialize(Code::KEYED_LOAD_IC);
   }
 
   virtual void InitializeInterfaceDescriptor(
index c1df93769ee8f8ad6ec6c939cb9931fc4626073f..2b39ff6965e89a1290c03d1af0ea33c20c2c963a 100644 (file)
@@ -1841,7 +1841,8 @@ Handle<Object> Deoptimizer::MaterializeNextHeapObject() {
         object->set_elements(FixedArrayBase::cast(*elements));
         for (int i = 0; i < length - 3; ++i) {
           Handle<Object> value = MaterializeNextValue();
-          object->FastPropertyAtPut(i, *value);
+          FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
+          object->FastPropertyAtPut(index, *value);
         }
         break;
       }
@@ -3406,7 +3407,8 @@ Handle<Object> SlotRefValueBuilder::GetNext(Isolate* isolate, int lvl) {
           object->set_elements(FixedArrayBase::cast(*elements));
           for (int i = 0; i < length - 3; ++i) {
             Handle<Object> value = GetNext(isolate, lvl + 1);
-            object->FastPropertyAtPut(i, *value);
+            FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i);
+            object->FastPropertyAtPut(index, *value);
           }
           return object;
         }
diff --git a/src/field-index-inl.h b/src/field-index-inl.h
new file mode 100644 (file)
index 0000000..dd13709
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_FIELD_INDEX_INL_H_
+#define V8_FIELD_INDEX_INL_H_
+
+#include "src/field-index.h"
+
+namespace v8 {
+namespace internal {
+
+
+inline FieldIndex FieldIndex::ForInObjectOffset(int offset, Map* map) {
+  ASSERT((offset % kPointerSize) == 0);
+  int index = offset / kPointerSize;
+  if (map == NULL) {
+    return FieldIndex(true, index, false, index + 1, 0, true);
+  }
+  int first_inobject_offset = map->GetInObjectPropertyOffset(0);
+  if (offset < first_inobject_offset) {
+    return FieldIndex(true, index, false, 0, 0, true);
+  } else {
+    return FieldIndex::ForPropertyIndex(map, offset / kPointerSize);
+  }
+}
+
+
+inline FieldIndex FieldIndex::ForPropertyIndex(Map* map,
+                                               int property_index,
+                                               bool is_double) {
+  ASSERT(map->instance_type() >= FIRST_NONSTRING_TYPE);
+  int inobject_properties = map->inobject_properties();
+  bool is_inobject = property_index < inobject_properties;
+  int first_inobject_offset;
+  if (is_inobject) {
+    first_inobject_offset = map->GetInObjectPropertyOffset(0);
+  } else {
+    first_inobject_offset = FixedArray::kHeaderSize;
+    property_index -= inobject_properties;
+  }
+  return FieldIndex(is_inobject,
+                    property_index + first_inobject_offset / kPointerSize,
+                    is_double, inobject_properties, first_inobject_offset);
+}
+
+
+inline FieldIndex FieldIndex::ForLoadByFieldIndex(Map* map, int orig_index) {
+  int field_index = orig_index;
+  int is_inobject = true;
+  bool is_double = field_index & 1;
+  int first_inobject_offset = 0;
+  field_index >>= 1;
+  if (field_index < 0) {
+    field_index = -(field_index + 1);
+    is_inobject = false;
+    first_inobject_offset = FixedArray::kHeaderSize;
+    field_index += FixedArray::kHeaderSize / kPointerSize;
+  } else {
+    first_inobject_offset = map->GetInObjectPropertyOffset(0);
+    field_index += JSObject::kHeaderSize / kPointerSize;
+  }
+  return FieldIndex(is_inobject, field_index, is_double,
+                    map->inobject_properties(), first_inobject_offset);
+}
+
+
+inline FieldIndex FieldIndex::ForDescriptor(Map* map, int descriptor_index) {
+  PropertyDetails details =
+      map->instance_descriptors()->GetDetails(descriptor_index);
+  int field_index =
+      map->instance_descriptors()->GetFieldIndex(descriptor_index);
+  return ForPropertyIndex(map, field_index,
+                          details.representation().IsDouble());
+}
+
+
+} }  // namespace v8::internal
+
+#endif
diff --git a/src/field-index.cc b/src/field-index.cc
new file mode 100644 (file)
index 0000000..5392afc
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/field-index.h"
+#include "src/objects.h"
+#include "src/objects-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+FieldIndex FieldIndex::ForLookupResult(const LookupResult* lookup_result) {
+  Map* map = lookup_result->holder()->map();
+  return ForPropertyIndex(map,
+                          lookup_result->GetFieldIndexFromMap(map),
+                          lookup_result->representation().IsDouble());
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/field-index.h b/src/field-index.h
new file mode 100644 (file)
index 0000000..d770764
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_FIELD_INDEX_H_
+#define V8_FIELD_INDEX_H_
+
+#include "src/utils.h"
+#include "src/property-details.h"
+
+namespace v8 {
+namespace internal {
+
+class Map;
+
+// Wrapper class to hold a field index, usually but not necessarily generated
+// from a property index. When available, the wrapper class captures additional
+// information to allow the field index to be translated back into the property
+// index it was originally generated from.
+class FieldIndex V8_FINAL {
+ public:
+  static FieldIndex ForPropertyIndex(Map* map,
+                                     int index,
+                                     bool is_double = false);
+  static FieldIndex ForInObjectOffset(int offset, Map* map = NULL);
+  static FieldIndex ForLookupResult(const LookupResult* result);
+  static FieldIndex ForDescriptor(Map* map, int descriptor_index);
+  static FieldIndex ForLoadByFieldIndex(Map* map, int index);
+  static FieldIndex ForKeyedLookupCacheIndex(Map* map, int index) {
+    return ForPropertyIndex(map, index);
+  }
+
+  bool is_inobject() const {
+    return IsInObjectBits::decode(bit_field_);
+  }
+
+  bool is_double() const {
+    return IsDoubleBits::decode(bit_field_);
+  }
+
+  int offset() const {
+    return index() * kPointerSize;
+  }
+
+  int index() const {
+    return IndexBits::decode(bit_field_);
+  }
+
+  int outobject_array_index() const {
+    ASSERT(!is_inobject());
+    return index() - first_inobject_property_offset() / kPointerSize;
+  }
+
+  int property_index() const {
+    ASSERT(!IsHiddenField::decode(bit_field_));
+    int result = index() - first_inobject_property_offset() / kPointerSize;
+    if (!is_inobject()) {
+      result += InObjectPropertyBits::decode(bit_field_);
+    }
+    return result;
+  }
+
+  int GetLoadByFieldIndex() const {
+    // For efficiency, the LoadByFieldIndex instruction takes an index that is
+    // optimized for quick access. If the property is inline, the index is
+    // positive. If it's out-of-line, the encoded index is -raw_index - 1 to
+    // disambiguate the zero out-of-line index from the zero inobject case.
+    // The index itself is shifted up by one bit, the lower-most bit
+    // signifying if the field is a mutable double box (1) or not (0).
+    int result = index() - first_inobject_property_offset() / kPointerSize;
+    if (!is_inobject()) {
+      result = -result - 1;
+    }
+    result <<= 1;
+    return is_double() ? (result | 1) : result;
+  }
+
+  int GetKeyedLookupCacheIndex() const {
+    return property_index();
+  }
+
+  int GetLoadFieldStubKey() const {
+    return bit_field_ &
+        (IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask);
+  }
+
+ private:
+  FieldIndex(bool is_inobject, int local_index, bool is_double,
+             int inobject_properties, int first_inobject_property_offset,
+             bool is_hidden = false) {
+    ASSERT((first_inobject_property_offset & (kPointerSize - 1)) == 0);
+    bit_field_ = IsInObjectBits::encode(is_inobject) |
+      IsDoubleBits::encode(is_double) |
+      FirstInobjectPropertyOffsetBits::encode(first_inobject_property_offset) |
+      IsHiddenField::encode(is_hidden) |
+      IndexBits::encode(local_index) |
+      InObjectPropertyBits::encode(inobject_properties);
+  }
+
+  int first_inobject_property_offset() const {
+    ASSERT(!IsHiddenField::decode(bit_field_));
+    return FirstInobjectPropertyOffsetBits::decode(bit_field_);
+  }
+
+  static const int kIndexBitsSize = kDescriptorIndexBitCount + 1;
+
+  class IndexBits: public BitField<int, 0, kIndexBitsSize> {};
+  class IsInObjectBits: public BitField<bool, IndexBits::kNext, 1> {};
+  class IsDoubleBits: public BitField<bool, IsInObjectBits::kNext, 1> {};
+  class InObjectPropertyBits: public BitField<int, IsDoubleBits::kNext,
+                                              kDescriptorIndexBitCount> {};
+  class FirstInobjectPropertyOffsetBits:
+      public BitField<int, InObjectPropertyBits::kNext, 7> {};
+  class IsHiddenField:
+      public BitField<bool, FirstInobjectPropertyOffsetBits::kNext, 1> {};
+  STATIC_ASSERT(IsHiddenField::kNext <= 32);
+
+  int bit_field_;
+};
+
+} }  // namespace v8::internal
+
+#endif
index ae07f6a6ee27ea2307b788afaca2099aa158bfd4..fbc798d92192de01e924775d59a7d37eaba50611 100644 (file)
@@ -1660,7 +1660,9 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
                   js_obj->GetInObjectPropertyOffset(index));
             }
           } else {
-            Object* value = js_obj->RawFastPropertyAt(index);
+            FieldIndex field_index =
+                FieldIndex::ForDescriptor(js_obj->map(), i);
+            Object* value = js_obj->RawFastPropertyAt(field_index);
             if (k != heap_->hidden_string()) {
               SetPropertyReference(js_obj, entry, k, value);
             } else {
index 75533d1259e143cfd47c32f4e4027209d69e6183..9eb113cede43253aa7738657f86e8b74e67eb9c6 100644 (file)
@@ -661,12 +661,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // checks.
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
-  int index = lookup->GetFieldIndex().field_index();
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= object->map()->inobject_properties();
+  FieldIndex index = lookup->GetFieldIndex();
 
   Representation representation = lookup->representation();
   ASSERT(!representation.IsNone());
@@ -691,13 +686,11 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.
-    if (index < 0) {
-      int offset = object->map()->instance_size() + (index * kPointerSize);
-      __ mov(scratch1, FieldOperand(receiver_reg, offset));
+    if (index.is_inobject()) {
+      __ mov(scratch1, FieldOperand(receiver_reg, index.offset()));
     } else {
       __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-      int offset = index * kPointerSize + FixedArray::kHeaderSize;
-      __ mov(scratch1, FieldOperand(scratch1, offset));
+      __ mov(scratch1, FieldOperand(scratch1, index.offset()));
     }
 
     // Store the value into the storage.
@@ -723,17 +716,16 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // TODO(verwaest): Share this code as a code stub.
   SmiCheck smi_check = representation.IsTagged()
       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
+  if (index.is_inobject()) {
     // Set the property straight into the object.
-    int offset = object->map()->instance_size() + (index * kPointerSize);
-    __ mov(FieldOperand(receiver_reg, offset), value_reg);
+    __ mov(FieldOperand(receiver_reg, index.offset()), value_reg);
 
     if (!representation.IsSmi()) {
       // Update the write barrier for the array address.
       // Pass the value being stored in the now unused name_reg.
       __ mov(name_reg, value_reg);
       __ RecordWriteField(receiver_reg,
-                          offset,
+                          index.offset(),
                           name_reg,
                           scratch1,
                           kDontSaveFPRegs,
@@ -742,17 +734,16 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array (optimistically).
     __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ mov(FieldOperand(scratch1, offset), value_reg);
+    __ mov(FieldOperand(scratch1, index.offset()), value_reg);
 
     if (!representation.IsSmi()) {
       // Update the write barrier for the array address.
       // Pass the value being stored in the now unused name_reg.
       __ mov(name_reg, value_reg);
       __ RecordWriteField(scratch1,
-                          offset,
+                          index.offset(),
                           name_reg,
                           receiver_reg,
                           kDontSaveFPRegs,
@@ -972,20 +963,14 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
 
 void LoadStubCompiler::GenerateLoadField(Register reg,
                                          Handle<JSObject> holder,
-                                         PropertyIndex field,
+                                         FieldIndex field,
                                          Representation representation) {
   if (!reg.is(receiver())) __ mov(receiver(), reg);
   if (kind() == Code::LOAD_IC) {
-    LoadFieldStub stub(isolate(),
-                       field.is_inobject(holder),
-                       field.translate(holder),
-                       representation);
+    LoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   } else {
-    KeyedLoadFieldStub stub(isolate(),
-                            field.is_inobject(holder),
-                            field.translate(holder),
-                            representation);
+    KeyedLoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   }
 }
index 0040b1d352f2ac1a43c92a1f1f55c67dd283a50d..1a6ab41e4fdf076da121eb1dca88950540b2246b 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -838,14 +838,12 @@ Handle<Code> LoadIC::megamorphic_stub() {
 }
 
 
-Handle<Code> LoadIC::SimpleFieldLoad(int offset,
-                                     bool inobject,
-                                     Representation representation) {
+Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
   if (kind() == Code::LOAD_IC) {
-    LoadFieldStub stub(isolate(), inobject, offset, representation);
+    LoadFieldStub stub(isolate(), index);
     return stub.GetCode();
   } else {
-    KeyedLoadFieldStub stub(isolate(), inobject, offset, representation);
+    KeyedLoadFieldStub stub(isolate(), index);
     return stub.GetCode();
   }
 }
@@ -924,8 +922,8 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
                                     InlineCacheHolderFlag cache_holder) {
   if (object->IsString() &&
       String::Equals(isolate()->factory()->length_string(), name)) {
-    int length_index = String::kLengthOffset / kPointerSize;
-    return SimpleFieldLoad(length_index);
+    FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
+    return SimpleFieldLoad(index);
   }
 
   if (object->IsStringWrapper() &&
@@ -945,11 +943,9 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
 
   switch (lookup->type()) {
     case FIELD: {
-      PropertyIndex field = lookup->GetFieldIndex();
+      FieldIndex field = lookup->GetFieldIndex();
       if (object.is_identical_to(holder)) {
-        return SimpleFieldLoad(field.translate(holder),
-                               field.is_inobject(holder),
-                               lookup->representation());
+        return SimpleFieldLoad(field);
       }
       return compiler.CompileLoadField(
           type, holder, name, field, lookup->representation());
@@ -985,12 +981,15 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
       // Use simple field loads for some well-known callback properties.
       if (object->IsJSObject()) {
         Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+        Handle<Map> map(receiver->map());
         Handle<HeapType> type = IC::MapToType<HeapType>(
             handle(receiver->map()), isolate());
         int object_offset;
         if (Accessors::IsJSObjectFieldAccessor<HeapType>(
                 type, name, &object_offset)) {
-          return SimpleFieldLoad(object_offset / kPointerSize);
+          FieldIndex index = FieldIndex::ForInObjectOffset(
+              object_offset, receiver->map());
+          return SimpleFieldLoad(index);
         }
       }
 
index 5b4100abaf21cfa2cc14926d5c30dca18527c005..f3e2418ee61d2a0ce5286900be19c3dc88b61640 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -481,10 +481,7 @@ class LoadIC: public IC {
     return pre_monomorphic_stub(isolate(), extra_ic_state());
   }
 
-  Handle<Code> SimpleFieldLoad(int offset,
-                               bool inobject = true,
-                               Representation representation =
-                                    Representation::Tagged());
+  Handle<Code> SimpleFieldLoad(FieldIndex index);
 
   static void Clear(Isolate* isolate,
                     Address address,
index 7f3809d2580c672075d4f98a66b7af4a0eb4387d..60855a0a801f5c38d683ae442520ed046d79f83f 100644 (file)
@@ -414,7 +414,8 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
         int length = properties.length();
         for (int i = 0; i < length; i++) {
           Handle<Object> value = properties[i];
-          json_object->FastPropertyAtPut(i, *value);
+          FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
+          json_object->FastPropertyAtPut(index, *value);
         }
       } else {
         key = ParseJsonInternalizedString();
@@ -438,7 +439,8 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
       int length = properties.length();
       for (int i = 0; i < length; i++) {
         Handle<Object> value = properties[i];
-        json_object->FastPropertyAtPut(i, *value);
+        FieldIndex index = FieldIndex::ForPropertyIndex(*map, i);
+        json_object->FastPropertyAtPut(index, *value);
       }
     }
   }
index f6149ae36d850fc7f85a5d90c0b07b5dd14e2c77..23927b162edc09514d3cadb77efa3a604ed5fb32 100644 (file)
@@ -657,10 +657,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
       if (details.IsDontEnum()) continue;
       Handle<Object> property;
       if (details.type() == FIELD && *map == object->map()) {
-        property = Handle<Object>(
-                       object->RawFastPropertyAt(
-                           map->instance_descriptors()->GetFieldIndex(i)),
-                       isolate_);
+        property = Handle<Object>(object->RawFastPropertyAt(
+            FieldIndex::ForDescriptor(*map, i)), isolate_);
       } else {
         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
             isolate_, property,
index 762354e184586b41377857b7a16ce2e2efa4555d..877a9d51da7b1057e576ee8f1af398183d9fffd7 100644 (file)
@@ -261,8 +261,8 @@ void JSObject::JSObjectVerify() {
     for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
       if (descriptors->GetDetails(i).type() == FIELD) {
         Representation r = descriptors->GetDetails(i).representation();
-        int field = descriptors->GetFieldIndex(i);
-        Object* value = RawFastPropertyAt(field);
+        FieldIndex index = FieldIndex::ForDescriptor(map(), i);
+        Object* value = RawFastPropertyAt(index);
         if (r.IsDouble()) ASSERT(value->IsHeapNumber());
         if (value->IsUninitialized()) continue;
         if (r.IsSmi()) ASSERT(value->IsSmi());
index 5f58306ec22d41b4dd98ba8303c00b06b6c5a656..cd61ab52b92a657d66eaef1d2b759e3123584d0d 100644 (file)
@@ -17,6 +17,7 @@
 #include "src/objects.h"
 #include "src/contexts.h"
 #include "src/conversions-inl.h"
+#include "src/field-index-inl.h"
 #include "src/heap.h"
 #include "src/isolate.h"
 #include "src/heap-inl.h"
@@ -1945,29 +1946,22 @@ void JSObject::SetInternalField(int index, Smi* value) {
 // Access fast-case object properties at index. The use of these routines
 // is needed to correctly distinguish between properties stored in-object and
 // properties stored in the properties array.
-Object* JSObject::RawFastPropertyAt(int index) {
-  // Adjust for the number of properties stored in the object.
-  index -= map()->inobject_properties();
-  if (index < 0) {
-    int offset = map()->instance_size() + (index * kPointerSize);
-    return READ_FIELD(this, offset);
+Object* JSObject::RawFastPropertyAt(FieldIndex index) {
+  if (index.is_inobject()) {
+    return READ_FIELD(this, index.offset());
   } else {
-    ASSERT(index < properties()->length());
-    return properties()->get(index);
+    return properties()->get(index.outobject_array_index());
   }
 }
 
 
-void JSObject::FastPropertyAtPut(int index, Object* value) {
-  // Adjust for the number of properties stored in the object.
-  index -= map()->inobject_properties();
-  if (index < 0) {
-    int offset = map()->instance_size() + (index * kPointerSize);
+void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
+  if (index.is_inobject()) {
+    int offset = index.offset();
     WRITE_FIELD(this, offset, value);
     WRITE_BARRIER(GetHeap(), this, offset, value);
   } else {
-    ASSERT(index < properties()->length());
-    properties()->set(index, value);
+    properties()->set(index.outobject_array_index(), value);
   }
 }
 
@@ -4076,7 +4070,7 @@ int Map::pre_allocated_property_fields() {
 int Map::GetInObjectPropertyOffset(int index) {
   // Adjust for the number of properties stored in the object.
   index -= inobject_properties();
-  ASSERT(index < 0);
+  ASSERT(index <= 0);
   return instance_size() + (index * kPointerSize);
 }
 
index c51c04e3fe223e01367dcb8843405338039e9623..54a7b5532bb31e4129597de1aa916e4dca5a672f 100644 (file)
@@ -232,9 +232,9 @@ void JSObject::PrintProperties(FILE* out) {
       PrintF(out, ": ");
       switch (descs->GetType(i)) {
         case FIELD: {
-          int index = descs->GetFieldIndex(i);
+          FieldIndex index = FieldIndex::ForDescriptor(map(), i);
           RawFastPropertyAt(index)->ShortPrint(out);
-          PrintF(out, " (field at offset %d)\n", index);
+          PrintF(out, " (field at offset %d)\n", index.property_index());
           break;
         }
         case CONSTANT:
index 3f9a9ca1f7a4b164d905f17a3f2c5cba8c644ef4..351fba81455d011fe3fe7df20b8672ba8395ec25 100644 (file)
@@ -17,6 +17,8 @@
 #include "src/date.h"
 #include "src/elements.h"
 #include "src/execution.h"
+#include "src/field-index.h"
+#include "src/field-index-inl.h"
 #include "src/full-codegen.h"
 #include "src/hydrogen.h"
 #include "src/isolate-inl.h"
@@ -847,8 +849,7 @@ MaybeHandle<Object> Object::GetProperty(Handle<Object> object,
     }
     case FIELD:
       value = JSObject::FastPropertyAt(handle(result->holder(), isolate),
-                                       result->representation(),
-                                       result->GetFieldIndex().field_index());
+          result->representation(), FieldIndex::ForLookupResult(result));
       break;
     case CONSTANT:
       return handle(result->GetConstant(), isolate);
@@ -2280,7 +2281,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
            old_details.type() == FIELD);
     Object* raw_value = old_details.type() == CONSTANT
         ? old_descriptors->GetValue(i)
-        : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
+        : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
     Handle<Object> value(raw_value, isolate);
     if (!old_details.representation().IsDouble() &&
         details.representation().IsDouble()) {
@@ -2316,7 +2317,8 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
   // avoid overwriting |one_pointer_filler_map|.
   int limit = Min(inobject, number_of_fields);
   for (int i = 0; i < limit; i++) {
-    object->FastPropertyAtPut(i, array->get(external + i));
+    FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
+    object->FastPropertyAtPut(index, array->get(external + i));
   }
 
   // Create filler object past the new instance size.
@@ -3515,7 +3517,7 @@ void JSObject::LookupOwnRealNamedProperty(Handle<Name> name,
     // occur as fields.
     if (result->IsField() &&
         result->IsReadOnly() &&
-        RawFastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
+        RawFastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
       result->DisallowCaching();
     }
     return;
@@ -4031,14 +4033,14 @@ void JSObject::WriteToField(int descriptor, Object* value) {
 
   ASSERT(details.type() == FIELD);
 
-  int field_index = desc->GetFieldIndex(descriptor);
+  FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
   if (details.representation().IsDouble()) {
     // Nothing more to be done.
     if (value->IsUninitialized()) return;
-    HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(field_index));
+    HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
     box->set_value(value->Number());
   } else {
-    FastPropertyAtPut(field_index, value);
+    FastPropertyAtPut(index, value);
   }
 }
 
@@ -4727,8 +4729,9 @@ void JSObject::NormalizeProperties(Handle<JSObject> object,
       }
       case FIELD: {
         Handle<Name> key(descs->GetKey(i));
+        FieldIndex index = FieldIndex::ForDescriptor(*map, i);
         Handle<Object> value(
-            object->RawFastPropertyAt(descs->GetFieldIndex(i)), isolate);
+            object->RawFastPropertyAt(index), isolate);
         PropertyDetails d =
             PropertyDetails(details.attributes(), NORMAL, i + 1);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
@@ -5235,8 +5238,9 @@ Object* JSObject::GetHiddenPropertiesHashTable() {
         ASSERT(descriptors->GetType(sorted_index) == FIELD);
         ASSERT(descriptors->GetDetails(sorted_index).representation().
                IsCompatibleForLoad(Representation::Tagged()));
-        return this->RawFastPropertyAt(
-            descriptors->GetFieldIndex(sorted_index));
+        FieldIndex index = FieldIndex::ForDescriptor(this->map(),
+                                                     sorted_index);
+        return this->RawFastPropertyAt(index);
       } else {
         return GetHeap()->undefined_value();
       }
@@ -5916,7 +5920,7 @@ void JSObject::SetObserved(Handle<JSObject> object) {
 
 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
                                         Representation representation,
-                                        int index) {
+                                        FieldIndex index) {
   Isolate* isolate = object->GetIsolate();
   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
   return Object::NewStorageFor(isolate, raw_value, representation);
@@ -6007,7 +6011,7 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
       for (int i = 0; i < limit; i++) {
         PropertyDetails details = descriptors->GetDetails(i);
         if (details.type() != FIELD) continue;
-        int index = descriptors->GetFieldIndex(i);
+        FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
         Handle<Object> value(object->RawFastPropertyAt(index), isolate);
         if (value->IsJSObject()) {
           ASSIGN_RETURN_ON_EXCEPTION(
@@ -6174,7 +6178,7 @@ Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
       case FIELD:
         result = FastPropertyAt(Handle<JSObject>(lookup.holder(), isolate),
                                 lookup.representation(),
-                                lookup.GetFieldIndex().field_index());
+                                lookup.GetFieldIndex());
         break;
       case CONSTANT:
         result = Handle<Object>(lookup.GetConstant(), isolate);
@@ -6408,15 +6412,9 @@ static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
           if (details.type() != FIELD) {
             indices = Handle<FixedArray>();
           } else {
-            int field_index = descs->GetFieldIndex(i);
-            if (field_index >= map->inobject_properties()) {
-              field_index = -(field_index - map->inobject_properties() + 1);
-            }
-            field_index = field_index << 1;
-            if (details.representation().IsDouble()) {
-              field_index |= 1;
-            }
-            indices->set(index, Smi::FromInt(field_index));
+            FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
+            int load_by_field_index = field_index.GetLoadByFieldIndex();
+            indices->set(index, Smi::FromInt(load_by_field_index));
           }
         }
         index++;
@@ -7120,7 +7118,8 @@ Object* JSObject::SlowReverseLookup(Object* value) {
     DescriptorArray* descs = map()->instance_descriptors();
     for (int i = 0; i < number_of_own_descriptors; i++) {
       if (descs->GetType(i) == FIELD) {
-        Object* property = RawFastPropertyAt(descs->GetFieldIndex(i));
+        Object* property =
+            RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
         if (descs->GetDetails(i).representation().IsDouble()) {
           ASSERT(property->IsHeapNumber());
           if (value->IsNumber() && property->Number() == value->Number()) {
index 0ba12ba2ce49e95910328071c266615300b34ecc..8c67765774e5be0f99a0cc112422a1a70b04aa97 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/assert-scope.h"
 #include "src/builtins.h"
 #include "src/elements-kind.h"
+#include "src/field-index.h"
 #include "src/flags.h"
 #include "src/list.h"
 #include "src/property-details.h"
@@ -2499,9 +2500,9 @@ class JSObject: public JSReceiver {
   // Access fast-case object properties at index.
   static Handle<Object> FastPropertyAt(Handle<JSObject> object,
                                        Representation representation,
-                                       int index);
-  inline Object* RawFastPropertyAt(int index);
-  inline void FastPropertyAtPut(int index, Object* value);
+                                       FieldIndex index);
+  inline Object* RawFastPropertyAt(FieldIndex index);
+  inline void FastPropertyAtPut(FieldIndex index, Object* value);
   void WriteToField(int descriptor, Object* value);
 
   // Access to in object properties.
index fa5046de5b1a3c67411a8576b11537a1b4f53653..24b39a959215e0eac9dc7760f3c7b482a5ac3918 100644 (file)
@@ -47,7 +47,8 @@ void LookupResult::Print(FILE* out) {
       break;
     case FIELD:
       PrintF(out, " -type = field\n");
-      PrintF(out, " -index = %d\n", GetFieldIndex().field_index());
+      PrintF(out, " -index = %d\n",
+             GetFieldIndex().property_index());
       PrintF(out, " -field type:\n");
       GetFieldType()->TypePrint(out);
       break;
index 093285c94e77c7c5df7b2eeed336abd038652ede..ebb43430a04b6920f8aec27ae35f9f64f4cb470a 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "src/isolate.h"
 #include "src/factory.h"
+#include "src/field-index.h"
+#include "src/field-index-inl.h"
 #include "src/types.h"
 
 namespace v8 {
@@ -108,56 +110,6 @@ class CallbacksDescriptor V8_FINAL : public Descriptor {
 };
 
 
-// Holds a property index value distinguishing if it is a field index or an
-// index inside the object header.
-class PropertyIndex V8_FINAL {
- public:
-  static PropertyIndex NewFieldIndex(int index) {
-    return PropertyIndex(index, false);
-  }
-  static PropertyIndex NewHeaderIndex(int index) {
-    return PropertyIndex(index, true);
-  }
-
-  bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
-  bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
-
-  int field_index() {
-    ASSERT(is_field_index());
-    return value();
-  }
-  int header_index() {
-    ASSERT(is_header_index());
-    return value();
-  }
-
-  bool is_inobject(Handle<JSObject> holder) {
-    if (is_header_index()) return true;
-    return field_index() < holder->map()->inobject_properties();
-  }
-
-  int translate(Handle<JSObject> holder) {
-    if (is_header_index()) return header_index();
-    int index = field_index() - holder->map()->inobject_properties();
-    if (index >= 0) return index;
-    return index + holder->map()->instance_size() / kPointerSize;
-  }
-
- private:
-  static const int kHeaderIndexBit = 1 << 31;
-  static const int kIndexMask = ~kHeaderIndexBit;
-
-  int value() { return index_ & kIndexMask; }
-
-  PropertyIndex(int index, bool is_header_based)
-      : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
-    ASSERT(index <= kIndexMask);
-  }
-
-  int index_;
-};
-
-
 class LookupResult V8_FINAL BASE_EMBEDDED {
  public:
   explicit LookupResult(Isolate* isolate)
@@ -374,7 +326,7 @@ class LookupResult V8_FINAL BASE_EMBEDDED {
       case DICTIONARY_TYPE:
         switch (type()) {
           case FIELD:
-            return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
+            return holder()->RawFastPropertyAt(GetFieldIndex());
           case NORMAL: {
             Object* value = holder()->property_dictionary()->ValueAt(
                 GetDictionaryEntry());
@@ -416,10 +368,10 @@ class LookupResult V8_FINAL BASE_EMBEDDED {
     return number_;
   }
 
-  PropertyIndex GetFieldIndex() const {
+  FieldIndex GetFieldIndex() const {
     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
            lookup_type_ == TRANSITION_TYPE);
-    return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
+    return FieldIndex::ForLookupResult(this);
   }
 
   int GetLocalFieldIndexFromMap(Map* map) const {
index e5966efd8fec8c087442df54573470e218af212e..a824d6a7977c34fbd0f6508c3dd4779193a56fa5 100644 (file)
@@ -2555,7 +2555,7 @@ RUNTIME_FUNCTION(RuntimeHidden_InitializeConstGlobal) {
   // Strict mode handling not needed (const is disallowed in strict mode).
   if (lookup.IsField()) {
     FixedArray* properties = global->properties();
-    int index = lookup.GetFieldIndex().field_index();
+    int index = lookup.GetFieldIndex().outobject_array_index();
     if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
       properties->set(index, *value);
     }
@@ -2644,9 +2644,10 @@ RUNTIME_FUNCTION(RuntimeHidden_InitializeConstContextSlot) {
 
     if (lookup.IsField()) {
       FixedArray* properties = object->properties();
-      int index = lookup.GetFieldIndex().field_index();
-      if (properties->get(index)->IsTheHole()) {
-        properties->set(index, *value);
+      FieldIndex index = lookup.GetFieldIndex();
+      ASSERT(!index.is_inobject());
+      if (properties->get(index.outobject_array_index())->IsTheHole()) {
+        properties->set(index.outobject_array_index(), *value);
       }
     } else if (lookup.IsNormal()) {
       if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
@@ -5053,10 +5054,11 @@ RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
         // Attempt to use lookup cache.
         Handle<Map> receiver_map(receiver->map(), isolate);
         KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
-        int offset = keyed_lookup_cache->Lookup(receiver_map, key);
-        if (offset != -1) {
+        int index = keyed_lookup_cache->Lookup(receiver_map, key);
+        if (index != -1) {
           // Doubles are not cached, so raw read the value.
-          Object* value = receiver->RawFastPropertyAt(offset);
+          Object* value = receiver->RawFastPropertyAt(
+              FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
           return value->IsTheHole()
               ? isolate->heap()->undefined_value()
               : value;
@@ -5066,15 +5068,16 @@ RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
         LookupResult result(isolate);
         receiver->LookupOwn(key, &result);
         if (result.IsField()) {
-          int offset = result.GetFieldIndex().field_index();
+          FieldIndex field_index = result.GetFieldIndex();
           // Do not track double fields in the keyed lookup cache. Reading
           // double values requires boxing.
           if (!result.representation().IsDouble()) {
-            keyed_lookup_cache->Update(receiver_map, key, offset);
+            keyed_lookup_cache->Update(receiver_map, key,
+                field_index.GetKeyedLookupCacheIndex());
           }
           AllowHeapAllocation allow_allocation;
-          return *JSObject::FastPropertyAt(
-              receiver, result.representation(), offset);
+          return *JSObject::FastPropertyAt(receiver, result.representation(),
+                                           field_index);
         }
       } else {
         // Attempt dictionary lookup.
@@ -10776,7 +10779,7 @@ static Handle<Object> DebugLookupResultValue(Isolate* isolate,
     case FIELD:
       value = JSObject::FastPropertyAt(handle(result->holder(), isolate),
                                        result->representation(),
-                                       result->GetFieldIndex().field_index());
+                                       result->GetFieldIndex());
       break;
     case CONSTANT:
       return handle(result->GetConstant(), isolate);
@@ -14545,14 +14548,17 @@ RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
   ASSERT(args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
   CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
-  int idx = index->value() >> 1;
-  int inobject_properties = object->map()->inobject_properties();
-  if (idx < 0) {
-    idx = -idx + inobject_properties - 1;
-  }
-  int max_idx = object->properties()->length() + inobject_properties;
-  RUNTIME_ASSERT(idx < max_idx);
-  Handle<Object> raw_value(object->RawFastPropertyAt(idx), isolate);
+  RUNTIME_ASSERT((index->value() & 1) == 1);
+  FieldIndex field_index =
+      FieldIndex::ForLoadByFieldIndex(object->map(), index->value() >> 1);
+  if (field_index.is_inobject()) {
+    RUNTIME_ASSERT(field_index.property_index() <
+                   object->map()->inobject_properties());
+  } else {
+    RUNTIME_ASSERT(field_index.outobject_array_index() <
+                   object->properties()->length());
+  }
+  Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
   RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized());
   return *Object::NewStorageFor(isolate, raw_value, Representation::Double());
 }
index 480b788adcb9cd65d5c5fec1b32a8cc8452ce9e9..fb73719492597880bf57091a04918156a6e350ea 100644 (file)
@@ -348,7 +348,8 @@ void StringStream::PrintUsingMap(JSObject* js_object) {
           key->ShortPrint();
         }
         Add(": ");
-        Object* value = js_object->RawFastPropertyAt(descs->GetFieldIndex(i));
+        FieldIndex index = FieldIndex::ForDescriptor(map, i);
+        Object* value = js_object->RawFastPropertyAt(index);
         Add("%o\n", value);
       }
     }
index b42f7489f4f1f7b88527101b6ee7dba31c5f3355..ef9270fb49f0709e3921ad62d046cfa5ffc6c229 100644 (file)
@@ -888,7 +888,7 @@ Handle<Code> LoadStubCompiler::CompileLoadField(
     Handle<HeapType> type,
     Handle<JSObject> holder,
     Handle<Name> name,
-    PropertyIndex field,
+    FieldIndex field,
     Representation representation) {
   Register reg = HandlerFrontend(type, receiver(), holder, name);
   GenerateLoadField(reg, holder, field, representation);
@@ -966,7 +966,7 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
     LookupResult* lookup) {
   Handle<JSObject> holder(lookup->holder());
   if (lookup->IsField()) {
-    PropertyIndex field = lookup->GetFieldIndex();
+    FieldIndex field = lookup->GetFieldIndex();
     if (interceptor_holder.is_identical_to(holder)) {
       GenerateLoadField(
           interceptor_reg, holder, field, lookup->representation());
index e2de10144750cf1f2a05db8a1d6adf6b746b01ce..7ab7bed115742e82c739509dbc163059288e4004 100644 (file)
@@ -518,7 +518,7 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
   Handle<Code> CompileLoadField(Handle<HeapType> type,
                                 Handle<JSObject> holder,
                                 Handle<Name> name,
-                                PropertyIndex index,
+                                FieldIndex index,
                                 Representation representation);
 
   Handle<Code> CompileLoadCallback(Handle<HeapType> type,
@@ -589,7 +589,7 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
 
   void GenerateLoadField(Register reg,
                          Handle<JSObject> holder,
-                         PropertyIndex field,
+                         FieldIndex field,
                          Representation representation);
   void GenerateLoadConstant(Handle<Object> value);
   void GenerateLoadCallback(Register reg,
index d30db9bdb659491b3618b074bbcca0eb8da0aab8..8f07ab3f2b520c325be4397d4ff9e6cae66ce0a6 100644 (file)
@@ -248,6 +248,7 @@ class BitFieldBase {
   static const U kMask = ((kOne << shift) << size) - (kOne << shift);
   static const U kShift = shift;
   static const U kSize = size;
+  static const U kNext = kShift + kSize;
 
   // Value for the field with all bits set.
   static const T kMax = static_cast<T>((1U << size) - 1);
index c8be271cf969f2818214eabf041f0263bd99b6b2..b0aa310b7419d90d5aaaa5fba1c7182b9c7c97c2 100644 (file)
@@ -618,12 +618,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // checks.
   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
 
-  int index = lookup->GetFieldIndex().field_index();
-
-  // Adjust for the number of properties stored in the object. Even in the
-  // face of a transition we can use the old map here because the size of the
-  // object and the number of in-object properties is not going to change.
-  index -= object->map()->inobject_properties();
+  FieldIndex index = lookup->GetFieldIndex();
 
   Representation representation = lookup->representation();
   ASSERT(!representation.IsNone());
@@ -648,14 +643,12 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.
-    if (index < 0) {
-      int offset = object->map()->instance_size() + (index * kPointerSize);
-      __ movp(scratch1, FieldOperand(receiver_reg, offset));
+    if (index.is_inobject()) {
+      __ movp(scratch1, FieldOperand(receiver_reg, index.offset()));
     } else {
       __ movp(scratch1,
               FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-      int offset = index * kPointerSize + FixedArray::kHeaderSize;
-      __ movp(scratch1, FieldOperand(scratch1, offset));
+      __ movp(scratch1, FieldOperand(scratch1, index.offset()));
     }
 
     // Store the value into the storage.
@@ -680,32 +673,30 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   // TODO(verwaest): Share this code as a code stub.
   SmiCheck smi_check = representation.IsTagged()
       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
-  if (index < 0) {
+  if (index.is_inobject()) {
     // Set the property straight into the object.
-    int offset = object->map()->instance_size() + (index * kPointerSize);
-    __ movp(FieldOperand(receiver_reg, offset), value_reg);
+    __ movp(FieldOperand(receiver_reg, index.offset()), value_reg);
 
     if (!representation.IsSmi()) {
       // Update the write barrier for the array address.
       // Pass the value being stored in the now unused name_reg.
       __ movp(name_reg, value_reg);
       __ RecordWriteField(
-          receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs,
+          receiver_reg, index.offset(), name_reg, scratch1, kDontSaveFPRegs,
           EMIT_REMEMBERED_SET, smi_check);
     }
   } else {
     // Write to the properties array.
-    int offset = index * kPointerSize + FixedArray::kHeaderSize;
     // Get the properties array (optimistically).
     __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
-    __ movp(FieldOperand(scratch1, offset), value_reg);
+    __ movp(FieldOperand(scratch1, index.offset()), value_reg);
 
     if (!representation.IsSmi()) {
       // Update the write barrier for the array address.
       // Pass the value being stored in the now unused name_reg.
       __ movp(name_reg, value_reg);
       __ RecordWriteField(
-          scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs,
+          scratch1, index.offset(), name_reg, receiver_reg, kDontSaveFPRegs,
           EMIT_REMEMBERED_SET, smi_check);
     }
   }
@@ -913,20 +904,14 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
 
 void LoadStubCompiler::GenerateLoadField(Register reg,
                                          Handle<JSObject> holder,
-                                         PropertyIndex field,
+                                         FieldIndex field,
                                          Representation representation) {
   if (!reg.is(receiver())) __ movp(receiver(), reg);
   if (kind() == Code::LOAD_IC) {
-    LoadFieldStub stub(isolate(),
-                       field.is_inobject(holder),
-                       field.translate(holder),
-                       representation);
+    LoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   } else {
-    KeyedLoadFieldStub stub(isolate(),
-                            field.is_inobject(holder),
-                            field.translate(holder),
-                            representation);
+    KeyedLoadFieldStub stub(isolate(), field);
     GenerateTailCall(masm(), stub.GetCode());
   }
 }
index 158e146967ce067485272c37ca6df11976066004..b86b96db009cade488d690739f39329fc47eb20e 100644 (file)
@@ -1018,7 +1018,9 @@ TEST(Regression39128) {
   CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
   CHECK_EQ(0, jsobject->properties()->length());
   // Create a reference to object in new space in jsobject.
-  jsobject->FastPropertyAtPut(-1, array);
+  FieldIndex index = FieldIndex::ForInObjectOffset(
+      JSObject::kHeaderSize - kPointerSize);
+  jsobject->FastPropertyAtPut(index, array);
 
   CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
 
@@ -2318,13 +2320,17 @@ TEST(OptimizedPretenuringMixedInObjectProperties) {
       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
 
   CHECK(CcTest::heap()->InOldPointerSpace(*o));
-  CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(0)));
-  CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(1)));
+  FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
+  FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
+  CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
+  CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
 
-  JSObject* inner_object = reinterpret_cast<JSObject*>(o->RawFastPropertyAt(0));
+  JSObject* inner_object =
+      reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
-  CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(0)));
-  CHECK(CcTest::heap()->InOldPointerSpace(inner_object->RawFastPropertyAt(1)));
+  CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  CHECK(CcTest::heap()->InOldPointerSpace(
+      inner_object->RawFastPropertyAt(idx2)));
 }
 
 
@@ -3081,9 +3087,9 @@ TEST(Regress2211) {
     CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
 
     // Check size.
-    DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
+    FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0);
     ObjectHashTable* hashtable = ObjectHashTable::cast(
-        internal_obj->RawFastPropertyAt(descriptors->GetFieldIndex(0)));
+        internal_obj->RawFastPropertyAt(index));
     // HashTable header (5) and 4 initial entries (8).
     CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
   }
index 8368d81d93a1a2a86ff07c39a30be7f2ae36e041..f88771e457062fbcfe97e5d7a8eef2668735c5e3 100644 (file)
         '../../src/fast-dtoa.cc',
         '../../src/fast-dtoa.h',
         '../../src/feedback-slots.h',
+        '../../src/field-index.cc',
+        '../../src/field-index.h',
+        '../../src/field-index-inl.h',
         '../../src/fixed-dtoa.cc',
         '../../src/fixed-dtoa.h',
         '../../src/flag-definitions.h',