Revert "In-object double fields unboxing (for 64-bit only)."
Revert "Fixes for Windows and Mac builds after r25250." TBR=ishell@chromium.org Review URL: https://codereview.chromium.org/699613004 Cr-Commit-Position: refs/heads/master@{#25252} git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25252 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
07085da575
commit
2d9079ca1d
3
BUILD.gn
3
BUILD.gn
@ -782,9 +782,6 @@ source_set("v8_base") {
|
||||
"src/jsregexp-inl.h",
|
||||
"src/jsregexp.cc",
|
||||
"src/jsregexp.h",
|
||||
"src/layout-descriptor-inl.h",
|
||||
"src/layout-descriptor.cc",
|
||||
"src/layout-descriptor.h",
|
||||
"src/list-inl.h",
|
||||
"src/list.h",
|
||||
"src/lithium-allocator-inl.h",
|
||||
|
@ -2400,7 +2400,7 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
|
||||
LOperand* temp1 = NULL;
|
||||
|
||||
if (instr->access().IsExternalMemory() ||
|
||||
(!FLAG_unbox_double_fields && instr->field_representation().IsDouble())) {
|
||||
instr->field_representation().IsDouble()) {
|
||||
value = UseRegister(instr->value());
|
||||
} else if (instr->NeedsWriteBarrier()) {
|
||||
value = UseRegisterAndClobber(instr->value());
|
||||
|
@ -3660,7 +3660,6 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
||||
}
|
||||
|
||||
if (instr->hydrogen()->representation().IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
FPRegister result = ToDoubleRegister(instr->result());
|
||||
__ Ldr(result, FieldMemOperand(object, offset));
|
||||
return;
|
||||
@ -5351,7 +5350,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
|
||||
__ AssertNotSmi(object);
|
||||
|
||||
if (!FLAG_unbox_double_fields && representation.IsDouble()) {
|
||||
if (representation.IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
DCHECK(!instr->hydrogen()->has_transition());
|
||||
DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
|
||||
@ -5360,6 +5359,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Register value = ToRegister(instr->value());
|
||||
|
||||
DCHECK(!representation.IsSmi() ||
|
||||
!instr->value()->IsConstantOperand() ||
|
||||
IsInteger32Constant(LConstantOperand::cast(instr->value())));
|
||||
@ -5391,12 +5392,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
destination = temp0;
|
||||
}
|
||||
|
||||
if (FLAG_unbox_double_fields && representation.IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
FPRegister value = ToDoubleRegister(instr->value());
|
||||
__ Str(value, FieldMemOperand(object, offset));
|
||||
} else if (representation.IsSmi() &&
|
||||
instr->hydrogen()->value()->representation().IsInteger32()) {
|
||||
if (representation.IsSmi() &&
|
||||
instr->hydrogen()->value()->representation().IsInteger32()) {
|
||||
DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY);
|
||||
#ifdef DEBUG
|
||||
Register temp0 = ToRegister(instr->temp0());
|
||||
@ -5411,15 +5408,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
#endif
|
||||
STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
Register value = ToRegister(instr->value());
|
||||
__ Store(value, UntagSmiFieldMemOperand(destination, offset),
|
||||
Representation::Integer32());
|
||||
} else {
|
||||
Register value = ToRegister(instr->value());
|
||||
__ Store(value, FieldMemOperand(destination, offset), representation);
|
||||
}
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
Register value = ToRegister(instr->value());
|
||||
__ RecordWriteField(destination,
|
||||
offset,
|
||||
value, // Clobbered.
|
||||
|
@ -951,7 +951,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
CallbacksDescriptor d(
|
||||
Handle<Name>(Name::cast(array_length->name())),
|
||||
array_length, attribs);
|
||||
initial_map->AppendDescriptor(&d);
|
||||
array_function->initial_map()->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
// array_function is used internally. JS code creating array object should
|
||||
@ -1091,6 +1091,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
initial_map->set_unused_property_fields(0);
|
||||
initial_map->set_instance_size(
|
||||
initial_map->instance_size() + 5 * kPointerSize);
|
||||
initial_map->set_visitor_id(StaticVisitorBase::GetVisitorId(*initial_map));
|
||||
|
||||
// RegExp prototype object is itself a RegExp.
|
||||
Handle<Map> proto_map = Map::Copy(initial_map, "RegExpPrototype");
|
||||
@ -1677,7 +1678,7 @@ Handle<JSFunction> Genesis::InstallInternalArray(
|
||||
{ // Add length.
|
||||
CallbacksDescriptor d(
|
||||
Handle<Name>(Name::cast(array_length->name())), array_length, attribs);
|
||||
initial_map->AppendDescriptor(&d);
|
||||
array_function->initial_map()->AppendDescriptor(&d);
|
||||
}
|
||||
|
||||
return array_function;
|
||||
|
@ -538,8 +538,7 @@ HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField(
|
||||
HObjectAccess access = index.is_inobject()
|
||||
? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
|
||||
: HObjectAccess::ForBackingStoreOffset(offset, representation);
|
||||
if (index.is_double() &&
|
||||
(!FLAG_unbox_double_fields || !index.is_inobject())) {
|
||||
if (index.is_double()) {
|
||||
// Load the heap number.
|
||||
object = Add<HLoadNamedField>(
|
||||
object, static_cast<HValue*>(NULL),
|
||||
@ -706,32 +705,30 @@ void CodeStubGraphBuilderBase::BuildStoreNamedField(
|
||||
: HObjectAccess::ForBackingStoreOffset(offset, representation);
|
||||
|
||||
if (representation.IsDouble()) {
|
||||
if (!FLAG_unbox_double_fields || !index.is_inobject()) {
|
||||
HObjectAccess heap_number_access =
|
||||
access.WithRepresentation(Representation::Tagged());
|
||||
if (transition_to_field) {
|
||||
// The store requires a mutable HeapNumber to be allocated.
|
||||
NoObservableSideEffectsScope no_side_effects(this);
|
||||
HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
|
||||
HObjectAccess heap_number_access =
|
||||
access.WithRepresentation(Representation::Tagged());
|
||||
if (transition_to_field) {
|
||||
// The store requires a mutable HeapNumber to be allocated.
|
||||
NoObservableSideEffectsScope no_side_effects(this);
|
||||
HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
|
||||
|
||||
// TODO(hpayer): Allocation site pretenuring support.
|
||||
HInstruction* heap_number =
|
||||
Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
|
||||
MUTABLE_HEAP_NUMBER_TYPE);
|
||||
AddStoreMapConstant(heap_number,
|
||||
isolate()->factory()->mutable_heap_number_map());
|
||||
Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
|
||||
value);
|
||||
// Store the new mutable heap number into the object.
|
||||
access = heap_number_access;
|
||||
value = heap_number;
|
||||
} else {
|
||||
// Load the heap number.
|
||||
object = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
||||
heap_number_access);
|
||||
// Store the double value into it.
|
||||
access = HObjectAccess::ForHeapNumberValue();
|
||||
}
|
||||
// TODO(hpayer): Allocation site pretenuring support.
|
||||
HInstruction* heap_number =
|
||||
Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
|
||||
MUTABLE_HEAP_NUMBER_TYPE);
|
||||
AddStoreMapConstant(heap_number,
|
||||
isolate()->factory()->mutable_heap_number_map());
|
||||
Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
|
||||
value);
|
||||
// Store the new mutable heap number into the object.
|
||||
access = heap_number_access;
|
||||
value = heap_number;
|
||||
} else {
|
||||
// Load the heap number.
|
||||
object = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
||||
heap_number_access);
|
||||
// Store the double value into it.
|
||||
access = HObjectAccess::ForHeapNumberValue();
|
||||
}
|
||||
} else if (representation.IsHeapObject()) {
|
||||
BuildCheckHeapObject(value);
|
||||
|
@ -34,8 +34,6 @@ class FieldIndex FINAL {
|
||||
return IsInObjectBits::decode(bit_field_);
|
||||
}
|
||||
|
||||
bool is_hidden_field() const { return IsHiddenField::decode(bit_field_); }
|
||||
|
||||
bool is_double() const {
|
||||
return IsDoubleBits::decode(bit_field_);
|
||||
}
|
||||
@ -57,7 +55,7 @@ class FieldIndex FINAL {
|
||||
// Zero-based from the first inobject property. Overflows to out-of-object
|
||||
// properties.
|
||||
int property_index() const {
|
||||
DCHECK(!is_hidden_field());
|
||||
DCHECK(!IsHiddenField::decode(bit_field_));
|
||||
int result = index() - first_inobject_property_offset() / kPointerSize;
|
||||
if (!is_inobject()) {
|
||||
result += InObjectPropertyBits::decode(bit_field_);
|
||||
@ -88,7 +86,7 @@ class FieldIndex FINAL {
|
||||
explicit FieldIndex(int bit_field) : bit_field_(bit_field) {}
|
||||
|
||||
int first_inobject_property_offset() const {
|
||||
DCHECK(!is_hidden_field());
|
||||
DCHECK(!IsHiddenField::decode(bit_field_));
|
||||
return FirstInobjectPropertyOffsetBits::decode(bit_field_);
|
||||
}
|
||||
|
||||
|
@ -947,11 +947,6 @@ DEFINE_INT(dump_allocations_digest_at_alloc, 0,
|
||||
DEFINE_BOOL(enable_ool_constant_pool, V8_OOL_CONSTANT_POOL,
|
||||
"enable use of out-of-line constant pools (ARM only)")
|
||||
|
||||
DEFINE_BOOL(unbox_double_fields, V8_DOUBLE_FIELDS_UNBOXING,
|
||||
"enable in-object double fields unboxing (64-bit only)")
|
||||
DEFINE_IMPLICATION(unbox_double_fields, track_double_fields)
|
||||
|
||||
|
||||
// Cleanup...
|
||||
#undef FLAG_FULL
|
||||
#undef FLAG_READONLY
|
||||
|
@ -81,13 +81,6 @@ namespace internal {
|
||||
#endif
|
||||
|
||||
|
||||
// Determine whether double field unboxing feature is enabled.
|
||||
#if (V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64)
|
||||
#define V8_DOUBLE_FIELDS_UNBOXING 0
|
||||
#else
|
||||
#define V8_DOUBLE_FIELDS_UNBOXING 0
|
||||
#endif
|
||||
|
||||
// Support for alternative bool type. This is only enabled if the code is
|
||||
// compiled with USE_MYBOOL defined. This catches some nasty type bugs.
|
||||
// For instance, 'bool b = "false";' results in b == true! This is a hidden
|
||||
|
@ -2308,13 +2308,8 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
|
||||
reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
|
||||
reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
|
||||
reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
|
||||
// Initialize to only containing tagged fields.
|
||||
reinterpret_cast<Map*>(result)->set_visitor_id(
|
||||
StaticVisitorBase::GetVisitorId(instance_type, instance_size, false));
|
||||
if (FLAG_unbox_double_fields) {
|
||||
reinterpret_cast<Map*>(result)
|
||||
->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
StaticVisitorBase::GetVisitorId(instance_type, instance_size));
|
||||
reinterpret_cast<Map*>(result)->set_inobject_properties(0);
|
||||
reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
|
||||
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
|
||||
@ -2337,6 +2332,8 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
|
||||
result->set_map_no_write_barrier(meta_map());
|
||||
Map* map = Map::cast(result);
|
||||
map->set_instance_type(instance_type);
|
||||
map->set_visitor_id(
|
||||
StaticVisitorBase::GetVisitorId(instance_type, instance_size));
|
||||
map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
|
||||
map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
|
||||
map->set_instance_size(instance_size);
|
||||
@ -2348,12 +2345,6 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
|
||||
map->init_back_pointer(undefined_value());
|
||||
map->set_unused_property_fields(0);
|
||||
map->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
map->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
// Must be called only after |instance_type|, |instance_size| and
|
||||
// |layout_descriptor| are set.
|
||||
map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
|
||||
map->set_bit_field(0);
|
||||
map->set_bit_field2(1 << Map::kIsExtensible);
|
||||
int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) |
|
||||
@ -2480,46 +2471,28 @@ bool Heap::CreateInitialMaps() {
|
||||
meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
|
||||
meta_map()->init_back_pointer(undefined_value());
|
||||
meta_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
|
||||
fixed_array_map()->set_code_cache(empty_fixed_array());
|
||||
fixed_array_map()->set_dependent_code(
|
||||
DependentCode::cast(empty_fixed_array()));
|
||||
fixed_array_map()->init_back_pointer(undefined_value());
|
||||
fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
fixed_array_map()->set_layout_descriptor(
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
|
||||
undefined_map()->set_code_cache(empty_fixed_array());
|
||||
undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
|
||||
undefined_map()->init_back_pointer(undefined_value());
|
||||
undefined_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
undefined_map()->set_layout_descriptor(
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
|
||||
null_map()->set_code_cache(empty_fixed_array());
|
||||
null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
|
||||
null_map()->init_back_pointer(undefined_value());
|
||||
null_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
|
||||
constant_pool_array_map()->set_code_cache(empty_fixed_array());
|
||||
constant_pool_array_map()->set_dependent_code(
|
||||
DependentCode::cast(empty_fixed_array()));
|
||||
constant_pool_array_map()->init_back_pointer(undefined_value());
|
||||
constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
constant_pool_array_map()->set_layout_descriptor(
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
|
||||
// Fix prototype object for existing maps.
|
||||
meta_map()->set_prototype(null_value());
|
||||
|
@ -2810,23 +2810,12 @@ void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src,
|
||||
Address dst_slot = dst_addr;
|
||||
DCHECK(IsAligned(size, kPointerSize));
|
||||
|
||||
bool may_contain_raw_values = src->MayContainRawValues();
|
||||
#if V8_DOUBLE_FIELDS_UNBOXING
|
||||
InobjectPropertiesHelper helper(src->map());
|
||||
bool has_only_tagged_fields = helper.all_fields_tagged();
|
||||
#endif
|
||||
for (int remaining = size / kPointerSize; remaining > 0; remaining--) {
|
||||
Object* value = Memory::Object_at(src_slot);
|
||||
|
||||
Memory::Object_at(dst_slot) = value;
|
||||
|
||||
#if V8_DOUBLE_FIELDS_UNBOXING
|
||||
if (!may_contain_raw_values &&
|
||||
(has_only_tagged_fields || helper.IsTagged(src_slot - src_addr)))
|
||||
#else
|
||||
if (!may_contain_raw_values)
|
||||
#endif
|
||||
{
|
||||
if (!src->MayContainRawValues()) {
|
||||
RecordMigratedSlot(value, dst_slot);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace internal {
|
||||
|
||||
|
||||
StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
int instance_type, int instance_size, bool has_unboxed_fields) {
|
||||
int instance_type, int instance_size) {
|
||||
if (instance_type < FIRST_NONSTRING_TYPE) {
|
||||
switch (instance_type & kStringRepresentationMask) {
|
||||
case kSeqStringTag:
|
||||
@ -33,7 +33,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
|
||||
case kExternalStringTag:
|
||||
return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
|
||||
instance_size, has_unboxed_fields);
|
||||
instance_size);
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -74,11 +74,11 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
|
||||
case JS_SET_TYPE:
|
||||
return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
|
||||
JSSet::kSize, has_unboxed_fields);
|
||||
JSSet::kSize);
|
||||
|
||||
case JS_MAP_TYPE:
|
||||
return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
|
||||
JSMap::kSize, has_unboxed_fields);
|
||||
JSMap::kSize);
|
||||
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
@ -92,15 +92,15 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
|
||||
case JS_PROXY_TYPE:
|
||||
return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
|
||||
JSProxy::kSize, has_unboxed_fields);
|
||||
JSProxy::kSize);
|
||||
|
||||
case JS_FUNCTION_PROXY_TYPE:
|
||||
return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
|
||||
JSFunctionProxy::kSize, has_unboxed_fields);
|
||||
JSFunctionProxy::kSize);
|
||||
|
||||
case FOREIGN_TYPE:
|
||||
return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
|
||||
Foreign::kSize, has_unboxed_fields);
|
||||
Foreign::kSize);
|
||||
|
||||
case SYMBOL_TYPE:
|
||||
return kVisitSymbol;
|
||||
@ -131,7 +131,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
case JS_SET_ITERATOR_TYPE:
|
||||
case JS_MAP_ITERATOR_TYPE:
|
||||
return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
|
||||
instance_size, has_unboxed_fields);
|
||||
instance_size);
|
||||
|
||||
case JS_FUNCTION_TYPE:
|
||||
return kVisitJSFunction;
|
||||
@ -143,7 +143,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
|
||||
TYPED_ARRAYS(EXTERNAL_ARRAY_CASE)
|
||||
return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
|
||||
instance_size, has_unboxed_fields);
|
||||
instance_size);
|
||||
#undef EXTERNAL_ARRAY_CASE
|
||||
|
||||
case FIXED_UINT8_ARRAY_TYPE:
|
||||
@ -167,7 +167,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
|
||||
}
|
||||
|
||||
return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
|
||||
instance_size, has_unboxed_fields);
|
||||
instance_size);
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define V8_OBJECTS_VISITING_H_
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/layout-descriptor.h"
|
||||
|
||||
// This file provides base classes and auxiliary methods for defining
|
||||
// static object visitors used during GC.
|
||||
@ -106,29 +105,21 @@ class StaticVisitorBase : public AllStatic {
|
||||
|
||||
// Determine which specialized visitor should be used for given instance type
|
||||
// and instance type.
|
||||
static VisitorId GetVisitorId(int instance_type, int instance_size,
|
||||
bool has_unboxed_fields);
|
||||
static VisitorId GetVisitorId(int instance_type, int instance_size);
|
||||
|
||||
// Determine which specialized visitor should be used for given map.
|
||||
static VisitorId GetVisitorId(Map* map) {
|
||||
return GetVisitorId(map->instance_type(), map->instance_size(),
|
||||
FLAG_unbox_double_fields &&
|
||||
!map->layout_descriptor()->IsFastPointerLayout());
|
||||
return GetVisitorId(map->instance_type(), map->instance_size());
|
||||
}
|
||||
|
||||
// For visitors that allow specialization by size calculate VisitorId based
|
||||
// on size, base visitor id and generic visitor id.
|
||||
static VisitorId GetVisitorIdForSize(VisitorId base, VisitorId generic,
|
||||
int object_size,
|
||||
bool has_unboxed_fields) {
|
||||
int object_size) {
|
||||
DCHECK((base == kVisitDataObject) || (base == kVisitStruct) ||
|
||||
(base == kVisitJSObject));
|
||||
DCHECK(IsAligned(object_size, kPointerSize));
|
||||
DCHECK(kMinObjectSizeInWords * kPointerSize <= object_size);
|
||||
DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
|
||||
DCHECK(!has_unboxed_fields || (base == kVisitJSObject));
|
||||
|
||||
if (has_unboxed_fields) return generic;
|
||||
|
||||
const VisitorId specialization = static_cast<VisitorId>(
|
||||
base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords);
|
||||
@ -167,7 +158,7 @@ class VisitorDispatchTable {
|
||||
StaticVisitorBase::VisitorId generic, int object_size_in_words>
|
||||
void RegisterSpecialization() {
|
||||
static const int size = object_size_in_words * kPointerSize;
|
||||
Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size, false),
|
||||
Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size),
|
||||
&Visitor::template VisitSpecialized<size>);
|
||||
}
|
||||
|
||||
@ -198,47 +189,11 @@ class BodyVisitorBase : public AllStatic {
|
||||
public:
|
||||
INLINE(static void IteratePointers(Heap* heap, HeapObject* object,
|
||||
int start_offset, int end_offset)) {
|
||||
DCHECK(!FLAG_unbox_double_fields ||
|
||||
object->map()->layout_descriptor()->IsFastPointerLayout());
|
||||
IterateRawPointers(heap, object, start_offset, end_offset);
|
||||
}
|
||||
|
||||
INLINE(static void IterateBody(Heap* heap, HeapObject* object,
|
||||
int start_offset, int end_offset)) {
|
||||
if (!FLAG_unbox_double_fields ||
|
||||
object->map()->layout_descriptor()->IsFastPointerLayout()) {
|
||||
IterateRawPointers(heap, object, start_offset, end_offset);
|
||||
} else {
|
||||
IterateBodyUsingLayoutDescriptor(heap, object, start_offset, end_offset);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
INLINE(static void IterateRawPointers(Heap* heap, HeapObject* object,
|
||||
int start_offset, int end_offset)) {
|
||||
StaticVisitor::VisitPointers(heap,
|
||||
HeapObject::RawField(object, start_offset),
|
||||
HeapObject::RawField(object, end_offset));
|
||||
}
|
||||
|
||||
static void IterateBodyUsingLayoutDescriptor(Heap* heap, HeapObject* object,
|
||||
int start_offset,
|
||||
int end_offset) {
|
||||
DCHECK(FLAG_unbox_double_fields);
|
||||
DCHECK(IsAligned(start_offset, kPointerSize) &&
|
||||
IsAligned(end_offset, kPointerSize));
|
||||
|
||||
InobjectPropertiesHelper helper(object->map());
|
||||
DCHECK(!helper.all_fields_tagged());
|
||||
|
||||
for (int offset = start_offset; offset < end_offset;
|
||||
offset += kPointerSize) {
|
||||
// Visit tagged fields only.
|
||||
if (helper.IsTagged(offset)) {
|
||||
// TODO(ishell): call this once for contiguous region of tagged fields.
|
||||
IterateRawPointers(heap, object, offset, offset + kPointerSize);
|
||||
}
|
||||
}
|
||||
Object** start_slot =
|
||||
reinterpret_cast<Object**>(object->address() + start_offset);
|
||||
Object** end_slot =
|
||||
reinterpret_cast<Object**>(object->address() + end_offset);
|
||||
StaticVisitor::VisitPointers(heap, start_slot, end_slot);
|
||||
}
|
||||
};
|
||||
|
||||
@ -248,7 +203,7 @@ class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> {
|
||||
public:
|
||||
INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
|
||||
int object_size = BodyDescriptor::SizeOf(map, object);
|
||||
BodyVisitorBase<StaticVisitor>::IterateBody(
|
||||
BodyVisitorBase<StaticVisitor>::IteratePointers(
|
||||
map->GetHeap(), object, BodyDescriptor::kStartOffset, object_size);
|
||||
return static_cast<ReturnType>(object_size);
|
||||
}
|
||||
@ -267,9 +222,9 @@ template <typename StaticVisitor, typename BodyDescriptor, typename ReturnType>
|
||||
class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> {
|
||||
public:
|
||||
INLINE(static ReturnType Visit(Map* map, HeapObject* object)) {
|
||||
BodyVisitorBase<StaticVisitor>::IterateBody(map->GetHeap(), object,
|
||||
BodyDescriptor::kStartOffset,
|
||||
BodyDescriptor::kEndOffset);
|
||||
BodyVisitorBase<StaticVisitor>::IteratePointers(
|
||||
map->GetHeap(), object, BodyDescriptor::kStartOffset,
|
||||
BodyDescriptor::kEndOffset);
|
||||
return static_cast<ReturnType>(BodyDescriptor::kSize);
|
||||
}
|
||||
};
|
||||
|
@ -507,33 +507,11 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback,
|
||||
for (HeapObject* heap_object = iterator.Next(); heap_object != NULL;
|
||||
heap_object = iterator.Next()) {
|
||||
// We iterate over objects that contain new space pointers only.
|
||||
bool may_contain_raw_values = heap_object->MayContainRawValues();
|
||||
if (!may_contain_raw_values) {
|
||||
Address obj_address = heap_object->address();
|
||||
Address start_address = obj_address + HeapObject::kHeaderSize;
|
||||
Address end_address = obj_address + heap_object->Size();
|
||||
#if V8_DOUBLE_FIELDS_UNBOXING
|
||||
InobjectPropertiesHelper helper(heap_object->map());
|
||||
bool has_only_tagged_fields = helper.all_fields_tagged();
|
||||
|
||||
if (!has_only_tagged_fields) {
|
||||
for (Address slot = start_address; slot < end_address;
|
||||
slot += kPointerSize) {
|
||||
if (helper.IsTagged(slot - obj_address)) {
|
||||
// TODO(ishell): call this once for contiguous region
|
||||
// of tagged fields.
|
||||
FindPointersToNewSpaceInRegion(slot, slot + kPointerSize,
|
||||
slot_callback, clear_maps);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
// Object has only tagged fields.
|
||||
FindPointersToNewSpaceInRegion(start_address, end_address,
|
||||
slot_callback, clear_maps);
|
||||
#if V8_DOUBLE_FIELDS_UNBOXING
|
||||
}
|
||||
#endif
|
||||
if (!heap_object->MayContainRawValues()) {
|
||||
FindPointersToNewSpaceInRegion(
|
||||
heap_object->address() + HeapObject::kHeaderSize,
|
||||
heap_object->address() + heap_object->Size(), slot_callback,
|
||||
clear_maps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6943,9 +6943,7 @@ class HStoreNamedField FINAL : public HTemplateInstruction<3> {
|
||||
}
|
||||
|
||||
bool NeedsWriteBarrier() const {
|
||||
DCHECK(!field_representation().IsDouble() ||
|
||||
(FLAG_unbox_double_fields && access_.IsInobject()) ||
|
||||
!has_transition());
|
||||
DCHECK(!field_representation().IsDouble() || !has_transition());
|
||||
if (field_representation().IsDouble()) return false;
|
||||
if (field_representation().IsSmi()) return false;
|
||||
if (field_representation().IsInteger32()) return false;
|
||||
|
@ -5533,11 +5533,9 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
|
||||
for (int i = 0; i < limit; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.type() != FIELD) continue;
|
||||
int index = descriptors->GetFieldIndex(i);
|
||||
if ((*max_properties)-- == 0) return false;
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
|
||||
if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
|
||||
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
|
||||
isolate);
|
||||
Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
if (!IsFastLiteral(value_object,
|
||||
@ -5840,8 +5838,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
|
||||
}
|
||||
|
||||
HObjectAccess access = info->access();
|
||||
if (access.representation().IsDouble() &&
|
||||
(!FLAG_unbox_double_fields || !access.IsInobject())) {
|
||||
if (access.representation().IsDouble()) {
|
||||
// Load the heap number.
|
||||
checked_object = Add<HLoadNamedField>(
|
||||
checked_object, static_cast<HValue*>(NULL),
|
||||
@ -5873,8 +5870,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
|
||||
HObjectAccess field_access = info->access();
|
||||
|
||||
HStoreNamedField *instr;
|
||||
if (field_access.representation().IsDouble() &&
|
||||
(!FLAG_unbox_double_fields || !field_access.IsInobject())) {
|
||||
if (field_access.representation().IsDouble()) {
|
||||
HObjectAccess heap_number_access =
|
||||
field_access.WithRepresentation(Representation::Tagged());
|
||||
if (transition_to_field) {
|
||||
@ -11190,27 +11186,18 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.type() != FIELD) continue;
|
||||
copied_fields++;
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
|
||||
|
||||
|
||||
int property_offset = field_index.offset();
|
||||
int index = descriptors->GetFieldIndex(i);
|
||||
int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
|
||||
Handle<Name> name(descriptors->GetKey(i));
|
||||
Handle<Object> value =
|
||||
Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
|
||||
isolate());
|
||||
|
||||
// The access for the store depends on the type of the boilerplate.
|
||||
HObjectAccess access = boilerplate_object->IsJSArray() ?
|
||||
HObjectAccess::ForJSArrayOffset(property_offset) :
|
||||
HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
|
||||
|
||||
if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
|
||||
CHECK(!boilerplate_object->IsJSArray());
|
||||
double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
|
||||
access = access.WithRepresentation(Representation::Double());
|
||||
Add<HStoreNamedField>(object, access, Add<HConstant>(value));
|
||||
continue;
|
||||
}
|
||||
Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
|
||||
isolate());
|
||||
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
Handle<AllocationSite> current_site = site_context->EnterNewScope();
|
||||
|
@ -652,15 +652,8 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
|
||||
if (details.IsDontEnum()) continue;
|
||||
Handle<Object> property;
|
||||
if (details.type() == FIELD && *map == object->map()) {
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
if (object->IsUnboxedDoubleField(field_index)) {
|
||||
double value = object->RawFastDoublePropertyAt(field_index);
|
||||
property = isolate->factory()->NewHeapNumber(value);
|
||||
|
||||
} else {
|
||||
property = handle(object->RawFastPropertyAt(field_index), isolate);
|
||||
}
|
||||
property = Handle<Object>(object->RawFastPropertyAt(
|
||||
FieldIndex::ForDescriptor(*map, i)), isolate_);
|
||||
} else {
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate_, property,
|
||||
|
@ -1,185 +0,0 @@
|
||||
// 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_LAYOUT_DESCRIPTOR_INL_H_
|
||||
#define V8_LAYOUT_DESCRIPTOR_INL_H_
|
||||
|
||||
#include "src/layout-descriptor.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
LayoutDescriptor* LayoutDescriptor::FromSmi(Smi* smi) {
|
||||
return LayoutDescriptor::cast(smi);
|
||||
}
|
||||
|
||||
|
||||
Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
|
||||
if (length <= kSmiValueSize) {
|
||||
// The whole bit vector fits into a smi.
|
||||
return handle(LayoutDescriptor::FromSmi(Smi::FromInt(0)), isolate);
|
||||
}
|
||||
|
||||
length = (length + kNumberOfBits - 1) / kNumberOfBits;
|
||||
DCHECK(length > 0);
|
||||
|
||||
if (SmiValuesAre32Bits() && (length & 1)) {
|
||||
// On 64-bit systems if the length is odd then the half-word space would be
|
||||
// lost anyway (due to alignment and the fact that we are allocating
|
||||
// uint32-typed array), so we increase the length of allocated array
|
||||
// to utilize that "lost" space which could also help to avoid layout
|
||||
// descriptor reallocations.
|
||||
++length;
|
||||
}
|
||||
return Handle<LayoutDescriptor>::cast(
|
||||
isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array));
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::InobjectUnboxedField(int inobject_properties,
|
||||
PropertyDetails details) {
|
||||
if (details.type() != FIELD || !details.representation().IsDouble()) {
|
||||
return false;
|
||||
}
|
||||
// We care only about in-object properties.
|
||||
return details.field_index() < inobject_properties;
|
||||
}
|
||||
|
||||
|
||||
LayoutDescriptor* LayoutDescriptor::FastPointerLayout() {
|
||||
return LayoutDescriptor::FromSmi(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
|
||||
uint32_t* layout_mask) {
|
||||
if (static_cast<unsigned>(field_index) >= static_cast<unsigned>(capacity())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*layout_word_index = field_index / kNumberOfBits;
|
||||
CHECK((!IsSmi() && (*layout_word_index < length())) ||
|
||||
(IsSmi() && (*layout_word_index < 1)));
|
||||
|
||||
int layout_bit_index = field_index % kNumberOfBits;
|
||||
*layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) {
|
||||
int layout_word_index;
|
||||
uint32_t layout_mask;
|
||||
|
||||
if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) {
|
||||
CHECK(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (IsSlowLayout()) {
|
||||
uint32_t value = get_scalar(layout_word_index);
|
||||
if (tagged) {
|
||||
value &= ~layout_mask;
|
||||
} else {
|
||||
value |= layout_mask;
|
||||
}
|
||||
set(layout_word_index, value);
|
||||
return this;
|
||||
} else {
|
||||
uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
|
||||
if (tagged) {
|
||||
value &= ~layout_mask;
|
||||
} else {
|
||||
value |= layout_mask;
|
||||
}
|
||||
return LayoutDescriptor::FromSmi(Smi::FromInt(static_cast<int>(value)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::IsTagged(int field_index) {
|
||||
if (IsFastPointerLayout()) return true;
|
||||
|
||||
int layout_word_index;
|
||||
uint32_t layout_mask;
|
||||
|
||||
if (!GetIndexes(field_index, &layout_word_index, &layout_mask)) {
|
||||
// All bits after Out of bounds queries
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSlowLayout()) {
|
||||
uint32_t value = get_scalar(layout_word_index);
|
||||
return (value & layout_mask) == 0;
|
||||
} else {
|
||||
uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
|
||||
return (value & layout_mask) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::IsFastPointerLayout() {
|
||||
return IsSmi() && (Smi::cast(this)->value() == 0);
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
|
||||
|
||||
|
||||
int LayoutDescriptor::capacity() {
|
||||
return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize;
|
||||
}
|
||||
|
||||
|
||||
LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
|
||||
if (object->IsSmi()) {
|
||||
// Fast mode layout descriptor.
|
||||
return reinterpret_cast<LayoutDescriptor*>(object);
|
||||
}
|
||||
|
||||
// This is a mixed descriptor which is a fixed typed array.
|
||||
MapWord map_word = reinterpret_cast<HeapObject*>(object)->map_word();
|
||||
if (map_word.IsForwardingAddress()) {
|
||||
// Mark-compact has already moved layout descriptor.
|
||||
object = map_word.ToForwardingAddress();
|
||||
}
|
||||
return LayoutDescriptor::cast(object);
|
||||
}
|
||||
|
||||
|
||||
// InobjectPropertiesHelper is a helper class for querying whether inobject
|
||||
// property at offset is Double or not.
|
||||
InobjectPropertiesHelper::InobjectPropertiesHelper(Map* map)
|
||||
: all_fields_tagged_(true),
|
||||
header_size_(0),
|
||||
layout_descriptor_(LayoutDescriptor::FastPointerLayout()) {
|
||||
if (!FLAG_unbox_double_fields) return;
|
||||
|
||||
layout_descriptor_ = map->layout_descriptor_gc_safe();
|
||||
if (layout_descriptor_->IsFastPointerLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int inobject_properties = map->inobject_properties();
|
||||
DCHECK(inobject_properties > 0);
|
||||
header_size_ = map->instance_size() - (inobject_properties * kPointerSize);
|
||||
DCHECK(header_size_ >= 0);
|
||||
|
||||
all_fields_tagged_ = false;
|
||||
}
|
||||
|
||||
|
||||
bool InobjectPropertiesHelper::IsTagged(int offset_in_bytes) {
|
||||
DCHECK(IsAligned(offset_in_bytes, kPointerSize));
|
||||
if (all_fields_tagged_) return true;
|
||||
// Object headers do not contain non-tagged fields.
|
||||
if (offset_in_bytes < header_size_) return true;
|
||||
int field_index = (offset_in_bytes - header_size_) / kPointerSize;
|
||||
|
||||
return layout_descriptor_->IsTagged(field_index);
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
||||
#endif // V8_LAYOUT_DESCRIPTOR_INL_H_
|
@ -1,146 +0,0 @@
|
||||
// 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 <sstream>
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/layout-descriptor.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Handle<LayoutDescriptor> LayoutDescriptor::New(
|
||||
Handle<Map> map, Handle<DescriptorArray> descriptors, int num_descriptors) {
|
||||
Isolate* isolate = descriptors->GetIsolate();
|
||||
if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);
|
||||
|
||||
int inobject_properties = map->inobject_properties();
|
||||
if (inobject_properties == 0) return handle(FastPointerLayout(), isolate);
|
||||
|
||||
DCHECK(num_descriptors <= descriptors->number_of_descriptors());
|
||||
|
||||
int layout_descriptor_length;
|
||||
const int kMaxWordsPerField = kDoubleSize / kPointerSize;
|
||||
|
||||
if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
|
||||
// Even in the "worst" case (all fields are doubles) it would fit into
|
||||
// a Smi, so no need to calculate length.
|
||||
layout_descriptor_length = kSmiValueSize;
|
||||
|
||||
} else {
|
||||
layout_descriptor_length = 0;
|
||||
|
||||
for (int i = 0; i < num_descriptors; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (!InobjectUnboxedField(inobject_properties, details)) continue;
|
||||
int field_index = details.field_index();
|
||||
int field_width_in_words = details.field_width_in_words();
|
||||
layout_descriptor_length =
|
||||
Max(layout_descriptor_length, field_index + field_width_in_words);
|
||||
}
|
||||
|
||||
if (layout_descriptor_length == 0) {
|
||||
// No double fields were found, use fast pointer layout.
|
||||
return handle(FastPointerLayout(), isolate);
|
||||
}
|
||||
}
|
||||
layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
|
||||
|
||||
// Initially, layout descriptor corresponds to an object with all fields
|
||||
// tagged.
|
||||
Handle<LayoutDescriptor> layout_descriptor_handle =
|
||||
LayoutDescriptor::New(isolate, layout_descriptor_length);
|
||||
|
||||
DisallowHeapAllocation no_allocation;
|
||||
LayoutDescriptor* layout_descriptor = *layout_descriptor_handle;
|
||||
|
||||
for (int i = 0; i < num_descriptors; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (!InobjectUnboxedField(inobject_properties, details)) continue;
|
||||
int field_index = details.field_index();
|
||||
layout_descriptor = layout_descriptor->SetRawData(field_index);
|
||||
if (details.field_width_in_words() > 1) {
|
||||
layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
|
||||
}
|
||||
}
|
||||
return handle(layout_descriptor, isolate);
|
||||
}
|
||||
|
||||
|
||||
Handle<LayoutDescriptor> LayoutDescriptor::Append(Handle<Map> map,
|
||||
PropertyDetails details) {
|
||||
Handle<LayoutDescriptor> layout_descriptor = map->GetLayoutDescriptor();
|
||||
|
||||
if (!InobjectUnboxedField(map->inobject_properties(), details)) {
|
||||
return layout_descriptor;
|
||||
}
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
int field_index = details.field_index();
|
||||
layout_descriptor = LayoutDescriptor::EnsureCapacity(
|
||||
isolate, layout_descriptor, field_index + details.field_width_in_words());
|
||||
|
||||
DisallowHeapAllocation no_allocation;
|
||||
LayoutDescriptor* layout_desc = *layout_descriptor;
|
||||
layout_desc = layout_desc->SetRawData(field_index);
|
||||
if (details.field_width_in_words() > 1) {
|
||||
layout_desc = layout_desc->SetRawData(field_index + 1);
|
||||
}
|
||||
return handle(layout_desc, isolate);
|
||||
}
|
||||
|
||||
|
||||
Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
|
||||
Handle<Map> map, PropertyDetails details,
|
||||
Handle<LayoutDescriptor> full_layout_descriptor) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
LayoutDescriptor* layout_descriptor = map->layout_descriptor();
|
||||
if (layout_descriptor->IsSlowLayout()) {
|
||||
return full_layout_descriptor;
|
||||
}
|
||||
if (!InobjectUnboxedField(map->inobject_properties(), details)) {
|
||||
return handle(layout_descriptor, map->GetIsolate());
|
||||
}
|
||||
int field_index = details.field_index();
|
||||
int new_capacity = field_index + details.field_width_in_words();
|
||||
if (new_capacity > layout_descriptor->capacity()) {
|
||||
// Current map's layout descriptor runs out of space, so use the full
|
||||
// layout descriptor.
|
||||
return full_layout_descriptor;
|
||||
}
|
||||
|
||||
layout_descriptor = layout_descriptor->SetRawData(field_index);
|
||||
if (details.field_width_in_words() > 1) {
|
||||
layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
|
||||
}
|
||||
return handle(layout_descriptor, map->GetIsolate());
|
||||
}
|
||||
|
||||
|
||||
Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
|
||||
Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
|
||||
int new_capacity) {
|
||||
int old_capacity = layout_descriptor->capacity();
|
||||
if (new_capacity <= old_capacity) {
|
||||
// Nothing to do with layout in Smi-form.
|
||||
return layout_descriptor;
|
||||
}
|
||||
Handle<LayoutDescriptor> new_layout_descriptor =
|
||||
LayoutDescriptor::New(isolate, new_capacity);
|
||||
DCHECK(new_layout_descriptor->IsSlowLayout());
|
||||
|
||||
if (layout_descriptor->IsSlowLayout()) {
|
||||
memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(),
|
||||
layout_descriptor->DataSize());
|
||||
return new_layout_descriptor;
|
||||
} else {
|
||||
// Fast layout.
|
||||
uint32_t value =
|
||||
static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value());
|
||||
new_layout_descriptor->set(0, value);
|
||||
return new_layout_descriptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
@ -1,126 +0,0 @@
|
||||
// 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_LAYOUT_DESCRIPTOR_H_
|
||||
#define V8_LAYOUT_DESCRIPTOR_H_
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "src/objects.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// LayoutDescriptor is a bit vector defining which fields contain non-tagged
|
||||
// values. It could either be a fixed typed array (slow form) or a Smi
|
||||
// if the length fits (fast form).
|
||||
// Each bit in the layout represents a FIELD. The bits are referenced by
|
||||
// field_index which is a field number. If the bit is set then the corresponding
|
||||
// field contains a non-tagged value and therefore must be skipped by GC.
|
||||
// Otherwise the field is considered tagged. If the queried bit lays "outside"
|
||||
// of the descriptor then the field is also considered tagged.
|
||||
// Once a layout descriptor is created it is allowed only to append properties
|
||||
// to it.
|
||||
class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
|
||||
public:
|
||||
V8_INLINE bool IsTagged(int field_index);
|
||||
|
||||
// Returns true if this is a layout of the object having only tagged fields.
|
||||
V8_INLINE bool IsFastPointerLayout();
|
||||
|
||||
// Returns true if the layout descriptor is in non-Smi form.
|
||||
V8_INLINE bool IsSlowLayout();
|
||||
|
||||
V8_INLINE static LayoutDescriptor* cast(Object* object);
|
||||
V8_INLINE static const LayoutDescriptor* cast(const Object* object);
|
||||
|
||||
V8_INLINE static LayoutDescriptor* cast_gc_safe(Object* object);
|
||||
|
||||
// Builds layout descriptor optimized for given |map| by |num_descriptors|
|
||||
// elements of given descriptors array. The |map|'s descriptors could be
|
||||
// different.
|
||||
static Handle<LayoutDescriptor> New(Handle<Map> map,
|
||||
Handle<DescriptorArray> descriptors,
|
||||
int num_descriptors);
|
||||
|
||||
// Creates new layout descriptor by appending property with |details| to
|
||||
// |map|'s layout descriptor.
|
||||
static Handle<LayoutDescriptor> Append(Handle<Map> map,
|
||||
PropertyDetails details);
|
||||
|
||||
// Creates new layout descriptor by appending property with |details| to
|
||||
// |map|'s layout descriptor and if it is still fast then returns it.
|
||||
// Otherwise the |full_layout_descriptor| is returned.
|
||||
static Handle<LayoutDescriptor> AppendIfFastOrUseFull(
|
||||
Handle<Map> map, PropertyDetails details,
|
||||
Handle<LayoutDescriptor> full_layout_descriptor);
|
||||
|
||||
// Layout descriptor that corresponds to an object all fields of which are
|
||||
// tagged (FastPointerLayout).
|
||||
V8_INLINE static LayoutDescriptor* FastPointerLayout();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check that this layout descriptor corresponds to given map.
|
||||
bool IsConsistentWithMap(Map* map);
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_PRINT
|
||||
// For our gdb macros, we should perhaps change these in the future.
|
||||
void Print();
|
||||
|
||||
void Print(std::ostream& os); // NOLINT
|
||||
#endif
|
||||
|
||||
// Capacity of layout descriptors in bits.
|
||||
V8_INLINE int capacity();
|
||||
|
||||
V8_INLINE LayoutDescriptor* SetTaggedForTesting(int field_index,
|
||||
bool tagged) {
|
||||
return SetTagged(field_index, tagged);
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kNumberOfBits = 32;
|
||||
|
||||
V8_INLINE static Handle<LayoutDescriptor> New(Isolate* isolate, int length);
|
||||
V8_INLINE static LayoutDescriptor* FromSmi(Smi* smi);
|
||||
|
||||
V8_INLINE static bool InobjectUnboxedField(int inobject_properties,
|
||||
PropertyDetails details);
|
||||
|
||||
static Handle<LayoutDescriptor> EnsureCapacity(
|
||||
Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
|
||||
int new_capacity);
|
||||
|
||||
// Returns false if requested field_index is out of bounds.
|
||||
V8_INLINE bool GetIndexes(int field_index, int* layout_word_index,
|
||||
uint32_t* layout_mask);
|
||||
|
||||
V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetRawData(int field_index) {
|
||||
return SetTagged(field_index, false);
|
||||
}
|
||||
|
||||
V8_INLINE MUST_USE_RESULT LayoutDescriptor* SetTagged(int field_index,
|
||||
bool tagged);
|
||||
};
|
||||
|
||||
|
||||
// InobjectPropertiesHelper is a helper class for querying layout descriptor
|
||||
// about whether the field at given offset is tagged or not.
|
||||
class InobjectPropertiesHelper {
|
||||
public:
|
||||
inline explicit InobjectPropertiesHelper(Map* map);
|
||||
|
||||
bool all_fields_tagged() { return all_fields_tagged_; }
|
||||
inline bool IsTagged(int offset_in_bytes);
|
||||
|
||||
private:
|
||||
bool all_fields_tagged_;
|
||||
int header_size_;
|
||||
LayoutDescriptor* layout_descriptor_;
|
||||
};
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
||||
#endif // V8_LAYOUT_DESCRIPTOR_H_
|
@ -275,10 +275,6 @@ void JSObject::JSObjectVerify() {
|
||||
if (descriptors->GetDetails(i).type() == FIELD) {
|
||||
Representation r = descriptors->GetDetails(i).representation();
|
||||
FieldIndex index = FieldIndex::ForDescriptor(map(), i);
|
||||
if (IsUnboxedDoubleField(index)) {
|
||||
DCHECK(r.IsDouble());
|
||||
continue;
|
||||
}
|
||||
Object* value = RawFastPropertyAt(index);
|
||||
if (r.IsDouble()) DCHECK(value->IsMutableHeapNumber());
|
||||
if (value->IsUninitialized()) continue;
|
||||
@ -320,8 +316,6 @@ void Map::MapVerify() {
|
||||
SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
|
||||
SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
|
||||
}
|
||||
SLOW_DCHECK(!FLAG_unbox_double_fields ||
|
||||
layout_descriptor()->IsConsistentWithMap(this));
|
||||
}
|
||||
|
||||
|
||||
@ -331,7 +325,8 @@ void Map::DictionaryMapVerify() {
|
||||
CHECK(instance_descriptors()->IsEmpty());
|
||||
CHECK_EQ(0, pre_allocated_property_fields());
|
||||
CHECK_EQ(0, unused_property_fields());
|
||||
CHECK_EQ(StaticVisitorBase::GetVisitorId(this), visitor_id());
|
||||
CHECK_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()),
|
||||
visitor_id());
|
||||
}
|
||||
|
||||
|
||||
@ -1184,27 +1179,6 @@ bool DescriptorArray::IsSortedNoDuplicates(int valid_entries) {
|
||||
}
|
||||
|
||||
|
||||
bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
|
||||
if (FLAG_unbox_double_fields) {
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
int nof_descriptors = map->NumberOfOwnDescriptors();
|
||||
for (int i = 0; i < nof_descriptors; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.type() != FIELD) continue;
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
|
||||
bool tagged_expected =
|
||||
!field_index.is_inobject() || !details.representation().IsDouble();
|
||||
for (int bit = 0; bit < details.field_width_in_words(); bit++) {
|
||||
bool tagged_actual = IsTagged(details.field_index() + bit);
|
||||
DCHECK_EQ(tagged_expected, tagged_actual);
|
||||
if (tagged_actual != tagged_expected) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
|
||||
DCHECK(valid_entries == -1);
|
||||
Name* prev_key = NULL;
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "src/heap/spaces.h"
|
||||
#include "src/heap/store-buffer.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/layout-descriptor-inl.h"
|
||||
#include "src/lookup.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/property.h"
|
||||
@ -57,14 +56,6 @@ PropertyDetails PropertyDetails::AsDeleted() const {
|
||||
}
|
||||
|
||||
|
||||
int PropertyDetails::field_width_in_words() const {
|
||||
DCHECK(type() == FIELD);
|
||||
if (!FLAG_unbox_double_fields) return 1;
|
||||
if (kDoubleSize == kPointerSize) return 1;
|
||||
return representation().IsDouble() ? kDoubleSize / kPointerSize : 1;
|
||||
}
|
||||
|
||||
|
||||
#define TYPE_CHECKER(type, instancetype) \
|
||||
bool Object::Is##type() const { \
|
||||
return Object::IsHeapObject() && \
|
||||
@ -713,11 +704,6 @@ bool Object::IsDescriptorArray() const {
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsLayoutDescriptor() const {
|
||||
return IsSmi() || IsFixedTypedArrayBase();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsTransitionArray() const {
|
||||
return IsFixedArray();
|
||||
}
|
||||
@ -2084,24 +2070,10 @@ void JSObject::SetInternalField(int index, Smi* value) {
|
||||
}
|
||||
|
||||
|
||||
bool JSObject::IsUnboxedDoubleField(FieldIndex index) {
|
||||
if (!FLAG_unbox_double_fields) return false;
|
||||
return map()->IsUnboxedDoubleField(index);
|
||||
}
|
||||
|
||||
|
||||
bool Map::IsUnboxedDoubleField(FieldIndex index) {
|
||||
if (!FLAG_unbox_double_fields) return false;
|
||||
if (index.is_hidden_field() || !index.is_inobject()) return false;
|
||||
return !layout_descriptor()->IsTagged(index.property_index());
|
||||
}
|
||||
|
||||
|
||||
// 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(FieldIndex index) {
|
||||
DCHECK(!IsUnboxedDoubleField(index));
|
||||
if (index.is_inobject()) {
|
||||
return READ_FIELD(this, index.offset());
|
||||
} else {
|
||||
@ -2110,13 +2082,7 @@ Object* JSObject::RawFastPropertyAt(FieldIndex index) {
|
||||
}
|
||||
|
||||
|
||||
double JSObject::RawFastDoublePropertyAt(FieldIndex index) {
|
||||
DCHECK(IsUnboxedDoubleField(index));
|
||||
return READ_DOUBLE_FIELD(this, index.offset());
|
||||
}
|
||||
|
||||
|
||||
void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) {
|
||||
void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
|
||||
if (index.is_inobject()) {
|
||||
int offset = index.offset();
|
||||
WRITE_FIELD(this, offset, value);
|
||||
@ -2127,21 +2093,6 @@ void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) {
|
||||
}
|
||||
|
||||
|
||||
void JSObject::RawFastDoublePropertyAtPut(FieldIndex index, double value) {
|
||||
WRITE_DOUBLE_FIELD(this, index.offset(), value);
|
||||
}
|
||||
|
||||
|
||||
void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
|
||||
if (IsUnboxedDoubleField(index)) {
|
||||
DCHECK(value->IsMutableHeapNumber());
|
||||
RawFastDoublePropertyAtPut(index, HeapNumber::cast(value)->value());
|
||||
} else {
|
||||
RawFastPropertyAtPut(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int JSObject::GetInObjectPropertyOffset(int index) {
|
||||
return map()->GetInObjectPropertyOffset(index);
|
||||
}
|
||||
@ -3160,7 +3111,8 @@ void DescriptorArray::Set(int descriptor_number,
|
||||
NoIncrementalWriteBarrierSet(this,
|
||||
ToValueIndex(descriptor_number),
|
||||
*desc->GetValue());
|
||||
NoIncrementalWriteBarrierSet(this, ToDetailsIndex(descriptor_number),
|
||||
NoIncrementalWriteBarrierSet(this,
|
||||
ToDetailsIndex(descriptor_number),
|
||||
desc->GetDetails().AsSmi());
|
||||
}
|
||||
|
||||
@ -3335,7 +3287,6 @@ CAST_ACCESSOR(JSTypedArray)
|
||||
CAST_ACCESSOR(JSValue)
|
||||
CAST_ACCESSOR(JSWeakMap)
|
||||
CAST_ACCESSOR(JSWeakSet)
|
||||
CAST_ACCESSOR(LayoutDescriptor)
|
||||
CAST_ACCESSOR(Map)
|
||||
CAST_ACCESSOR(MapCache)
|
||||
CAST_ACCESSOR(Name)
|
||||
@ -4378,14 +4329,6 @@ int Map::GetInObjectPropertyOffset(int index) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> Map::CopyInstallDescriptorsForTesting(
|
||||
Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> layout_descriptor) {
|
||||
return CopyInstallDescriptors(map, new_descriptor, descriptors,
|
||||
layout_descriptor);
|
||||
}
|
||||
|
||||
|
||||
int HeapObject::SizeFromMap(Map* map) {
|
||||
int instance_size = map->instance_size();
|
||||
if (instance_size != kVariableSizeSentinel) return instance_size;
|
||||
@ -5231,41 +5174,14 @@ static void EnsureHasTransitionArray(Handle<Map> map) {
|
||||
}
|
||||
|
||||
|
||||
LayoutDescriptor* Map::layout_descriptor_gc_safe() {
|
||||
Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
|
||||
return LayoutDescriptor::cast_gc_safe(layout_desc);
|
||||
}
|
||||
|
||||
|
||||
void Map::UpdateDescriptors(DescriptorArray* descriptors,
|
||||
LayoutDescriptor* layout_desc) {
|
||||
set_instance_descriptors(descriptors);
|
||||
if (FLAG_unbox_double_fields) {
|
||||
if (layout_descriptor()->IsSlowLayout()) {
|
||||
set_layout_descriptor(layout_desc);
|
||||
}
|
||||
SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this));
|
||||
DCHECK(visitor_id() == StaticVisitorBase::GetVisitorId(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Map::InitializeDescriptors(DescriptorArray* descriptors,
|
||||
LayoutDescriptor* layout_desc) {
|
||||
void Map::InitializeDescriptors(DescriptorArray* descriptors) {
|
||||
int len = descriptors->number_of_descriptors();
|
||||
set_instance_descriptors(descriptors);
|
||||
SetNumberOfOwnDescriptors(len);
|
||||
|
||||
if (FLAG_unbox_double_fields) {
|
||||
set_layout_descriptor(layout_desc);
|
||||
SLOW_DCHECK(layout_descriptor()->IsConsistentWithMap(this));
|
||||
set_visitor_id(StaticVisitorBase::GetVisitorId(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset)
|
||||
ACCESSORS(Map, layout_descriptor, LayoutDescriptor, kLayoutDecriptorOffset)
|
||||
|
||||
|
||||
void Map::set_bit_field3(uint32_t bits) {
|
||||
@ -5281,27 +5197,12 @@ uint32_t Map::bit_field3() {
|
||||
}
|
||||
|
||||
|
||||
Handle<LayoutDescriptor> Map::GetLayoutDescriptor() {
|
||||
LayoutDescriptor* layout_desc = FLAG_unbox_double_fields
|
||||
? layout_descriptor()
|
||||
: LayoutDescriptor::FastPointerLayout();
|
||||
return handle(layout_desc, GetIsolate());
|
||||
}
|
||||
|
||||
|
||||
void Map::AppendDescriptor(Descriptor* desc) {
|
||||
DescriptorArray* descriptors = instance_descriptors();
|
||||
int number_of_own_descriptors = NumberOfOwnDescriptors();
|
||||
DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
|
||||
descriptors->Append(desc);
|
||||
SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
|
||||
|
||||
// This function does not support appending double field descriptors and
|
||||
// it should never try to (otherwise, layout descriptor must be updated too).
|
||||
#ifdef DEBUG
|
||||
PropertyDetails details = desc->GetDetails();
|
||||
CHECK(details.type() != FIELD || !details.representation().IsDouble());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -7378,37 +7279,12 @@ void ExternalTwoByteString::ExternalTwoByteStringIterateBody() {
|
||||
}
|
||||
|
||||
|
||||
static inline void IterateBodyUsingLayoutDescriptor(HeapObject* object,
|
||||
int start_offset,
|
||||
int end_offset,
|
||||
ObjectVisitor* v) {
|
||||
DCHECK(FLAG_unbox_double_fields);
|
||||
DCHECK(IsAligned(start_offset, kPointerSize) &&
|
||||
IsAligned(end_offset, kPointerSize));
|
||||
|
||||
InobjectPropertiesHelper helper(object->map());
|
||||
DCHECK(!helper.all_fields_tagged());
|
||||
|
||||
for (int offset = start_offset; offset < end_offset; offset += kPointerSize) {
|
||||
// Visit all tagged fields.
|
||||
if (helper.IsTagged(offset)) {
|
||||
v->VisitPointer(HeapObject::RawField(object, offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int start_offset, int end_offset, int size>
|
||||
void FixedBodyDescriptor<start_offset, end_offset, size>::IterateBody(
|
||||
HeapObject* obj,
|
||||
ObjectVisitor* v) {
|
||||
if (!FLAG_unbox_double_fields ||
|
||||
obj->map()->layout_descriptor()->IsFastPointerLayout()) {
|
||||
v->VisitPointers(HeapObject::RawField(obj, start_offset),
|
||||
HeapObject::RawField(obj, end_offset));
|
||||
} else {
|
||||
IterateBodyUsingLayoutDescriptor(obj, start_offset, end_offset, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7416,13 +7292,8 @@ template<int start_offset>
|
||||
void FlexibleBodyDescriptor<start_offset>::IterateBody(HeapObject* obj,
|
||||
int object_size,
|
||||
ObjectVisitor* v) {
|
||||
if (!FLAG_unbox_double_fields ||
|
||||
obj->map()->layout_descriptor()->IsFastPointerLayout()) {
|
||||
v->VisitPointers(HeapObject::RawField(obj, start_offset),
|
||||
HeapObject::RawField(obj, object_size));
|
||||
} else {
|
||||
IterateBodyUsingLayoutDescriptor(obj, start_offset, object_size, v);
|
||||
}
|
||||
v->VisitPointers(HeapObject::RawField(obj, start_offset),
|
||||
HeapObject::RawField(obj, object_size));
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,12 +233,8 @@ void JSObject::PrintProperties(std::ostream& os) { // NOLINT
|
||||
switch (descs->GetType(i)) {
|
||||
case FIELD: {
|
||||
FieldIndex index = FieldIndex::ForDescriptor(map(), i);
|
||||
if (IsUnboxedDoubleField(index)) {
|
||||
os << "<unboxed double> " << RawFastDoublePropertyAt(index);
|
||||
} else {
|
||||
os << Brief(RawFastPropertyAt(index));
|
||||
}
|
||||
os << " (field at offset " << index.property_index() << ")\n";
|
||||
os << Brief(RawFastPropertyAt(index)) << " (field at offset "
|
||||
<< index.property_index() << ")\n";
|
||||
break;
|
||||
}
|
||||
case CONSTANT:
|
||||
@ -434,9 +430,6 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "")
|
||||
<< "#" << NumberOfOwnDescriptors() << ": "
|
||||
<< Brief(instance_descriptors());
|
||||
if (FLAG_unbox_double_fields) {
|
||||
os << "\n - layout descriptor: " << Brief(layout_descriptor());
|
||||
}
|
||||
if (HasTransitionArray()) {
|
||||
os << "\n - transitions: " << Brief(transitions());
|
||||
}
|
||||
@ -445,9 +438,6 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n - code cache: " << Brief(code_cache());
|
||||
os << "\n - dependent code: " << Brief(dependent_code());
|
||||
os << "\n";
|
||||
instance_descriptors()->PrintDescriptors(os);
|
||||
os << "\n";
|
||||
if (FLAG_unbox_double_fields) layout_descriptor()->Print(os);
|
||||
}
|
||||
|
||||
|
||||
@ -1086,43 +1076,6 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT
|
||||
}
|
||||
|
||||
|
||||
static void PrintBitMask(std::ostream& os, uint32_t value) { // NOLINT
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if ((i & 7) == 0) os << " ";
|
||||
os << (((value & 1) == 0) ? "_" : "x");
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LayoutDescriptor::Print() {
|
||||
OFStream os(stdout);
|
||||
this->Print(os);
|
||||
os << std::flush;
|
||||
}
|
||||
|
||||
|
||||
void LayoutDescriptor::Print(std::ostream& os) { // NOLINT
|
||||
os << "Layout descriptor: ";
|
||||
if (IsUninitialized()) {
|
||||
os << "<uninitialized>";
|
||||
} else if (IsFastPointerLayout()) {
|
||||
os << "<all tagged>";
|
||||
} else if (IsSmi()) {
|
||||
os << "fast";
|
||||
PrintBitMask(os, static_cast<uint32_t>(Smi::cast(this)->value()));
|
||||
} else {
|
||||
os << "slow";
|
||||
int len = length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > 0) os << " |";
|
||||
PrintBitMask(os, get_scalar(i));
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
||||
void TransitionArray::Print() {
|
||||
OFStream os(stdout);
|
||||
this->PrintTransitions(os);
|
||||
|
306
src/objects.cc
306
src/objects.cc
@ -1953,8 +1953,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
// Clear out the old descriptor array to avoid problems to sharing
|
||||
// the descriptor array without using an explicit.
|
||||
old_map->InitializeDescriptors(
|
||||
old_map->GetHeap()->empty_descriptor_array(),
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
old_map->GetHeap()->empty_descriptor_array());
|
||||
// Ensure that no transition was inserted for prototype migrations.
|
||||
DCHECK(!old_map->HasTransitionArray());
|
||||
DCHECK(new_map->GetBackPointer()->IsUndefined());
|
||||
@ -2013,14 +2012,10 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
|
||||
if (old_map->unused_property_fields() > 0) {
|
||||
if (details.representation().IsDouble()) {
|
||||
Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
|
||||
FieldIndex index =
|
||||
FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
|
||||
if (new_map->IsUnboxedDoubleField(index)) {
|
||||
object->RawFastDoublePropertyAtPut(index, 0);
|
||||
} else {
|
||||
Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
|
||||
object->RawFastPropertyAtPut(index, *value);
|
||||
}
|
||||
object->FastPropertyAtPut(index, *value);
|
||||
}
|
||||
object->synchronized_set_map(*new_map);
|
||||
return;
|
||||
@ -2072,35 +2067,23 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
DCHECK(details.representation().IsTagged());
|
||||
continue;
|
||||
}
|
||||
Representation old_representation = old_details.representation();
|
||||
Representation representation = details.representation();
|
||||
DCHECK(old_details.type() == CONSTANT ||
|
||||
old_details.type() == FIELD);
|
||||
Handle<Object> value;
|
||||
if (old_details.type() == CONSTANT) {
|
||||
value = handle(old_descriptors->GetValue(i), isolate);
|
||||
DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
|
||||
} else {
|
||||
FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
|
||||
if (object->IsUnboxedDoubleField(index)) {
|
||||
double old = object->RawFastDoublePropertyAt(index);
|
||||
value = isolate->factory()->NewHeapNumber(
|
||||
old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
|
||||
|
||||
} else {
|
||||
value = handle(object->RawFastPropertyAt(index), isolate);
|
||||
if (!old_representation.IsDouble() && representation.IsDouble()) {
|
||||
if (old_representation.IsNone()) {
|
||||
value = handle(Smi::FromInt(0), isolate);
|
||||
}
|
||||
value = Object::NewStorageFor(isolate, value, representation);
|
||||
} else if (old_representation.IsDouble() &&
|
||||
!representation.IsDouble()) {
|
||||
value = Object::WrapForRead(isolate, value, old_representation);
|
||||
}
|
||||
Object* raw_value = old_details.type() == CONSTANT
|
||||
? old_descriptors->GetValue(i)
|
||||
: object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
|
||||
Handle<Object> value(raw_value, isolate);
|
||||
if (!old_details.representation().IsDouble() &&
|
||||
details.representation().IsDouble()) {
|
||||
if (old_details.representation().IsNone()) {
|
||||
value = handle(Smi::FromInt(0), isolate);
|
||||
}
|
||||
value = Object::NewStorageFor(isolate, value, details.representation());
|
||||
} else if (old_details.representation().IsDouble() &&
|
||||
!details.representation().IsDouble()) {
|
||||
value = Object::WrapForRead(isolate, value, old_details.representation());
|
||||
}
|
||||
DCHECK(!(representation.IsDouble() && value->IsSmi()));
|
||||
DCHECK(!(details.representation().IsDouble() && value->IsSmi()));
|
||||
int target_index = new_descriptors->GetFieldIndex(i) - inobject;
|
||||
if (target_index < 0) target_index += total_size;
|
||||
array->set(target_index, *value);
|
||||
@ -2128,16 +2111,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
int limit = Min(inobject, number_of_fields);
|
||||
for (int i = 0; i < limit; i++) {
|
||||
FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
|
||||
Object* value = array->get(external + i);
|
||||
// Can't use JSObject::FastPropertyAtPut() because proper map was not set
|
||||
// yet.
|
||||
if (new_map->IsUnboxedDoubleField(index)) {
|
||||
DCHECK(value->IsMutableHeapNumber());
|
||||
object->RawFastDoublePropertyAtPut(index,
|
||||
HeapNumber::cast(value)->value());
|
||||
} else {
|
||||
object->RawFastPropertyAtPut(index, value);
|
||||
}
|
||||
object->FastPropertyAtPut(index, array->get(external + i));
|
||||
}
|
||||
|
||||
Heap* heap = isolate->heap();
|
||||
@ -2261,8 +2235,7 @@ void Map::DeprecateTransitionTree() {
|
||||
// arrays.
|
||||
void Map::DeprecateTarget(PropertyType type, Name* key,
|
||||
PropertyAttributes attributes,
|
||||
DescriptorArray* new_descriptors,
|
||||
LayoutDescriptor* new_layout_descriptor) {
|
||||
DescriptorArray* new_descriptors) {
|
||||
if (HasTransitionArray()) {
|
||||
TransitionArray* transitions = this->transitions();
|
||||
int transition = transitions->Search(type, key, attributes);
|
||||
@ -2279,7 +2252,7 @@ void Map::DeprecateTarget(PropertyType type, Name* key,
|
||||
GetHeap()->incremental_marking()->RecordWrites(to_replace);
|
||||
while (current->instance_descriptors() == to_replace) {
|
||||
current->SetEnumLength(kInvalidEnumCacheSentinel);
|
||||
current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
|
||||
current->set_instance_descriptors(new_descriptors);
|
||||
Object* next = current->GetBackPointer();
|
||||
if (next->IsUndefined()) break;
|
||||
current = Map::cast(next);
|
||||
@ -2618,9 +2591,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < root_nof; ++i) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(i);
|
||||
if (old_details.type() == FIELD) {
|
||||
current_offset += old_details.field_width_in_words();
|
||||
}
|
||||
if (old_details.type() == FIELD) current_offset++;
|
||||
Descriptor d(handle(old_descriptors->GetKey(i), isolate),
|
||||
handle(old_descriptors->GetValue(i), isolate),
|
||||
old_details);
|
||||
@ -2658,10 +2629,11 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
||||
target_field_type = GeneralizeFieldType(
|
||||
target_field_type, new_field_type, isolate);
|
||||
}
|
||||
FieldDescriptor d(target_key, current_offset, target_field_type,
|
||||
FieldDescriptor d(target_key,
|
||||
current_offset++,
|
||||
target_field_type,
|
||||
target_details.attributes(),
|
||||
target_details.representation());
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
DCHECK_NE(FIELD, target_details.type());
|
||||
@ -2687,20 +2659,23 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
||||
old_field_type = GeneralizeFieldType(
|
||||
old_field_type, new_field_type, isolate);
|
||||
}
|
||||
FieldDescriptor d(old_key, current_offset, old_field_type,
|
||||
old_details.attributes(), old_details.representation());
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
FieldDescriptor d(old_key,
|
||||
current_offset++,
|
||||
old_field_type,
|
||||
old_details.attributes(),
|
||||
old_details.representation());
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
|
||||
if (modify_index == i && store_mode == FORCE_FIELD) {
|
||||
FieldDescriptor d(
|
||||
old_key, current_offset,
|
||||
GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType(
|
||||
isolate, old_details.representation()),
|
||||
new_field_type, isolate),
|
||||
old_details.attributes(), old_details.representation());
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
FieldDescriptor d(old_key,
|
||||
current_offset++,
|
||||
GeneralizeFieldType(
|
||||
old_descriptors->GetValue(i)->OptimalType(
|
||||
isolate, old_details.representation()),
|
||||
new_field_type, isolate),
|
||||
old_details.attributes(),
|
||||
old_details.representation());
|
||||
new_descriptors->Set(i, &d);
|
||||
} else {
|
||||
DCHECK_NE(FIELD, old_details.type());
|
||||
@ -2722,13 +2697,10 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
||||
int split_nof = split_map->NumberOfOwnDescriptors();
|
||||
DCHECK_NE(old_nof, split_nof);
|
||||
|
||||
Handle<LayoutDescriptor> new_layout_descriptor =
|
||||
LayoutDescriptor::New(split_map, new_descriptors, old_nof);
|
||||
PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
|
||||
split_map->DeprecateTarget(split_prop_details.type(),
|
||||
old_descriptors->GetKey(split_nof),
|
||||
split_prop_details.attributes(), *new_descriptors,
|
||||
*new_layout_descriptor);
|
||||
split_prop_details.attributes(), *new_descriptors);
|
||||
|
||||
if (FLAG_trace_generalization) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
||||
@ -2755,8 +2727,7 @@ Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
|
||||
return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
|
||||
"can't have more transitions");
|
||||
}
|
||||
new_map = CopyInstallDescriptors(new_map, i, new_descriptors,
|
||||
new_layout_descriptor);
|
||||
new_map = CopyInstallDescriptors(new_map, i, new_descriptors);
|
||||
}
|
||||
new_map->set_owns_descriptors(true);
|
||||
return new_map;
|
||||
@ -3179,12 +3150,8 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
|
||||
Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
|
||||
descriptors, old_size, slack);
|
||||
|
||||
DisallowHeapAllocation no_allocation;
|
||||
// The descriptors are still the same, so keep the layout descriptor.
|
||||
LayoutDescriptor* layout_descriptor = map->layout_descriptor();
|
||||
|
||||
if (old_size == 0) {
|
||||
map->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
||||
map->set_instance_descriptors(*new_descriptors);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3206,10 +3173,10 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
|
||||
current = walk_map->GetBackPointer()) {
|
||||
walk_map = Map::cast(current);
|
||||
if (walk_map->instance_descriptors() != *descriptors) break;
|
||||
walk_map->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
||||
walk_map->set_instance_descriptors(*new_descriptors);
|
||||
}
|
||||
|
||||
map->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
||||
map->set_instance_descriptors(*new_descriptors);
|
||||
}
|
||||
|
||||
|
||||
@ -3883,15 +3850,11 @@ void JSObject::WriteToField(int descriptor, Object* value) {
|
||||
if (details.representation().IsDouble()) {
|
||||
// Nothing more to be done.
|
||||
if (value->IsUninitialized()) return;
|
||||
if (IsUnboxedDoubleField(index)) {
|
||||
RawFastDoublePropertyAtPut(index, value->Number());
|
||||
} else {
|
||||
HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
|
||||
DCHECK(box->IsMutableHeapNumber());
|
||||
box->set_value(value->Number());
|
||||
}
|
||||
HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
|
||||
DCHECK(box->IsMutableHeapNumber());
|
||||
box->set_value(value->Number());
|
||||
} else {
|
||||
RawFastPropertyAtPut(index, value);
|
||||
FastPropertyAtPut(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4353,17 +4316,12 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
|
||||
case FIELD: {
|
||||
Handle<Name> key(descs->GetKey(i));
|
||||
FieldIndex index = FieldIndex::ForDescriptor(*map, i);
|
||||
Handle<Object> value;
|
||||
if (object->IsUnboxedDoubleField(index)) {
|
||||
double old_value = object->RawFastDoublePropertyAt(index);
|
||||
value = isolate->factory()->NewHeapNumber(old_value);
|
||||
} else {
|
||||
value = handle(object->RawFastPropertyAt(index), isolate);
|
||||
if (details.representation().IsDouble()) {
|
||||
DCHECK(value->IsMutableHeapNumber());
|
||||
Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
|
||||
value = isolate->factory()->NewHeapNumber(old->value());
|
||||
}
|
||||
Handle<Object> value(
|
||||
object->RawFastPropertyAt(index), isolate);
|
||||
if (details.representation().IsDouble()) {
|
||||
DCHECK(value->IsMutableHeapNumber());
|
||||
Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
|
||||
value = isolate->factory()->NewHeapNumber(old->value());
|
||||
}
|
||||
PropertyDetails d =
|
||||
PropertyDetails(details.attributes(), NORMAL, i + 1);
|
||||
@ -4533,10 +4491,9 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
|
||||
int offset = current_offset - inobject_props;
|
||||
fields->set(offset, value);
|
||||
}
|
||||
FieldDescriptor d(key, current_offset, details.attributes(),
|
||||
FieldDescriptor d(key, current_offset++, details.attributes(),
|
||||
// TODO(verwaest): value->OptimalRepresentation();
|
||||
Representation::Tagged());
|
||||
current_offset += d.GetDetails().field_width_in_words();
|
||||
descriptors->Set(enumeration_index - 1, &d);
|
||||
} else if (type == CALLBACKS) {
|
||||
CallbacksDescriptor d(key, handle(value, isolate), details.attributes());
|
||||
@ -4549,11 +4506,8 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
|
||||
|
||||
descriptors->Sort();
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
|
||||
new_map, descriptors, descriptors->number_of_descriptors());
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
new_map->InitializeDescriptors(*descriptors);
|
||||
new_map->set_unused_property_fields(unused_property_fields);
|
||||
|
||||
// Transform the object.
|
||||
@ -5524,10 +5478,6 @@ Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
|
||||
Representation representation,
|
||||
FieldIndex index) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
if (object->IsUnboxedDoubleField(index)) {
|
||||
double value = object->RawFastDoublePropertyAt(index);
|
||||
return isolate->factory()->NewHeapNumber(value);
|
||||
}
|
||||
Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
|
||||
return Object::WrapForRead(isolate, raw_value, representation);
|
||||
}
|
||||
@ -5618,28 +5568,18 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.type() != FIELD) continue;
|
||||
FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
|
||||
if (object->IsUnboxedDoubleField(index)) {
|
||||
if (copying) {
|
||||
double value = object->RawFastDoublePropertyAt(index);
|
||||
copy->RawFastDoublePropertyAtPut(index, value);
|
||||
}
|
||||
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
|
||||
if (value->IsJSObject()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, value,
|
||||
VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
|
||||
JSObject);
|
||||
} else {
|
||||
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
|
||||
if (value->IsJSObject()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, value,
|
||||
VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
|
||||
JSObject);
|
||||
if (copying) {
|
||||
copy->FastPropertyAtPut(index, *value);
|
||||
}
|
||||
} else {
|
||||
if (copying) {
|
||||
Representation representation = details.representation();
|
||||
value = Object::NewStorageFor(isolate, value, representation);
|
||||
copy->FastPropertyAtPut(index, *value);
|
||||
}
|
||||
}
|
||||
Representation representation = details.representation();
|
||||
value = Object::NewStorageFor(isolate, value, representation);
|
||||
}
|
||||
if (copying) {
|
||||
copy->FastPropertyAtPut(index, *value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -5836,17 +5776,16 @@ int Map::NumberOfDescribedProperties(DescriptorFlag which,
|
||||
|
||||
|
||||
int Map::NextFreePropertyIndex() {
|
||||
int free_index = 0;
|
||||
int max_index = -1;
|
||||
int number_of_own_descriptors = NumberOfOwnDescriptors();
|
||||
DescriptorArray* descs = instance_descriptors();
|
||||
for (int i = 0; i < number_of_own_descriptors; i++) {
|
||||
PropertyDetails details = descs->GetDetails(i);
|
||||
if (details.type() == FIELD) {
|
||||
int candidate = details.field_index() + details.field_width_in_words();
|
||||
if (candidate > free_index) free_index = candidate;
|
||||
if (descs->GetType(i) == FIELD) {
|
||||
int current_index = descs->GetFieldIndex(i);
|
||||
if (current_index > max_index) max_index = current_index;
|
||||
}
|
||||
}
|
||||
return free_index;
|
||||
return max_index + 1;
|
||||
}
|
||||
|
||||
|
||||
@ -6531,27 +6470,17 @@ Object* JSObject::SlowReverseLookup(Object* value) {
|
||||
if (HasFastProperties()) {
|
||||
int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
|
||||
DescriptorArray* descs = map()->instance_descriptors();
|
||||
bool value_is_number = value->IsNumber();
|
||||
for (int i = 0; i < number_of_own_descriptors; i++) {
|
||||
if (descs->GetType(i) == FIELD) {
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
|
||||
if (IsUnboxedDoubleField(field_index)) {
|
||||
if (value_is_number) {
|
||||
double property = RawFastDoublePropertyAt(field_index);
|
||||
if (property == value->Number()) {
|
||||
return descs->GetKey(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object* property = RawFastPropertyAt(field_index);
|
||||
if (field_index.is_double()) {
|
||||
DCHECK(property->IsMutableHeapNumber());
|
||||
if (value_is_number && property->Number() == value->Number()) {
|
||||
return descs->GetKey(i);
|
||||
}
|
||||
} else if (property == value) {
|
||||
Object* property =
|
||||
RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
|
||||
if (descs->GetDetails(i).representation().IsDouble()) {
|
||||
DCHECK(property->IsMutableHeapNumber());
|
||||
if (value->IsNumber() && property->Number() == value->Number()) {
|
||||
return descs->GetKey(i);
|
||||
}
|
||||
} else if (property == value) {
|
||||
return descs->GetKey(i);
|
||||
}
|
||||
} else if (descs->GetType(i) == CONSTANT) {
|
||||
if (descs->GetConstant(i) == value) {
|
||||
@ -6705,15 +6634,10 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
|
||||
}
|
||||
}
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor =
|
||||
FLAG_unbox_double_fields
|
||||
? LayoutDescriptor::Append(map, descriptor->GetDetails())
|
||||
: map->GetLayoutDescriptor();
|
||||
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
descriptors->Append(descriptor);
|
||||
result->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
result->InitializeDescriptors(*descriptors);
|
||||
}
|
||||
|
||||
DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
|
||||
@ -6773,19 +6697,19 @@ void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> Map::CopyReplaceDescriptors(
|
||||
Handle<Map> map, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
|
||||
MaybeHandle<Name> maybe_name, const char* reason,
|
||||
SimpleTransitionFlag simple_flag) {
|
||||
Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
|
||||
Handle<DescriptorArray> descriptors,
|
||||
TransitionFlag flag,
|
||||
MaybeHandle<Name> maybe_name,
|
||||
const char* reason,
|
||||
SimpleTransitionFlag simple_flag) {
|
||||
DCHECK(descriptors->IsSortedNoDuplicates());
|
||||
|
||||
Handle<Map> result = CopyDropDescriptors(map);
|
||||
result->InitializeDescriptors(*descriptors);
|
||||
|
||||
if (!map->is_prototype_map()) {
|
||||
if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
|
||||
result->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
|
||||
Handle<Name> name;
|
||||
CHECK(maybe_name.ToHandle(&name));
|
||||
ConnectTransition(map, result, name, simple_flag);
|
||||
@ -6797,11 +6721,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
|
||||
descriptors->SetValue(i, HeapType::Any());
|
||||
}
|
||||
}
|
||||
result->InitializeDescriptors(*descriptors,
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
} else {
|
||||
result->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
}
|
||||
#if TRACE_MAPS
|
||||
if (FLAG_trace_maps &&
|
||||
@ -6820,34 +6740,25 @@ Handle<Map> Map::CopyReplaceDescriptors(
|
||||
|
||||
// Since this method is used to rewrite an existing transition tree, it can
|
||||
// always insert transitions without checking.
|
||||
Handle<Map> Map::CopyInstallDescriptors(
|
||||
Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> full_layout_descriptor) {
|
||||
Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
|
||||
int new_descriptor,
|
||||
Handle<DescriptorArray> descriptors) {
|
||||
DCHECK(descriptors->IsSortedNoDuplicates());
|
||||
|
||||
Handle<Map> result = CopyDropDescriptors(map);
|
||||
|
||||
result->set_instance_descriptors(*descriptors);
|
||||
result->InitializeDescriptors(*descriptors);
|
||||
result->SetNumberOfOwnDescriptors(new_descriptor + 1);
|
||||
|
||||
int unused_property_fields = map->unused_property_fields();
|
||||
PropertyDetails details = descriptors->GetDetails(new_descriptor);
|
||||
if (details.type() == FIELD) {
|
||||
if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
|
||||
unused_property_fields = map->unused_property_fields() - 1;
|
||||
if (unused_property_fields < 0) {
|
||||
unused_property_fields += JSObject::kFieldsAdded;
|
||||
}
|
||||
}
|
||||
result->set_unused_property_fields(unused_property_fields);
|
||||
|
||||
if (FLAG_unbox_double_fields) {
|
||||
Handle<LayoutDescriptor> layout_descriptor =
|
||||
LayoutDescriptor::AppendIfFastOrUseFull(map, details,
|
||||
full_layout_descriptor);
|
||||
result->set_layout_descriptor(*layout_descriptor);
|
||||
SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
|
||||
result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result));
|
||||
}
|
||||
result->set_unused_property_fields(unused_property_fields);
|
||||
|
||||
Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
|
||||
ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
|
||||
@ -6883,9 +6794,7 @@ Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
|
||||
ConnectElementsTransition(map, new_map);
|
||||
|
||||
new_map->set_elements_kind(kind);
|
||||
// The properties did not change, so reuse descriptors.
|
||||
new_map->InitializeDescriptors(map->instance_descriptors(),
|
||||
map->layout_descriptor());
|
||||
new_map->InitializeDescriptors(map->instance_descriptors());
|
||||
return new_map;
|
||||
}
|
||||
|
||||
@ -6921,9 +6830,7 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
|
||||
|
||||
new_map->set_is_observed();
|
||||
if (map->owns_descriptors()) {
|
||||
// The properties did not change, so reuse descriptors.
|
||||
new_map->InitializeDescriptors(map->instance_descriptors(),
|
||||
map->layout_descriptor());
|
||||
new_map->InitializeDescriptors(map->instance_descriptors());
|
||||
}
|
||||
|
||||
if (map->CanHaveMoreTransitions()) {
|
||||
@ -6939,9 +6846,8 @@ Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
|
||||
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
|
||||
Handle<DescriptorArray> new_descriptors =
|
||||
DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
|
||||
Handle<LayoutDescriptor> new_layout_descriptor = map->GetLayoutDescriptor();
|
||||
return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
|
||||
OMIT_TRANSITION, MaybeHandle<Name>(), reason,
|
||||
return CopyReplaceDescriptors(map, new_descriptors, OMIT_TRANSITION,
|
||||
MaybeHandle<Name>(), reason,
|
||||
SPECIAL_TRANSITION);
|
||||
}
|
||||
|
||||
@ -6977,10 +6883,9 @@ Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
|
||||
handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN);
|
||||
Handle<LayoutDescriptor> new_layout_descriptor = map->GetLayoutDescriptor();
|
||||
Handle<Map> new_map = CopyReplaceDescriptors(
|
||||
map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
|
||||
isolate->factory()->frozen_symbol(), "CopyForFreeze", SPECIAL_TRANSITION);
|
||||
map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol(),
|
||||
"CopyForFreeze", SPECIAL_TRANSITION);
|
||||
new_map->freeze();
|
||||
new_map->set_is_extensible(false);
|
||||
new_map->set_elements_kind(DICTIONARY_ELEMENTS);
|
||||
@ -7205,13 +7110,8 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
|
||||
descriptors, map->NumberOfOwnDescriptors(), 1);
|
||||
new_descriptors->Append(descriptor);
|
||||
|
||||
Handle<LayoutDescriptor> new_layout_descriptor =
|
||||
FLAG_unbox_double_fields
|
||||
? LayoutDescriptor::Append(map, descriptor->GetDetails())
|
||||
: map->GetLayoutDescriptor();
|
||||
|
||||
return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
|
||||
flag, descriptor->GetKey(), "CopyAddDescriptor",
|
||||
return CopyReplaceDescriptors(map, new_descriptors, flag,
|
||||
descriptor->GetKey(), "CopyAddDescriptor",
|
||||
SIMPLE_PROPERTY_TRANSITION);
|
||||
}
|
||||
|
||||
@ -7303,16 +7203,13 @@ Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
|
||||
descriptors, map->NumberOfOwnDescriptors());
|
||||
|
||||
new_descriptors->Replace(insertion_index, descriptor);
|
||||
Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
|
||||
map, new_descriptors, new_descriptors->number_of_descriptors());
|
||||
|
||||
SimpleTransitionFlag simple_flag =
|
||||
(insertion_index == descriptors->number_of_descriptors() - 1)
|
||||
? SIMPLE_PROPERTY_TRANSITION
|
||||
: PROPERTY_TRANSITION;
|
||||
return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
|
||||
flag, key, "CopyReplaceDescriptor",
|
||||
simple_flag);
|
||||
return CopyReplaceDescriptors(map, new_descriptors, flag, key,
|
||||
"CopyReplaceDescriptor", simple_flag);
|
||||
}
|
||||
|
||||
|
||||
@ -8119,7 +8016,8 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
|
||||
}
|
||||
|
||||
|
||||
void DescriptorArray::CopyFrom(int index, DescriptorArray* src,
|
||||
void DescriptorArray::CopyFrom(int index,
|
||||
DescriptorArray* src,
|
||||
const WhitenessWitness& witness) {
|
||||
Object* value = src->GetValue(index);
|
||||
PropertyDetails details = src->GetDetails(index);
|
||||
|
@ -858,9 +858,8 @@ class DictionaryElementsAccessor;
|
||||
class ElementsAccessor;
|
||||
class FixedArrayBase;
|
||||
class GlobalObject;
|
||||
class LayoutDescriptor;
|
||||
class LookupIterator;
|
||||
class ObjectVisitor;
|
||||
class LookupIterator;
|
||||
class StringStream;
|
||||
class TypeFeedbackVector;
|
||||
class WeakCell;
|
||||
@ -935,7 +934,6 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(JSContextExtensionObject) \
|
||||
V(JSGeneratorObject) \
|
||||
V(JSModule) \
|
||||
V(LayoutDescriptor) \
|
||||
V(Map) \
|
||||
V(DescriptorArray) \
|
||||
V(TransitionArray) \
|
||||
@ -2065,18 +2063,12 @@ class JSObject: public JSReceiver {
|
||||
static void MigrateSlowToFast(Handle<JSObject> object,
|
||||
int unused_property_fields, const char* reason);
|
||||
|
||||
inline bool IsUnboxedDoubleField(FieldIndex index);
|
||||
|
||||
// Access fast-case object properties at index.
|
||||
static Handle<Object> FastPropertyAt(Handle<JSObject> object,
|
||||
Representation representation,
|
||||
FieldIndex index);
|
||||
inline Object* RawFastPropertyAt(FieldIndex index);
|
||||
inline double RawFastDoublePropertyAt(FieldIndex index);
|
||||
|
||||
inline void FastPropertyAtPut(FieldIndex index, Object* value);
|
||||
inline void RawFastPropertyAtPut(FieldIndex index, Object* value);
|
||||
inline void RawFastDoublePropertyAtPut(FieldIndex index, double value);
|
||||
void WriteToField(int descriptor, Object* value);
|
||||
|
||||
// Access to in object properties.
|
||||
@ -3140,7 +3132,9 @@ class DescriptorArray: public FixedArray {
|
||||
|
||||
// Transfer a complete descriptor from the src descriptor array to this
|
||||
// descriptor array.
|
||||
void CopyFrom(int index, DescriptorArray* src, const WhitenessWitness&);
|
||||
void CopyFrom(int index,
|
||||
DescriptorArray* src,
|
||||
const WhitenessWitness&);
|
||||
|
||||
inline void Set(int descriptor_number,
|
||||
Descriptor* desc,
|
||||
@ -4820,7 +4814,6 @@ TYPED_ARRAYS(FIXED_TYPED_ARRAY_TRAITS)
|
||||
|
||||
#undef FIXED_TYPED_ARRAY_TRAITS
|
||||
|
||||
|
||||
// DeoptimizationInputData is a fixed array used to hold the deoptimization
|
||||
// data for code generated by the Hydrogen/Lithium compiler. It also
|
||||
// contains information about functions that were inlined. If N different
|
||||
@ -5918,19 +5911,7 @@ class Map: public HeapObject {
|
||||
|
||||
// [instance descriptors]: describes the object.
|
||||
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
|
||||
|
||||
// [layout descriptor]: describes the object layout.
|
||||
DECL_ACCESSORS(layout_descriptor, LayoutDescriptor)
|
||||
// |layout descriptor| accessor which can be used from GC.
|
||||
inline LayoutDescriptor* layout_descriptor_gc_safe();
|
||||
|
||||
// |layout descriptor| accessor that returns a handle.
|
||||
inline Handle<LayoutDescriptor> GetLayoutDescriptor();
|
||||
|
||||
inline void UpdateDescriptors(DescriptorArray* descriptors,
|
||||
LayoutDescriptor* layout_descriptor);
|
||||
inline void InitializeDescriptors(DescriptorArray* descriptors,
|
||||
LayoutDescriptor* layout_descriptor);
|
||||
inline void InitializeDescriptors(DescriptorArray* descriptors);
|
||||
|
||||
// [stub cache]: contains stubs compiled for this map.
|
||||
DECL_ACCESSORS(code_cache, Object)
|
||||
@ -6260,13 +6241,7 @@ class Map: public HeapObject {
|
||||
kConstructorOffset + kPointerSize;
|
||||
static const int kDescriptorsOffset =
|
||||
kTransitionsOrBackPointerOffset + kPointerSize;
|
||||
#if V8_DOUBLE_FIELDS_UNBOXING
|
||||
static const int kLayoutDecriptorOffset = kDescriptorsOffset + kPointerSize;
|
||||
static const int kCodeCacheOffset = kLayoutDecriptorOffset + kPointerSize;
|
||||
#else
|
||||
static const int kLayoutDecriptorOffset = 1; // Must not be ever accessed.
|
||||
static const int kCodeCacheOffset = kDescriptorsOffset + kPointerSize;
|
||||
#endif
|
||||
static const int kDependentCodeOffset = kCodeCacheOffset + kPointerSize;
|
||||
static const int kSize = kDependentCodeOffset + kPointerSize;
|
||||
|
||||
@ -6344,18 +6319,11 @@ class Map: public HeapObject {
|
||||
// The "shared" flags of both this map and |other| are ignored.
|
||||
bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
|
||||
|
||||
// Returns true if given field is unboxed double.
|
||||
inline bool IsUnboxedDoubleField(FieldIndex index);
|
||||
|
||||
#if TRACE_MAPS
|
||||
static void TraceTransition(const char* what, Map* from, Map* to, Name* name);
|
||||
static void TraceAllTransitions(Map* map);
|
||||
#endif
|
||||
|
||||
static inline Handle<Map> CopyInstallDescriptorsForTesting(
|
||||
Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> layout_descriptor);
|
||||
|
||||
private:
|
||||
static void ConnectElementsTransition(Handle<Map> parent, Handle<Map> child);
|
||||
static void ConnectTransition(Handle<Map> parent, Handle<Map> child,
|
||||
@ -6367,17 +6335,18 @@ class Map: public HeapObject {
|
||||
Handle<DescriptorArray> descriptors,
|
||||
Descriptor* descriptor);
|
||||
static Handle<Map> CopyInstallDescriptors(
|
||||
Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> layout_descriptor);
|
||||
Handle<Map> map,
|
||||
int new_descriptor,
|
||||
Handle<DescriptorArray> descriptors);
|
||||
static Handle<Map> CopyAddDescriptor(Handle<Map> map,
|
||||
Descriptor* descriptor,
|
||||
TransitionFlag flag);
|
||||
static Handle<Map> CopyReplaceDescriptors(
|
||||
Handle<Map> map, Handle<DescriptorArray> descriptors,
|
||||
Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
|
||||
MaybeHandle<Name> maybe_name, const char* reason,
|
||||
SimpleTransitionFlag simple_flag);
|
||||
|
||||
static Handle<Map> CopyReplaceDescriptors(Handle<Map> map,
|
||||
Handle<DescriptorArray> descriptors,
|
||||
TransitionFlag flag,
|
||||
MaybeHandle<Name> maybe_name,
|
||||
const char* reason,
|
||||
SimpleTransitionFlag simple_flag);
|
||||
static Handle<Map> CopyReplaceDescriptor(Handle<Map> map,
|
||||
Handle<DescriptorArray> descriptors,
|
||||
Descriptor* descriptor,
|
||||
@ -6407,8 +6376,7 @@ class Map: public HeapObject {
|
||||
void DeprecateTransitionTree();
|
||||
void DeprecateTarget(PropertyType type, Name* key,
|
||||
PropertyAttributes attributes,
|
||||
DescriptorArray* new_descriptors,
|
||||
LayoutDescriptor* new_layout_descriptor);
|
||||
DescriptorArray* new_descriptors);
|
||||
|
||||
Map* FindLastMatchMap(int verbatim, int length, DescriptorArray* descriptors);
|
||||
|
||||
|
@ -248,8 +248,6 @@ class PropertyDetails BASE_EMBEDDED {
|
||||
return FieldIndexField::decode(value_);
|
||||
}
|
||||
|
||||
inline int field_width_in_words() const;
|
||||
|
||||
inline PropertyDetails AsDeleted() const;
|
||||
|
||||
static bool IsValidIndex(int index) {
|
||||
|
@ -1400,8 +1400,9 @@ RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
|
||||
RUNTIME_ASSERT(field_index.outobject_array_index() <
|
||||
object->properties()->length());
|
||||
}
|
||||
return *JSObject::FastPropertyAt(object, Representation::Double(),
|
||||
field_index);
|
||||
Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
|
||||
RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
|
||||
return *Object::WrapForRead(isolate, raw_value, Representation::Double());
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,13 +351,8 @@ void StringStream::PrintUsingMap(JSObject* js_object) {
|
||||
}
|
||||
Add(": ");
|
||||
FieldIndex index = FieldIndex::ForDescriptor(map, i);
|
||||
if (js_object->IsUnboxedDoubleField(index)) {
|
||||
double value = js_object->RawFastDoublePropertyAt(index);
|
||||
Add("<unboxed double> %.16g\n", FmtElm(value));
|
||||
} else {
|
||||
Object* value = js_object->RawFastPropertyAt(index);
|
||||
Add("%o\n", value);
|
||||
}
|
||||
Object* value = js_object->RawFastPropertyAt(index);
|
||||
Add("%o\n", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2976,7 +2976,6 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
||||
|
||||
Register object = ToRegister(instr->object());
|
||||
if (instr->hydrogen()->representation().IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
__ movsd(result, FieldOperand(object, offset));
|
||||
return;
|
||||
@ -4123,7 +4122,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
DCHECK(!representation.IsSmi() ||
|
||||
!instr->value()->IsConstantOperand() ||
|
||||
IsInteger32Constant(LConstantOperand::cast(instr->value())));
|
||||
if (!FLAG_unbox_double_fields && representation.IsDouble()) {
|
||||
if (representation.IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
DCHECK(!hinstr->has_transition());
|
||||
DCHECK(!hinstr->NeedsWriteBarrier());
|
||||
@ -4173,12 +4172,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
|
||||
Operand operand = FieldOperand(write_register, offset);
|
||||
|
||||
if (FLAG_unbox_double_fields && representation.IsDouble()) {
|
||||
DCHECK(access.IsInobject());
|
||||
XMMRegister value = ToDoubleRegister(instr->value());
|
||||
__ movsd(operand, value);
|
||||
|
||||
} else if (instr->value()->IsRegister()) {
|
||||
if (instr->value()->IsRegister()) {
|
||||
Register value = ToRegister(instr->value());
|
||||
__ Store(operand, value, representation);
|
||||
} else {
|
||||
|
@ -159,7 +159,6 @@
|
||||
'test-transitions.cc',
|
||||
'test-types.cc',
|
||||
'test-unbound-queue.cc',
|
||||
'test-unboxed-doubles.cc',
|
||||
'test-unique.cc',
|
||||
'test-unscopables-hidden-prototype.cc',
|
||||
'test-utils.cc',
|
||||
|
@ -2476,21 +2476,12 @@ TEST(OptimizedPretenuringMixedInObjectProperties) {
|
||||
FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
|
||||
FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
|
||||
CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
|
||||
if (!o->IsUnboxedDoubleField(idx2)) {
|
||||
CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
|
||||
} else {
|
||||
CHECK_EQ(1.1, o->RawFastDoublePropertyAt(idx2));
|
||||
}
|
||||
CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
|
||||
|
||||
JSObject* inner_object =
|
||||
reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
|
||||
CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
|
||||
if (!inner_object->IsUnboxedDoubleField(idx1)) {
|
||||
CHECK(
|
||||
CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
|
||||
} else {
|
||||
CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
|
||||
}
|
||||
CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
|
||||
CHECK(CcTest::heap()->InOldPointerSpace(
|
||||
inner_object->RawFastPropertyAt(idx2)));
|
||||
}
|
||||
|
@ -1,668 +0,0 @@
|
||||
// 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 <stdlib.h>
|
||||
#include <utility>
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/compilation-cache.h"
|
||||
#include "src/execution.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/global-handles.h"
|
||||
#include "src/ic/ic.h"
|
||||
#include "src/macro-assembler.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
using namespace v8::base;
|
||||
using namespace v8::internal;
|
||||
|
||||
#if (V8_DOUBLE_FIELDS_UNBOXING)
|
||||
|
||||
|
||||
static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
|
||||
if (obj->IsUnboxedDoubleField(field_index)) {
|
||||
return obj->RawFastDoublePropertyAt(field_index);
|
||||
} else {
|
||||
Object* value = obj->RawFastPropertyAt(field_index);
|
||||
DCHECK(value->IsMutableHeapNumber());
|
||||
return HeapNumber::cast(value)->value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum PropertyKind {
|
||||
PROP_CONSTANT,
|
||||
PROP_SMI,
|
||||
PROP_DOUBLE,
|
||||
PROP_TAGGED,
|
||||
PROP_KIND_NUMBER,
|
||||
};
|
||||
|
||||
static Representation representations[PROP_KIND_NUMBER] = {
|
||||
Representation::None(), Representation::Smi(), Representation::Double(),
|
||||
Representation::Tagged()};
|
||||
|
||||
|
||||
static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
|
||||
PropertyKind* props,
|
||||
int kPropsCount) {
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> func_name = factory->InternalizeUtf8String("func");
|
||||
Handle<JSFunction> func = factory->NewFunction(func_name);
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
DescriptorArray::Allocate(isolate, 0, kPropsCount);
|
||||
|
||||
int next_field_offset = 0;
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
EmbeddedVector<char, 64> buffer;
|
||||
SNPrintF(buffer, "prop%d", i);
|
||||
Handle<String> name = factory->InternalizeUtf8String(buffer.start());
|
||||
|
||||
PropertyKind kind = props[i];
|
||||
|
||||
if (kind == PROP_CONSTANT) {
|
||||
ConstantDescriptor d(name, func, NONE);
|
||||
descriptors->Append(&d);
|
||||
|
||||
} else {
|
||||
FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
|
||||
next_field_offset += f.GetDetails().field_width_in_words();
|
||||
descriptors->Append(&f);
|
||||
}
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorBasicFast) {
|
||||
CcTest::InitializeVM();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
|
||||
|
||||
CHECK(!layout_desc->IsSlowLayout());
|
||||
CHECK(layout_desc->IsFastPointerLayout());
|
||||
CHECK_EQ(kSmiValueSize, layout_desc->capacity());
|
||||
|
||||
for (int i = 0; i < kSmiValueSize + 13; i++) {
|
||||
CHECK_EQ(true, layout_desc->IsTagged(i));
|
||||
}
|
||||
CHECK_EQ(true, layout_desc->IsTagged(-1));
|
||||
CHECK_EQ(true, layout_desc->IsTagged(-12347));
|
||||
CHECK_EQ(true, layout_desc->IsTagged(15635));
|
||||
CHECK(layout_desc->IsFastPointerLayout());
|
||||
|
||||
for (int i = 0; i < kSmiValueSize; i++) {
|
||||
layout_desc = layout_desc->SetTaggedForTesting(i, false);
|
||||
CHECK_EQ(false, layout_desc->IsTagged(i));
|
||||
layout_desc = layout_desc->SetTaggedForTesting(i, true);
|
||||
CHECK_EQ(true, layout_desc->IsTagged(i));
|
||||
}
|
||||
CHECK(layout_desc->IsFastPointerLayout());
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorBasicSlow) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
// All properties tagged.
|
||||
props[i] = PROP_TAGGED;
|
||||
}
|
||||
|
||||
{
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
Handle<Map> map = Map::Create(isolate, kPropsCount);
|
||||
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
props[0] = PROP_DOUBLE;
|
||||
props[kPropsCount - 1] = PROP_DOUBLE;
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
{
|
||||
int inobject_properties = kPropsCount - 1;
|
||||
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
||||
|
||||
// Should be fast as the only double property is the first one.
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
CHECK(!layout_descriptor->IsFastPointerLayout());
|
||||
|
||||
CHECK_EQ(false, layout_descriptor->IsTagged(0));
|
||||
for (int i = 1; i < kPropsCount; i++) {
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(i));
|
||||
}
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
int inobject_properties = kPropsCount;
|
||||
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
||||
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
CHECK(!layout_descriptor->IsFastPointerLayout());
|
||||
CHECK(layout_descriptor->capacity() > kSmiValueSize);
|
||||
|
||||
CHECK_EQ(false, layout_descriptor->IsTagged(0));
|
||||
CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
|
||||
for (int i = 1; i < kPropsCount - 1; i++) {
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(i));
|
||||
}
|
||||
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
|
||||
// Here we have truly slow layout descriptor, so play with the bits.
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(-1));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(15635));
|
||||
|
||||
LayoutDescriptor* layout_desc = *layout_descriptor;
|
||||
// Play with the bits but leave it in consistent state with map at the end.
|
||||
for (int i = 1; i < kPropsCount - 1; i++) {
|
||||
layout_desc = layout_desc->SetTaggedForTesting(i, false);
|
||||
CHECK_EQ(false, layout_desc->IsTagged(i));
|
||||
layout_desc = layout_desc->SetTaggedForTesting(i, true);
|
||||
CHECK_EQ(true, layout_desc->IsTagged(i));
|
||||
}
|
||||
CHECK(layout_desc->IsSlowLayout());
|
||||
CHECK(!layout_desc->IsFastPointerLayout());
|
||||
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorCreateNewFast) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
PropertyKind props[] = {
|
||||
PROP_CONSTANT,
|
||||
PROP_TAGGED, // field #0
|
||||
PROP_CONSTANT,
|
||||
PROP_DOUBLE, // field #1
|
||||
PROP_CONSTANT,
|
||||
PROP_TAGGED, // field #2
|
||||
PROP_CONSTANT,
|
||||
};
|
||||
const int kPropsCount = arraysize(props);
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 0);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 1);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 2);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(0));
|
||||
CHECK_EQ(false, layout_descriptor->IsTagged(1));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(2));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(125));
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorCreateNewSlow) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
|
||||
}
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 0);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 1);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<Map> map = Map::Create(isolate, 2);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(0));
|
||||
CHECK_EQ(false, layout_descriptor->IsTagged(1));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(2));
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(125));
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
{
|
||||
int inobject_properties = kPropsCount / 2;
|
||||
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
||||
layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
// PROP_DOUBLE has index 1 among FIELD properties.
|
||||
const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
|
||||
CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
|
||||
}
|
||||
// Every property after inobject_properties must be tagged.
|
||||
for (int i = inobject_properties; i < kPropsCount; i++) {
|
||||
CHECK_EQ(true, layout_descriptor->IsTagged(i));
|
||||
}
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
|
||||
// Now test LayoutDescriptor::cast_gc_safe().
|
||||
Handle<LayoutDescriptor> layout_descriptor_copy =
|
||||
LayoutDescriptor::New(map, descriptors, kPropsCount);
|
||||
|
||||
LayoutDescriptor* layout_desc = *layout_descriptor;
|
||||
CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
|
||||
CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
|
||||
CHECK(layout_descriptor->IsFixedTypedArrayBase());
|
||||
// Now make it look like a forwarding pointer to layout_descriptor_copy.
|
||||
MapWord map_word = layout_desc->map_word();
|
||||
CHECK(!map_word.IsForwardingAddress());
|
||||
layout_desc->set_map_word(
|
||||
MapWord::FromForwardingAddress(*layout_descriptor_copy));
|
||||
CHECK(layout_desc->map_word().IsForwardingAddress());
|
||||
CHECK_EQ(*layout_descriptor_copy,
|
||||
LayoutDescriptor::cast_gc_safe(layout_desc));
|
||||
|
||||
// Restore it back.
|
||||
layout_desc->set_map_word(map_word);
|
||||
CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
|
||||
Isolate* isolate, int inobject_properties, PropertyKind* props,
|
||||
int kPropsCount) {
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<String> func_name = factory->InternalizeUtf8String("func");
|
||||
Handle<JSFunction> func = factory->NewFunction(func_name);
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
DescriptorArray::Allocate(isolate, 0, kPropsCount);
|
||||
|
||||
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
||||
map->InitializeDescriptors(*descriptors,
|
||||
LayoutDescriptor::FastPointerLayout());
|
||||
|
||||
int next_field_offset = 0;
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
EmbeddedVector<char, 64> buffer;
|
||||
SNPrintF(buffer, "prop%d", i);
|
||||
Handle<String> name = factory->InternalizeUtf8String(buffer.start());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
PropertyKind kind = props[i];
|
||||
if (kind == PROP_CONSTANT) {
|
||||
ConstantDescriptor d(name, func, NONE);
|
||||
layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails());
|
||||
descriptors->Append(&d);
|
||||
|
||||
} else {
|
||||
FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
|
||||
int field_width_in_words = f.GetDetails().field_width_in_words();
|
||||
next_field_offset += field_width_in_words;
|
||||
layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails());
|
||||
descriptors->Append(&f);
|
||||
|
||||
int field_index = f.GetDetails().field_index();
|
||||
bool is_inobject = field_index < map->inobject_properties();
|
||||
for (int bit = 0; bit < field_width_in_words; bit++) {
|
||||
CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
|
||||
!layout_descriptor->IsTagged(field_index + bit));
|
||||
}
|
||||
CHECK(layout_descriptor->IsTagged(next_field_offset));
|
||||
}
|
||||
map->InitializeDescriptors(*descriptors, *layout_descriptor);
|
||||
}
|
||||
Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
return layout_descriptor;
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorAppend) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
|
||||
}
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
|
||||
props, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorAppendAllDoubles) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
props[i] = PROP_DOUBLE;
|
||||
}
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
|
||||
props, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
|
||||
props, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
{
|
||||
// Ensure layout descriptor switches into slow mode at the right moment.
|
||||
layout_descriptor =
|
||||
TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
|
||||
kSmiValueSize + 1);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
Isolate* isolate, int inobject_properties,
|
||||
Handle<DescriptorArray> descriptors, int number_of_descriptors) {
|
||||
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
||||
|
||||
Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
|
||||
map, descriptors, descriptors->number_of_descriptors());
|
||||
|
||||
int nof = 0;
|
||||
bool switched_to_slow_mode = false;
|
||||
|
||||
for (int i = 0; i < number_of_descriptors; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
|
||||
// This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
|
||||
// and does all the required map-descriptors related book keeping.
|
||||
map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
|
||||
full_layout_descriptor);
|
||||
|
||||
LayoutDescriptor* layout_desc = map->layout_descriptor();
|
||||
|
||||
if (layout_desc->IsSlowLayout()) {
|
||||
switched_to_slow_mode = true;
|
||||
CHECK_EQ(*full_layout_descriptor, layout_desc);
|
||||
} else {
|
||||
CHECK(!switched_to_slow_mode);
|
||||
if (details.type() == FIELD) {
|
||||
nof++;
|
||||
int field_index = details.field_index();
|
||||
int field_width_in_words = details.field_width_in_words();
|
||||
|
||||
bool is_inobject = field_index < map->inobject_properties();
|
||||
for (int bit = 0; bit < field_width_in_words; bit++) {
|
||||
CHECK_EQ(is_inobject && details.representation().IsDouble(),
|
||||
!layout_desc->IsTagged(field_index + bit));
|
||||
}
|
||||
CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
|
||||
}
|
||||
}
|
||||
DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
|
||||
}
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor = map->GetLayoutDescriptor();
|
||||
DCHECK(layout_descriptor->IsConsistentWithMap(*map));
|
||||
return layout_descriptor;
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorAppendIfFastOrUseFull) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER);
|
||||
}
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, 0, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, 13, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kSmiValueSize, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kSmiValueSize * 2, descriptors, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kPropsCount, descriptors, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
}
|
||||
|
||||
|
||||
TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
Handle<LayoutDescriptor> layout_descriptor;
|
||||
const int kPropsCount = kSmiValueSize * 3;
|
||||
PropertyKind props[kPropsCount];
|
||||
for (int i = 0; i < kPropsCount; i++) {
|
||||
props[i] = PROP_DOUBLE;
|
||||
}
|
||||
Handle<DescriptorArray> descriptors =
|
||||
CreateDescriptorArray(isolate, props, kPropsCount);
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, 0, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, 13, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kSmiValueSize, descriptors, kPropsCount);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kSmiValueSize + 1, descriptors, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kSmiValueSize * 2, descriptors, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kPropsCount, descriptors, kPropsCount);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
|
||||
{
|
||||
// Ensure layout descriptor switches into slow mode at the right moment.
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kPropsCount, descriptors, kSmiValueSize);
|
||||
CHECK(!layout_descriptor->IsSlowLayout());
|
||||
|
||||
layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
isolate, kPropsCount, descriptors, kSmiValueSize + 1);
|
||||
CHECK(layout_descriptor->IsSlowLayout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(StoreBufferScanOnScavenge) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
|
||||
CompileRun(
|
||||
"function A() {"
|
||||
" this.x = 42.5;"
|
||||
" this.o = {};"
|
||||
"};"
|
||||
"var o = new A();");
|
||||
|
||||
Handle<String> obj_name = factory->InternalizeUtf8String("o");
|
||||
|
||||
Handle<Object> obj_value =
|
||||
Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
|
||||
CHECK(obj_value->IsJSObject());
|
||||
Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
|
||||
|
||||
{
|
||||
// Ensure the object is properly set up.
|
||||
Map* map = obj->map();
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
CHECK(map->NumberOfOwnDescriptors() == 2);
|
||||
CHECK(descriptors->GetDetails(0).representation().IsDouble());
|
||||
CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
|
||||
CHECK(field_index.is_inobject() && field_index.is_double());
|
||||
CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
|
||||
CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
|
||||
}
|
||||
CHECK(isolate->heap()->new_space()->Contains(*obj));
|
||||
|
||||
// Trigger GCs so that the newly allocated object moves to old gen.
|
||||
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
|
||||
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
|
||||
|
||||
CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
|
||||
|
||||
// Create temp object in the new space.
|
||||
Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
|
||||
CHECK(isolate->heap()->new_space()->Contains(*temp));
|
||||
|
||||
// Construct a double value that looks like a pointer to the new space object
|
||||
// and store it into the obj.
|
||||
Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
|
||||
double boom_value = bit_cast<double>(fake_object);
|
||||
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
|
||||
obj->FastPropertyAtPut(field_index,
|
||||
*factory->NewHeapNumber(boom_value, MUTABLE));
|
||||
|
||||
// Enforce scan on scavenge for the obj's page.
|
||||
MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
|
||||
chunk->set_scan_on_scavenge(true);
|
||||
|
||||
// Trigger GCs and force evacuation. Should not crash there.
|
||||
CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
||||
|
||||
CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
|
||||
}
|
||||
|
||||
#endif
|
@ -694,9 +694,6 @@
|
||||
'../../src/jsregexp-inl.h',
|
||||
'../../src/jsregexp.cc',
|
||||
'../../src/jsregexp.h',
|
||||
'../../src/layout-descriptor-inl.h',
|
||||
'../../src/layout-descriptor.cc',
|
||||
'../../src/layout-descriptor.h',
|
||||
'../../src/list-inl.h',
|
||||
'../../src/list.h',
|
||||
'../../src/lithium-allocator-inl.h',
|
||||
|
Loading…
Reference in New Issue
Block a user