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:
parent
3a58f23bcd
commit
7c56c0e864
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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
80
src/field-index-inl.h
Normal 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
23
src/field-index.cc
Normal 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
123
src/field-index.h
Normal 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
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
23
src/ic.cc
23
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
5
src/ic.h
5
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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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()) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
66
test/mjsunit/outobject-double-for-in.js
Normal file
66
test/mjsunit/outobject-double-for-in.js
Normal 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);
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user