// 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,
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.
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);
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);
}
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);
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);
// @@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()));
}
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);
}
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(
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()));
}
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);
// 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
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);
}
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) {
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;
}
->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);
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);
#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);
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;
}
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)
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
}
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),
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() {
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();
{
Token::LT);
receiver_is_not_spec_object.Then();
{
- // Load native context.
- HValue* native_context = BuildGetNativeContext();
-
- 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);
-
- 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);
+ // Load the constructor function index from the {receiver} map.
+ HValue* constructor_function_index = Add<HLoadNamedField>(
+ receiver_map, nullptr,
+ HObjectAccess::ForMapInObjectPropertiesOrConstructorFunctionIndex());
+
+ // 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();
+
+ // Use the global constructor function.
+ Push(constructor_function_index);
}
receiver_is_not_spec_object.JoinContinuation(&wrap);
}
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.
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();
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),
}
}
- 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++) {
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) {
__ 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,
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);
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.
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;
}
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());
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);
}
-// 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),
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);
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;
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());
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);
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);
}
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) {
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;
}
bool Object::IsPrimitive() const {
- return IsOddball() || IsNumber() || IsString();
+ return IsSmi() || HeapObject::cast(this)->map()->IsPrimitiveMap();
}
// 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();
}
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);
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;
}
}
-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);
}
}
-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); }
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";
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);
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();
}
// 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;
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
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) {
// 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));
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);
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);
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());
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));
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;
}
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);
} 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());
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 =
// 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,
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,
// 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();
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; }
// 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;
__ 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) {
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);
}
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());
__ 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,
__ 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,
// 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();
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));
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));