📄 objects.cc.svn-base
字号:
InstanceType instance_type = map->instance_type(); if (instance_type < FIRST_NONSTRING_TYPE && (reinterpret_cast<String*>(this)->map_representation_tag(map) == kSeqStringTag)) { if (reinterpret_cast<String*>(this)->is_ascii_map(map)) { return reinterpret_cast<AsciiString*>(this)->AsciiStringSize(map); } else { return reinterpret_cast<TwoByteString*>(this)->TwoByteStringSize(map); } } switch (instance_type) { case FIXED_ARRAY_TYPE: return reinterpret_cast<FixedArray*>(this)->FixedArraySize(); case BYTE_ARRAY_TYPE: return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); case CODE_TYPE: return reinterpret_cast<Code*>(this)->CodeSize(); case MAP_TYPE: return Map::kSize; default: return map->instance_size(); }}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 <Type>::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: reinterpret_cast<ConsString*>(this)->ConsStringIterateBody(v); break; case kSlicedStringTag: reinterpret_cast<SlicedString*>(this)->SlicedStringIterateBody(v); break; } return; } switch (type) { case FIXED_ARRAY_TYPE: reinterpret_cast<FixedArray*>(this)->FixedArrayIterateBody(v); break; case JS_OBJECT_TYPE: case JS_VALUE_TYPE: case JS_ARRAY_TYPE: case JS_REGEXP_TYPE: case JS_FUNCTION_TYPE: case JS_GLOBAL_OBJECT_TYPE: reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v); break; case JS_BUILTINS_OBJECT_TYPE: reinterpret_cast<JSObject*>(this)->JSObjectIterateBody(object_size, v); break; case ODDBALL_TYPE: reinterpret_cast<Oddball*>(this)->OddballIterateBody(v); break; case PROXY_TYPE: reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v); break; case MAP_TYPE: reinterpret_cast<Map*>(this)->MapIterateBody(v); break; case CODE_TYPE: reinterpret_cast<Code*>(this)->CodeIterateBody(v); break; case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: break; case SHARED_FUNCTION_INFO_TYPE: { SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); shared->SharedFunctionInfoIterateBody(v); break; }#define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: STRUCT_LIST(MAKE_STRUCT_CASE)#undef MAKE_STRUCT_CASE IterateStructBody(object_size, v); break; default: PrintF("Unknown type: %d\n", type); UNREACHABLE(); }}void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) { IteratePointers(v, HeapObject::kHeaderSize, object_size);}Object* HeapNumber::HeapNumberToBoolean() { // NaN, +0, and -0 should return the false object switch (fpclassify(value())) { case FP_NAN: // fall through case FP_ZERO: return Heap::false_value(); default: return Heap::true_value(); }}void HeapNumber::HeapNumberPrint() { PrintF("%.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<char, 100> buffer; OS::SNPrintF(buffer, "%.16g", Number()); accumulator->Add("%s", buffer.start());}String* JSObject::class_name() { if (IsJSFunction()) return Heap::function_class_symbol(); // If the constructor is not present "Object" is returned. String* result = Heap::Object_symbol(); if (map()->constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(map()->constructor()); return String::cast(constructor->shared()->instance_class_name()); } return result;}void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) { // Iterate over all fields in the body. Assumes all are Object*. IteratePointers(v, kPropertiesOffset, object_size);}Object* JSObject::Copy(PretenureFlag pretenure) { // Never used to copy functions. If functions need to be copied we // have to be careful to clear the literals array. ASSERT(!IsJSFunction()); // Copy the elements and properties. Object* elem = FixedArray::cast(elements())->Copy(); if (elem->IsFailure()) return elem; Object* prop = properties()->Copy(); if (prop->IsFailure()) return prop; // Make the clone. Object* clone = (pretenure == NOT_TENURED) ? Heap::Allocate(map(), NEW_SPACE) : Heap::Allocate(map(), OLD_POINTER_SPACE); if (clone->IsFailure()) return clone; JSObject::cast(clone)->CopyBody(this); // Set the new elements and properties. JSObject::cast(clone)->set_elements(FixedArray::cast(elem)); JSObject::cast(clone)->set_properties(FixedArray::cast(prop)); // Return the new clone. return clone;}Object* JSObject::AddFastPropertyUsingMap(Map* new_map, String* name, Object* value) { int index = new_map->PropertyIndexFor(name); if (map()->unused_property_fields() > 0) { ASSERT(index < properties()->length()); properties()->set(index, value); } else { ASSERT(map()->unused_property_fields() == 0); int new_unused = new_map->unused_property_fields(); Object* values = properties()->CopySize(properties()->length() + new_unused + 1); if (values->IsFailure()) return values; FixedArray::cast(values)->set(index, value); set_properties(FixedArray::cast(values)); } set_map(new_map); return value;}Object* JSObject::AddFastProperty(String* name, Object* value, PropertyAttributes attributes) { // Normalize the object if the name is not a real identifier. StringInputBuffer buffer(name); if (!Scanner::IsIdentifier(&buffer)) { Object* obj = NormalizeProperties(); if (obj->IsFailure()) return obj; return AddSlowProperty(name, value, attributes); } // Replace a CONSTANT_TRANSITION flag with a transition. // Do this by removing it, and the standard code for adding a map transition // will then run. DescriptorArray* old_descriptors = map()->instance_descriptors(); int old_name_index = old_descriptors->Search(name); bool constant_transition = false; // Only used in assertions. if (old_name_index != DescriptorArray::kNotFound && CONSTANT_TRANSITION == PropertyDetails(old_descriptors->GetDetails(old_name_index)).type()) { constant_transition = true; Object* r = old_descriptors->CopyRemove(name); if (r->IsFailure()) return r; old_descriptors = DescriptorArray::cast(r); old_name_index = DescriptorArray::kNotFound; } // Compute the new index for new field. int index = map()->NextFreePropertyIndex(); // Allocate new instance descriptors with (name, index) added FieldDescriptor new_field(name, index, attributes); Object* new_descriptors = old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); if (new_descriptors->IsFailure()) return new_descriptors; // Only allow map transition if the object's map is NOT equal to the // global object_function's map and there is not a transition for name. bool allow_map_transition = !old_descriptors->Contains(name) && (Top::context()->global_context()->object_function()->map() != map()); ASSERT(allow_map_transition || !constant_transition); if (map()->unused_property_fields() > 0) { ASSERT(index < properties()->length()); // Allocate a new map for the object. Object* r = map()->Copy(); if (r->IsFailure()) return r; Map* new_map = Map::cast(r); if (allow_map_transition) { // Allocate new instance descriptors for the old map with map transition. MapTransitionDescriptor d(name, Map::cast(new_map), attributes); Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); if (r->IsFailure()) return r; old_descriptors = DescriptorArray::cast(r); } // We have now allocated all the necessary objects. // All the changes can be applied at once, so they are atomic. map()->set_instance_descriptors(old_descriptors); new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); new_map->set_unused_property_fields(map()->unused_property_fields() - 1); set_map(new_map); properties()->set(index, value); } else { ASSERT(map()->unused_property_fields() == 0); if (properties()->length() > kMaxFastProperties) { Object* obj = NormalizeProperties(); if (obj->IsFailure()) return obj; return AddSlowProperty(name, value, attributes); } static const int kExtraFields = 3; // Make room for the new value Object* values = properties()->CopySize(properties()->length() + kExtraFields); if (values->IsFailure()) return values; FixedArray::cast(values)->set(index, value); // Allocate a new map for the object. Object* r = map()->Copy(); if (r->IsFailure()) return r; Map* new_map = Map::cast(r); if (allow_map_transition) { MapTransitionDescriptor d(name, Map::cast(new_map), attributes); // Allocate new instance descriptors for the old map with map transition. Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); if (r->IsFailure()) return r; old_descriptors = DescriptorArray::cast(r); } // We have now allocated all the necessary objects. // All changes can be done at once, atomically. map()->set_instance_descriptors(old_descriptors); new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); new_map->set_unused_property_fields(kExtraFields - 1); set_map(new_map); set_properties(FixedArray::cast(values)); } return value;}Object* JSObject::AddConstantFunctionProperty(String* name, JSFunction* function, PropertyAttributes attributes) { // Allocate new instance descriptors with (name, function) added ConstantFunctionDescriptor d(name, function, attributes); Object* new_descriptors = map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); if (new_descriptors->IsFailure()) return new_descriptors; // Allocate a new map for the object. Object* new_map = map()->Copy(); if (new_map->IsFailure()) return new_map; DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); Map::cast(new_map)->set_instance_descriptors(descriptors); Map* old_map = map(); set_map(Map::cast(new_map)); // If the old map is the global object map (from new Object()), // then transitions are not added to it, so we are done. if (old_map == Top::context()->global_context()->object_function()->map()) { return function; } // Do not add CONSTANT_TRANSITIONS to global objects if (IsGlobalObject()) { return function; } // Add a CONSTANT_TRANSITION descriptor to the old map, // so future assignments to this property on other objects // of the same type will create a normal field, not a constant function. // Don't do this for special properties, with non-trival attributes. if (attributes != NONE) { return function; } ConstTransitionDescriptor mark(name); new_descriptors = old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); if (new_descriptors->IsFailure()) { return function; // We have accomplished the main goal, so return success. } old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); return function;}Object* JSObject::ReplaceConstantFunctionProperty(String* name, Object* value) { // There are two situations to handle here: // 1: Replace a constant function with another function. // 2: Replace a constant function with an object. if (value->IsJSFunction()) { JSFunction* function = JSFunction::cast(value); Object* new_map = map()->CopyDropTransitions(); if (new_map->IsFailure()) return new_map; set_map(Map::cast(new_map)); // Replace the function entry int index = map()->instance_descriptors()->Search(name); ASSERT(index != DescriptorArray::kNotFound); map()->instance_descriptors()->ReplaceConstantFunction(index, function); } else { // Allocate new instance descriptors with updated property index. int index = map()->NextFreePropertyIndex(); Object* new_descriptors = map()->instance_descriptors()->CopyReplace(name, index, NONE); if (new_descriptors->IsFailure()) return new_descriptors; if (map()->unused_property_fields() > 0) { ASSERT(index < properties()->length()); // Allocate a new map for the object. Object* new_map = map()->Copy(); if (new_map->IsFailure()) return new_map;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -