Reland 21720: Introduce FieldIndex to unify and abstract property/field offset

R=verwaest@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21746 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2014-06-10 14:01:08 +00:00
parent 3a58f23bcd
commit 7c56c0e864
31 changed files with 500 additions and 320 deletions

View 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());
}
}

View 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());
}
}

View 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());

View 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));
}

View 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(

View 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;
}

80
src/field-index-inl.h Normal file
View File

@ -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

23
src/field-index.cc Normal file
View File

@ -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

123
src/field-index.h Normal file
View File

@ -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

View 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 {

View 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());
}
}

View File

@ -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);
}
}

View File

@ -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,

View 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);
}
}
}

View 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,

View 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());

View 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);
}

View 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:

View 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.
@ -3526,7 +3528,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;
@ -4042,14 +4044,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);
}
}
@ -4738,8 +4740,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);
@ -5246,8 +5249,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();
}
@ -5927,7 +5931,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);
@ -6018,7 +6022,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(
@ -6185,7 +6189,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);
@ -6419,15 +6423,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++;
@ -7131,7 +7129,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()) {

View 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.

View 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;

View 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 {

View 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;
RUNTIME_ASSERT((index->value() & 1) == 1);
FieldIndex field_index =
FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
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());
}
int max_idx = object->properties()->length() + inobject_properties;
RUNTIME_ASSERT(idx < max_idx);
Handle<Object> raw_value(object->RawFastPropertyAt(idx), isolate);
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());
}

View 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);
}
}

View 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());

View 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,

View 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);

View 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());
}
}

View 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);
}

View File

@ -0,0 +1,66 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
function DoubleContainer() {
this.x0 = 0.5;
this.x1 = undefined;
this.x2 = undefined;
this.x3 = undefined;
this.x4 = undefined;
this.x5 = undefined;
this.x6 = undefined;
this.x7 = 5;
this.x8 = undefined;
this.x9 = undefined;
this.x10 = undefined;
this.x11 = undefined;
this.x12 = undefined;
this.x13 = undefined;
this.x14 = undefined;
this.x15 = undefined;
this.x16 = true;
this.y = 2.5;
}
var z = new DoubleContainer();
function test_props(a) {
for (var i in a) {
assertTrue(i !== "x0" || a[i] === 0.5);
assertTrue(i !== "y" || a[i] === 2.5);
assertTrue(i !== "x12" || a[i] === undefined);
assertTrue(i !== "x16" || a[i] === true);
assertTrue(i !== "x7" || a[i] === 5);
}
}
test_props(z);
test_props(z);
%OptimizeFunctionOnNextCall(test_props);
test_props(z);

View File

@ -345,6 +345,9 @@
'../../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',