"); break; case ODDBALL_TYPE: { if (IsUndefined()) accumulator->Add(""); else if (IsTheHole()) accumulator->Add(""); else if (IsNull()) accumulator->Add(""); else if (IsTrue()) accumulator->Add(""); else if (IsFalse()) accumulator->Add(""); else accumulator->Add(""); break; } case SYMBOL_TYPE: { Symbol* symbol = Symbol::cast(this); accumulator->Add("Hash()); if (!symbol->name()->IsUndefined()) { accumulator->Add(" "); String::cast(symbol->name())->StringShortPrint(accumulator); } accumulator->Add(">"); break; } case HEAP_NUMBER_TYPE: accumulator->Add("HeapNumberPrint(accumulator); accumulator->Put('>'); break; case JS_PROXY_TYPE: accumulator->Add(""); break; case JS_FUNCTION_PROXY_TYPE: accumulator->Add(""); break; case FOREIGN_TYPE: accumulator->Add(""); break; case CELL_TYPE: accumulator->Add("Cell for "); Cell::cast(this)->value()->ShortPrint(accumulator); break; case PROPERTY_CELL_TYPE: accumulator->Add("PropertyCell for "); PropertyCell::cast(this)->value()->ShortPrint(accumulator); break; default: accumulator->Add("", map()->instance_type()); break; } } void HeapObject::Iterate(ObjectVisitor* v) { // Handle header IteratePointer(v, kMapOffset); // Handle object body Map* m = map(); IterateBody(m->instance_type(), SizeFromMap(m), v); } void HeapObject::IterateBody(InstanceType type, int object_size, ObjectVisitor* v) { // Avoiding ::cast(this) because it accesses the map pointer field. // During GC, the map pointer field is encoded. if (type < FIRST_NONSTRING_TYPE) { switch (type & kStringRepresentationMask) { case kSeqStringTag: break; case kConsStringTag: ConsString::BodyDescriptor::IterateBody(this, v); break; case kSlicedStringTag: SlicedString::BodyDescriptor::IterateBody(this, v); break; case kExternalStringTag: if ((type & kStringEncodingMask) == kOneByteStringTag) { reinterpret_cast(this)-> ExternalAsciiStringIterateBody(v); } else { reinterpret_cast(this)-> ExternalTwoByteStringIterateBody(v); } break; } return; } switch (type) { case FIXED_ARRAY_TYPE: FixedArray::BodyDescriptor::IterateBody(this, object_size, v); break; case CONSTANT_POOL_ARRAY_TYPE: reinterpret_cast(this)->ConstantPoolIterateBody(v); break; case FIXED_DOUBLE_ARRAY_TYPE: break; case JS_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE: case JS_MODULE_TYPE: case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: case JS_ARRAY_BUFFER_TYPE: case JS_TYPED_ARRAY_TYPE: case JS_DATA_VIEW_TYPE: case JS_SET_TYPE: case JS_MAP_TYPE: case JS_SET_ITERATOR_TYPE: case JS_MAP_ITERATOR_TYPE: case JS_WEAK_MAP_TYPE: case JS_WEAK_SET_TYPE: case JS_REGEXP_TYPE: case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: case JS_MESSAGE_OBJECT_TYPE: JSObject::BodyDescriptor::IterateBody(this, object_size, v); break; case JS_FUNCTION_TYPE: reinterpret_cast(this) ->JSFunctionIterateBody(object_size, v); break; case ODDBALL_TYPE: Oddball::BodyDescriptor::IterateBody(this, v); break; case JS_PROXY_TYPE: JSProxy::BodyDescriptor::IterateBody(this, v); break; case JS_FUNCTION_PROXY_TYPE: JSFunctionProxy::BodyDescriptor::IterateBody(this, v); break; case FOREIGN_TYPE: reinterpret_cast(this)->ForeignIterateBody(v); break; case MAP_TYPE: Map::BodyDescriptor::IterateBody(this, v); break; case CODE_TYPE: reinterpret_cast(this)->CodeIterateBody(v); break; case CELL_TYPE: Cell::BodyDescriptor::IterateBody(this, v); break; case PROPERTY_CELL_TYPE: PropertyCell::BodyDescriptor::IterateBody(this, v); break; case SYMBOL_TYPE: Symbol::BodyDescriptor::IterateBody(this, v); break; case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: case FREE_SPACE_TYPE: break; #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case EXTERNAL_##TYPE##_ARRAY_TYPE: \ case FIXED_##TYPE##_ARRAY_TYPE: \ break; TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE case SHARED_FUNCTION_INFO_TYPE: { SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); break; } #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE if (type == ALLOCATION_SITE_TYPE) { AllocationSite::BodyDescriptor::IterateBody(this, v); } else { StructBodyDescriptor::IterateBody(this, object_size, v); } break; default: PrintF("Unknown type: %d\n", type); UNREACHABLE(); } } bool HeapNumber::HeapNumberBooleanValue() { // NaN, +0, and -0 should return the false object #if __BYTE_ORDER == __LITTLE_ENDIAN union IeeeDoubleLittleEndianArchType u; #elif __BYTE_ORDER == __BIG_ENDIAN union IeeeDoubleBigEndianArchType u; #endif u.d = value(); if (u.bits.exp == 2047) { // Detect NaN for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) != 0) return false; } if (u.bits.exp == 0) { // Detect +0, and -0 for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) == 0) return false; } return true; } void HeapNumber::HeapNumberPrint(FILE* out) { PrintF(out, "%.16g", Number()); } void HeapNumber::HeapNumberPrint(StringStream* accumulator) { // The Windows version of vsnprintf can allocate when printing a %g string // into a buffer that may not be big enough. We don't want random memory // allocation when producing post-crash stack traces, so we print into a // buffer that is plenty big enough for any floating point number, then // print that using vsnprintf (which may truncate but never allocate if // there is no more space in the buffer). EmbeddedVector buffer; SNPrintF(buffer, "%.16g", Number()); accumulator->Add("%s", buffer.start()); } String* JSReceiver::class_name() { if (IsJSFunction() && IsJSFunctionProxy()) { return GetHeap()->function_class_string(); } if (map()->constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(map()->constructor()); return String::cast(constructor->shared()->instance_class_name()); } // If the constructor is not present, return "Object". return GetHeap()->Object_string(); } String* Map::constructor_name() { if (constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(this->constructor()); String* name = String::cast(constructor->shared()->name()); if (name->length() > 0) return name; String* inferred_name = constructor->shared()->inferred_name(); if (inferred_name->length() > 0) return inferred_name; Object* proto = prototype(); if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); } // TODO(rossberg): what about proxies? // If the constructor is not present, return "Object". return GetHeap()->Object_string(); } String* JSReceiver::constructor_name() { return map()->constructor_name(); } MaybeHandle Map::CopyWithField(Handle map, Handle name, Handle type, PropertyAttributes attributes, Representation representation, TransitionFlag flag) { ASSERT(DescriptorArray::kNotFound == map->instance_descriptors()->Search( *name, map->NumberOfOwnDescriptors())); // Ensure the descriptor array does not get too big. if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { return MaybeHandle(); } Isolate* isolate = map->GetIsolate(); // Compute the new index for new field. int index = map->NextFreePropertyIndex(); if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { representation = Representation::Tagged(); type = HeapType::Any(isolate); } FieldDescriptor new_field_desc(name, index, type, attributes, representation); Handle new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag); int unused_property_fields = new_map->unused_property_fields() - 1; if (unused_property_fields < 0) { unused_property_fields += JSObject::kFieldsAdded; } new_map->set_unused_property_fields(unused_property_fields); return new_map; } MaybeHandle Map::CopyWithConstant(Handle map, Handle name, Handle constant, PropertyAttributes attributes, TransitionFlag flag) { // Ensure the descriptor array does not get too big. if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { return MaybeHandle(); } // Allocate new instance descriptors with (name, constant) added. ConstantDescriptor new_constant_desc(name, constant, attributes); return Map::CopyAddDescriptor(map, &new_constant_desc, flag); } void JSObject::AddFastProperty(Handle object, Handle name, Handle value, PropertyAttributes attributes, StoreFromKeyed store_mode, ValueType value_type, TransitionFlag flag) { ASSERT(!object->IsJSGlobalProxy()); MaybeHandle maybe_map; if (value->IsJSFunction()) { maybe_map = Map::CopyWithConstant( handle(object->map()), name, value, attributes, flag); } else if (!object->TooManyFastProperties(store_mode)) { Isolate* isolate = object->GetIsolate(); Representation representation = value->OptimalRepresentation(value_type); maybe_map = Map::CopyWithField( handle(object->map(), isolate), name, value->OptimalType(isolate, representation), attributes, representation, flag); } Handle new_map; if (!maybe_map.ToHandle(&new_map)) { NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); return; } JSObject::MigrateToNewProperty(object, new_map, value); } void JSObject::AddSlowProperty(Handle object, Handle name, Handle value, PropertyAttributes attributes) { ASSERT(!object->HasFastProperties()); Isolate* isolate = object->GetIsolate(); Handle dict(object->property_dictionary()); if (object->IsGlobalObject()) { // In case name is an orphaned property reuse the cell. int entry = dict->FindEntry(name); if (entry != NameDictionary::kNotFound) { Handle cell(PropertyCell::cast(dict->ValueAt(entry))); PropertyCell::SetValueInferType(cell, value); // Assign an enumeration index to the property and update // SetNextEnumerationIndex. int index = dict->NextEnumerationIndex(); PropertyDetails details = PropertyDetails(attributes, NORMAL, index); dict->SetNextEnumerationIndex(index + 1); dict->SetEntry(entry, name, cell, details); return; } Handle cell = isolate->factory()->NewPropertyCell(value); PropertyCell::SetValueInferType(cell, value); value = cell; } PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); Handle result = NameDictionary::Add(dict, name, value, details); if (*dict != *result) object->set_properties(*result); } MaybeHandle JSObject::AddProperty( Handle object, Handle name, Handle value, PropertyAttributes attributes, StrictMode strict_mode, JSReceiver::StoreFromKeyed store_mode, ExtensibilityCheck extensibility_check, ValueType value_type, StoreMode mode, TransitionFlag transition_flag) { ASSERT(!object->IsJSGlobalProxy()); Isolate* isolate = object->GetIsolate(); if (!name->IsUniqueName()) { name = isolate->factory()->InternalizeString( Handle
(this)->CodeIterateBody(v); break; case CELL_TYPE: Cell::BodyDescriptor::IterateBody(this, v); break; case PROPERTY_CELL_TYPE: PropertyCell::BodyDescriptor::IterateBody(this, v); break; case SYMBOL_TYPE: Symbol::BodyDescriptor::IterateBody(this, v); break; case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: case FREE_SPACE_TYPE: break; #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case EXTERNAL_##TYPE##_ARRAY_TYPE: \ case FIXED_##TYPE##_ARRAY_TYPE: \ break; TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE case SHARED_FUNCTION_INFO_TYPE: { SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); break; } #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE if (type == ALLOCATION_SITE_TYPE) { AllocationSite::BodyDescriptor::IterateBody(this, v); } else { StructBodyDescriptor::IterateBody(this, object_size, v); } break; default: PrintF("Unknown type: %d\n", type); UNREACHABLE(); } } bool HeapNumber::HeapNumberBooleanValue() { // NaN, +0, and -0 should return the false object #if __BYTE_ORDER == __LITTLE_ENDIAN union IeeeDoubleLittleEndianArchType u; #elif __BYTE_ORDER == __BIG_ENDIAN union IeeeDoubleBigEndianArchType u; #endif u.d = value(); if (u.bits.exp == 2047) { // Detect NaN for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) != 0) return false; } if (u.bits.exp == 0) { // Detect +0, and -0 for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) == 0) return false; } return true; } void HeapNumber::HeapNumberPrint(FILE* out) { PrintF(out, "%.16g", Number()); } void HeapNumber::HeapNumberPrint(StringStream* accumulator) { // The Windows version of vsnprintf can allocate when printing a %g string // into a buffer that may not be big enough. We don't want random memory // allocation when producing post-crash stack traces, so we print into a // buffer that is plenty big enough for any floating point number, then // print that using vsnprintf (which may truncate but never allocate if // there is no more space in the buffer). EmbeddedVector buffer; SNPrintF(buffer, "%.16g", Number()); accumulator->Add("%s", buffer.start()); } String* JSReceiver::class_name() { if (IsJSFunction() && IsJSFunctionProxy()) { return GetHeap()->function_class_string(); } if (map()->constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(map()->constructor()); return String::cast(constructor->shared()->instance_class_name()); } // If the constructor is not present, return "Object". return GetHeap()->Object_string(); } String* Map::constructor_name() { if (constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(this->constructor()); String* name = String::cast(constructor->shared()->name()); if (name->length() > 0) return name; String* inferred_name = constructor->shared()->inferred_name(); if (inferred_name->length() > 0) return inferred_name; Object* proto = prototype(); if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); } // TODO(rossberg): what about proxies? // If the constructor is not present, return "Object". return GetHeap()->Object_string(); } String* JSReceiver::constructor_name() { return map()->constructor_name(); } MaybeHandle Map::CopyWithField(Handle map, Handle name, Handle type, PropertyAttributes attributes, Representation representation, TransitionFlag flag) { ASSERT(DescriptorArray::kNotFound == map->instance_descriptors()->Search( *name, map->NumberOfOwnDescriptors())); // Ensure the descriptor array does not get too big. if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { return MaybeHandle(); } Isolate* isolate = map->GetIsolate(); // Compute the new index for new field. int index = map->NextFreePropertyIndex(); if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) { representation = Representation::Tagged(); type = HeapType::Any(isolate); } FieldDescriptor new_field_desc(name, index, type, attributes, representation); Handle new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag); int unused_property_fields = new_map->unused_property_fields() - 1; if (unused_property_fields < 0) { unused_property_fields += JSObject::kFieldsAdded; } new_map->set_unused_property_fields(unused_property_fields); return new_map; } MaybeHandle Map::CopyWithConstant(Handle map, Handle name, Handle constant, PropertyAttributes attributes, TransitionFlag flag) { // Ensure the descriptor array does not get too big. if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) { return MaybeHandle(); } // Allocate new instance descriptors with (name, constant) added. ConstantDescriptor new_constant_desc(name, constant, attributes); return Map::CopyAddDescriptor(map, &new_constant_desc, flag); } void JSObject::AddFastProperty(Handle object, Handle name, Handle value, PropertyAttributes attributes, StoreFromKeyed store_mode, ValueType value_type, TransitionFlag flag) { ASSERT(!object->IsJSGlobalProxy()); MaybeHandle maybe_map; if (value->IsJSFunction()) { maybe_map = Map::CopyWithConstant( handle(object->map()), name, value, attributes, flag); } else if (!object->TooManyFastProperties(store_mode)) { Isolate* isolate = object->GetIsolate(); Representation representation = value->OptimalRepresentation(value_type); maybe_map = Map::CopyWithField( handle(object->map(), isolate), name, value->OptimalType(isolate, representation), attributes, representation, flag); } Handle new_map; if (!maybe_map.ToHandle(&new_map)) { NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0); return; } JSObject::MigrateToNewProperty(object, new_map, value); } void JSObject::AddSlowProperty(Handle object, Handle name, Handle value, PropertyAttributes attributes) { ASSERT(!object->HasFastProperties()); Isolate* isolate = object->GetIsolate(); Handle dict(object->property_dictionary()); if (object->IsGlobalObject()) { // In case name is an orphaned property reuse the cell. int entry = dict->FindEntry(name); if (entry != NameDictionary::kNotFound) { Handle cell(PropertyCell::cast(dict->ValueAt(entry))); PropertyCell::SetValueInferType(cell, value); // Assign an enumeration index to the property and update // SetNextEnumerationIndex. int index = dict->NextEnumerationIndex(); PropertyDetails details = PropertyDetails(attributes, NORMAL, index); dict->SetNextEnumerationIndex(index + 1); dict->SetEntry(entry, name, cell, details); return; } Handle cell = isolate->factory()->NewPropertyCell(value); PropertyCell::SetValueInferType(cell, value); value = cell; } PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); Handle result = NameDictionary::Add(dict, name, value, details); if (*dict != *result) object->set_properties(*result); } MaybeHandle JSObject::AddProperty( Handle object, Handle name, Handle value, PropertyAttributes attributes, StrictMode strict_mode, JSReceiver::StoreFromKeyed store_mode, ExtensibilityCheck extensibility_check, ValueType value_type, StoreMode mode, TransitionFlag transition_flag) { ASSERT(!object->IsJSGlobalProxy()); Isolate* isolate = object->GetIsolate(); if (!name->IsUniqueName()) { name = isolate->factory()->InternalizeString( Handle