// Copyright 2013 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "v8.h" #include "api.h" #include "debug.h" #include "execution.h" #include "factory.h" #include "isolate-inl.h" #include "macro-assembler.h" #include "objects.h" #include "objects-visiting.h" #include "platform.h" #include "scopeinfo.h" namespace v8 { namespace internal { Handle Factory::NewBox(Handle value, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateBox(*value, pretenure), Box); } 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()->AllocateFixedArrayWithHoles(size, pretenure), FixedArray); } Handle Factory::NewFixedDoubleArray(int size, PretenureFlag pretenure) { ASSERT(0 <= size); CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure), FixedDoubleArray); } 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::NewNameDictionary(int at_least_space_for) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), NameDictionary::Allocate(isolate()->heap(), at_least_space_for), NameDictionary); } Handle Factory::NewSeededNumberDictionary( int at_least_space_for) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), SeededNumberDictionary::Allocate(isolate()->heap(), at_least_space_for), SeededNumberDictionary); } Handle Factory::NewUnseededNumberDictionary( int at_least_space_for) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), UnseededNumberDictionary::Allocate(isolate()->heap(), at_least_space_for), UnseededNumberDictionary); } Handle Factory::NewObjectHashSet(int at_least_space_for) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), ObjectHashSet::Allocate(isolate()->heap(), at_least_space_for), ObjectHashSet); } Handle Factory::NewObjectHashTable( int at_least_space_for, MinimumCapacity capacity_option) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), ObjectHashTable::Allocate(isolate()->heap(), at_least_space_for, capacity_option), ObjectHashTable); } Handle Factory::NewWeakHashTable(int at_least_space_for) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION( isolate(), WeakHashTable::Allocate(isolate()->heap(), at_least_space_for, USE_DEFAULT_MINIMUM_CAPACITY, TENURED), WeakHashTable); } Handle Factory::NewDescriptorArray(int number_of_descriptors, int slack) { ASSERT(0 <= number_of_descriptors); CALL_HEAP_FUNCTION(isolate(), DescriptorArray::Allocate( isolate(), number_of_descriptors, slack), DescriptorArray); } Handle Factory::NewDeoptimizationInputData( int deopt_entry_count, PretenureFlag pretenure) { ASSERT(deopt_entry_count > 0); CALL_HEAP_FUNCTION(isolate(), DeoptimizationInputData::Allocate(isolate(), deopt_entry_count, pretenure), DeoptimizationInputData); } Handle Factory::NewDeoptimizationOutputData( int deopt_entry_count, PretenureFlag pretenure) { ASSERT(deopt_entry_count > 0); CALL_HEAP_FUNCTION(isolate(), DeoptimizationOutputData::Allocate(isolate(), deopt_entry_count, pretenure), DeoptimizationOutputData); } Handle Factory::NewAccessorPair() { CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateAccessorPair(), AccessorPair); } Handle Factory::NewTypeFeedbackInfo() { CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateTypeFeedbackInfo(), TypeFeedbackInfo); } // 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) { CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->InternalizeString(*string), 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) { CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->InternalizeStringWithKey(key), String); } template Handle Factory::InternalizeStringWithKey< SubStringKey > (SubStringKey* key); template Handle Factory::InternalizeStringWithKey< SubStringKey > (SubStringKey* key); Handle Factory::NewStringFromOneByte(Vector string, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStringFromOneByte(string, pretenure), String); } Handle Factory::NewStringFromUtf8(Vector string, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStringFromUtf8(string, pretenure), String); } Handle Factory::NewStringFromTwoByte(Vector string, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStringFromTwoByte(string, pretenure), String); } Handle Factory::NewRawOneByteString(int length, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateRawOneByteString(length, pretenure), SeqOneByteString); } Handle Factory::NewRawTwoByteString(int length, PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateRawTwoByteString(length, pretenure), SeqTwoByteString); } // 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); uint8_t* dest = str->GetChars(); dest[0] = static_cast(c1); dest[1] = static_cast(c2); return str; } else { Handle str = isolate->factory()->NewRawTwoByteString(2); 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; } Handle Factory::NewRawConsString(String::Encoding encoding) { Handle map = (encoding == String::ONE_BYTE_ENCODING) ? cons_ascii_string_map() : cons_string_map(); CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->Allocate(*map, NEW_SPACE), ConsString); } Handle 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) { isolate()->context()->mark_out_of_memory(); V8::FatalProcessOutOfMemory("String concatenation result too large."); UNREACHABLE(); return Handle::null(); } 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()); if (is_one_byte) { Handle result = NewRawOneByteString(length); 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), left, right) : ConcatStringContent(NewRawTwoByteString(length), left, right); } Handle result = NewRawConsString( (is_one_byte || is_one_byte_data_in_two_byte_string) ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING); 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), first, second); } else { return ConcatStringContent( NewRawTwoByteString(total_length), first, second); } } Handle Factory::NewRawSlicedString(String::Encoding encoding) { Handle map = (encoding == String::ONE_BYTE_ENCODING) ? sliced_ascii_string_map() : sliced_string_map(); CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->Allocate(*map, NEW_SPACE), SlicedString); } 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()); int length = end - begin; if (length <= 0) return empty_string(); if (length == 1) { return LookupSingleCharacterStringFromCode(isolate(), 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); uint8_t* dest = result->GetChars(); DisallowHeapAllocation no_gc; String::WriteToFlat(*str, dest, begin, end); return result; } else { Handle result = NewRawTwoByteString(length); uc16* dest = result->GetChars(); DisallowHeapAllocation no_gc; String::WriteToFlat(*str, dest, begin, end); return result; } } int offset = begin; while (str->IsConsString()) { Handle cons = Handle::cast(str); int split = cons->first()->length(); if (split <= offset) { // Slice is fully contained in the second part. str = Handle(cons->second(), isolate()); offset -= split; // Adjust for offset. continue; } else if (offset + length <= split) { // Slice is fully contained in the first part. str = Handle(cons->first(), isolate()); continue; } break; } if (str->IsSlicedString()) { Handle slice = Handle::cast(str); str = Handle(slice->parent(), isolate()); offset += slice->offset(); } else { str = FlattenGetString(str); } ASSERT(str->IsSeqString() || str->IsExternalString()); Handle slice = NewRawSlicedString( str->IsOneByteRepresentation() ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING); slice->set_hash_field(String::kEmptyHashField); slice->set_length(length); slice->set_parent(*str); slice->set_offset(offset); return slice; } Handle Factory::NewExternalStringFromAscii( const ExternalAsciiString::Resource* resource) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateExternalStringFromAscii(resource), String); } Handle Factory::NewExternalStringFromTwoByte( const ExternalTwoByteString::Resource* resource) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateExternalStringFromTwoByte(resource), String); } Handle Factory::NewSymbol() { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateSymbol(), Symbol); } Handle Factory::NewPrivateSymbol() { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocatePrivateSymbol(), Symbol); } Handle Factory::NewNativeContext() { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateNativeContext(), Context); } Handle Factory::NewGlobalContext(Handle function, Handle scope_info) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateGlobalContext(*function, *scope_info), Context); } Handle Factory::NewModuleContext(Handle scope_info) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateModuleContext(*scope_info), Context); } Handle Factory::NewFunctionContext(int length, Handle function) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateFunctionContext(length, *function), Context); } Handle Factory::NewCatchContext(Handle function, Handle previous, Handle name, Handle thrown_object) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateCatchContext(*function, *previous, *name, *thrown_object), Context); } Handle Factory::NewWithContext(Handle function, Handle previous, Handle extension) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateWithContext(*function, *previous, *extension), Context); } Handle Factory::NewBlockContext(Handle function, Handle previous, Handle scope_info) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateBlockContext(*function, *previous, *scope_info), Context); } Handle Factory::NewStruct(InstanceType type) { CALL_HEAP_FUNCTION( isolate(), isolate()->heap()->AllocateStruct(type), Struct); } 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