// 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 "factory.h" #include "conversions.h" #include "isolate-inl.h" #include "macro-assembler.h" namespace v8 { namespace internal { template Handle Factory::New(Handle map, AllocationSpace space) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->Allocate(*map, space), T); } template Handle Factory::New(Handle map, AllocationSpace space, Handle allocation_site) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->Allocate(*map, space, *allocation_site), T); } Handle Factory::NewFillerObject(int size, bool double_align, AllocationSpace space) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateFillerObject(size, double_align, space), HeapObject); } Handle Factory::NewBox(Handle value) { Handle result = Handle::cast(NewStruct(BOX_TYPE)); result->set_value(*value); return result; } Handle Factory::NewOddball(Handle map, const char* to_string, Handle to_number, byte kind) { Handle oddball = New(map, OLD_POINTER_SPACE); Oddball::Initialize(isolate(), oddball, to_string, to_number, kind); return oddball; } Handle Factory::NewFixedArray(int size, PretenureFlag pretenure) { ASSERT(0 <= size); CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateFixedArray(size, pretenure), FixedArray); } Handle Factory::NewFixedArrayWithHoles(int size, PretenureFlag pretenure) { ASSERT(0 <= size); CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateFixedArrayWithFiller(size, pretenure, *the_hole_value()), FixedArray); } Handle Factory::NewUninitializedFixedArray(int size) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateUninitializedFixedArray(size), FixedArray); } Handle Factory::NewFixedDoubleArray(int size, PretenureFlag pretenure) { ASSERT(0 <= size); CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure), FixedArrayBase); } Handle Factory::NewFixedDoubleArrayWithHoles( int size, PretenureFlag pretenure) { ASSERT(0 <= size); Handle array = NewFixedDoubleArray(size, pretenure); if (size > 0) { Handle double_array = Handle::cast(array); for (int i = 0; i < size; ++i) { double_array->set_the_hole(i); } } return array; } Handle Factory::NewConstantPoolArray( int number_of_int64_entries, int number_of_code_ptr_entries, int number_of_heap_ptr_entries, int number_of_int32_entries) { ASSERT(number_of_int64_entries > 0 || number_of_code_ptr_entries > 0 || number_of_heap_ptr_entries > 0 || number_of_int32_entries > 0); CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateConstantPoolArray(number_of_int64_entries, number_of_code_ptr_entries, number_of_heap_ptr_entries, number_of_int32_entries), ConstantPoolArray); } Handle Factory::NewOrderedHashSet() { return OrderedHashSet::Allocate(isolate(), 4); } Handle Factory::NewOrderedHashMap() { return OrderedHashMap::Allocate(isolate(), 4); } Handle Factory::NewAccessorPair() { Handle accessors = Handle::cast(NewStruct(ACCESSOR_PAIR_TYPE)); accessors->set_getter(*the_hole_value(), SKIP_WRITE_BARRIER); accessors->set_setter(*the_hole_value(), SKIP_WRITE_BARRIER); accessors->set_access_flags(Smi::FromInt(0), SKIP_WRITE_BARRIER); return accessors; } Handle Factory::NewTypeFeedbackInfo() { Handle info = Handle::cast(NewStruct(TYPE_FEEDBACK_INFO_TYPE)); info->initialize_storage(); info->set_feedback_vector(*empty_fixed_array(), SKIP_WRITE_BARRIER); return info; } // Internalized strings are created in the old generation (data space). Handle Factory::InternalizeUtf8String(Vector string) { Utf8StringKey key(string, isolate()->heap()->HashSeed()); return InternalizeStringWithKey(&key); } // Internalized strings are created in the old generation (data space). Handle Factory::InternalizeString(Handle string) { if (string->IsInternalizedString()) return string; return StringTable::LookupString(isolate(), string); } Handle Factory::InternalizeOneByteString(Vector string) { OneByteStringKey key(string, isolate()->heap()->HashSeed()); return InternalizeStringWithKey(&key); } Handle Factory::InternalizeOneByteString( Handle string, int from, int length) { SubStringKey key(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); } template Handle Factory::InternalizeStringWithKey< SubStringKey > (SubStringKey* key); template Handle Factory::InternalizeStringWithKey< SubStringKey > (SubStringKey* key); MaybeHandle Factory::NewStringFromOneByte(Vector string, PretenureFlag pretenure) { int length = string.length(); 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* start = string.start(); int length = string.length(); int non_ascii_start = String::NonAsciiStart(start, 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. CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStringFromUtf8Slow(string, non_ascii_start, pretenure), String); } MaybeHandle Factory::NewStringFromTwoByte(Vector string, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStringFromTwoByte(string, pretenure), String); } Handle Factory::NewInternalizedStringFromUtf8(Vector str, int chars, uint32_t hash_field) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateInternalizedStringFromUtf8( str, chars, hash_field), String); } MUST_USE_RESULT Handle Factory::NewOneByteInternalizedString( Vector str, uint32_t hash_field) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateOneByteInternalizedString(str, hash_field), String); } MUST_USE_RESULT Handle Factory::NewTwoByteInternalizedString( Vector str, uint32_t hash_field) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateTwoByteInternalizedString(str, hash_field), String); } Handle Factory::NewInternalizedStringImpl( Handle string, int chars, uint32_t hash_field) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateInternalizedStringImpl( *string, chars, hash_field), String); } MaybeHandle Factory::InternalizedStringMapForString( Handle string) { // If the string is in new space it cannot be used as internalized. if (isolate()->heap()->InNewSpace(*string)) return MaybeHandle(); // Find the corresponding internalized string map for strings. switch (string->map()->instance_type()) { case STRING_TYPE: return internalized_string_map(); case ASCII_STRING_TYPE: return ascii_internalized_string_map(); case EXTERNAL_STRING_TYPE: return external_internalized_string_map(); case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_internalized_string_map(); case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: return external_internalized_string_with_one_byte_data_map(); case SHORT_EXTERNAL_STRING_TYPE: return short_external_internalized_string_map(); case SHORT_EXTERNAL_ASCII_STRING_TYPE: return short_external_ascii_internalized_string_map(); case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: return short_external_internalized_string_with_one_byte_data_map(); default: return MaybeHandle(); // No match found. } } MaybeHandle Factory::NewRawOneByteString( int length, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateRawOneByteString(length, pretenure), SeqOneByteString); } MaybeHandle Factory::NewRawTwoByteString( int length, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateRawTwoByteString(length, pretenure), SeqTwoByteString); } 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; } ASSERT(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')) { String* result; StringTable* table = isolate->heap()->string_table(); if (table->LookupTwoCharsStringIfExists(c1, c2, &result)) { return handle(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. ASSERT(IsPowerOf2(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) { 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) { return isolate()->Throw(NewInvalidStringLengthError()); } 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 short ASCII strings below, but // we can try to save memory if all chars actually fit in ASCII. 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_ascii()->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); ASSERT(left->IsFlat()); ASSERT(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); } Handle map = (is_one_byte || is_one_byte_data_in_two_byte_string) ? cons_ascii_string_map() : cons_string_map(); Handle result = New(map, NEW_SPACE); DisallowHeapAllocation no_gc; WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); result->set_hash_field(String::kEmptyHashField); result->set_length(length); result->set_first(*left, mode); result->set_second(*right, mode); return result; } Handle Factory::NewFlatConcatString(Handle first, Handle second) { int total_length = first->length() + second->length(); if (first->IsOneByteRepresentation() && second->IsOneByteRepresentation()) { return ConcatStringContent( NewRawOneByteString(total_length).ToHandleChecked(), first, second); } else { return ConcatStringContent( NewRawTwoByteString(total_length).ToHandleChecked(), first, second); } } Handle Factory::NewProperSubString(Handle str, int begin, int end) { #if VERIFY_HEAP if (FLAG_verify_heap) str->StringVerify(); #endif ASSERT(begin > 0 || end < str->length()); str = String::Flatten(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(); } ASSERT(str->IsSeqString() || str->IsExternalString()); Handle map = str->IsOneByteRepresentation() ? sliced_ascii_string_map() : sliced_string_map(); Handle slice = New(map, NEW_SPACE); slice->set_hash_field(String::kEmptyHashField); slice->set_length(length); slice->set_parent(*str); slice->set_offset(offset); return slice; } MaybeHandle Factory::NewExternalStringFromAscii( const ExternalAsciiString::Resource* resource) { size_t length = resource->length(); if (length > static_cast(String::kMaxLength)) { isolate()->ThrowInvalidStringLength(); return MaybeHandle(); } Handle map = external_ascii_string_map(); Handle external_string = New(map, NEW_SPACE); external_string->set_length(static_cast(length)); external_string->set_hash_field(String::kEmptyHashField); external_string->set_resource(resource); return external_string; } MaybeHandle Factory::NewExternalStringFromTwoByte( const ExternalTwoByteString::Resource* resource) { size_t length = resource->length(); if (length > static_cast(String::kMaxLength)) { isolate()->ThrowInvalidStringLength(); return MaybeHandle(); } // 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 = is_one_byte ? external_string_with_one_byte_data_map() : external_string_map(); Handle external_string = New(map, NEW_SPACE); external_string->set_length(static_cast(length)); external_string->set_hash_field(String::kEmptyHashField); external_string->set_resource(resource); return external_string; } Handle Factory::NewSymbol() { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateSymbol(), Symbol); } Handle Factory::NewPrivateSymbol() { Handle symbol = NewSymbol(); symbol->set_is_private(true); return symbol; } Handle Factory::NewNativeContext() { Handle array = NewFixedArray(Context::NATIVE_CONTEXT_SLOTS); array->set_map_no_write_barrier(*native_context_map()); Handle context = Handle::cast(array); context->set_js_array_maps(*undefined_value()); ASSERT(context->IsNativeContext()); return context; } Handle Factory::NewGlobalContext(Handle function, Handle scope_info) { Handle array = NewFixedArray(scope_info->ContextLength(), TENURED); array->set_map_no_write_barrier(*global_context_map()); Handle context = Handle::cast(array); context->set_closure(*function); context->set_previous(function->context()); context->set_extension(*scope_info); context->set_global_object(function->context()->global_object()); ASSERT(context->IsGlobalContext()); return context; } Handle Factory::NewModuleContext(Handle scope_info) { Handle array = NewFixedArray(scope_info->ContextLength(), TENURED); array->set_map_no_write_barrier(*module_context_map()); // Instance link will be set later. Handle context = Handle::cast(array); context->set_extension(Smi::FromInt(0)); return context; } Handle Factory::NewFunctionContext(int length, Handle function) { ASSERT(length >= Context::MIN_CONTEXT_SLOTS); Handle array = NewFixedArray(length); array->set_map_no_write_barrier(*function_context_map()); Handle context = Handle::cast(array); context->set_closure(*function); context->set_previous(function->context()); context->set_extension(Smi::FromInt(0)); context->set_global_object(function->context()->global_object()); return context; } Handle Factory::NewCatchContext(Handle function, Handle previous, Handle name, Handle thrown_object) { STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX); Handle array = NewFixedArray(Context::MIN_CONTEXT_SLOTS + 1); array->set_map_no_write_barrier(*catch_context_map()); Handle context = Handle::cast(array); context->set_closure(*function); context->set_previous(*previous); context->set_extension(*name); context->set_global_object(previous->global_object()); context->set(Context::THROWN_OBJECT_INDEX, *thrown_object); return context; } Handle Factory::NewWithContext(Handle function, Handle previous, Handle extension) { Handle array = NewFixedArray(Context::MIN_CONTEXT_SLOTS); array->set_map_no_write_barrier(*with_context_map()); Handle context = Handle::cast(array); context->set_closure(*function); context->set_previous(*previous); context->set_extension(*extension); context->set_global_object(previous->global_object()); return context; } Handle Factory::NewBlockContext(Handle function, Handle previous, Handle scope_info) { Handle array = NewFixedArrayWithHoles(scope_info->ContextLength()); array->set_map_no_write_barrier(*block_context_map()); Handle context = Handle::cast(array); context->set_closure(*function); context->set_previous(*previous); context->set_extension(*scope_info); context->set_global_object(previous->global_object()); return context; } Handle Factory::NewStruct(InstanceType type) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStruct(type), Struct); } Handle Factory::NewCodeCache() { Handle code_cache = Handle::cast(NewStruct(CODE_CACHE_TYPE)); code_cache->set_default_cache(*empty_fixed_array(), SKIP_WRITE_BARRIER); code_cache->set_normal_type_cache(*undefined_value(), SKIP_WRITE_BARRIER); return code_cache; } Handle Factory::NewAliasedArgumentsEntry( int aliased_context_slot) { Handle entry = Handle::cast( NewStruct(ALIASED_ARGUMENTS_ENTRY_TYPE)); entry->set_aliased_context_slot(aliased_context_slot); return entry; } Handle Factory::NewDeclaredAccessorDescriptor() { return Handle::cast( NewStruct(DECLARED_ACCESSOR_DESCRIPTOR_TYPE)); } Handle Factory::NewDeclaredAccessorInfo() { Handle info = Handle::cast( NewStruct(DECLARED_ACCESSOR_INFO_TYPE)); info->set_flag(0); // Must clear the flag, it was initialized as undefined. return info; } Handle Factory::NewExecutableAccessorInfo() { Handle info = Handle::cast( NewStruct(EXECUTABLE_ACCESSOR_INFO_TYPE)); info->set_flag(0); // Must clear the flag, it was initialized as undefined. return info; } Handle