// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/heap/factory.h" #include "src/accessors.h" #include "src/allocation-site-scopes.h" #include "src/ast/ast-source-ranges.h" #include "src/ast/ast.h" #include "src/base/bits.h" #include "src/bootstrapper.h" #include "src/builtins/constants-table-builder.h" #include "src/compiler.h" #include "src/conversions.h" #include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/macro-assembler.h" #include "src/objects/api-callbacks.h" #include "src/objects/arguments-inl.h" #include "src/objects/bigint.h" #include "src/objects/debug-objects-inl.h" #include "src/objects/frame-array-inl.h" #include "src/objects/js-array-inl.h" #include "src/objects/js-collection-inl.h" #include "src/objects/js-generator-inl.h" #include "src/objects/js-regexp-inl.h" #include "src/objects/literal-objects-inl.h" #include "src/objects/microtask-inl.h" #include "src/objects/microtask-queue-inl.h" #include "src/objects/module-inl.h" #include "src/objects/promise-inl.h" #include "src/objects/scope-info.h" #include "src/objects/stack-frame-info-inl.h" #include "src/unicode-cache.h" #include "src/unicode-decoder.h" namespace v8 { namespace internal { namespace { int ComputeCodeObjectSize(const CodeDesc& desc) { bool has_unwinding_info = desc.unwinding_info != nullptr; DCHECK((has_unwinding_info && desc.unwinding_info_size > 0) || (!has_unwinding_info && desc.unwinding_info_size == 0)); int body_size = desc.instr_size; int unwinding_info_size_field_size = kInt64Size; if (has_unwinding_info) { body_size = RoundUp(body_size, kInt64Size) + desc.unwinding_info_size + unwinding_info_size_field_size; } int object_size = Code::SizeFor(RoundUp(body_size, kObjectAlignment)); DCHECK(IsAligned(static_cast(object_size), kCodeAlignment)); return object_size; } void InitializeCode(Heap* heap, Handle code, int object_size, const CodeDesc& desc, Code::Kind kind, Handle self_ref, int32_t builtin_index, Handle source_position_table, Handle deopt_data, Handle reloc_info, Handle data_container, uint32_t stub_key, bool is_turbofanned, int stack_slots, int safepoint_table_offset, int handler_table_offset) { DCHECK(IsAligned(code->address(), kCodeAlignment)); DCHECK_IMPLIES( !heap->memory_allocator()->code_range().is_empty(), heap->memory_allocator()->code_range().contains(code->address())); bool has_unwinding_info = desc.unwinding_info != nullptr; code->set_raw_instruction_size(desc.instr_size); code->set_relocation_info(*reloc_info); const bool is_off_heap_trampoline = false; code->initialize_flags(kind, has_unwinding_info, is_turbofanned, stack_slots, is_off_heap_trampoline); code->set_safepoint_table_offset(safepoint_table_offset); code->set_handler_table_offset(handler_table_offset); code->set_code_data_container(*data_container); code->set_deoptimization_data(*deopt_data); code->set_stub_key(stub_key); code->set_source_position_table(*source_position_table); code->set_constant_pool_offset(desc.instr_size - desc.constant_pool_size); code->set_builtin_index(builtin_index); // Allow self references to created code object by patching the handle to // point to the newly allocated Code object. if (!self_ref.is_null()) { DCHECK(self_ref->IsOddball()); DCHECK(Oddball::cast(*self_ref)->kind() == Oddball::kSelfReferenceMarker); if (FLAG_embedded_builtins) { auto builder = heap->isolate()->builtins_constants_table_builder(); if (builder != nullptr) builder->PatchSelfReference(self_ref, code); } *(self_ref.location()) = *code; } // Migrate generated code. // The generated code can contain Object** values (typically from handles) // that are dereferenced during the copy to point directly to the actual heap // objects. These pointers can include references to the code object itself, // through the self_reference parameter. code->CopyFromNoFlush(heap, desc); code->clear_padding(); #ifdef VERIFY_HEAP if (FLAG_verify_heap) code->ObjectVerify(heap->isolate()); #endif } } // namespace HeapObject* Factory::AllocateRawWithImmortalMap(int size, PretenureFlag pretenure, Map* map, AllocationAlignment alignment) { HeapObject* result = isolate()->heap()->AllocateRawWithRetryOrFail( size, Heap::SelectSpace(pretenure), alignment); result->set_map_after_allocation(map, SKIP_WRITE_BARRIER); return result; } HeapObject* Factory::AllocateRawWithAllocationSite( Handle map, PretenureFlag pretenure, Handle allocation_site) { DCHECK(map->instance_type() != MAP_TYPE); int size = map->instance_size(); if (!allocation_site.is_null()) size += AllocationMemento::kSize; AllocationSpace space = Heap::SelectSpace(pretenure); HeapObject* result = isolate()->heap()->AllocateRawWithRetryOrFail(size, space); WriteBarrierMode write_barrier_mode = space == NEW_SPACE ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; result->set_map_after_allocation(*map, write_barrier_mode); if (!allocation_site.is_null()) { AllocationMemento* alloc_memento = reinterpret_cast( reinterpret_cast
(result) + map->instance_size()); InitializeAllocationMemento(alloc_memento, *allocation_site); } return result; } void Factory::InitializeAllocationMemento(AllocationMemento* memento, AllocationSite* allocation_site) { memento->set_map_after_allocation(*allocation_memento_map(), SKIP_WRITE_BARRIER); memento->set_allocation_site(allocation_site, SKIP_WRITE_BARRIER); if (FLAG_allocation_site_pretenuring) { allocation_site->IncrementMementoCreateCount(); } } HeapObject* Factory::AllocateRawArray(int size, PretenureFlag pretenure) { AllocationSpace space = Heap::SelectSpace(pretenure); HeapObject* result = isolate()->heap()->AllocateRawWithRetryOrFail(size, space); if (size > kMaxRegularHeapObjectSize && FLAG_use_marking_progress_bar) { MemoryChunk* chunk = MemoryChunk::FromAddress(result->address()); chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR); } return result; } HeapObject* Factory::AllocateRawFixedArray(int length, PretenureFlag pretenure) { if (length < 0 || length > FixedArray::kMaxLength) { isolate()->heap()->FatalProcessOutOfMemory("invalid array length"); } return AllocateRawArray(FixedArray::SizeFor(length), pretenure); } HeapObject* Factory::AllocateRawWeakArrayList(int capacity, PretenureFlag pretenure) { if (capacity < 0 || capacity > WeakArrayList::kMaxCapacity) { isolate()->heap()->FatalProcessOutOfMemory("invalid array length"); } return AllocateRawArray(WeakArrayList::SizeForCapacity(capacity), pretenure); } HeapObject* Factory::New(Handle map, PretenureFlag pretenure) { DCHECK(map->instance_type() != MAP_TYPE); int size = map->instance_size(); AllocationSpace space = Heap::SelectSpace(pretenure); HeapObject* result = isolate()->heap()->AllocateRawWithRetryOrFail(size, space); // New space objects are allocated white. WriteBarrierMode write_barrier_mode = space == NEW_SPACE ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; result->set_map_after_allocation(*map, write_barrier_mode); return result; } Handle Factory::NewFillerObject(int size, bool double_align, AllocationSpace space) { AllocationAlignment alignment = double_align ? kDoubleAligned : kWordAligned; Heap* heap = isolate()->heap(); HeapObject* result = heap->AllocateRawWithRetryOrFail(size, space, alignment); #ifdef DEBUG MemoryChunk* chunk = MemoryChunk::FromAddress(result->address()); DCHECK(chunk->owner()->identity() == space); #endif heap->CreateFillerObjectAt(result->address(), size, ClearRecordedSlots::kNo); return Handle(result, isolate()); } Handle Factory::NewPrototypeInfo() { Handle result = Handle::cast(NewStruct(PROTOTYPE_INFO_TYPE, TENURED)); result->set_prototype_users(*empty_weak_array_list()); result->set_registry_slot(PrototypeInfo::UNREGISTERED); result->set_bit_field(0); result->set_module_namespace(*undefined_value()); return result; } Handle Factory::NewEnumCache(Handle keys, Handle indices) { return Handle::cast(NewTuple2(keys, indices, TENURED)); } Handle Factory::NewTuple2(Handle value1, Handle value2, PretenureFlag pretenure) { Handle result = Handle::cast(NewStruct(TUPLE2_TYPE, pretenure)); result->set_value1(*value1); result->set_value2(*value2); return result; } Handle Factory::NewTuple3(Handle value1, Handle value2, Handle value3, PretenureFlag pretenure) { Handle result = Handle::cast(NewStruct(TUPLE3_TYPE, pretenure)); result->set_value1(*value1); result->set_value2(*value2); result->set_value3(*value3); return result; } Handle Factory::NewArrayBoilerplateDescription( ElementsKind elements_kind, Handle constant_values) { Handle result = Handle::cast( NewStruct(ARRAY_BOILERPLATE_DESCRIPTION_TYPE, TENURED)); result->set_elements_kind(elements_kind); result->set_constant_elements(*constant_values); return result; } Handle Factory::NewTemplateObjectDescription( Handle raw_strings, Handle cooked_strings) { DCHECK_EQ(raw_strings->length(), cooked_strings->length()); DCHECK_LT(0, raw_strings->length()); Handle result = Handle::cast(NewStruct(TUPLE2_TYPE, TENURED)); result->set_raw_strings(*raw_strings); result->set_cooked_strings(*cooked_strings); return result; } Handle Factory::NewOddball(Handle map, const char* to_string, Handle to_number, const char* type_of, byte kind, PretenureFlag pretenure) { Handle oddball(Oddball::cast(New(map, pretenure)), isolate()); Oddball::Initialize(isolate(), oddball, to_string, to_number, type_of, kind); return oddball; } Handle Factory::NewSelfReferenceMarker(PretenureFlag pretenure) { return NewOddball(self_reference_marker_map(), "self_reference_marker", handle(Smi::FromInt(-1), isolate()), "undefined", Oddball::kSelfReferenceMarker, pretenure); } Handle Factory::NewPropertyArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_property_array(); HeapObject* result = AllocateRawFixedArray(length, pretenure); result->set_map_after_allocation(*property_array_map(), SKIP_WRITE_BARRIER); Handle array(PropertyArray::cast(result), isolate()); array->initialize_length(length); MemsetPointer(array->data_start(), *undefined_value(), length); return array; } Handle Factory::NewFixedArrayWithFiller(RootIndex map_root_index, int length, Object* filler, PretenureFlag pretenure) { HeapObject* result = AllocateRawFixedArray(length, pretenure); DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); Map* map = Map::cast(isolate()->heap()->root(map_root_index)); result->set_map_after_allocation(map, SKIP_WRITE_BARRIER); Handle array(FixedArray::cast(result), isolate()); array->set_length(length); MemsetPointer(array->data_start(), filler, length); return array; } template Handle Factory::NewFixedArrayWithMap(RootIndex map_root_index, int length, PretenureFlag pretenure) { static_assert(std::is_base_of::value, "T must be a descendant of FixedArray"); // Zero-length case must be handled outside, where the knowledge about // the map is. DCHECK_LT(0, length); return Handle::cast(NewFixedArrayWithFiller( map_root_index, length, *undefined_value(), pretenure)); } template Handle Factory::NewWeakFixedArrayWithMap(RootIndex map_root_index, int length, PretenureFlag pretenure) { static_assert(std::is_base_of::value, "T must be a descendant of WeakFixedArray"); // Zero-length case must be handled outside. DCHECK_LT(0, length); HeapObject* result = AllocateRawArray(WeakFixedArray::SizeFor(length), pretenure); Map* map = Map::cast(isolate()->heap()->root(map_root_index)); result->set_map_after_allocation(map, SKIP_WRITE_BARRIER); Handle array(WeakFixedArray::cast(result), isolate()); array->set_length(length); MemsetPointer(array->data_start(), HeapObjectReference::Strong(*undefined_value()), length); return Handle::cast(array); } template Handle Factory::NewFixedArrayWithMap( RootIndex, int, PretenureFlag); template Handle Factory::NewWeakFixedArrayWithMap(RootIndex, int, PretenureFlag); Handle Factory::NewFixedArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_fixed_array(); return NewFixedArrayWithFiller(RootIndex::kFixedArrayMap, length, *undefined_value(), pretenure); } Handle Factory::NewWeakFixedArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_weak_fixed_array(); HeapObject* result = AllocateRawArray(WeakFixedArray::SizeFor(length), pretenure); DCHECK(Heap::RootIsImmortalImmovable(RootIndex::kWeakFixedArrayMap)); result->set_map_after_allocation(*weak_fixed_array_map(), SKIP_WRITE_BARRIER); Handle array(WeakFixedArray::cast(result), isolate()); array->set_length(length); MemsetPointer(array->data_start(), HeapObjectReference::Strong(*undefined_value()), length); return array; } MaybeHandle Factory::TryNewFixedArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_fixed_array(); int size = FixedArray::SizeFor(length); AllocationSpace space = Heap::SelectSpace(pretenure); Heap* heap = isolate()->heap(); AllocationResult allocation = heap->AllocateRaw(size, space); HeapObject* result = nullptr; if (!allocation.To(&result)) return MaybeHandle(); if (size > kMaxRegularHeapObjectSize && FLAG_use_marking_progress_bar) { MemoryChunk* chunk = MemoryChunk::FromAddress(result->address()); chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR); } result->set_map_after_allocation(*fixed_array_map(), SKIP_WRITE_BARRIER); Handle array(FixedArray::cast(result), isolate()); array->set_length(length); MemsetPointer(array->data_start(), ReadOnlyRoots(heap).undefined_value(), length); return array; } Handle Factory::NewFixedArrayWithHoles(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_fixed_array(); return NewFixedArrayWithFiller(RootIndex::kFixedArrayMap, length, *the_hole_value(), pretenure); } Handle Factory::NewUninitializedFixedArray( int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_fixed_array(); // TODO(ulan): As an experiment this temporarily returns an initialized fixed // array. After getting canary/performance coverage, either remove the // function or revert to returning uninitilized array. return NewFixedArrayWithFiller(RootIndex::kFixedArrayMap, length, *undefined_value(), pretenure); } Handle Factory::NewFeedbackVector( Handle shared, PretenureFlag pretenure) { int length = shared->feedback_metadata()->slot_count(); DCHECK_LE(0, length); int size = FeedbackVector::SizeFor(length); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, *feedback_vector_map()); Handle vector(FeedbackVector::cast(result), isolate()); vector->set_shared_function_info(*shared); vector->set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum( FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution : OptimizationMarker::kNone))); vector->set_length(length); vector->set_invocation_count(0); vector->set_profiler_ticks(0); vector->set_deopt_count(0); // TODO(leszeks): Initialize based on the feedback metadata. MemsetPointer(vector->slots_start(), MaybeObject::FromObject(*undefined_value()), length); return vector; } Handle Factory::NewObjectBoilerplateDescription( int boilerplate, int all_properties, int index_keys, bool has_seen_proto) { DCHECK_GE(boilerplate, 0); DCHECK_GE(all_properties, index_keys); DCHECK_GE(index_keys, 0); int backing_store_size = all_properties - index_keys - (has_seen_proto ? 1 : 0); DCHECK_GE(backing_store_size, 0); bool has_different_size_backing_store = boilerplate != backing_store_size; // Space for name and value for every boilerplate property + LiteralType flag. int size = 2 * boilerplate + ObjectBoilerplateDescription::kDescriptionStartIndex; if (has_different_size_backing_store) { // An extra entry for the backing store size. size++; } Handle description = Handle::cast(NewFixedArrayWithMap( RootIndex::kObjectBoilerplateDescriptionMap, size, TENURED)); if (has_different_size_backing_store) { DCHECK_IMPLIES((boilerplate == (all_properties - index_keys)), has_seen_proto); description->set_backing_store_size(isolate(), backing_store_size); } description->set_flags(0); return description; } Handle Factory::NewFixedDoubleArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); if (length == 0) return empty_fixed_array(); if (length > FixedDoubleArray::kMaxLength) { isolate()->heap()->FatalProcessOutOfMemory("invalid array length"); } int size = FixedDoubleArray::SizeFor(length); Map* map = *fixed_double_array_map(); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map, kDoubleAligned); Handle array(FixedDoubleArray::cast(result), isolate()); array->set_length(length); return array; } Handle Factory::NewFixedDoubleArrayWithHoles( int length, PretenureFlag pretenure) { DCHECK_LE(0, length); Handle array = NewFixedDoubleArray(length, pretenure); if (length > 0) { Handle::cast(array)->FillWithHoles(0, length); } return array; } Handle Factory::NewFeedbackMetadata(int slot_count, PretenureFlag tenure) { DCHECK_LE(0, slot_count); int size = FeedbackMetadata::SizeFor(slot_count); HeapObject* result = AllocateRawWithImmortalMap(size, tenure, *feedback_metadata_map()); Handle data(FeedbackMetadata::cast(result), isolate()); data->set_slot_count(slot_count); // Initialize the data section to 0. int data_size = size - FeedbackMetadata::kHeaderSize; Address data_start = data->address() + FeedbackMetadata::kHeaderSize; memset(reinterpret_cast(data_start), 0, data_size); // Fields have been zeroed out but not initialized, so this object will not // pass object verification at this point. return data; } Handle Factory::NewFrameArray(int number_of_frames, PretenureFlag pretenure) { DCHECK_LE(0, number_of_frames); Handle result = NewFixedArrayWithHoles( FrameArray::LengthFor(number_of_frames), pretenure); result->set(FrameArray::kFrameCountIndex, Smi::kZero); return Handle::cast(result); } Handle Factory::NewSmallOrderedHashSet( int capacity, PretenureFlag pretenure) { DCHECK_LE(0, capacity); CHECK_LE(capacity, SmallOrderedHashSet::kMaxCapacity); DCHECK_EQ(0, capacity % SmallOrderedHashSet::kLoadFactor); int size = SmallOrderedHashSet::SizeFor(capacity); Map* map = *small_ordered_hash_set_map(); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map); Handle table(SmallOrderedHashSet::cast(result), isolate()); table->Initialize(isolate(), capacity); return table; } Handle Factory::NewSmallOrderedHashMap( int capacity, PretenureFlag pretenure) { DCHECK_LE(0, capacity); CHECK_LE(capacity, SmallOrderedHashMap::kMaxCapacity); DCHECK_EQ(0, capacity % SmallOrderedHashMap::kLoadFactor); int size = SmallOrderedHashMap::SizeFor(capacity); Map* map = *small_ordered_hash_map_map(); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map); Handle table(SmallOrderedHashMap::cast(result), isolate()); table->Initialize(isolate(), capacity); return table; } Handle Factory::NewOrderedHashSet() { return OrderedHashSet::Allocate(isolate(), OrderedHashSet::kMinCapacity); } Handle Factory::NewOrderedHashMap() { return OrderedHashMap::Allocate(isolate(), OrderedHashMap::kMinCapacity); } Handle Factory::NewAccessorPair() { Handle accessors = Handle::cast(NewStruct(ACCESSOR_PAIR_TYPE, TENURED)); accessors->set_getter(*null_value(), SKIP_WRITE_BARRIER); accessors->set_setter(*null_value(), SKIP_WRITE_BARRIER); return accessors; } // Internalized strings are created in the old generation (data space). Handle Factory::InternalizeUtf8String(Vector string) { Utf8StringKey key(string, isolate()->heap()->HashSeed()); return InternalizeStringWithKey(&key); } Handle Factory::InternalizeOneByteString(Vector string) { OneByteStringKey key(string, isolate()->heap()->HashSeed()); return InternalizeStringWithKey(&key); } Handle Factory::InternalizeOneByteString( Handle string, int from, int length) { SeqOneByteSubStringKey key(isolate(), string, from, length); return InternalizeStringWithKey(&key); } Handle Factory::InternalizeTwoByteString(Vector string) { TwoByteStringKey key(string, isolate()->heap()->HashSeed()); return InternalizeStringWithKey(&key); } template Handle Factory::InternalizeStringWithKey(StringTableKey* key) { return StringTable::LookupKey(isolate(), key); } MaybeHandle Factory::NewStringFromOneByte(Vector string, PretenureFlag pretenure) { int length = string.length(); if (length == 0) return empty_string(); if (length == 1) return LookupSingleCharacterStringFromCode(string[0]); Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, NewRawOneByteString(string.length(), pretenure), String); DisallowHeapAllocation no_gc; // Copy the characters into the new object. CopyChars(SeqOneByteString::cast(*result)->GetChars(), string.start(), length); return result; } MaybeHandle Factory::NewStringFromUtf8(Vector string, PretenureFlag pretenure) { // Check for ASCII first since this is the common case. const char* ascii_data = string.start(); int length = string.length(); int non_ascii_start = String::NonAsciiStart(ascii_data, length); if (non_ascii_start >= length) { // If the string is ASCII, we do not need to convert the characters // since UTF8 is backwards compatible with ASCII. return NewStringFromOneByte(Vector::cast(string), pretenure); } // Non-ASCII and we need to decode. auto non_ascii = string.SubVector(non_ascii_start, length); Access decoder( isolate()->unicode_cache()->utf8_decoder()); decoder->Reset(non_ascii); int utf16_length = static_cast(decoder->Utf16Length()); DCHECK_GT(utf16_length, 0); // Allocate string. Handle result; ASSIGN_RETURN_ON_EXCEPTION( isolate(), result, NewRawTwoByteString(non_ascii_start + utf16_length, pretenure), String); // Copy ASCII portion. uint16_t* data = result->GetChars(); for (int i = 0; i < non_ascii_start; i++) { *data++ = *ascii_data++; } // Now write the remainder. decoder->WriteUtf16(data, utf16_length, non_ascii); return result; } MaybeHandle Factory::NewStringFromUtf8SubString( Handle str, int begin, int length, PretenureFlag pretenure) { const char* ascii_data = reinterpret_cast(str->GetChars() + begin); int non_ascii_start = String::NonAsciiStart(ascii_data, length); if (non_ascii_start >= length) { // If the string is ASCII, we can just make a substring. // TODO(v8): the pretenure flag is ignored in this case. return NewSubString(str, begin, begin + length); } // Non-ASCII and we need to decode. auto non_ascii = Vector(ascii_data + non_ascii_start, length - non_ascii_start); Access decoder( isolate()->unicode_cache()->utf8_decoder()); decoder->Reset(non_ascii); int utf16_length = static_cast(decoder->Utf16Length()); DCHECK_GT(utf16_length, 0); // Allocate string. Handle result; ASSIGN_RETURN_ON_EXCEPTION( isolate(), result, NewRawTwoByteString(non_ascii_start + utf16_length, pretenure), String); // Update pointer references, since the original string may have moved after // allocation. ascii_data = reinterpret_cast(str->GetChars() + begin); non_ascii = Vector(ascii_data + non_ascii_start, length - non_ascii_start); // Copy ASCII portion. uint16_t* data = result->GetChars(); for (int i = 0; i < non_ascii_start; i++) { *data++ = *ascii_data++; } // Now write the remainder. decoder->WriteUtf16(data, utf16_length, non_ascii); return result; } MaybeHandle Factory::NewStringFromTwoByte(const uc16* string, int length, PretenureFlag pretenure) { if (length == 0) return empty_string(); if (String::IsOneByte(string, length)) { if (length == 1) return LookupSingleCharacterStringFromCode(string[0]); Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, NewRawOneByteString(length, pretenure), String); CopyChars(result->GetChars(), string, length); return result; } else { Handle result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, NewRawTwoByteString(length, pretenure), String); CopyChars(result->GetChars(), string, length); return result; } } MaybeHandle Factory::NewStringFromTwoByte(Vector string, PretenureFlag pretenure) { return NewStringFromTwoByte(string.start(), string.length(), pretenure); } MaybeHandle Factory::NewStringFromTwoByte( const ZoneVector* string, PretenureFlag pretenure) { return NewStringFromTwoByte(string->data(), static_cast(string->size()), pretenure); } namespace { bool inline IsOneByte(Vector str, int chars) { // TODO(dcarney): incorporate Latin-1 check when Latin-1 is supported? return chars == str.length(); } bool inline IsOneByte(Handle str) { return str->IsOneByteRepresentation(); } inline void WriteOneByteData(Vector vector, uint8_t* chars, int len) { // Only works for one byte strings. DCHECK(vector.length() == len); MemCopy(chars, vector.start(), len); } inline void WriteTwoByteData(Vector vector, uint16_t* chars, int len) { unibrow::Utf8Iterator it = unibrow::Utf8Iterator(vector); while (!it.Done()) { DCHECK_GT(len, 0); len -= 1; uint16_t c = *it; ++it; DCHECK_NE(unibrow::Utf8::kBadChar, c); *chars++ = c; } DCHECK_EQ(len, 0); } inline void WriteOneByteData(Handle s, uint8_t* chars, int len) { DCHECK(s->length() == len); String::WriteToFlat(*s, chars, 0, len); } inline void WriteTwoByteData(Handle s, uint16_t* chars, int len) { DCHECK(s->length() == len); String::WriteToFlat(*s, chars, 0, len); } } // namespace Handle Factory::AllocateRawOneByteInternalizedString( int length, uint32_t hash_field) { CHECK_GE(String::kMaxLength, length); // The canonical empty_string is the only zero-length string we allow. DCHECK_IMPLIES( length == 0, isolate()->heap()->roots_[RootIndex::kempty_string] == nullptr); Map* map = *one_byte_internalized_string_map(); int size = SeqOneByteString::SizeFor(length); HeapObject* result = AllocateRawWithImmortalMap( size, isolate()->heap()->CanAllocateInReadOnlySpace() ? TENURED_READ_ONLY : TENURED, map); Handle answer(SeqOneByteString::cast(result), isolate()); answer->set_length(length); answer->set_hash_field(hash_field); DCHECK_EQ(size, answer->Size()); return answer; } Handle Factory::AllocateTwoByteInternalizedString( Vector str, uint32_t hash_field) { CHECK_GE(String::kMaxLength, str.length()); DCHECK_NE(0, str.length()); // Use Heap::empty_string() instead. Map* map = *internalized_string_map(); int size = SeqTwoByteString::SizeFor(str.length()); HeapObject* result = AllocateRawWithImmortalMap(size, TENURED, map); Handle answer(SeqTwoByteString::cast(result), isolate()); answer->set_length(str.length()); answer->set_hash_field(hash_field); DCHECK_EQ(size, answer->Size()); // Fill in the characters. MemCopy(answer->GetChars(), str.start(), str.length() * kUC16Size); return answer; } template Handle Factory::AllocateInternalizedStringImpl(T t, int chars, uint32_t hash_field) { DCHECK_LE(0, chars); DCHECK_GE(String::kMaxLength, chars); // Compute map and object size. int size; Map* map; if (is_one_byte) { map = *one_byte_internalized_string_map(); size = SeqOneByteString::SizeFor(chars); } else { map = *internalized_string_map(); size = SeqTwoByteString::SizeFor(chars); } HeapObject* result = AllocateRawWithImmortalMap( size, isolate()->heap()->CanAllocateInReadOnlySpace() ? TENURED_READ_ONLY : TENURED, map); Handle answer(String::cast(result), isolate()); answer->set_length(chars); answer->set_hash_field(hash_field); DCHECK_EQ(size, answer->Size()); if (is_one_byte) { WriteOneByteData(t, SeqOneByteString::cast(*answer)->GetChars(), chars); } else { WriteTwoByteData(t, SeqTwoByteString::cast(*answer)->GetChars(), chars); } return answer; } Handle Factory::NewInternalizedStringFromUtf8(Vector str, int chars, uint32_t hash_field) { if (IsOneByte(str, chars)) { Handle result = AllocateRawOneByteInternalizedString(str.length(), hash_field); MemCopy(result->GetChars(), str.start(), str.length()); return result; } return AllocateInternalizedStringImpl(str, chars, hash_field); } Handle Factory::NewOneByteInternalizedString(Vector str, uint32_t hash_field) { Handle result = AllocateRawOneByteInternalizedString(str.length(), hash_field); MemCopy(result->GetChars(), str.start(), str.length()); return result; } Handle Factory::NewOneByteInternalizedSubString( Handle string, int offset, int length, uint32_t hash_field) { Handle result = AllocateRawOneByteInternalizedString(length, hash_field); MemCopy(result->GetChars(), string->GetChars() + offset, length); return result; } Handle Factory::NewTwoByteInternalizedString(Vector str, uint32_t hash_field) { return AllocateTwoByteInternalizedString(str, hash_field); } Handle Factory::NewInternalizedStringImpl(Handle string, int chars, uint32_t hash_field) { if (IsOneByte(string)) { return AllocateInternalizedStringImpl(string, chars, hash_field); } return AllocateInternalizedStringImpl(string, chars, hash_field); } namespace { MaybeHandle GetInternalizedStringMap(Factory* f, Handle string) { switch (string->map()->instance_type()) { case STRING_TYPE: return f->internalized_string_map(); case ONE_BYTE_STRING_TYPE: return f->one_byte_internalized_string_map(); case EXTERNAL_STRING_TYPE: return f->external_internalized_string_map(); case EXTERNAL_ONE_BYTE_STRING_TYPE: return f->external_one_byte_internalized_string_map(); case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: return f->external_internalized_string_with_one_byte_data_map(); case UNCACHED_EXTERNAL_STRING_TYPE: return f->uncached_external_internalized_string_map(); case UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE: return f->uncached_external_one_byte_internalized_string_map(); case UNCACHED_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: return f->uncached_external_internalized_string_with_one_byte_data_map(); default: return MaybeHandle(); // No match found. } } } // namespace MaybeHandle Factory::InternalizedStringMapForString( Handle string) { // If the string is in new space it cannot be used as internalized. if (Heap::InNewSpace(*string)) return MaybeHandle(); return GetInternalizedStringMap(this, string); } template Handle Factory::InternalizeExternalString(Handle string) { Handle cast_string = Handle::cast(string); Handle map = GetInternalizedStringMap(this, string).ToHandleChecked(); Handle external_string(StringClass::cast(New(map, TENURED)), isolate()); external_string->set_length(cast_string->length()); external_string->set_hash_field(cast_string->hash_field()); external_string->SetResource(isolate(), nullptr); isolate()->heap()->RegisterExternalString(*external_string); return external_string; } template Handle Factory::InternalizeExternalString(Handle); template Handle Factory::InternalizeExternalString(Handle); MaybeHandle Factory::NewRawOneByteString( int length, PretenureFlag pretenure) { if (length > String::kMaxLength || length < 0) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError(), SeqOneByteString); } DCHECK_GT(length, 0); // Use Factory::empty_string() instead. int size = SeqOneByteString::SizeFor(length); DCHECK_GE(SeqOneByteString::kMaxSize, size); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, *one_byte_string_map()); Handle string(SeqOneByteString::cast(result), isolate()); string->set_length(length); string->set_hash_field(String::kEmptyHashField); DCHECK_EQ(size, string->Size()); return string; } MaybeHandle Factory::NewRawTwoByteString( int length, PretenureFlag pretenure) { if (length > String::kMaxLength || length < 0) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError(), SeqTwoByteString); } DCHECK_GT(length, 0); // Use Factory::empty_string() instead. int size = SeqTwoByteString::SizeFor(length); DCHECK_GE(SeqTwoByteString::kMaxSize, size); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, *string_map()); Handle string(SeqTwoByteString::cast(result), isolate()); string->set_length(length); string->set_hash_field(String::kEmptyHashField); DCHECK_EQ(size, string->Size()); return string; } Handle Factory::LookupSingleCharacterStringFromCode(uint32_t code) { if (code <= String::kMaxOneByteCharCodeU) { { DisallowHeapAllocation no_allocation; Object* value = single_character_string_cache()->get(code); if (value != *undefined_value()) { return handle(String::cast(value), isolate()); } } uint8_t buffer[1]; buffer[0] = static_cast(code); Handle result = InternalizeOneByteString(Vector(buffer, 1)); single_character_string_cache()->set(code, *result); return result; } DCHECK_LE(code, String::kMaxUtf16CodeUnitU); Handle result = NewRawTwoByteString(1).ToHandleChecked(); result->SeqTwoByteStringSet(0, static_cast(code)); return result; } // Returns true for a character in a range. Both limits are inclusive. static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { // This makes uses of the the unsigned wraparound. return character - from <= to - from; } static inline Handle MakeOrFindTwoCharacterString(Isolate* isolate, uint16_t c1, uint16_t c2) { // Numeric strings have a different hash algorithm not known by // LookupTwoCharsStringIfExists, so we skip this step for such strings. if (!Between(c1, '0', '9') || !Between(c2, '0', '9')) { Handle result; if (StringTable::LookupTwoCharsStringIfExists(isolate, c1, c2) .ToHandle(&result)) { return result; } } // Now we know the length is 2, we might as well make use of that fact // when building the new string. if (static_cast(c1 | c2) <= String::kMaxOneByteCharCodeU) { // We can do this. DCHECK(base::bits::IsPowerOfTwo(String::kMaxOneByteCharCodeU + 1)); // because of this. Handle str = isolate->factory()->NewRawOneByteString(2).ToHandleChecked(); uint8_t* dest = str->GetChars(); dest[0] = static_cast(c1); dest[1] = static_cast(c2); return str; } else { Handle str = isolate->factory()->NewRawTwoByteString(2).ToHandleChecked(); uc16* dest = str->GetChars(); dest[0] = c1; dest[1] = c2; return str; } } template Handle ConcatStringContent(Handle result, Handle first, Handle second) { DisallowHeapAllocation pointer_stays_valid; SinkChar* sink = result->GetChars(); String::WriteToFlat(*first, sink, 0, first->length()); String::WriteToFlat(*second, sink + first->length(), 0, second->length()); return result; } MaybeHandle Factory::NewConsString(Handle left, Handle right) { if (left->IsThinString()) { left = handle(Handle::cast(left)->actual(), isolate()); } if (right->IsThinString()) { right = handle(Handle::cast(right)->actual(), isolate()); } int left_length = left->length(); if (left_length == 0) return right; int right_length = right->length(); if (right_length == 0) return left; int length = left_length + right_length; if (length == 2) { uint16_t c1 = left->Get(0); uint16_t c2 = right->Get(0); return MakeOrFindTwoCharacterString(isolate(), c1, c2); } // Make sure that an out of memory exception is thrown if the length // of the new cons string is too large. if (length > String::kMaxLength || length < 0) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError(), String); } bool left_is_one_byte = left->IsOneByteRepresentation(); bool right_is_one_byte = right->IsOneByteRepresentation(); bool is_one_byte = left_is_one_byte && right_is_one_byte; bool is_one_byte_data_in_two_byte_string = false; if (!is_one_byte) { // At least one of the strings uses two-byte representation so we // can't use the fast case code for uncached one-byte strings below, but // we can try to save memory if all chars actually fit in one-byte. is_one_byte_data_in_two_byte_string = left->HasOnlyOneByteChars() && right->HasOnlyOneByteChars(); if (is_one_byte_data_in_two_byte_string) { isolate()->counters()->string_add_runtime_ext_to_one_byte()->Increment(); } } // If the resulting string is small make a flat string. if (length < ConsString::kMinLength) { // Note that neither of the two inputs can be a slice because: STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength); DCHECK(left->IsFlat()); DCHECK(right->IsFlat()); STATIC_ASSERT(ConsString::kMinLength <= String::kMaxLength); if (is_one_byte) { Handle result = NewRawOneByteString(length).ToHandleChecked(); DisallowHeapAllocation no_gc; uint8_t* dest = result->GetChars(); // Copy left part. const uint8_t* src = left->IsExternalString() ? Handle::cast(left)->GetChars() : Handle::cast(left)->GetChars(); for (int i = 0; i < left_length; i++) *dest++ = src[i]; // Copy right part. src = right->IsExternalString() ? Handle::cast(right)->GetChars() : Handle::cast(right)->GetChars(); for (int i = 0; i < right_length; i++) *dest++ = src[i]; return result; } return (is_one_byte_data_in_two_byte_string) ? ConcatStringContent( NewRawOneByteString(length).ToHandleChecked(), left, right) : ConcatStringContent( NewRawTwoByteString(length).ToHandleChecked(), left, right); } bool one_byte = (is_one_byte || is_one_byte_data_in_two_byte_string); return NewConsString(left, right, length, one_byte); } Handle Factory::NewConsString(Handle left, Handle right, int length, bool one_byte) { DCHECK(!left->IsThinString()); DCHECK(!right->IsThinString()); DCHECK_GE(length, ConsString::kMinLength); DCHECK_LE(length, String::kMaxLength); Handle result( ConsString::cast(one_byte ? New(cons_one_byte_string_map(), NOT_TENURED) : New(cons_string_map(), NOT_TENURED)), isolate()); DisallowHeapAllocation no_gc; WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); result->set_hash_field(String::kEmptyHashField); result->set_length(length); result->set_first(isolate(), *left, mode); result->set_second(isolate(), *right, mode); return result; } Handle Factory::NewSurrogatePairString(uint16_t lead, uint16_t trail) { DCHECK_GE(lead, 0xD800); DCHECK_LE(lead, 0xDBFF); DCHECK_GE(trail, 0xDC00); DCHECK_LE(trail, 0xDFFF); Handle str = isolate()->factory()->NewRawTwoByteString(2).ToHandleChecked(); uc16* dest = str->GetChars(); dest[0] = lead; dest[1] = trail; return str; } Handle Factory::NewProperSubString(Handle str, int begin, int end) { #if VERIFY_HEAP if (FLAG_verify_heap) str->StringVerify(isolate()); #endif DCHECK(begin > 0 || end < str->length()); str = String::Flatten(isolate(), str); int length = end - begin; if (length <= 0) return empty_string(); if (length == 1) { return LookupSingleCharacterStringFromCode(str->Get(begin)); } if (length == 2) { // Optimization for 2-byte strings often used as keys in a decompression // dictionary. Check whether we already have the string in the string // table to prevent creation of many unnecessary strings. uint16_t c1 = str->Get(begin); uint16_t c2 = str->Get(begin + 1); return MakeOrFindTwoCharacterString(isolate(), c1, c2); } if (!FLAG_string_slices || length < SlicedString::kMinLength) { if (str->IsOneByteRepresentation()) { Handle result = NewRawOneByteString(length).ToHandleChecked(); uint8_t* dest = result->GetChars(); DisallowHeapAllocation no_gc; String::WriteToFlat(*str, dest, begin, end); return result; } else { Handle result = NewRawTwoByteString(length).ToHandleChecked(); uc16* dest = result->GetChars(); DisallowHeapAllocation no_gc; String::WriteToFlat(*str, dest, begin, end); return result; } } int offset = begin; if (str->IsSlicedString()) { Handle slice = Handle::cast(str); str = Handle(slice->parent(), isolate()); offset += slice->offset(); } if (str->IsThinString()) { Handle thin = Handle::cast(str); str = handle(thin->actual(), isolate()); } DCHECK(str->IsSeqString() || str->IsExternalString()); Handle map = str->IsOneByteRepresentation() ? sliced_one_byte_string_map() : sliced_string_map(); Handle slice(SlicedString::cast(New(map, NOT_TENURED)), isolate()); slice->set_hash_field(String::kEmptyHashField); slice->set_length(length); slice->set_parent(isolate(), *str); slice->set_offset(offset); return slice; } MaybeHandle Factory::NewExternalStringFromOneByte( const ExternalOneByteString::Resource* resource) { size_t length = resource->length(); if (length > static_cast(String::kMaxLength)) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError(), String); } if (length == 0) return empty_string(); Handle map; if (!resource->IsCacheable()) { map = uncached_external_one_byte_string_map(); } else { map = external_one_byte_string_map(); } Handle external_string( ExternalOneByteString::cast(New(map, TENURED)), isolate()); external_string->set_length(static_cast(length)); external_string->set_hash_field(String::kEmptyHashField); external_string->SetResource(isolate(), resource); isolate()->heap()->RegisterExternalString(*external_string); return external_string; } MaybeHandle Factory::NewExternalStringFromTwoByte( const ExternalTwoByteString::Resource* resource) { size_t length = resource->length(); if (length > static_cast(String::kMaxLength)) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError(), String); } if (length == 0) return empty_string(); // For small strings we check whether the resource contains only // one byte characters. If yes, we use a different string map. static const size_t kOneByteCheckLengthLimit = 32; bool is_one_byte = length <= kOneByteCheckLengthLimit && String::IsOneByte(resource->data(), static_cast(length)); Handle map; if (!resource->IsCacheable()) { map = is_one_byte ? uncached_external_string_with_one_byte_data_map() : uncached_external_string_map(); } else { map = is_one_byte ? external_string_with_one_byte_data_map() : external_string_map(); } Handle external_string( ExternalTwoByteString::cast(New(map, TENURED)), isolate()); external_string->set_length(static_cast(length)); external_string->set_hash_field(String::kEmptyHashField); external_string->SetResource(isolate(), resource); isolate()->heap()->RegisterExternalString(*external_string); return external_string; } Handle Factory::NewNativeSourceString( const ExternalOneByteString::Resource* resource) { size_t length = resource->length(); DCHECK_LE(length, static_cast(String::kMaxLength)); Handle map = native_source_string_map(); Handle external_string( ExternalOneByteString::cast(New(map, TENURED)), isolate()); external_string->set_length(static_cast(length)); external_string->set_hash_field(String::kEmptyHashField); external_string->SetResource(isolate(), resource); isolate()->heap()->RegisterExternalString(*external_string); return external_string; } Handle Factory::NewJSStringIterator(Handle string) { Handle map(isolate()->native_context()->initial_string_iterator_map(), isolate()); Handle flat_string = String::Flatten(isolate(), string); Handle iterator = Handle::cast(NewJSObjectFromMap(map)); iterator->set_string(*flat_string); iterator->set_index(0); return iterator; } Handle Factory::NewSymbol(PretenureFlag flag) { DCHECK(flag != NOT_TENURED); // Statically ensure that it is safe to allocate symbols in paged spaces. STATIC_ASSERT(Symbol::kSize <= kMaxRegularHeapObjectSize); HeapObject* result = AllocateRawWithImmortalMap(Symbol::kSize, flag, *symbol_map()); // Generate a random hash value. int hash = isolate()->GenerateIdentityHash(Name::kHashBitMask); Handle symbol(Symbol::cast(result), isolate()); symbol->set_hash_field(Name::kIsNotArrayIndexMask | (hash << Name::kHashShift)); symbol->set_name(*undefined_value()); symbol->set_flags(0); DCHECK(!symbol->is_private()); return symbol; } Handle Factory::NewPrivateSymbol(PretenureFlag flag) { DCHECK(flag != NOT_TENURED); Handle symbol = NewSymbol(flag); symbol->set_is_private(true); return symbol; } Handle Factory::NewPrivateFieldSymbol() { Handle symbol = NewSymbol(); symbol->set_is_private_field(); return symbol; } Handle Factory::NewNativeContext() { Handle context = NewFixedArrayWithMap( RootIndex::kNativeContextMap, Context::NATIVE_CONTEXT_SLOTS, TENURED); context->set_native_context(*context); context->set_errors_thrown(Smi::kZero); context->set_math_random_index(Smi::kZero); context->set_serialized_objects(*empty_fixed_array()); return context; } Handle Factory::NewScriptContext(Handle outer, Handle scope_info) { DCHECK_EQ(scope_info->scope_type(), SCRIPT_SCOPE); Handle context = NewFixedArrayWithMap( RootIndex::kScriptContextMap, scope_info->ContextLength(), TENURED); context->set_scope_info(*scope_info); context->set_previous(*outer); context->set_extension(*the_hole_value()); context->set_native_context(*outer); DCHECK(context->IsScriptContext()); return context; } Handle Factory::NewScriptContextTable() { Handle context_table = NewFixedArrayWithMap( RootIndex::kScriptContextTableMap, ScriptContextTable::kMinLength); context_table->set_used(0); return context_table; } Handle Factory::NewModuleContext(Handle module, Handle outer, Handle scope_info) { DCHECK_EQ(scope_info->scope_type(), MODULE_SCOPE); Handle context = NewFixedArrayWithMap( RootIndex::kModuleContextMap, scope_info->ContextLength(), TENURED); context->set_scope_info(*scope_info); context->set_previous(*outer); context->set_extension(*module); context->set_native_context(*outer); DCHECK(context->IsModuleContext()); return context; } Handle Factory::NewFunctionContext(Handle outer, Handle scope_info) { int length = scope_info->ContextLength(); DCHECK_LE(Context::MIN_CONTEXT_SLOTS, length); RootIndex mapRootIndex; switch (scope_info->scope_type()) { case EVAL_SCOPE: mapRootIndex = RootIndex::kEvalContextMap; break; case FUNCTION_SCOPE: mapRootIndex = RootIndex::kFunctionContextMap; break; default: UNREACHABLE(); } Handle context = NewFixedArrayWithMap(mapRootIndex, length); context->set_scope_info(*scope_info); context->set_previous(*outer); context->set_extension(*the_hole_value()); context->set_native_context(outer->native_context()); return context; } Handle Factory::NewCatchContext(Handle previous, Handle scope_info, Handle thrown_object) { STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX); Handle context = NewFixedArrayWithMap( RootIndex::kCatchContextMap, Context::MIN_CONTEXT_SLOTS + 1); context->set_scope_info(*scope_info); context->set_previous(*previous); context->set_extension(*the_hole_value()); context->set_native_context(previous->native_context()); context->set(Context::THROWN_OBJECT_INDEX, *thrown_object); return context; } Handle Factory::NewDebugEvaluateContext(Handle previous, Handle scope_info, Handle extension, Handle wrapped, Handle whitelist) { STATIC_ASSERT(Context::WHITE_LIST_INDEX == Context::MIN_CONTEXT_SLOTS + 1); DCHECK(scope_info->IsDebugEvaluateScope()); Handle ext = extension.is_null() ? Handle::cast(the_hole_value()) : Handle::cast(extension); Handle c = NewFixedArrayWithMap( RootIndex::kDebugEvaluateContextMap, Context::MIN_CONTEXT_SLOTS + 2); c->set_scope_info(*scope_info); c->set_previous(*previous); c->set_native_context(previous->native_context()); c->set_extension(*ext); if (!wrapped.is_null()) c->set(Context::WRAPPED_CONTEXT_INDEX, *wrapped); if (!whitelist.is_null()) c->set(Context::WHITE_LIST_INDEX, *whitelist); return c; } Handle Factory::NewWithContext(Handle previous, Handle scope_info, Handle extension) { Handle context = NewFixedArrayWithMap( RootIndex::kWithContextMap, Context::MIN_CONTEXT_SLOTS); context->set_scope_info(*scope_info); context->set_previous(*previous); context->set_extension(*extension); context->set_native_context(previous->native_context()); return context; } Handle Factory::NewBlockContext(Handle previous, Handle scope_info) { DCHECK_EQ(scope_info->scope_type(), BLOCK_SCOPE); Handle context = NewFixedArrayWithMap( RootIndex::kBlockContextMap, scope_info->ContextLength()); context->set_scope_info(*scope_info); context->set_previous(*previous); context->set_extension(*the_hole_value()); context->set_native_context(previous->native_context()); return context; } Handle Factory::NewBuiltinContext(Handle native_context, int length) { DCHECK_GE(length, Context::MIN_CONTEXT_SLOTS); Handle context = NewFixedArrayWithMap(RootIndex::kFunctionContextMap, length); context->set_scope_info(ReadOnlyRoots(isolate()).empty_scope_info()); context->set_extension(*the_hole_value()); context->set_native_context(*native_context); return context; } Handle Factory::NewStruct(InstanceType type, PretenureFlag pretenure) { Map* map; switch (type) { #define MAKE_CASE(TYPE, Name, name) \ case TYPE: \ map = *name##_map(); \ break; STRUCT_LIST(MAKE_CASE) #undef MAKE_CASE default: UNREACHABLE(); } int size = map->instance_size(); HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map); Handle str(Struct::cast(result), isolate()); str->InitializeBody(size); return str; } Handle Factory::NewAliasedArgumentsEntry( int aliased_context_slot) { Handle entry = Handle::cast( NewStruct(ALIASED_ARGUMENTS_ENTRY_TYPE, NOT_TENURED)); entry->set_aliased_context_slot(aliased_context_slot); return entry; } Handle Factory::NewAccessorInfo() { Handle info = Handle::cast(NewStruct(ACCESSOR_INFO_TYPE, TENURED)); info->set_name(*empty_string()); info->set_flags(0); // Must clear the flags, it was initialized as undefined. info->set_is_sloppy(true); info->set_initial_property_attributes(NONE); return info; } Handle