(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 MUTABLE_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() { return DoubleToBoolean(value()); } void HeapNumber::HeapNumberPrint(OStream& os) { // NOLINT os << value(); } String* JSReceiver::class_name() { if (IsJSFunction() || IsJSFunctionProxy()) { return GetHeap()->Function_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) { DCHECK(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::AddSlowProperty(Handle object, Handle name, Handle value, PropertyAttributes attributes) { DCHECK(!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); } Context* JSObject::GetCreationContext() { Object* constructor = this->map()->constructor(); JSFunction* function; if (!constructor->IsJSFunction()) { // Functions have null as a constructor, // but any JSFunction knows its context immediately. function = JSFunction::cast(this); } else { function = JSFunction::cast(constructor); } return function->context()->native_context(); } void JSObject::EnqueueChangeRecord(Handle object, const char* type_str, Handle name, Handle old_value) { DCHECK(!object->IsJSGlobalProxy()); DCHECK(!object->IsJSGlobalObject()); Isolate* isolate = object->GetIsolate(); HandleScope scope(isolate); Handle type = isolate->factory()->InternalizeUtf8String(type_str); Handle args[] = { type, object, name, old_value }; int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; Execution::Call(isolate, Handle(isolate->observers_notify_change()), isolate->factory()->undefined_value(), argc, args).Assert(); } const char* Representation::Mnemonic() const { switch (kind_) { case kNone: return "v"; case kTagged: return "t"; case kSmi: return "s"; case kDouble: return "d"; case kInteger32: return "i"; case kHeapObject: return "h"; case kExternal: return "x"; default: UNREACHABLE(); return NULL; } } bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, int target_inobject, int target_unused, int* old_number_of_fields) { // If fields were added (or removed), rewrite the instance. *old_number_of_fields = NumberOfFields(); DCHECK(target_number_of_fields >= *old_number_of_fields); if (target_number_of_fields != *old_number_of_fields) return true; // If smi descriptors were replaced by double descriptors, rewrite. DescriptorArray* old_desc = instance_descriptors(); DescriptorArray* new_desc = target->instance_descriptors(); int limit = NumberOfOwnDescriptors(); for (int i = 0; i < limit; i++) { if (new_desc->GetDetails(i).representation().IsDouble() != old_desc->GetDetails(i).representation().IsDouble()) { return true; } } // If no fields were added, and no inobject properties were removed, setting // the map is sufficient. if (target_inobject == inobject_properties()) 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()); if (target_number_of_fields <= target_inobject) { DCHECK(target_number_of_fields + target_unused == target_inobject); return false; } // Otherwise, properties will need to be moved to the backing store. return true; } void Map::ConnectElementsTransition(Handle parent, Handle child) { Isolate* isolate = parent->GetIsolate(); Handle name = isolate->factory()->elements_transition_symbol(); ConnectTransition(parent, child, name, FULL_TRANSITION); } void JSObject::MigrateToMap(Handle object, Handle new_map) { if (object->map() == *new_map) return; if (object->HasFastProperties()) { if (!new_map->is_dictionary_map()) { Handle old_map(object->map()); MigrateFastToFast(object, new_map); if (old_map->is_prototype_map()) { // Clear out the old descriptor array to avoid problems to sharing // the descriptor array without using an explicit. old_map->InitializeDescriptors( old_map->GetHeap()->empty_descriptor_array()); // Ensure that no transition was inserted for prototype migrations. DCHECK(!old_map->HasTransitionArray()); DCHECK(new_map->GetBackPointer()->IsUndefined()); } } else { MigrateFastToSlow(object, new_map, 0); } } else { // For slow-to-fast migrations JSObject::TransformToFastProperties() // must be used instead. CHECK(new_map->is_dictionary_map()); // Slow-to-slow migration is trivial. object->set_map(*new_map); } } // To migrate a fast instance to a fast map: // - First check whether the instance needs to be rewritten. If not, simply // change the map. // - Otherwise, allocate a fixed array large enough to hold all fields, in // addition to unused space. // - Copy all existing properties in, in the following order: backing store // properties, unused fields, inobject properties. // - If all allocation succeeded, commit the state atomically: // * Copy inobject properties from the backing store back into the object. // * Trim the difference in instance size of the object. This also cleanly // frees inobject properties that moved to the backing store. // * If there are properties left in the backing store, trim of the space used // to temporarily store the inobject properties. // * If there are properties left in the backing store, install the backing // store. void JSObject::MigrateFastToFast(Handle object, Handle new_map) { Isolate* isolate = object->GetIsolate(); Handle old_map(object->map()); int old_number_of_fields; int number_of_fields = new_map->NumberOfFields(); int inobject = new_map->inobject_properties(); int unused = new_map->unused_property_fields(); // Nothing to do if no functions were converted to fields and no smis were // converted to doubles. if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject, unused, &old_number_of_fields)) { object->synchronized_set_map(*new_map); return; } int total_size = number_of_fields + unused; int external = total_size - inobject; if (number_of_fields != old_number_of_fields && new_map->GetBackPointer() == *old_map) { PropertyDetails details = new_map->GetLastDescriptorDetails(); if (old_map->unused_property_fields() > 0) { if (details.representation().IsDouble()) { Handle value = isolate->factory()->NewHeapNumber(0, MUTABLE); FieldIndex index = FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); object->FastPropertyAtPut(index, *value); } object->synchronized_set_map(*new_map); return; } DCHECK(number_of_fields == old_number_of_fields + 1); // This migration is a transition from a map that has run out out property // space. Therefore it could be done by extending the backing store. Handle old_storage = handle(object->properties(), isolate); Handle new_storage = FixedArray::CopySize(old_storage, external); // Properly initialize newly added property. Handle value; if (details.representation().IsDouble()) { value = isolate->factory()->NewHeapNumber(0, MUTABLE); } else { value = isolate->factory()->uninitialized_value(); } DCHECK(details.type() == FIELD); int target_index = details.field_index() - inobject; DCHECK(target_index >= 0); // Must be a backing store index. new_storage->set(target_index, *value); // From here on we cannot fail and we shouldn't GC anymore. DisallowHeapAllocation no_allocation; // Set the new property value and do the map transition. object->set_properties(*new_storage); object->synchronized_set_map(*new_map); return; } Handle array = isolate->factory()->NewFixedArray(total_size); Handle old_descriptors(old_map->instance_descriptors()); Handle new_descriptors(new_map->instance_descriptors()); int old_nof = old_map->NumberOfOwnDescriptors(); int new_nof = new_map->NumberOfOwnDescriptors(); // This method only supports generalizing instances to at least the same // number of properties. DCHECK(old_nof <= new_nof); for (int i = 0; i < old_nof; i++) { PropertyDetails details = new_descriptors->GetDetails(i); if (details.type() != FIELD) continue; PropertyDetails old_details = old_descriptors->GetDetails(i); if (old_details.type() == CALLBACKS) { DCHECK(details.representation().IsTagged()); continue; } DCHECK(old_details.type() == CONSTANT || old_details.type() == FIELD); Object* raw_value = old_details.type() == CONSTANT ? old_descriptors->GetValue(i) : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i)); Handle value(raw_value, isolate); if (!old_details.representation().IsDouble() && details.representation().IsDouble()) { if (old_details.representation().IsNone()) { value = handle(Smi::FromInt(0), isolate); } value = Object::NewStorageFor(isolate, value, details.representation()); } else if (old_details.representation().IsDouble() && !details.representation().IsDouble()) { value = Object::WrapForRead(isolate, value, old_details.representation()); } DCHECK(!(details.representation().IsDouble() && value->IsSmi())); int target_index = new_descriptors->GetFieldIndex(i) - inobject; if (target_index < 0) target_index += total_size; array->set(target_index, *value); } for (int i = old_nof; i < new_nof; i++) { PropertyDetails details = new_descriptors->GetDetails(i); if (details.type() != FIELD) continue; Handle