[runtime] Store constructor function index on primitive maps.
This way we can greatly simplify the different variants of ToObject in our codebase and make them more uniform and robust. Adding a new primitive doesn't require finding and changing all those places again, but it is sufficient to setup the constructor function index when allocating the map. We use the inobject properties field of Map, which is invalid primitive maps anyway. R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/1276533003 Cr-Commit-Position: refs/heads/master@{#30119}
This commit is contained in:
parent
8f733867ac
commit
6c743b2b39
@ -442,7 +442,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ ldr(r0, FieldMemOperand(r2, Map::kInstanceSizesOffset));
|
||||
__ Ubfx(r0, r0, Map::kInObjectPropertiesByte * kBitsPerByte,
|
||||
__ Ubfx(r0, r0, Map::kInObjectPropertiesOrConstructorFunctionIndexByte *
|
||||
kBitsPerByte,
|
||||
kBitsPerByte);
|
||||
__ ldr(r2, FieldMemOperand(r2, Map::kInstanceAttributesOffset));
|
||||
__ Ubfx(r2, r2, Map::kUnusedPropertyFieldsByte * kBitsPerByte,
|
||||
|
@ -436,8 +436,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
Map::kUnusedPropertyFieldsByte * kBitsPerByte, kBitsPerByte);
|
||||
__ Ldr(inst_sizes_or_attrs,
|
||||
FieldMemOperand(init_map, Map::kInstanceSizesOffset));
|
||||
__ Ubfx(inobject_props, inst_sizes_or_attrs,
|
||||
Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte);
|
||||
__ Ubfx(
|
||||
inobject_props, inst_sizes_or_attrs,
|
||||
Map::kInObjectPropertiesOrConstructorFunctionIndexByte * kBitsPerByte,
|
||||
kBitsPerByte);
|
||||
__ Sub(prealloc_fields, inobject_props, unused_props);
|
||||
|
||||
// Calculate number of property fields in the object.
|
||||
|
@ -533,7 +533,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
|
||||
int instance_size = JSObject::kHeaderSize + kPointerSize * unused;
|
||||
Handle<Map> object_function_map =
|
||||
factory->NewMap(JS_OBJECT_TYPE, instance_size);
|
||||
object_function_map->set_inobject_properties(unused);
|
||||
object_function_map->SetInObjectProperties(unused);
|
||||
JSFunction::SetInitialMap(object_fun, object_function_map,
|
||||
isolate->factory()->null_value());
|
||||
object_function_map->set_unused_property_fields(unused);
|
||||
@ -1172,7 +1172,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
DCHECK(regexp_fun->has_initial_map());
|
||||
Handle<Map> initial_map(regexp_fun->initial_map());
|
||||
|
||||
DCHECK_EQ(0, initial_map->inobject_properties());
|
||||
DCHECK_EQ(0, initial_map->GetInObjectProperties());
|
||||
|
||||
PropertyAttributes final =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
@ -1217,7 +1217,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
}
|
||||
|
||||
static const int num_fields = JSRegExp::kInObjectFieldCount;
|
||||
initial_map->set_inobject_properties(num_fields);
|
||||
initial_map->SetInObjectProperties(num_fields);
|
||||
initial_map->set_unused_property_fields(0);
|
||||
initial_map->set_instance_size(initial_map->instance_size() +
|
||||
num_fields * kPointerSize);
|
||||
@ -1313,7 +1313,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
DCHECK_EQ(JSGeneratorObject::kResultSize,
|
||||
iterator_result_map->instance_size());
|
||||
DCHECK_EQ(JSGeneratorObject::kResultPropertyCount,
|
||||
iterator_result_map->inobject_properties());
|
||||
iterator_result_map->GetInObjectProperties());
|
||||
Map::EnsureDescriptorSlack(iterator_result_map,
|
||||
JSGeneratorObject::kResultPropertyCount);
|
||||
|
||||
@ -1368,15 +1368,15 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
// @@iterator method is added later.
|
||||
|
||||
map->set_function_with_prototype(true);
|
||||
map->set_inobject_properties(2);
|
||||
map->SetInObjectProperties(2);
|
||||
native_context()->set_sloppy_arguments_map(*map);
|
||||
|
||||
DCHECK(!function->has_initial_map());
|
||||
JSFunction::SetInitialMap(function, map,
|
||||
isolate->initial_object_prototype());
|
||||
|
||||
DCHECK(map->inobject_properties() > Heap::kArgumentsCalleeIndex);
|
||||
DCHECK(map->inobject_properties() > Heap::kArgumentsLengthIndex);
|
||||
DCHECK(map->GetInObjectProperties() > Heap::kArgumentsCalleeIndex);
|
||||
DCHECK(map->GetInObjectProperties() > Heap::kArgumentsLengthIndex);
|
||||
DCHECK(!map->is_dictionary_map());
|
||||
DCHECK(IsFastObjectElementsKind(map->elements_kind()));
|
||||
}
|
||||
@ -1385,12 +1385,12 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
Handle<Map> map = isolate->sloppy_arguments_map();
|
||||
map = Map::Copy(map, "FastAliasedArguments");
|
||||
map->set_elements_kind(FAST_SLOPPY_ARGUMENTS_ELEMENTS);
|
||||
DCHECK_EQ(2, map->inobject_properties());
|
||||
DCHECK_EQ(2, map->GetInObjectProperties());
|
||||
native_context()->set_fast_aliased_arguments_map(*map);
|
||||
|
||||
map = Map::Copy(map, "SlowAliasedArguments");
|
||||
map->set_elements_kind(SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
|
||||
DCHECK_EQ(2, map->inobject_properties());
|
||||
DCHECK_EQ(2, map->GetInObjectProperties());
|
||||
native_context()->set_slow_aliased_arguments_map(*map);
|
||||
}
|
||||
|
||||
@ -1437,7 +1437,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
DCHECK_EQ(native_context()->object_function()->prototype(),
|
||||
*isolate->initial_object_prototype());
|
||||
Map::SetPrototype(map, isolate->initial_object_prototype());
|
||||
map->set_inobject_properties(1);
|
||||
map->SetInObjectProperties(1);
|
||||
|
||||
// Copy constructor from the sloppy arguments boilerplate.
|
||||
map->SetConstructor(
|
||||
@ -1445,7 +1445,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> global_object,
|
||||
|
||||
native_context()->set_strict_arguments_map(*map);
|
||||
|
||||
DCHECK(map->inobject_properties() > Heap::kArgumentsLengthIndex);
|
||||
DCHECK(map->GetInObjectProperties() > Heap::kArgumentsLengthIndex);
|
||||
DCHECK(!map->is_dictionary_map());
|
||||
DCHECK(IsFastObjectElementsKind(map->elements_kind()));
|
||||
}
|
||||
@ -2496,7 +2496,7 @@ bool Genesis::InstallNatives(ContextType context_type) {
|
||||
initial_map->AppendDescriptor(&input_field);
|
||||
}
|
||||
|
||||
initial_map->set_inobject_properties(2);
|
||||
initial_map->SetInObjectProperties(2);
|
||||
initial_map->set_unused_property_fields(0);
|
||||
|
||||
native_context()->set_regexp_result_map(*initial_map);
|
||||
|
@ -1601,7 +1601,7 @@ Handle<GlobalObject> Factory::NewGlobalObject(Handle<JSFunction> constructor) {
|
||||
// Make sure we don't have a ton of pre-allocated slots in the
|
||||
// global objects. They will be unused once we normalize the object.
|
||||
DCHECK(map->unused_property_fields() == 0);
|
||||
DCHECK(map->inobject_properties() == 0);
|
||||
DCHECK(map->GetInObjectProperties() == 0);
|
||||
|
||||
// Initial size of the backing store to avoid resize of the storage during
|
||||
// bootstrapping. The size differs between the JS global object ad the
|
||||
|
@ -16,7 +16,7 @@ inline FieldIndex FieldIndex::ForInObjectOffset(int offset, Map* map) {
|
||||
int index = offset / kPointerSize;
|
||||
DCHECK(map == NULL ||
|
||||
index < (map->GetInObjectPropertyOffset(0) / kPointerSize +
|
||||
map->inobject_properties()));
|
||||
map->GetInObjectProperties()));
|
||||
return FieldIndex(true, index, false, 0, 0, true);
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ inline FieldIndex FieldIndex::ForPropertyIndex(Map* map,
|
||||
int property_index,
|
||||
bool is_double) {
|
||||
DCHECK(map->instance_type() >= FIRST_NONSTRING_TYPE);
|
||||
int inobject_properties = map->inobject_properties();
|
||||
int inobject_properties = map->GetInObjectProperties();
|
||||
bool is_inobject = property_index < inobject_properties;
|
||||
int first_inobject_offset;
|
||||
if (is_inobject) {
|
||||
@ -58,7 +58,7 @@ inline FieldIndex FieldIndex::ForLoadByFieldIndex(Map* map, int orig_index) {
|
||||
field_index += JSObject::kHeaderSize / kPointerSize;
|
||||
}
|
||||
FieldIndex result(is_inobject, field_index, is_double,
|
||||
map->inobject_properties(), first_inobject_offset);
|
||||
map->GetInObjectProperties(), first_inobject_offset);
|
||||
DCHECK(result.GetLoadByFieldIndex() == orig_index);
|
||||
return result;
|
||||
}
|
||||
|
@ -2654,7 +2654,8 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
|
||||
->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
|
||||
}
|
||||
reinterpret_cast<Map*>(result)->clear_unused();
|
||||
reinterpret_cast<Map*>(result)->set_inobject_properties(0);
|
||||
reinterpret_cast<Map*>(result)
|
||||
->set_inobject_properties_or_constructor_function_index(0);
|
||||
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
|
||||
reinterpret_cast<Map*>(result)->set_bit_field(0);
|
||||
reinterpret_cast<Map*>(result)->set_bit_field2(0);
|
||||
@ -2681,7 +2682,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
|
||||
map->set_constructor_or_backpointer(null_value(), SKIP_WRITE_BARRIER);
|
||||
map->set_instance_size(instance_size);
|
||||
map->clear_unused();
|
||||
map->set_inobject_properties(0);
|
||||
map->set_inobject_properties_or_constructor_function_index(0);
|
||||
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
|
||||
map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
|
||||
SKIP_WRITE_BARRIER);
|
||||
@ -2870,22 +2871,34 @@ bool Heap::CreateInitialMaps() {
|
||||
#define ALLOCATE_VARSIZE_MAP(instance_type, field_name) \
|
||||
ALLOCATE_MAP(instance_type, kVariableSizeSentinel, field_name)
|
||||
|
||||
#define ALLOCATE_PRIMITIVE_MAP(instance_type, size, field_name, \
|
||||
constructor_function_index) \
|
||||
{ \
|
||||
ALLOCATE_MAP((instance_type), (size), field_name); \
|
||||
field_name##_map()->SetConstructorFunctionIndex( \
|
||||
(constructor_function_index)); \
|
||||
}
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, fixed_cow_array)
|
||||
DCHECK(fixed_array_map() != fixed_cow_array_map());
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info)
|
||||
ALLOCATE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number)
|
||||
ALLOCATE_PRIMITIVE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number,
|
||||
Context::NUMBER_FUNCTION_INDEX)
|
||||
ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize,
|
||||
mutable_heap_number)
|
||||
ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol)
|
||||
ALLOCATE_PRIMITIVE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol,
|
||||
Context::SYMBOL_FUNCTION_INDEX)
|
||||
#define ALLOCATE_SIMD128_MAP(TYPE, Type, type, lane_count, lane_type) \
|
||||
ALLOCATE_MAP(SIMD128_VALUE_TYPE, Type::kSize, type)
|
||||
ALLOCATE_PRIMITIVE_MAP(SIMD128_VALUE_TYPE, Type::kSize, type, \
|
||||
Context::TYPE##_FUNCTION_INDEX)
|
||||
SIMD128_TYPES(ALLOCATE_SIMD128_MAP)
|
||||
#undef ALLOCATE_SIMD128_MAP
|
||||
ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign)
|
||||
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, the_hole);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, boolean);
|
||||
ALLOCATE_PRIMITIVE_MAP(ODDBALL_TYPE, Oddball::kSize, boolean,
|
||||
Context::BOOLEAN_FUNCTION_INDEX);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel);
|
||||
@ -2898,9 +2911,10 @@ bool Heap::CreateInitialMaps() {
|
||||
AllocationResult allocation = AllocateMap(entry.type, entry.size);
|
||||
if (!allocation.To(&obj)) return false;
|
||||
}
|
||||
Map* map = Map::cast(obj);
|
||||
map->SetConstructorFunctionIndex(Context::STRING_FUNCTION_INDEX);
|
||||
// Mark cons string maps as unstable, because their objects can change
|
||||
// maps during GC.
|
||||
Map* map = Map::cast(obj);
|
||||
if (StringShape(entry.type).IsCons()) map->mark_unstable();
|
||||
roots_[entry.index] = map;
|
||||
}
|
||||
@ -2909,7 +2923,9 @@ bool Heap::CreateInitialMaps() {
|
||||
AllocationResult allocation = AllocateMap(EXTERNAL_ONE_BYTE_STRING_TYPE,
|
||||
ExternalOneByteString::kSize);
|
||||
if (!allocation.To(&obj)) return false;
|
||||
set_native_source_string_map(Map::cast(obj));
|
||||
Map* map = Map::cast(obj);
|
||||
map->SetConstructorFunctionIndex(Context::STRING_FUNCTION_INDEX);
|
||||
set_native_source_string_map(map);
|
||||
}
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array)
|
||||
@ -2963,6 +2979,7 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kSize, message_object)
|
||||
ALLOCATE_MAP(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize, external)
|
||||
external_map()->set_is_extensible(false);
|
||||
#undef ALLOCATE_PRIMITIVE_MAP
|
||||
#undef ALLOCATE_VARSIZE_MAP
|
||||
#undef ALLOCATE_MAP
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ template <typename StaticVisitor>
|
||||
void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp(Map* map,
|
||||
HeapObject* object) {
|
||||
int last_property_offset =
|
||||
JSRegExp::kSize + kPointerSize * map->inobject_properties();
|
||||
JSRegExp::kSize + kPointerSize * map->GetInObjectProperties();
|
||||
StaticVisitor::VisitPointers(
|
||||
map->GetHeap(), object,
|
||||
HeapObject::RawField(object, JSRegExp::kPropertiesOffset),
|
||||
|
@ -6106,10 +6106,10 @@ class HObjectAccess final {
|
||||
Representation::Integer32());
|
||||
}
|
||||
|
||||
static HObjectAccess ForMapInObjectProperties() {
|
||||
return HObjectAccess(kInobject,
|
||||
Map::kInObjectPropertiesOffset,
|
||||
Representation::UInteger8());
|
||||
static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() {
|
||||
return HObjectAccess(
|
||||
kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
|
||||
Representation::UInteger8());
|
||||
}
|
||||
|
||||
static HObjectAccess ForMapInstanceType() {
|
||||
|
109
src/hydrogen.cc
109
src/hydrogen.cc
@ -2047,14 +2047,8 @@ HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
|
||||
receiver_is_smi.If<HIsSmiAndBranch>(receiver);
|
||||
receiver_is_smi.Then();
|
||||
{
|
||||
// Load native context.
|
||||
HValue* native_context = BuildGetNativeContext();
|
||||
|
||||
// Load global Number function.
|
||||
HValue* constructor = Add<HLoadNamedField>(
|
||||
native_context, nullptr,
|
||||
HObjectAccess::ForContextSlot(Context::NUMBER_FUNCTION_INDEX));
|
||||
Push(constructor);
|
||||
// Use global Number function.
|
||||
Push(Add<HConstant>(Context::NUMBER_FUNCTION_INDEX));
|
||||
}
|
||||
receiver_is_smi.Else();
|
||||
{
|
||||
@ -2071,75 +2065,23 @@ HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
|
||||
Token::LT);
|
||||
receiver_is_not_spec_object.Then();
|
||||
{
|
||||
// Load native context.
|
||||
HValue* native_context = BuildGetNativeContext();
|
||||
// Load the constructor function index from the {receiver} map.
|
||||
HValue* constructor_function_index = Add<HLoadNamedField>(
|
||||
receiver_map, nullptr,
|
||||
HObjectAccess::ForMapInObjectPropertiesOrConstructorFunctionIndex());
|
||||
|
||||
IfBuilder receiver_is_heap_number(this);
|
||||
receiver_is_heap_number.If<HCompareNumericAndBranch>(
|
||||
receiver_instance_type, Add<HConstant>(HEAP_NUMBER_TYPE), Token::EQ);
|
||||
receiver_is_heap_number.Then();
|
||||
{
|
||||
// Load global Number function.
|
||||
HValue* constructor = Add<HLoadNamedField>(
|
||||
native_context, nullptr,
|
||||
HObjectAccess::ForContextSlot(Context::NUMBER_FUNCTION_INDEX));
|
||||
Push(constructor);
|
||||
}
|
||||
receiver_is_heap_number.Else();
|
||||
{
|
||||
// Load boolean map (we cannot decide based on instance type, because
|
||||
// it's ODDBALL_TYPE, which would also include null and undefined).
|
||||
HValue* boolean_map = Add<HLoadRoot>(Heap::kBooleanMapRootIndex);
|
||||
// Check if {receiver} has a constructor (null and undefined have no
|
||||
// constructors, so we deoptimize to the runtime to throw an exception).
|
||||
IfBuilder constructor_function_index_is_invalid(this);
|
||||
constructor_function_index_is_invalid.If<HCompareNumericAndBranch>(
|
||||
constructor_function_index,
|
||||
Add<HConstant>(Map::kNoConstructorFunctionIndex), Token::EQ);
|
||||
constructor_function_index_is_invalid.ThenDeopt(
|
||||
Deoptimizer::kUndefinedOrNullInToObject);
|
||||
constructor_function_index_is_invalid.End();
|
||||
|
||||
IfBuilder receiver_is_boolean(this);
|
||||
receiver_is_boolean.If<HCompareObjectEqAndBranch>(receiver_map,
|
||||
boolean_map);
|
||||
receiver_is_boolean.Then();
|
||||
{
|
||||
// Load global Boolean function.
|
||||
HValue* constructor = Add<HLoadNamedField>(
|
||||
native_context, nullptr,
|
||||
HObjectAccess::ForContextSlot(Context::BOOLEAN_FUNCTION_INDEX));
|
||||
Push(constructor);
|
||||
}
|
||||
receiver_is_boolean.Else();
|
||||
{
|
||||
IfBuilder receiver_is_string(this);
|
||||
receiver_is_string.If<HCompareNumericAndBranch>(
|
||||
receiver_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE),
|
||||
Token::LT);
|
||||
receiver_is_string.Then();
|
||||
{
|
||||
// Load global String function.
|
||||
HValue* constructor = Add<HLoadNamedField>(
|
||||
native_context, nullptr,
|
||||
HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX));
|
||||
Push(constructor);
|
||||
}
|
||||
receiver_is_string.Else();
|
||||
{
|
||||
IfBuilder receiver_is_symbol(this);
|
||||
receiver_is_symbol.If<HCompareNumericAndBranch>(
|
||||
receiver_instance_type, Add<HConstant>(SYMBOL_TYPE), Token::EQ);
|
||||
receiver_is_symbol.Then();
|
||||
{
|
||||
// Load global Symbol function.
|
||||
HValue* constructor = Add<HLoadNamedField>(
|
||||
native_context, nullptr, HObjectAccess::ForContextSlot(
|
||||
Context::SYMBOL_FUNCTION_INDEX));
|
||||
Push(constructor);
|
||||
}
|
||||
// TODO(bmeurer): Don't inline this into crankshaft code, as it will
|
||||
// deoptimize on all SIMD128 objects.
|
||||
receiver_is_symbol.ElseDeopt(
|
||||
Deoptimizer::kUndefinedOrNullInToObject);
|
||||
receiver_is_symbol.JoinContinuation(&wrap);
|
||||
}
|
||||
receiver_is_string.JoinContinuation(&wrap);
|
||||
}
|
||||
receiver_is_boolean.JoinContinuation(&wrap);
|
||||
}
|
||||
receiver_is_heap_number.JoinContinuation(&wrap);
|
||||
// Use the global constructor function.
|
||||
Push(constructor_function_index);
|
||||
}
|
||||
receiver_is_not_spec_object.JoinContinuation(&wrap);
|
||||
}
|
||||
@ -2149,8 +2091,15 @@ HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
|
||||
IfBuilder if_wrap(this, &wrap);
|
||||
if_wrap.Then();
|
||||
{
|
||||
// Grab the constructor function index.
|
||||
HValue* constructor_index = Pop();
|
||||
|
||||
// Load native context.
|
||||
HValue* native_context = BuildGetNativeContext();
|
||||
|
||||
// Determine the initial map for the global constructor.
|
||||
HValue* constructor = Pop();
|
||||
HValue* constructor = Add<HLoadKeyed>(native_context, constructor_index,
|
||||
nullptr, FAST_ELEMENTS);
|
||||
HValue* constructor_initial_map = Add<HLoadNamedField>(
|
||||
constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap());
|
||||
// Allocate and initialize a JSValue wrapper.
|
||||
@ -6443,7 +6392,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
int descriptor = transition()->LastAdded();
|
||||
int index =
|
||||
transition()->instance_descriptors()->GetFieldIndex(descriptor) -
|
||||
map_->inobject_properties();
|
||||
map_->GetInObjectProperties();
|
||||
PropertyDetails details =
|
||||
transition()->instance_descriptors()->GetDetails(descriptor);
|
||||
Representation representation = details.representation();
|
||||
@ -9963,9 +9912,9 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
|
||||
|
||||
void HOptimizedGraphBuilder::BuildInitializeInobjectProperties(
|
||||
HValue* receiver, Handle<Map> initial_map) {
|
||||
if (initial_map->inobject_properties() != 0) {
|
||||
if (initial_map->GetInObjectProperties() != 0) {
|
||||
HConstant* undefined = graph()->GetConstantUndefined();
|
||||
for (int i = 0; i < initial_map->inobject_properties(); i++) {
|
||||
for (int i = 0; i < initial_map->GetInObjectProperties(); i++) {
|
||||
int property_offset = initial_map->GetInObjectPropertyOffset(i);
|
||||
Add<HStoreNamedField>(receiver, HObjectAccess::ForMapAndOffset(
|
||||
initial_map, property_offset),
|
||||
@ -11778,7 +11727,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
}
|
||||
}
|
||||
|
||||
int inobject_properties = boilerplate_object->map()->inobject_properties();
|
||||
int inobject_properties = boilerplate_object->map()->GetInObjectProperties();
|
||||
HInstruction* value_instruction =
|
||||
Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
|
||||
for (int i = copied_fields; i < inobject_properties; i++) {
|
||||
|
@ -2637,7 +2637,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
lookup_type_ == TRANSITION_TYPE);
|
||||
DCHECK(number_ < map->NumberOfOwnDescriptors());
|
||||
int field_index = map->instance_descriptors()->GetFieldIndex(number_);
|
||||
return field_index - map->inobject_properties();
|
||||
return field_index - map->GetInObjectProperties();
|
||||
}
|
||||
|
||||
void LookupDescriptor(Map* map, Name* name) {
|
||||
|
@ -224,7 +224,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
__ j(less, &no_inobject_slack_tracking);
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ movzx_b(esi, FieldOperand(eax, Map::kInObjectPropertiesOffset));
|
||||
__ movzx_b(
|
||||
esi,
|
||||
FieldOperand(
|
||||
eax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
|
||||
__ sub(esi, eax);
|
||||
__ lea(esi,
|
||||
|
@ -99,28 +99,11 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Handle<Name> name,
|
||||
Label* miss,
|
||||
ReturnHolder return_what) {
|
||||
PrototypeCheckType check_type = CHECK_ALL_MAPS;
|
||||
int function_index = -1;
|
||||
if (map()->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
function_index = Context::STRING_FUNCTION_INDEX;
|
||||
} else if (map()->instance_type() == SYMBOL_TYPE) {
|
||||
function_index = Context::SYMBOL_FUNCTION_INDEX;
|
||||
} else if (map()->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
function_index = Context::NUMBER_FUNCTION_INDEX;
|
||||
} else if (*map() == isolate()->heap()->boolean_map()) {
|
||||
function_index = Context::BOOLEAN_FUNCTION_INDEX;
|
||||
// clang-format off
|
||||
#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
|
||||
} else if (map().is_identical_to(isolate()->factory()->type##_map())) { \
|
||||
function_index = Context::TYPE##_FUNCTION_INDEX;
|
||||
SIMD128_TYPES(SIMD128_TYPE)
|
||||
#undef SIMD128_TYPE
|
||||
// clang-format on
|
||||
} else {
|
||||
check_type = SKIP_RECEIVER;
|
||||
}
|
||||
|
||||
if (check_type == CHECK_ALL_MAPS) {
|
||||
PrototypeCheckType check_type = SKIP_RECEIVER;
|
||||
int function_index = map()->IsPrimitiveMap()
|
||||
? map()->GetConstructorFunctionIndex()
|
||||
: Map::kNoConstructorFunctionIndex;
|
||||
if (function_index != Map::kNoConstructorFunctionIndex) {
|
||||
GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
|
||||
scratch1(), miss);
|
||||
Object* function = isolate()->native_context()->get(function_index);
|
||||
@ -128,6 +111,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
|
||||
Handle<Map> map(JSObject::cast(prototype)->map());
|
||||
set_map(map);
|
||||
object_reg = scratch1();
|
||||
check_type = CHECK_ALL_MAPS;
|
||||
}
|
||||
|
||||
// Check that the maps starting from the prototype haven't changed.
|
||||
|
@ -127,25 +127,14 @@ void IC::UpdateTarget() { target_ = handle(raw_target(), isolate_); }
|
||||
|
||||
|
||||
JSFunction* IC::GetRootConstructor(Map* receiver_map, Context* native_context) {
|
||||
Isolate* isolate = receiver_map->GetIsolate();
|
||||
if (receiver_map == isolate->heap()->boolean_map()) {
|
||||
return native_context->boolean_function();
|
||||
DisallowHeapAllocation no_alloc;
|
||||
if (receiver_map->IsPrimitiveMap()) {
|
||||
int constructor_function_index =
|
||||
receiver_map->GetConstructorFunctionIndex();
|
||||
if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
|
||||
return JSFunction::cast(native_context->get(constructor_function_index));
|
||||
}
|
||||
}
|
||||
if (receiver_map->instance_type() == HEAP_NUMBER_TYPE) {
|
||||
return native_context->number_function();
|
||||
}
|
||||
if (receiver_map->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
return native_context->string_function();
|
||||
}
|
||||
if (receiver_map->instance_type() == SYMBOL_TYPE) {
|
||||
return native_context->symbol_function();
|
||||
}
|
||||
#define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \
|
||||
if (receiver_map == isolate->heap()->type##_map()) { \
|
||||
return native_context->type##_function(); \
|
||||
}
|
||||
SIMD128_TYPES(SIMD128_TYPE)
|
||||
#undef SIMD128_TYPE
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
|
||||
|
||||
int LayoutDescriptor::CalculateCapacity(Map* map, DescriptorArray* descriptors,
|
||||
int num_descriptors) {
|
||||
int inobject_properties = map->inobject_properties();
|
||||
int inobject_properties = map->GetInObjectProperties();
|
||||
if (inobject_properties == 0) return 0;
|
||||
|
||||
DCHECK_LE(num_descriptors, descriptors->number_of_descriptors());
|
||||
@ -195,7 +195,7 @@ LayoutDescriptor* LayoutDescriptor::Initialize(
|
||||
LayoutDescriptor* layout_descriptor, Map* map, DescriptorArray* descriptors,
|
||||
int num_descriptors) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
int inobject_properties = map->inobject_properties();
|
||||
int inobject_properties = map->GetInObjectProperties();
|
||||
|
||||
for (int i = 0; i < num_descriptors; i++) {
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
@ -214,7 +214,7 @@ LayoutDescriptor* LayoutDescriptor::Initialize(
|
||||
}
|
||||
|
||||
|
||||
// InobjectPropertiesHelper is a helper class for querying whether inobject
|
||||
// LayoutDescriptorHelper is a helper class for querying whether inobject
|
||||
// property at offset is Double or not.
|
||||
LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
|
||||
: all_fields_tagged_(true),
|
||||
@ -227,7 +227,7 @@ LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
|
||||
return;
|
||||
}
|
||||
|
||||
int inobject_properties = map->inobject_properties();
|
||||
int inobject_properties = map->GetInObjectProperties();
|
||||
DCHECK(inobject_properties > 0);
|
||||
header_size_ = map->instance_size() - (inobject_properties * kPointerSize);
|
||||
DCHECK(header_size_ >= 0);
|
||||
|
@ -46,7 +46,7 @@ Handle<LayoutDescriptor> LayoutDescriptor::ShareAppend(
|
||||
Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
|
||||
isolate);
|
||||
|
||||
if (!InobjectUnboxedField(map->inobject_properties(), details)) {
|
||||
if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
|
||||
DCHECK(details.location() != kField ||
|
||||
layout_descriptor->IsTagged(details.field_index()));
|
||||
return layout_descriptor;
|
||||
@ -73,7 +73,7 @@ Handle<LayoutDescriptor> LayoutDescriptor::AppendIfFastOrUseFull(
|
||||
if (layout_descriptor->IsSlowLayout()) {
|
||||
return full_layout_descriptor;
|
||||
}
|
||||
if (!InobjectUnboxedField(map->inobject_properties(), details)) {
|
||||
if (!InobjectUnboxedField(map->GetInObjectProperties(), details)) {
|
||||
DCHECK(details.location() != kField ||
|
||||
layout_descriptor->IsTagged(details.field_index()));
|
||||
return handle(layout_descriptor, map->GetIsolate());
|
||||
|
@ -440,7 +440,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
Operand(Map::kSlackTrackingCounterEnd));
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ lbu(a0, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
|
||||
__ lbu(
|
||||
a0,
|
||||
FieldMemOperand(
|
||||
a2, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ lbu(a2, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset));
|
||||
__ subu(a0, a0, a2);
|
||||
__ sll(at, a0, kPointerSizeLog2);
|
||||
|
@ -439,7 +439,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
Operand(static_cast<int64_t>(Map::kSlackTrackingCounterEnd)));
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ lbu(a0, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
|
||||
__ lbu(
|
||||
a0,
|
||||
FieldMemOperand(
|
||||
a2, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ lbu(a2, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset));
|
||||
__ dsubu(a0, a0, a2);
|
||||
__ dsll(at, a0, kPointerSizeLog2);
|
||||
|
@ -264,7 +264,7 @@ void JSObject::JSObjectVerify() {
|
||||
}
|
||||
|
||||
if (HasFastProperties()) {
|
||||
int actual_unused_property_fields = map()->inobject_properties() +
|
||||
int actual_unused_property_fields = map()->GetInObjectProperties() +
|
||||
properties()->length() -
|
||||
map()->NextFreePropertyIndex();
|
||||
if (map()->unused_property_fields() != actual_unused_property_fields) {
|
||||
|
@ -186,7 +186,9 @@ bool Object::IsString() const {
|
||||
|
||||
|
||||
bool Object::IsName() const {
|
||||
return IsString() || IsSymbol();
|
||||
STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
|
||||
return Object::IsHeapObject() &&
|
||||
HeapObject::cast(this)->map()->instance_type() <= LAST_NAME_TYPE;
|
||||
}
|
||||
|
||||
|
||||
@ -985,7 +987,7 @@ bool Object::IsOrderedHashMap() const {
|
||||
|
||||
|
||||
bool Object::IsPrimitive() const {
|
||||
return IsOddball() || IsNumber() || IsString();
|
||||
return IsSmi() || HeapObject::cast(this)->map()->IsPrimitiveMap();
|
||||
}
|
||||
|
||||
|
||||
@ -2117,7 +2119,7 @@ int JSObject::GetInternalFieldCount() {
|
||||
// Make sure to adjust for the number of in-object properties. These
|
||||
// properties do contribute to the size, but are not internal fields.
|
||||
return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
|
||||
map()->inobject_properties();
|
||||
map()->GetInObjectProperties();
|
||||
}
|
||||
|
||||
|
||||
@ -2274,7 +2276,7 @@ void JSObject::InitializeBody(Map* map,
|
||||
int offset = kHeaderSize;
|
||||
if (filler_value != pre_allocated_value) {
|
||||
int pre_allocated =
|
||||
map->inobject_properties() - map->unused_property_fields();
|
||||
map->GetInObjectProperties() - map->unused_property_fields();
|
||||
DCHECK(pre_allocated * kPointerSize + kHeaderSize <= size);
|
||||
for (int i = 0; i < pre_allocated; i++) {
|
||||
WRITE_FIELD(this, offset, pre_allocated_value);
|
||||
@ -2298,8 +2300,8 @@ bool Map::TooManyFastProperties(StoreFromKeyed store_mode) {
|
||||
if (unused_property_fields() != 0) return false;
|
||||
if (is_prototype_map()) return false;
|
||||
int minimum = store_mode == CERTAINLY_NOT_STORE_FROM_KEYED ? 128 : 12;
|
||||
int limit = Max(minimum, inobject_properties());
|
||||
int external = NumberOfFields() - inobject_properties();
|
||||
int limit = Max(minimum, GetInObjectProperties());
|
||||
int external = NumberOfFields() - GetInObjectProperties();
|
||||
return external > limit;
|
||||
}
|
||||
|
||||
@ -3986,14 +3988,46 @@ int Map::instance_size() {
|
||||
}
|
||||
|
||||
|
||||
int Map::inobject_properties() {
|
||||
return READ_BYTE_FIELD(this, kInObjectPropertiesOffset);
|
||||
int Map::inobject_properties_or_constructor_function_index() {
|
||||
return READ_BYTE_FIELD(this,
|
||||
kInObjectPropertiesOrConstructorFunctionIndexOffset);
|
||||
}
|
||||
|
||||
|
||||
void Map::set_inobject_properties_or_constructor_function_index(int value) {
|
||||
DCHECK(0 <= value && value < 256);
|
||||
WRITE_BYTE_FIELD(this, kInObjectPropertiesOrConstructorFunctionIndexOffset,
|
||||
static_cast<byte>(value));
|
||||
}
|
||||
|
||||
|
||||
int Map::GetInObjectProperties() {
|
||||
DCHECK(IsJSObjectMap());
|
||||
return inobject_properties_or_constructor_function_index();
|
||||
}
|
||||
|
||||
|
||||
void Map::SetInObjectProperties(int value) {
|
||||
DCHECK(IsJSObjectMap());
|
||||
set_inobject_properties_or_constructor_function_index(value);
|
||||
}
|
||||
|
||||
|
||||
int Map::GetConstructorFunctionIndex() {
|
||||
DCHECK(IsPrimitiveMap());
|
||||
return inobject_properties_or_constructor_function_index();
|
||||
}
|
||||
|
||||
|
||||
void Map::SetConstructorFunctionIndex(int value) {
|
||||
DCHECK(IsPrimitiveMap());
|
||||
set_inobject_properties_or_constructor_function_index(value);
|
||||
}
|
||||
|
||||
|
||||
int Map::GetInObjectPropertyOffset(int index) {
|
||||
// Adjust for the number of properties stored in the object.
|
||||
index -= inobject_properties();
|
||||
index -= GetInObjectProperties();
|
||||
DCHECK(index <= 0);
|
||||
return instance_size() + (index * kPointerSize);
|
||||
}
|
||||
@ -4061,12 +4095,6 @@ void Map::set_instance_size(int value) {
|
||||
}
|
||||
|
||||
|
||||
void Map::set_inobject_properties(int value) {
|
||||
DCHECK(0 <= value && value < 256);
|
||||
WRITE_BYTE_FIELD(this, kInObjectPropertiesOffset, static_cast<byte>(value));
|
||||
}
|
||||
|
||||
|
||||
void Map::clear_unused() { WRITE_BYTE_FIELD(this, kUnusedOffset, 0); }
|
||||
|
||||
|
||||
|
@ -465,7 +465,9 @@ void Map::MapPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "Map");
|
||||
os << " - type: " << TypeToString(instance_type()) << "\n";
|
||||
os << " - instance size: " << instance_size() << "\n";
|
||||
os << " - inobject properties: " << inobject_properties() << "\n";
|
||||
if (IsJSObjectMap()) {
|
||||
os << " - inobject properties: " << GetInObjectProperties() << "\n";
|
||||
}
|
||||
os << " - elements kind: " << ElementsKindToString(elements_kind()) << "\n";
|
||||
os << " - unused property fields: " << unused_property_fields() << "\n";
|
||||
if (is_deprecated()) os << " - deprecated_map\n";
|
||||
|
112
src/objects.cc
112
src/objects.cc
@ -72,34 +72,17 @@ MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
|
||||
Handle<Context> native_context) {
|
||||
if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
|
||||
Handle<JSFunction> constructor;
|
||||
if (object->IsNumber()) {
|
||||
if (object->IsSmi()) {
|
||||
constructor = handle(native_context->number_function(), isolate);
|
||||
} else if (object->IsBoolean()) {
|
||||
constructor = handle(native_context->boolean_function(), isolate);
|
||||
} else if (object->IsString()) {
|
||||
constructor = handle(native_context->string_function(), isolate);
|
||||
} else if (object->IsSymbol()) {
|
||||
constructor = handle(native_context->symbol_function(), isolate);
|
||||
} else if (object->IsSimd128Value()) {
|
||||
if (object->IsFloat32x4()) {
|
||||
constructor = handle(native_context->float32x4_function(), isolate);
|
||||
} else if (object->IsInt32x4()) {
|
||||
constructor = handle(native_context->int32x4_function(), isolate);
|
||||
} else if (object->IsBool32x4()) {
|
||||
constructor = handle(native_context->bool32x4_function(), isolate);
|
||||
} else if (object->IsInt16x8()) {
|
||||
constructor = handle(native_context->int16x8_function(), isolate);
|
||||
} else if (object->IsBool16x8()) {
|
||||
constructor = handle(native_context->bool16x8_function(), isolate);
|
||||
} else if (object->IsInt8x16()) {
|
||||
constructor = handle(native_context->int8x16_function(), isolate);
|
||||
} else if (object->IsBool8x16()) {
|
||||
constructor = handle(native_context->bool8x16_function(), isolate);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
return MaybeHandle<JSReceiver>();
|
||||
int constructor_function_index =
|
||||
Handle<HeapObject>::cast(object)->map()->GetConstructorFunctionIndex();
|
||||
if (constructor_function_index == Map::kNoConstructorFunctionIndex) {
|
||||
return MaybeHandle<JSReceiver>();
|
||||
}
|
||||
constructor = handle(
|
||||
JSFunction::cast(native_context->get(constructor_function_index)),
|
||||
isolate);
|
||||
}
|
||||
Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
|
||||
Handle<JSValue>::cast(result)->set_value(*object);
|
||||
@ -618,49 +601,23 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
||||
Map* Object::GetRootMap(Isolate* isolate) {
|
||||
DisallowHeapAllocation no_alloc;
|
||||
if (IsSmi()) {
|
||||
Context* context = isolate->context()->native_context();
|
||||
return context->number_function()->initial_map();
|
||||
Context* native_context = isolate->context()->native_context();
|
||||
return native_context->number_function()->initial_map();
|
||||
}
|
||||
|
||||
HeapObject* heap_object = HeapObject::cast(this);
|
||||
|
||||
// The object is either a number, a string, a symbol, a boolean, a SIMD value,
|
||||
// a real JS object, or a Harmony proxy.
|
||||
HeapObject* heap_object = HeapObject::cast(this);
|
||||
if (heap_object->IsJSReceiver()) {
|
||||
return heap_object->map();
|
||||
}
|
||||
Context* context = isolate->context()->native_context();
|
||||
|
||||
if (heap_object->IsHeapNumber()) {
|
||||
return context->number_function()->initial_map();
|
||||
}
|
||||
if (heap_object->IsString()) {
|
||||
return context->string_function()->initial_map();
|
||||
}
|
||||
if (heap_object->IsSymbol()) {
|
||||
return context->symbol_function()->initial_map();
|
||||
}
|
||||
if (heap_object->IsBoolean()) {
|
||||
return context->boolean_function()->initial_map();
|
||||
}
|
||||
if (heap_object->IsSimd128Value()) {
|
||||
if (heap_object->IsFloat32x4()) {
|
||||
return context->float32x4_function()->initial_map();
|
||||
} else if (heap_object->IsInt32x4()) {
|
||||
return context->int32x4_function()->initial_map();
|
||||
} else if (heap_object->IsBool32x4()) {
|
||||
return context->bool32x4_function()->initial_map();
|
||||
} else if (heap_object->IsInt16x8()) {
|
||||
return context->int16x8_function()->initial_map();
|
||||
} else if (heap_object->IsBool16x8()) {
|
||||
return context->bool16x8_function()->initial_map();
|
||||
} else if (heap_object->IsInt8x16()) {
|
||||
return context->int8x16_function()->initial_map();
|
||||
} else if (heap_object->IsBool8x16()) {
|
||||
return context->bool8x16_function()->initial_map();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
int constructor_function_index =
|
||||
heap_object->map()->GetConstructorFunctionIndex();
|
||||
if (constructor_function_index != Map::kNoConstructorFunctionIndex) {
|
||||
Context* native_context = isolate->context()->native_context();
|
||||
JSFunction* constructor_function =
|
||||
JSFunction::cast(native_context->get(constructor_function_index));
|
||||
return constructor_function->initial_map();
|
||||
}
|
||||
return isolate->heap()->null_value()->map();
|
||||
}
|
||||
@ -1731,11 +1688,11 @@ bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
|
||||
|
||||
// If no fields were added, and no inobject properties were removed, setting
|
||||
// the map is sufficient.
|
||||
if (target_inobject == inobject_properties()) return false;
|
||||
if (target_inobject == GetInObjectProperties()) return false;
|
||||
// In-object slack tracking may have reduced the object size of the new map.
|
||||
// In that case, succeed if all existing fields were inobject, and they still
|
||||
// fit within the new inobject size.
|
||||
DCHECK(target_inobject < inobject_properties());
|
||||
DCHECK(target_inobject < GetInObjectProperties());
|
||||
if (target_number_of_fields <= target_inobject) {
|
||||
DCHECK(target_number_of_fields + target_unused == target_inobject);
|
||||
return false;
|
||||
@ -1842,7 +1799,7 @@ void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
|
||||
Handle<Map> old_map(object->map());
|
||||
int old_number_of_fields;
|
||||
int number_of_fields = new_map->NumberOfFields();
|
||||
int inobject = new_map->inobject_properties();
|
||||
int inobject = new_map->GetInObjectProperties();
|
||||
int unused = new_map->unused_property_fields();
|
||||
|
||||
// Nothing to do if no functions were converted to fields and no smis were
|
||||
@ -4049,7 +4006,8 @@ MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
|
||||
|
||||
|
||||
void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
|
||||
DCHECK(object->map()->inobject_properties() == map->inobject_properties());
|
||||
DCHECK(object->map()->GetInObjectProperties() ==
|
||||
map->GetInObjectProperties());
|
||||
ElementsKind obj_kind = object->map()->elements_kind();
|
||||
ElementsKind map_kind = map->elements_kind();
|
||||
if (map_kind != obj_kind) {
|
||||
@ -4561,7 +4519,7 @@ void JSObject::MigrateFastToSlow(Handle<JSObject> object,
|
||||
|
||||
// Ensure that in-object space of slow-mode object does not contain random
|
||||
// garbage.
|
||||
int inobject_properties = new_map->inobject_properties();
|
||||
int inobject_properties = new_map->GetInObjectProperties();
|
||||
for (int i = 0; i < inobject_properties; i++) {
|
||||
FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
|
||||
object->RawFastPropertyAtPut(index, Smi::FromInt(0));
|
||||
@ -4618,7 +4576,7 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
|
||||
|
||||
Handle<Map> old_map(object->map(), isolate);
|
||||
|
||||
int inobject_props = old_map->inobject_properties();
|
||||
int inobject_props = old_map->GetInObjectProperties();
|
||||
|
||||
// Allocate new map.
|
||||
Handle<Map> new_map = Map::CopyDropDescriptors(old_map);
|
||||
@ -6506,13 +6464,13 @@ Handle<Map> Map::CopyNormalized(Handle<Map> map,
|
||||
PropertyNormalizationMode mode) {
|
||||
int new_instance_size = map->instance_size();
|
||||
if (mode == CLEAR_INOBJECT_PROPERTIES) {
|
||||
new_instance_size -= map->inobject_properties() * kPointerSize;
|
||||
new_instance_size -= map->GetInObjectProperties() * kPointerSize;
|
||||
}
|
||||
|
||||
Handle<Map> result = RawCopy(map, new_instance_size);
|
||||
|
||||
if (mode != CLEAR_INOBJECT_PROPERTIES) {
|
||||
result->set_inobject_properties(map->inobject_properties());
|
||||
result->SetInObjectProperties(map->GetInObjectProperties());
|
||||
}
|
||||
|
||||
result->set_dictionary_map(true);
|
||||
@ -6530,7 +6488,7 @@ Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
|
||||
Handle<Map> result = RawCopy(map, map->instance_size());
|
||||
|
||||
// Please note instance_type and instance_size are set when allocated.
|
||||
result->set_inobject_properties(map->inobject_properties());
|
||||
result->SetInObjectProperties(map->GetInObjectProperties());
|
||||
result->set_unused_property_fields(map->unused_property_fields());
|
||||
|
||||
result->ClearCodeCache(map->GetHeap());
|
||||
@ -6842,7 +6800,7 @@ Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
|
||||
JSObject::kHeaderSize + kPointerSize * inobject_properties;
|
||||
|
||||
// Adjust the map with the extra inobject properties.
|
||||
copy->set_inobject_properties(inobject_properties);
|
||||
copy->SetInObjectProperties(inobject_properties);
|
||||
copy->set_unused_property_fields(inobject_properties);
|
||||
copy->set_instance_size(new_instance_size);
|
||||
copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
|
||||
@ -9236,10 +9194,10 @@ bool Map::EquivalentToForTransition(Map* other) {
|
||||
|
||||
bool Map::EquivalentToForNormalization(Map* other,
|
||||
PropertyNormalizationMode mode) {
|
||||
int properties = mode == CLEAR_INOBJECT_PROPERTIES
|
||||
? 0 : other->inobject_properties();
|
||||
int properties =
|
||||
mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties();
|
||||
return CheckEquivalent(this, other) && bit_field2() == other->bit_field2() &&
|
||||
inobject_properties() == properties;
|
||||
GetInObjectProperties() == properties;
|
||||
}
|
||||
|
||||
|
||||
@ -9497,7 +9455,7 @@ static void GetMinInobjectSlack(Map* map, void* data) {
|
||||
|
||||
static void ShrinkInstanceSize(Map* map, void* data) {
|
||||
int slack = *reinterpret_cast<int*>(data);
|
||||
map->set_inobject_properties(map->inobject_properties() - slack);
|
||||
map->SetInObjectProperties(map->GetInObjectProperties() - slack);
|
||||
map->set_unused_property_fields(map->unused_property_fields() - slack);
|
||||
map->set_instance_size(map->instance_size() - slack * kPointerSize);
|
||||
|
||||
@ -9979,7 +9937,7 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
}
|
||||
map->set_inobject_properties(in_object_properties);
|
||||
map->SetInObjectProperties(in_object_properties);
|
||||
map->set_unused_property_fields(in_object_properties);
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
|
@ -612,8 +612,8 @@ static inline bool IsShortcutCandidate(int type) {
|
||||
|
||||
enum InstanceType {
|
||||
// String types.
|
||||
INTERNALIZED_STRING_TYPE =
|
||||
kTwoByteStringTag | kSeqStringTag | kInternalizedTag,
|
||||
INTERNALIZED_STRING_TYPE = kTwoByteStringTag | kSeqStringTag |
|
||||
kInternalizedTag, // FIRST_PRIMITIVE_TYPE
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE =
|
||||
kOneByteStringTag | kSeqStringTag | kInternalizedTag,
|
||||
EXTERNAL_INTERNALIZED_STRING_TYPE =
|
||||
@ -660,16 +660,18 @@ enum InstanceType {
|
||||
// Non-string names
|
||||
SYMBOL_TYPE = kNotStringTag, // FIRST_NONSTRING_TYPE, LAST_NAME_TYPE
|
||||
|
||||
// Other primitives (cannot contain non-map-word pointers to heap objects).
|
||||
HEAP_NUMBER_TYPE,
|
||||
SIMD128_VALUE_TYPE,
|
||||
ODDBALL_TYPE, // LAST_PRIMITIVE_TYPE
|
||||
|
||||
// Objects allocated in their own spaces (never in new space).
|
||||
MAP_TYPE,
|
||||
CODE_TYPE,
|
||||
ODDBALL_TYPE,
|
||||
|
||||
// "Data", objects that cannot contain non-map-word pointers to heap
|
||||
// objects.
|
||||
HEAP_NUMBER_TYPE,
|
||||
MUTABLE_HEAP_NUMBER_TYPE,
|
||||
SIMD128_VALUE_TYPE,
|
||||
FOREIGN_TYPE,
|
||||
BYTE_ARRAY_TYPE,
|
||||
BYTECODE_ARRAY_TYPE,
|
||||
@ -753,6 +755,8 @@ enum InstanceType {
|
||||
FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE,
|
||||
LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE,
|
||||
FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
|
||||
FIRST_PRIMITIVE_TYPE = FIRST_NAME_TYPE,
|
||||
LAST_PRIMITIVE_TYPE = ODDBALL_TYPE,
|
||||
// Boundaries for testing for a fixed typed array.
|
||||
FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE,
|
||||
LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE,
|
||||
@ -5273,9 +5277,20 @@ class Map: public HeapObject {
|
||||
// Only to clear an unused byte, remove once byte is used.
|
||||
inline void clear_unused();
|
||||
|
||||
// Count of properties allocated in the object.
|
||||
inline int inobject_properties();
|
||||
inline void set_inobject_properties(int value);
|
||||
// [inobject_properties_or_constructor_function_index]: Provides access
|
||||
// to the inobject properties in case of JSObject maps, or the constructor
|
||||
// function index in case of primitive maps.
|
||||
inline int inobject_properties_or_constructor_function_index();
|
||||
inline void set_inobject_properties_or_constructor_function_index(int value);
|
||||
// Count of properties allocated in the object (JSObject only).
|
||||
inline int GetInObjectProperties();
|
||||
inline void SetInObjectProperties(int value);
|
||||
// Index of the constructor function in the native context (primitives only),
|
||||
// or the special sentinel value to indicate that there is no object wrapper
|
||||
// for the primitive (i.e. in case of null or undefined).
|
||||
static const int kNoConstructorFunctionIndex = 0;
|
||||
inline int GetConstructorFunctionIndex();
|
||||
inline void SetConstructorFunctionIndex(int value);
|
||||
|
||||
// Instance type.
|
||||
inline InstanceType instance_type();
|
||||
@ -5766,7 +5781,12 @@ class Map: public HeapObject {
|
||||
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
||||
}
|
||||
|
||||
bool IsPrimitiveMap() {
|
||||
STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
|
||||
return instance_type() <= LAST_PRIMITIVE_TYPE;
|
||||
}
|
||||
bool IsJSObjectMap() {
|
||||
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
|
||||
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
||||
}
|
||||
bool IsJSArrayMap() { return instance_type() == JS_ARRAY_TYPE; }
|
||||
@ -5847,9 +5867,9 @@ class Map: public HeapObject {
|
||||
|
||||
// Byte offsets within kInstanceSizesOffset.
|
||||
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
|
||||
static const int kInObjectPropertiesByte = 1;
|
||||
static const int kInObjectPropertiesOffset =
|
||||
kInstanceSizesOffset + kInObjectPropertiesByte;
|
||||
static const int kInObjectPropertiesOrConstructorFunctionIndexByte = 1;
|
||||
static const int kInObjectPropertiesOrConstructorFunctionIndexOffset =
|
||||
kInstanceSizesOffset + kInObjectPropertiesOrConstructorFunctionIndexByte;
|
||||
// Note there is one byte available for use here.
|
||||
static const int kUnusedByte = 2;
|
||||
static const int kUnusedOffset = kInstanceSizesOffset + kUnusedByte;
|
||||
|
@ -434,7 +434,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
__ blt(&no_inobject_slack_tracking);
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ lbz(r3, FieldMemOperand(r5, Map::kInObjectPropertiesOffset));
|
||||
__ lbz(
|
||||
r3,
|
||||
FieldMemOperand(
|
||||
r5, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ lbz(r5, FieldMemOperand(r5, Map::kUnusedPropertyFieldsOffset));
|
||||
__ sub(r3, r3, r5);
|
||||
if (FLAG_debug_code) {
|
||||
|
@ -299,7 +299,7 @@ RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
|
||||
|
||||
void Runtime::WeakCollectionInitialize(
|
||||
Isolate* isolate, Handle<JSWeakCollection> weak_collection) {
|
||||
DCHECK(weak_collection->map()->inobject_properties() == 0);
|
||||
DCHECK_EQ(0, weak_collection->map()->GetInObjectProperties());
|
||||
Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
|
||||
weak_collection->set_table(*table);
|
||||
}
|
||||
|
@ -1193,7 +1193,7 @@ RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
|
||||
FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
|
||||
if (field_index.is_inobject()) {
|
||||
RUNTIME_ASSERT(field_index.property_index() <
|
||||
object->map()->inobject_properties());
|
||||
object->map()->GetInObjectProperties());
|
||||
} else {
|
||||
RUNTIME_ASSERT(field_index.outobject_array_index() <
|
||||
object->properties()->length());
|
||||
|
@ -225,7 +225,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
__ j(less, &no_inobject_slack_tracking);
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ movzxbp(rsi, FieldOperand(rax, Map::kInObjectPropertiesOffset));
|
||||
__ movzxbp(
|
||||
rsi,
|
||||
FieldOperand(
|
||||
rax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ movzxbp(rax, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
|
||||
__ subp(rsi, rax);
|
||||
__ leap(rsi,
|
||||
|
@ -224,7 +224,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
__ j(less, &no_inobject_slack_tracking);
|
||||
|
||||
// Allocate object with a slack.
|
||||
__ movzx_b(esi, FieldOperand(eax, Map::kInObjectPropertiesOffset));
|
||||
__ movzx_b(
|
||||
esi,
|
||||
FieldOperand(
|
||||
eax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
|
||||
__ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
|
||||
__ sub(esi, eax);
|
||||
__ lea(esi,
|
||||
|
@ -1144,7 +1144,7 @@ TEST(Regression39128) {
|
||||
// Step 1: prepare a map for the object. We add 1 inobject property to it.
|
||||
// Create a map with single inobject property.
|
||||
Handle<Map> my_map = Map::Create(CcTest::i_isolate(), 1);
|
||||
int n_properties = my_map->inobject_properties();
|
||||
int n_properties = my_map->GetInObjectProperties();
|
||||
CHECK_GT(n_properties, 0);
|
||||
|
||||
int object_size = my_map->instance_size();
|
||||
|
@ -634,7 +634,7 @@ static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
|
||||
descriptors->Append(&f);
|
||||
|
||||
int field_index = f.GetDetails().field_index();
|
||||
bool is_inobject = field_index < map->inobject_properties();
|
||||
bool is_inobject = field_index < map->GetInObjectProperties();
|
||||
for (int bit = 0; bit < field_width_in_words; bit++) {
|
||||
CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
|
||||
!layout_descriptor->IsTagged(field_index + bit));
|
||||
@ -763,7 +763,7 @@ static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
|
||||
int field_index = details.field_index();
|
||||
int field_width_in_words = details.field_width_in_words();
|
||||
|
||||
bool is_inobject = field_index < map->inobject_properties();
|
||||
bool is_inobject = field_index < map->GetInObjectProperties();
|
||||
for (int bit = 0; bit < field_width_in_words; bit++) {
|
||||
CHECK_EQ(is_inobject && details.representation().IsDouble(),
|
||||
!layout_desc->IsTagged(field_index + bit));
|
||||
|
Loading…
Reference in New Issue
Block a user