v8/src/factory.cc

2375 lines
81 KiB
C++
Raw Normal View History

// 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/factory.h"
#include "src/conversions.h"
#include "src/isolate-inl.h"
#include "src/macro-assembler.h"
namespace v8 {
namespace internal {
template<typename T>
Handle<T> Factory::New(Handle<Map> map, AllocationSpace space) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->Allocate(*map, space),
T);
}
template<typename T>
Handle<T> Factory::New(Handle<Map> map,
AllocationSpace space,
Handle<AllocationSite> allocation_site) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->Allocate(*map, space, *allocation_site),
T);
}
Handle<HeapObject> Factory::NewFillerObject(int size,
bool double_align,
AllocationSpace space) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateFillerObject(size, double_align, space),
HeapObject);
}
Handle<Box> Factory::NewBox(Handle<Object> value) {
Handle<Box> result = Handle<Box>::cast(NewStruct(BOX_TYPE));
result->set_value(*value);
return result;
}
Handle<Oddball> Factory::NewOddball(Handle<Map> map,
const char* to_string,
Handle<Object> to_number,
byte kind) {
Handle<Oddball> oddball = New<Oddball>(map, OLD_POINTER_SPACE);
Oddball::Initialize(isolate(), oddball, to_string, to_number, kind);
return oddball;
}
Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateFixedArray(size, pretenure),
FixedArray);
}
Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateFixedArrayWithFiller(size,
pretenure,
*the_hole_value()),
FixedArray);
}
Handle<FixedArray> Factory::NewUninitializedFixedArray(int size) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateUninitializedFixedArray(size),
FixedArray);
}
Handle<FixedArrayBase> Factory::NewFixedDoubleArray(int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure),
FixedArrayBase);
}
Handle<FixedArrayBase> Factory::NewFixedDoubleArrayWithHoles(
int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
Handle<FixedArrayBase> array = NewFixedDoubleArray(size, pretenure);
if (size > 0) {
Handle<FixedDoubleArray> double_array =
Handle<FixedDoubleArray>::cast(array);
for (int i = 0; i < size; ++i) {
double_array->set_the_hole(i);
}
}
return array;
}
Handle<ConstantPoolArray> Factory::NewConstantPoolArray(
const ConstantPoolArray::NumberOfEntries& small) {
ASSERT(small.total_count() > 0);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateConstantPoolArray(small),
ConstantPoolArray);
}
Handle<ConstantPoolArray> Factory::NewExtendedConstantPoolArray(
const ConstantPoolArray::NumberOfEntries& small,
const ConstantPoolArray::NumberOfEntries& extended) {
ASSERT(small.total_count() > 0);
ASSERT(extended.total_count() > 0);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateExtendedConstantPoolArray(small, extended),
ConstantPoolArray);
}
Handle<OrderedHashSet> Factory::NewOrderedHashSet() {
return OrderedHashSet::Allocate(isolate(), 4);
}
Handle<OrderedHashMap> Factory::NewOrderedHashMap() {
return OrderedHashMap::Allocate(isolate(), 4);
}
Handle<AccessorPair> Factory::NewAccessorPair() {
Handle<AccessorPair> accessors =
Handle<AccessorPair>::cast(NewStruct(ACCESSOR_PAIR_TYPE));
accessors->set_getter(*the_hole_value(), SKIP_WRITE_BARRIER);
accessors->set_setter(*the_hole_value(), SKIP_WRITE_BARRIER);
return accessors;
}
Handle<TypeFeedbackInfo> Factory::NewTypeFeedbackInfo() {
Handle<TypeFeedbackInfo> info =
Handle<TypeFeedbackInfo>::cast(NewStruct(TYPE_FEEDBACK_INFO_TYPE));
info->initialize_storage();
return info;
}
// Internalized strings are created in the old generation (data space).
Handle<String> Factory::InternalizeUtf8String(Vector<const char> string) {
Utf8StringKey key(string, isolate()->heap()->HashSeed());
return InternalizeStringWithKey(&key);
}
// Internalized strings are created in the old generation (data space).
Handle<String> Factory::InternalizeString(Handle<String> string) {
if (string->IsInternalizedString()) return string;
return StringTable::LookupString(isolate(), string);
}
Handle<String> Factory::InternalizeOneByteString(Vector<const uint8_t> string) {
OneByteStringKey key(string, isolate()->heap()->HashSeed());
return InternalizeStringWithKey(&key);
}
Handle<String> Factory::InternalizeOneByteString(
Handle<SeqOneByteString> string, int from, int length) {
SubStringKey<uint8_t> key(string, from, length);
return InternalizeStringWithKey(&key);
}
Handle<String> Factory::InternalizeTwoByteString(Vector<const uc16> string) {
TwoByteStringKey key(string, isolate()->heap()->HashSeed());
return InternalizeStringWithKey(&key);
}
template<class StringTableKey>
Handle<String> Factory::InternalizeStringWithKey(StringTableKey* key) {
return StringTable::LookupKey(isolate(), key);
}
template Handle<String> Factory::InternalizeStringWithKey<
SubStringKey<uint8_t> > (SubStringKey<uint8_t>* key);
template Handle<String> Factory::InternalizeStringWithKey<
SubStringKey<uint16_t> > (SubStringKey<uint16_t>* key);
MaybeHandle<String> Factory::NewStringFromOneByte(Vector<const uint8_t> string,
PretenureFlag pretenure) {
int length = string.length();
if (length == 1) return LookupSingleCharacterStringFromCode(string[0]);
Handle<SeqOneByteString> 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<String> Factory::NewStringFromUtf8(Vector<const char> 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<const uint8_t>::cast(string), pretenure);
}
// Non-ASCII and we need to decode.
Access<UnicodeCache::Utf8Decoder>
decoder(isolate()->unicode_cache()->utf8_decoder());
decoder->Reset(string.start() + non_ascii_start,
length - non_ascii_start);
int utf16_length = decoder->Utf16Length();
ASSERT(utf16_length > 0);
// Allocate string.
Handle<SeqTwoByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result,
NewRawTwoByteString(non_ascii_start + utf16_length, pretenure),
String);
// Copy ascii portion.
uint16_t* data = result->GetChars();
const char* ascii_data = string.start();
for (int i = 0; i < non_ascii_start; i++) {
*data++ = *ascii_data++;
}
// Now write the remainder.
decoder->WriteUtf16(data, utf16_length);
return result;
}
MaybeHandle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string,
PretenureFlag pretenure) {
int length = string.length();
const uc16* start = string.start();
if (String::IsOneByte(start, length)) {
Handle<SeqOneByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(),
result,
NewRawOneByteString(length, pretenure),
String);
CopyChars(result->GetChars(), start, length);
return result;
} else {
Handle<SeqTwoByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(),
result,
NewRawTwoByteString(length, pretenure),
String);
CopyChars(result->GetChars(), start, length);
return result;
}
}
Handle<String> Factory::NewInternalizedStringFromUtf8(Vector<const char> str,
int chars,
uint32_t hash_field) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateInternalizedStringFromUtf8(
str, chars, hash_field),
String);
}
MUST_USE_RESULT Handle<String> Factory::NewOneByteInternalizedString(
Vector<const uint8_t> str,
uint32_t hash_field) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateOneByteInternalizedString(str, hash_field),
String);
}
MUST_USE_RESULT Handle<String> Factory::NewTwoByteInternalizedString(
Vector<const uc16> str,
uint32_t hash_field) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateTwoByteInternalizedString(str, hash_field),
String);
}
Handle<String> Factory::NewInternalizedStringImpl(
Handle<String> string, int chars, uint32_t hash_field) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateInternalizedStringImpl(
*string, chars, hash_field),
String);
}
MaybeHandle<Map> Factory::InternalizedStringMapForString(
Handle<String> string) {
// If the string is in new space it cannot be used as internalized.
if (isolate()->heap()->InNewSpace(*string)) return MaybeHandle<Map>();
// 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<Map>(); // No match found.
}
}
MaybeHandle<SeqOneByteString> Factory::NewRawOneByteString(
int length, PretenureFlag pretenure) {
if (length > String::kMaxLength || length < 0) {
return isolate()->Throw<SeqOneByteString>(NewInvalidStringLengthError());
}
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateRawOneByteString(length, pretenure),
SeqOneByteString);
}
MaybeHandle<SeqTwoByteString> Factory::NewRawTwoByteString(
int length, PretenureFlag pretenure) {
if (length > String::kMaxLength || length < 0) {
return isolate()->Throw<SeqTwoByteString>(NewInvalidStringLengthError());
}
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateRawTwoByteString(length, pretenure),
SeqTwoByteString);
}
Handle<String> 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<uint8_t>(code);
Handle<String> result =
InternalizeOneByteString(Vector<const uint8_t>(buffer, 1));
single_character_string_cache()->set(code, *result);
return result;
}
ASSERT(code <= String::kMaxUtf16CodeUnitU);
Handle<SeqTwoByteString> result = NewRawTwoByteString(1).ToHandleChecked();
result->SeqTwoByteStringSet(0, static_cast<uint16_t>(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<String> 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<String> 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<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) {
// We can do this.
ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1)); // because of this.
Handle<SeqOneByteString> str =
isolate->factory()->NewRawOneByteString(2).ToHandleChecked();
uint8_t* dest = str->GetChars();
dest[0] = static_cast<uint8_t>(c1);
dest[1] = static_cast<uint8_t>(c2);
return str;
} else {
Handle<SeqTwoByteString> str =
isolate->factory()->NewRawTwoByteString(2).ToHandleChecked();
uc16* dest = str->GetChars();
dest[0] = c1;
dest[1] = c2;
return str;
}
}
template<typename SinkChar, typename StringType>
Handle<String> ConcatStringContent(Handle<StringType> result,
Handle<String> first,
Handle<String> 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<String> Factory::NewConsString(Handle<String> left,
Handle<String> 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<String>(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<SeqOneByteString> result =
NewRawOneByteString(length).ToHandleChecked();
DisallowHeapAllocation no_gc;
uint8_t* dest = result->GetChars();
// Copy left part.
const uint8_t* src = left->IsExternalString()
? Handle<ExternalAsciiString>::cast(left)->GetChars()
: Handle<SeqOneByteString>::cast(left)->GetChars();
for (int i = 0; i < left_length; i++) *dest++ = src[i];
// Copy right part.
src = right->IsExternalString()
? Handle<ExternalAsciiString>::cast(right)->GetChars()
: Handle<SeqOneByteString>::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<uint8_t>(
NewRawOneByteString(length).ToHandleChecked(), left, right)
: ConcatStringContent<uc16>(
NewRawTwoByteString(length).ToHandleChecked(), left, right);
}
Handle<Map> map = (is_one_byte || is_one_byte_data_in_two_byte_string)
? cons_ascii_string_map() : cons_string_map();
Handle<ConsString> result = New<ConsString>(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<String> Factory::NewFlatConcatString(Handle<String> first,
Handle<String> second) {
int total_length = first->length() + second->length();
if (first->IsOneByteRepresentation() && second->IsOneByteRepresentation()) {
return ConcatStringContent<uint8_t>(
NewRawOneByteString(total_length).ToHandleChecked(), first, second);
} else {
return ConcatStringContent<uc16>(
NewRawTwoByteString(total_length).ToHandleChecked(), first, second);
}
}
Handle<String> Factory::NewProperSubString(Handle<String> 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<SeqOneByteString> result =
NewRawOneByteString(length).ToHandleChecked();
uint8_t* dest = result->GetChars();
DisallowHeapAllocation no_gc;
String::WriteToFlat(*str, dest, begin, end);
return result;
} else {
Handle<SeqTwoByteString> 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<SlicedString> slice = Handle<SlicedString>::cast(str);
str = Handle<String>(slice->parent(), isolate());
offset += slice->offset();
}
ASSERT(str->IsSeqString() || str->IsExternalString());
Handle<Map> map = str->IsOneByteRepresentation() ? sliced_ascii_string_map()
: sliced_string_map();
Handle<SlicedString> slice = New<SlicedString>(map, NEW_SPACE);
slice->set_hash_field(String::kEmptyHashField);
slice->set_length(length);
slice->set_parent(*str);
slice->set_offset(offset);
return slice;
}
MaybeHandle<String> Factory::NewExternalStringFromAscii(
const ExternalAsciiString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
return isolate()->Throw<String>(NewInvalidStringLengthError());
}
Handle<Map> map = external_ascii_string_map();
Handle<ExternalAsciiString> external_string =
New<ExternalAsciiString>(map, NEW_SPACE);
external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource);
return external_string;
}
MaybeHandle<String> Factory::NewExternalStringFromTwoByte(
const ExternalTwoByteString::Resource* resource) {
size_t length = resource->length();
if (length > static_cast<size_t>(String::kMaxLength)) {
return isolate()->Throw<String>(NewInvalidStringLengthError());
}
// 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<int>(length));
Handle<Map> map = is_one_byte ?
external_string_with_one_byte_data_map() : external_string_map();
Handle<ExternalTwoByteString> external_string =
New<ExternalTwoByteString>(map, NEW_SPACE);
external_string->set_length(static_cast<int>(length));
external_string->set_hash_field(String::kEmptyHashField);
external_string->set_resource(resource);
return external_string;
}
Handle<Symbol> Factory::NewSymbol() {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateSymbol(),
Symbol);
}
Handle<Symbol> Factory::NewPrivateSymbol() {
Handle<Symbol> symbol = NewSymbol();
symbol->set_is_private(true);
return symbol;
}
Handle<Context> Factory::NewNativeContext() {
Handle<FixedArray> array = NewFixedArray(Context::NATIVE_CONTEXT_SLOTS);
array->set_map_no_write_barrier(*native_context_map());
Handle<Context> context = Handle<Context>::cast(array);
context->set_js_array_maps(*undefined_value());
ASSERT(context->IsNativeContext());
return context;
}
Handle<Context> Factory::NewGlobalContext(Handle<JSFunction> function,
Handle<ScopeInfo> scope_info) {
Handle<FixedArray> array =
NewFixedArray(scope_info->ContextLength(), TENURED);
array->set_map_no_write_barrier(*global_context_map());
Handle<Context> context = Handle<Context>::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<Context> Factory::NewModuleContext(Handle<ScopeInfo> scope_info) {
Handle<FixedArray> array =
NewFixedArray(scope_info->ContextLength(), TENURED);
array->set_map_no_write_barrier(*module_context_map());
// Instance link will be set later.
Handle<Context> context = Handle<Context>::cast(array);
context->set_extension(Smi::FromInt(0));
return context;
}
Handle<Context> Factory::NewFunctionContext(int length,
Handle<JSFunction> function) {
ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
Handle<FixedArray> array = NewFixedArray(length);
array->set_map_no_write_barrier(*function_context_map());
Handle<Context> context = Handle<Context>::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<Context> Factory::NewCatchContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<String> name,
Handle<Object> thrown_object) {
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
Handle<FixedArray> array = NewFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
array->set_map_no_write_barrier(*catch_context_map());
Handle<Context> context = Handle<Context>::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<Context> Factory::NewWithContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<JSReceiver> extension) {
Handle<FixedArray> array = NewFixedArray(Context::MIN_CONTEXT_SLOTS);
array->set_map_no_write_barrier(*with_context_map());
Handle<Context> context = Handle<Context>::cast(array);
context->set_closure(*function);
context->set_previous(*previous);
context->set_extension(*extension);
context->set_global_object(previous->global_object());
return context;
}
Handle<Context> Factory::NewBlockContext(Handle<JSFunction> function,
Handle<Context> previous,
Handle<ScopeInfo> scope_info) {
Handle<FixedArray> array =
NewFixedArrayWithHoles(scope_info->ContextLength());
array->set_map_no_write_barrier(*block_context_map());
Handle<Context> context = Handle<Context>::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<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateStruct(type),
Struct);
}
Handle<CodeCache> Factory::NewCodeCache() {
Handle<CodeCache> code_cache =
Handle<CodeCache>::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<AliasedArgumentsEntry> Factory::NewAliasedArgumentsEntry(
int aliased_context_slot) {
Handle<AliasedArgumentsEntry> entry = Handle<AliasedArgumentsEntry>::cast(
NewStruct(ALIASED_ARGUMENTS_ENTRY_TYPE));
entry->set_aliased_context_slot(aliased_context_slot);
return entry;
}
Handle<DeclaredAccessorDescriptor> Factory::NewDeclaredAccessorDescriptor() {
return Handle<DeclaredAccessorDescriptor>::cast(
NewStruct(DECLARED_ACCESSOR_DESCRIPTOR_TYPE));
}
Handle<DeclaredAccessorInfo> Factory::NewDeclaredAccessorInfo() {
Handle<DeclaredAccessorInfo> info =
Handle<DeclaredAccessorInfo>::cast(
NewStruct(DECLARED_ACCESSOR_INFO_TYPE));
info->set_flag(0); // Must clear the flag, it was initialized as undefined.
return info;
}
Handle<ExecutableAccessorInfo> Factory::NewExecutableAccessorInfo() {
Handle<ExecutableAccessorInfo> info =
Handle<ExecutableAccessorInfo>::cast(
NewStruct(EXECUTABLE_ACCESSOR_INFO_TYPE));
info->set_flag(0); // Must clear the flag, it was initialized as undefined.
return info;
}
Handle<Script> Factory::NewScript(Handle<String> source) {
// Generate id for this script.
Heap* heap = isolate()->heap();
int id = heap->last_script_id()->value() + 1;
if (!Smi::IsValid(id) || id < 0) id = 1;
heap->set_last_script_id(Smi::FromInt(id));
// Create and initialize script object.
Handle<Foreign> wrapper = NewForeign(0, TENURED);
Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
script->set_source(*source);
script->set_name(heap->undefined_value());
script->set_id(Smi::FromInt(id));
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
script->set_context_data(heap->undefined_value());
script->set_type(Smi::FromInt(Script::TYPE_NORMAL));
script->set_wrapper(*wrapper);
script->set_line_ends(heap->undefined_value());
script->set_eval_from_shared(heap->undefined_value());
script->set_eval_from_instructions_offset(Smi::FromInt(0));
script->set_flags(Smi::FromInt(0));
return script;
}
Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateForeign(addr, pretenure),
Foreign);
}
Handle<Foreign> Factory::NewForeign(const AccessorDescriptor* desc) {
return NewForeign((Address) desc, TENURED);
}
Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
ASSERT(0 <= length);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateByteArray(length, pretenure),
ByteArray);
}
Handle<ExternalArray> Factory::NewExternalArray(int length,
ExternalArrayType array_type,
void* external_pointer,
PretenureFlag pretenure) {
ASSERT(0 <= length && length <= Smi::kMaxValue);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateExternalArray(length,
array_type,
external_pointer,
pretenure),
ExternalArray);
}
Handle<FixedTypedArrayBase> Factory::NewFixedTypedArray(
int length,
ExternalArrayType array_type,
PretenureFlag pretenure) {
ASSERT(0 <= length && length <= Smi::kMaxValue);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateFixedTypedArray(length,
array_type,
pretenure),
FixedTypedArrayBase);
}
Handle<Cell> Factory::NewCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateCell(*value),
Cell);
}
Handle<PropertyCell> Factory::NewPropertyCellWithHole() {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocatePropertyCell(),
PropertyCell);
}
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
Handle<PropertyCell> cell = NewPropertyCellWithHole();
PropertyCell::SetValueInferType(cell, value);
return cell;
}
Handle<AllocationSite> Factory::NewAllocationSite() {
Handle<Map> map = allocation_site_map();
Handle<AllocationSite> site = New<AllocationSite>(map, OLD_POINTER_SPACE);
site->Initialize();
// Link the site
site->set_weak_next(isolate()->heap()->allocation_sites_list());
isolate()->heap()->set_allocation_sites_list(*site);
return site;
}
Handle<Map> Factory::NewMap(InstanceType type,
int instance_size,
ElementsKind elements_kind) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateMap(type, instance_size, elements_kind),
Map);
}
Handle<JSObject> Factory::CopyJSObject(Handle<JSObject> object) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyJSObject(*object, NULL),
JSObject);
}
Handle<JSObject> Factory::CopyJSObjectWithAllocationSite(
Handle<JSObject> object,
Handle<AllocationSite> site) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyJSObject(
*object,
site.is_null() ? NULL : *site),
JSObject);
}
Handle<FixedArray> Factory::CopyFixedArrayWithMap(Handle<FixedArray> array,
Handle<Map> map) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyFixedArrayWithMap(*array, *map),
FixedArray);
}
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyFixedArray(*array),
FixedArray);
}
Handle<FixedArray> Factory::CopyAndTenureFixedCOWArray(
Handle<FixedArray> array) {
ASSERT(isolate()->heap()->InNewSpace(*array));
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyAndTenureFixedCOWArray(*array),
FixedArray);
}
Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray(
Handle<FixedDoubleArray> array) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyFixedDoubleArray(*array),
FixedDoubleArray);
}
Handle<ConstantPoolArray> Factory::CopyConstantPoolArray(
Handle<ConstantPoolArray> array) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyConstantPoolArray(*array),
ConstantPoolArray);
}
Handle<Object> Factory::NewNumber(double value,
PretenureFlag pretenure) {
// We need to distinguish the minus zero value and this cannot be
// done after conversion to int. Doing this by comparing bit
// patterns is faster than using fpclassify() et al.
if (IsMinusZero(value)) return NewHeapNumber(-0.0, pretenure);
int int_value = FastD2I(value);
if (value == int_value && Smi::IsValid(int_value)) {
return handle(Smi::FromInt(int_value), isolate());
}
// Materialize the value in the heap.
return NewHeapNumber(value, pretenure);
}
Handle<Object> Factory::NewNumberFromInt(int32_t value,
PretenureFlag pretenure) {
if (Smi::IsValid(value)) return handle(Smi::FromInt(value), isolate());
// Bypass NumberFromDouble to avoid various redundant checks.
return NewHeapNumber(FastI2D(value), pretenure);
}
Handle<Object> Factory::NewNumberFromUint(uint32_t value,
PretenureFlag pretenure) {
int32_t int32v = static_cast<int32_t>(value);
if (int32v >= 0 && Smi::IsValid(int32v)) {
return handle(Smi::FromInt(int32v), isolate());
}
return NewHeapNumber(FastUI2D(value), pretenure);
}
Handle<HeapNumber> Factory::NewHeapNumber(double value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateHeapNumber(value, pretenure), HeapNumber);
}
Handle<Object> Factory::NewTypeError(const char* message,
Vector< Handle<Object> > args) {
return NewError("MakeTypeError", message, args);
}
Handle<Object> Factory::NewTypeError(Handle<String> message) {
return NewError("$TypeError", message);
}
Handle<Object> Factory::NewRangeError(const char* message,
Vector< Handle<Object> > args) {
return NewError("MakeRangeError", message, args);
}
Handle<Object> Factory::NewRangeError(Handle<String> message) {
return NewError("$RangeError", message);
}
Handle<Object> Factory::NewSyntaxError(const char* message,
Handle<JSArray> args) {
return NewError("MakeSyntaxError", message, args);
}
Handle<Object> Factory::NewSyntaxError(Handle<String> message) {
return NewError("$SyntaxError", message);
}
Handle<Object> Factory::NewReferenceError(const char* message,
Vector< Handle<Object> > args) {
return NewError("MakeReferenceError", message, args);
}
Handle<Object> Factory::NewReferenceError(const char* message,
Handle<JSArray> args) {
return NewError("MakeReferenceError", message, args);
}
Handle<Object> Factory::NewReferenceError(Handle<String> message) {
return NewError("$ReferenceError", message);
}
Handle<Object> Factory::NewError(const char* maker,
const char* message,
Vector< Handle<Object> > args) {
// Instantiate a closeable HandleScope for EscapeFrom.
v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate()));
Handle<FixedArray> array = NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
array->set(i, *args[i]);
}
Handle<JSArray> object = NewJSArrayWithElements(array);
Handle<Object> result = NewError(maker, message, object);
return result.EscapeFrom(&scope);
}
Handle<Object> Factory::NewEvalError(const char* message,
Vector< Handle<Object> > args) {
return NewError("MakeEvalError", message, args);
}
Handle<Object> Factory::NewError(const char* message,
Vector< Handle<Object> > args) {
return NewError("MakeError", message, args);
}
Handle<String> Factory::EmergencyNewError(const char* message,
Handle<JSArray> args) {
const int kBufferSize = 1000;
char buffer[kBufferSize];
size_t space = kBufferSize;
char* p = &buffer[0];
Vector<char> v(buffer, kBufferSize);
StrNCpy(v, message, space);
space -= Min(space, strlen(message));
p = &buffer[kBufferSize] - space;
for (unsigned i = 0; i < ARRAY_SIZE(args); i++) {
if (space > 0) {
*p++ = ' ';
space--;
if (space > 0) {
Handle<String> arg_str = Handle<String>::cast(
Object::GetElement(isolate(), args, i).ToHandleChecked());
SmartArrayPointer<char> arg = arg_str->ToCString();
Vector<char> v2(p, static_cast<int>(space));
StrNCpy(v2, arg.get(), space);
space -= Min(space, strlen(arg.get()));
p = &buffer[kBufferSize] - space;
}
}
}
if (space > 0) {
*p = '\0';
} else {
buffer[kBufferSize - 1] = '\0';
}
return NewStringFromUtf8(CStrVector(buffer), TENURED).ToHandleChecked();
}
Handle<Object> Factory::NewError(const char* maker,
const char* message,
Handle<JSArray> args) {
Handle<String> make_str = InternalizeUtf8String(maker);
Handle<Object> fun_obj = Object::GetProperty(
isolate()->js_builtins_object(), make_str).ToHandleChecked();
// If the builtins haven't been properly configured yet this error
// constructor may not have been defined. Bail out.
if (!fun_obj->IsJSFunction()) {
return EmergencyNewError(message, args);
}
Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
Handle<Object> message_obj = InternalizeUtf8String(message);
Handle<Object> argv[] = { message_obj, args };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
Handle<Object> result;
Handle<Object> exception;
if (!Execution::TryCall(fun,
isolate()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&exception).ToHandle(&result)) {
return exception;
}
return result;
}
Handle<Object> Factory::NewError(Handle<String> message) {
return NewError("$Error", message);
}
Handle<Object> Factory::NewError(const char* constructor,
Handle<String> message) {
Handle<String> constr = InternalizeUtf8String(constructor);
Handle<JSFunction> fun = Handle<JSFunction>::cast(Object::GetProperty(
isolate()->js_builtins_object(), constr).ToHandleChecked());
Handle<Object> argv[] = { message };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
Handle<Object> result;
Handle<Object> exception;
if (!Execution::TryCall(fun,
isolate()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
&exception).ToHandle(&result)) {
return exception;
}
return result;
}
void Factory::InitializeFunction(Handle<JSFunction> function,
Handle<SharedFunctionInfo> info,
Handle<Context> context) {
function->initialize_properties();
function->initialize_elements();
function->set_shared(*info);
function->set_code(info->code());
function->set_context(*context);
function->set_prototype_or_initial_map(*the_hole_value());
function->set_literals_or_bindings(*empty_fixed_array());
function->set_next_function_link(*undefined_value());
}
Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
Handle<SharedFunctionInfo> info,
Handle<Context> context,
PretenureFlag pretenure) {
AllocationSpace space = pretenure == TENURED ? OLD_POINTER_SPACE : NEW_SPACE;
Handle<JSFunction> result = New<JSFunction>(map, space);
InitializeFunction(result, info, context);
return result;
}
Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
Handle<String> name,
MaybeHandle<Code> code) {
Handle<Context> context(isolate()->context()->native_context());
Handle<SharedFunctionInfo> info = NewSharedFunctionInfo(name, code);
ASSERT((info->strict_mode() == SLOPPY) &&
(map.is_identical_to(isolate()->sloppy_function_map()) ||
map.is_identical_to(
isolate()->sloppy_function_without_prototype_map()) ||
map.is_identical_to(
isolate()->sloppy_function_with_readonly_prototype_map())));
return NewFunction(map, info, context);
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name) {
return NewFunction(
isolate()->sloppy_function_map(), name, MaybeHandle<Code>());
}
Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<Code> code) {
return NewFunction(
isolate()->sloppy_function_without_prototype_map(), name, code);
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<Code> code,
Handle<Object> prototype,
bool read_only_prototype) {
Handle<Map> map = read_only_prototype
? isolate()->sloppy_function_with_readonly_prototype_map()
: isolate()->sloppy_function_map();
Handle<JSFunction> result = NewFunction(map, name, code);
result->set_prototype_or_initial_map(*prototype);
return result;
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<Code> code,
Handle<Object> prototype,
InstanceType type,
int instance_size,
bool read_only_prototype) {
// Allocate the function
Handle<JSFunction> function = NewFunction(
name, code, prototype, read_only_prototype);
Handle<Map> initial_map = NewMap(
type, instance_size, GetInitialFastElementsKind());
if (prototype->IsTheHole() && !function->shared()->is_generator()) {
prototype = NewFunctionPrototype(function);
}
initial_map->set_prototype(*prototype);
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
return function;
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<Code> code,
InstanceType type,
int instance_size) {
return NewFunction(name, code, the_hole_value(), type, instance_size);
}
Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
// Make sure to use globals from the function's context, since the function
// can be from a different context.
Handle<Context> native_context(function->context()->native_context());
Handle<Map> new_map;
if (function->shared()->is_generator()) {
// Generator prototypes can share maps since they don't have "constructor"
// properties.
new_map = handle(native_context->generator_object_prototype_map());
} else {
// Each function prototype gets a fresh map to avoid unwanted sharing of
// maps between prototypes of different constructors.
Handle<JSFunction> object_function(native_context->object_function());
ASSERT(object_function->has_initial_map());
new_map = Map::Copy(handle(object_function->initial_map()));
}
Handle<JSObject> prototype = NewJSObjectFromMap(new_map);
if (!function->shared()->is_generator()) {
JSObject::AddProperty(prototype, constructor_string(), function, DONT_ENUM);
}
return prototype;
}
Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> info,
Handle<Context> context,
PretenureFlag pretenure) {
int map_index = Context::FunctionMapIndex(info->strict_mode(),
info->is_generator());
Handle<Map> map(Map::cast(context->native_context()->get(map_index)));
Handle<JSFunction> result = NewFunction(map, info, context, pretenure);
if (info->ic_age() != isolate()->heap()->global_ic_age()) {
info->ResetForNewContext(isolate()->heap()->global_ic_age());
}
int index = info->SearchOptimizedCodeMap(context->native_context(),
BailoutId::None());
if (!info->bound() && index < 0) {
int number_of_literals = info->num_literals();
Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
if (number_of_literals > 0) {
// Store the native context in the literals array prefix. This
// context will be used when creating object, regexp and array
// literals in this function.
literals->set(JSFunction::kLiteralNativeContextIndex,
context->native_context());
}
result->set_literals(*literals);
}
if (index > 0) {
// Caching of optimized code enabled and optimized code found.
FixedArray* literals = info->GetLiteralsFromOptimizedCodeMap(index);
if (literals != NULL) result->set_literals(literals);
Code* code = info->GetCodeFromOptimizedCodeMap(index);
ASSERT(!code->marked_for_deoptimization());
result->ReplaceCode(code);
return result;
}
if (isolate()->use_crankshaft() &&
FLAG_always_opt &&
result->is_compiled() &&
!info->is_toplevel() &&
info->allows_lazy_compilation() &&
!info->optimization_disabled() &&
!isolate()->DebuggerHasBreakPoints()) {
result->MarkForOptimization();
}
return result;
}
Handle<ScopeInfo> Factory::NewScopeInfo(int length) {
Handle<FixedArray> array = NewFixedArray(length, TENURED);
array->set_map_no_write_barrier(*scope_info_map());
Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(array);
return scope_info;
}
Handle<JSObject> Factory::NewExternal(void* value) {
Handle<Foreign> foreign = NewForeign(static_cast<Address>(value));
Handle<JSObject> external = NewJSObjectFromMap(external_map());
external->SetInternalField(0, *foreign);
return external;
}
Handle<Code> Factory::NewCodeRaw(int object_size, bool immovable) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateCode(object_size, immovable),
Code);
}
Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_ref,
bool immovable,
bool crankshafted,
int prologue_offset,
bool is_debug) {
Handle<ByteArray> reloc_info = NewByteArray(desc.reloc_size, TENURED);
Handle<ConstantPoolArray> constant_pool =
desc.origin->NewConstantPool(isolate());
// Compute size.
int body_size = RoundUp(desc.instr_size, kObjectAlignment);
int obj_size = Code::SizeFor(body_size);
Handle<Code> code = NewCodeRaw(obj_size, immovable);
ASSERT(isolate()->code_range() == NULL ||
!isolate()->code_range()->valid() ||
isolate()->code_range()->contains(code->address()));
// The code object has not been fully initialized yet. We rely on the
// fact that no allocation will happen from this point on.
DisallowHeapAllocation no_gc;
code->set_gc_metadata(Smi::FromInt(0));
code->set_ic_age(isolate()->heap()->global_ic_age());
code->set_instruction_size(desc.instr_size);
code->set_relocation_info(*reloc_info);
code->set_flags(flags);
code->set_raw_kind_specific_flags1(0);
code->set_raw_kind_specific_flags2(0);
code->set_is_crankshafted(crankshafted);
code->set_deoptimization_data(*empty_fixed_array(), SKIP_WRITE_BARRIER);
code->set_raw_type_feedback_info(*undefined_value());
code->set_next_code_link(*undefined_value());
code->set_handler_table(*empty_fixed_array(), SKIP_WRITE_BARRIER);
code->set_prologue_offset(prologue_offset);
if (code->kind() == Code::OPTIMIZED_FUNCTION) {
code->set_marked_for_deoptimization(false);
}
if (is_debug) {
ASSERT(code->kind() == Code::FUNCTION);
code->set_has_debug_break_slots(true);
}
desc.origin->PopulateConstantPool(*constant_pool);
code->set_constant_pool(*constant_pool);
// Allow self references to created code object by patching the handle to
// point to the newly allocated Code object.
if (!self_ref.is_null()) *(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->CopyFrom(desc);
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) code->ObjectVerify();
#endif
return code;
}
Handle<Code> Factory::CopyCode(Handle<Code> code) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyCode(*code),
Code);
}
Handle<Code> Factory::CopyCode(Handle<Code> code, Vector<byte> reloc_info) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->CopyCode(*code, reloc_info),
Code);
}
Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure) {
JSFunction::EnsureHasInitialMap(constructor);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(*constructor, pretenure), JSObject);
}
Handle<JSObject> Factory::NewJSObjectWithMemento(
Handle<JSFunction> constructor,
Handle<AllocationSite> site) {
JSFunction::EnsureHasInitialMap(constructor);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(*constructor, NOT_TENURED, *site),
JSObject);
}
Handle<JSModule> Factory::NewJSModule(Handle<Context> context,
Handle<ScopeInfo> scope_info) {
// Allocate a fresh map. Modules do not have a prototype.
Handle<Map> map = NewMap(JS_MODULE_TYPE, JSModule::kSize);
// Allocate the object based on the map.
Handle<JSModule> module =
Handle<JSModule>::cast(NewJSObjectFromMap(map, TENURED));
module->set_context(*context);
module->set_scope_info(*scope_info);
return module;
}
Handle<GlobalObject> Factory::NewGlobalObject(Handle<JSFunction> constructor) {
ASSERT(constructor->has_initial_map());
Handle<Map> map(constructor->initial_map());
ASSERT(map->is_dictionary_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
// require us to change property values to PropertyCells.
ASSERT(map->NextFreePropertyIndex() == 0);
// Make sure we don't have a ton of pre-allocated slots in the
// global objects. They will be unused once we normalize the object.
ASSERT(map->unused_property_fields() == 0);
ASSERT(map->inobject_properties() == 0);
// Initial size of the backing store to avoid resize of the storage during
// bootstrapping. The size differs between the JS global object ad the
// builtins object.
int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
// Allocate a dictionary object for backing storage.
int at_least_space_for = map->NumberOfOwnDescriptors() * 2 + initial_size;
Handle<NameDictionary> dictionary =
NameDictionary::New(isolate(), at_least_space_for);
// The global object might be created from an object template with accessors.
// Fill these accessors into the dictionary.
Handle<DescriptorArray> descs(map->instance_descriptors());
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
Handle<Name> name(descs->GetKey(i));
Handle<Object> value(descs->GetCallbacksObject(i), isolate());
Handle<PropertyCell> cell = NewPropertyCell(value);
// |dictionary| already contains enough space for all properties.
USE(NameDictionary::Add(dictionary, name, cell, d));
}
// Allocate the global object and initialize it with the backing store.
Handle<GlobalObject> global = New<GlobalObject>(map, OLD_POINTER_SPACE);
isolate()->heap()->InitializeJSObjectFromMap(*global, *dictionary, *map);
// Create a new map for the global object.
Handle<Map> new_map = Map::CopyDropDescriptors(map);
new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(*new_map);
global->set_properties(*dictionary);
// Make sure result is a global object with properties in dictionary.
ASSERT(global->IsGlobalObject() && !global->HasFastProperties());
return global;
}
Handle<JSObject> Factory::NewJSObjectFromMap(
Handle<Map> map,
PretenureFlag pretenure,
bool alloc_props,
Handle<AllocationSite> allocation_site) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObjectFromMap(
*map,
pretenure,
alloc_props,
allocation_site.is_null() ? NULL : *allocation_site),
JSObject);
}
Handle<JSArray> Factory::NewJSArray(ElementsKind elements_kind,
PretenureFlag pretenure) {
Context* native_context = isolate()->context()->native_context();
JSFunction* array_function = native_context->array_function();
Map* map = array_function->initial_map();
Map* transition_map = isolate()->get_initial_js_array_map(elements_kind);
if (transition_map != NULL) map = transition_map;
return Handle<JSArray>::cast(NewJSObjectFromMap(handle(map), pretenure));
}
Handle<JSArray> Factory::NewJSArray(ElementsKind elements_kind,
int length,
int capacity,
ArrayStorageAllocationMode mode,
PretenureFlag pretenure) {
Handle<JSArray> array = NewJSArray(elements_kind, pretenure);
NewJSArrayStorage(array, length, capacity, mode);
return array;
}
Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArrayBase> elements,
ElementsKind elements_kind,
int length,
PretenureFlag pretenure) {
ASSERT(length <= elements->length());
Handle<JSArray> array = NewJSArray(elements_kind, pretenure);
array->set_elements(*elements);
array->set_length(Smi::FromInt(length));
JSObject::ValidateElements(array);
return array;
}
void Factory::NewJSArrayStorage(Handle<JSArray> array,
int length,
int capacity,
ArrayStorageAllocationMode mode) {
ASSERT(capacity >= length);
if (capacity == 0) {
array->set_length(Smi::FromInt(0));
array->set_elements(*empty_fixed_array());
return;
}
Handle<FixedArrayBase> elms;
ElementsKind elements_kind = array->GetElementsKind();
if (IsFastDoubleElementsKind(elements_kind)) {
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
elms = NewFixedDoubleArray(capacity);
} else {
ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
elms = NewFixedDoubleArrayWithHoles(capacity);
}
} else {
ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
elms = NewUninitializedFixedArray(capacity);
} else {
ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
elms = NewFixedArrayWithHoles(capacity);
}
}
array->set_elements(*elms);
array->set_length(Smi::FromInt(length));
}
Handle<JSGeneratorObject> Factory::NewJSGeneratorObject(
Handle<JSFunction> function) {
ASSERT(function->shared()->is_generator());
JSFunction::EnsureHasInitialMap(function);
Handle<Map> map(function->initial_map());
ASSERT(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObjectFromMap(*map),
JSGeneratorObject);
}
Handle<JSArrayBuffer> Factory::NewJSArrayBuffer() {
Handle<JSFunction> array_buffer_fun(
isolate()->context()->native_context()->array_buffer_fun());
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(*array_buffer_fun),
JSArrayBuffer);
}
Handle<JSDataView> Factory::NewJSDataView() {
Handle<JSFunction> data_view_fun(
isolate()->context()->native_context()->data_view_fun());
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(*data_view_fun),
JSDataView);
}
static JSFunction* GetTypedArrayFun(ExternalArrayType type,
Isolate* isolate) {
Context* native_context = isolate->context()->native_context();
switch (type) {
#define TYPED_ARRAY_FUN(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: \
return native_context->type##_array_fun();
TYPED_ARRAYS(TYPED_ARRAY_FUN)
#undef TYPED_ARRAY_FUN
default:
UNREACHABLE();
return NULL;
}
}
Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
Handle<JSFunction> typed_array_fun_handle(GetTypedArrayFun(type, isolate()));
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSObject(*typed_array_fun_handle),
JSTypedArray);
}
Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
// Allocate map.
// TODO(rossberg): Once we optimize proxies, think about a scheme to share
// maps. Will probably depend on the identity of the handler object, too.
Handle<Map> map = NewMap(JS_PROXY_TYPE, JSProxy::kSize);
map->set_prototype(*prototype);
// Allocate the proxy object.
Handle<JSProxy> result = New<JSProxy>(map, NEW_SPACE);
result->InitializeBody(map->instance_size(), Smi::FromInt(0));
result->set_handler(*handler);
result->set_hash(*undefined_value(), SKIP_WRITE_BARRIER);
return result;
}
Handle<JSProxy> Factory::NewJSFunctionProxy(Handle<Object> handler,
Handle<Object> call_trap,
Handle<Object> construct_trap,
Handle<Object> prototype) {
// Allocate map.
// TODO(rossberg): Once we optimize proxies, think about a scheme to share
// maps. Will probably depend on the identity of the handler object, too.
Handle<Map> map = NewMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
map->set_prototype(*prototype);
// Allocate the proxy object.
Handle<JSFunctionProxy> result = New<JSFunctionProxy>(map, NEW_SPACE);
result->InitializeBody(map->instance_size(), Smi::FromInt(0));
result->set_handler(*handler);
result->set_hash(*undefined_value(), SKIP_WRITE_BARRIER);
result->set_call_trap(*call_trap);
result->set_construct_trap(*construct_trap);
return result;
}
void Factory::ReinitializeJSReceiver(Handle<JSReceiver> object,
InstanceType type,
int size) {
ASSERT(type >= FIRST_JS_OBJECT_TYPE);
// Allocate fresh map.
// TODO(rossberg): Once we optimize proxies, cache these maps.
Handle<Map> map = NewMap(type, size);
// Check that the receiver has at least the size of the fresh object.
int size_difference = object->map()->instance_size() - map->instance_size();
ASSERT(size_difference >= 0);
map->set_prototype(object->map()->prototype());
// Allocate the backing storage for the properties.
int prop_size = map->InitialPropertiesLength();
Handle<FixedArray> properties = NewFixedArray(prop_size, TENURED);
Heap* heap = isolate()->heap();
MaybeHandle<SharedFunctionInfo> shared;
if (type == JS_FUNCTION_TYPE) {
OneByteStringKey key(STATIC_ASCII_VECTOR("<freezing call trap>"),
heap->HashSeed());
Handle<String> name = InternalizeStringWithKey(&key);
shared = NewSharedFunctionInfo(name, MaybeHandle<Code>());
}
// In order to keep heap in consistent state there must be no allocations
// before object re-initialization is finished and filler object is installed.
DisallowHeapAllocation no_allocation;
// Put in filler if the new object is smaller than the old.
if (size_difference > 0) {
Address address = object->address() + map->instance_size();
heap->CreateFillerObjectAt(address, size_difference);
heap->AdjustLiveBytes(address, -size_difference, Heap::FROM_MUTATOR);
}
// Reset the map for the object.
object->synchronized_set_map(*map);
Handle<JSObject> jsobj = Handle<JSObject>::cast(object);
// Reinitialize the object from the constructor map.
heap->InitializeJSObjectFromMap(*jsobj, *properties, *map);
// Functions require some minimal initialization.
if (type == JS_FUNCTION_TYPE) {
map->set_function_with_prototype(true);
Handle<JSFunction> js_function = Handle<JSFunction>::cast(object);
Handle<Context> context(isolate()->context()->native_context());
InitializeFunction(js_function, shared.ToHandleChecked(), context);
}
}
void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
Handle<JSFunction> constructor) {
ASSERT(constructor->has_initial_map());
Handle<Map> map(constructor->initial_map(), isolate());
// The proxy's hash should be retained across reinitialization.
Handle<Object> hash(object->hash(), isolate());
// Check that the already allocated object has the same size and type as
// objects allocated using the constructor.
ASSERT(map->instance_size() == object->map()->instance_size());
ASSERT(map->instance_type() == object->map()->instance_type());
// Allocate the backing storage for the properties.
int prop_size = map->InitialPropertiesLength();
Handle<FixedArray> properties = NewFixedArray(prop_size, TENURED);
// In order to keep heap in consistent state there must be no allocations
// before object re-initialization is finished.
DisallowHeapAllocation no_allocation;
// Reset the map for the object.
object->synchronized_set_map(*map);
Heap* heap = isolate()->heap();
// Reinitialize the object from the constructor map.
heap->InitializeJSObjectFromMap(*object, *properties, *map);
// Restore the saved hash.
object->set_hash(*hash);
}
void Factory::BecomeJSObject(Handle<JSReceiver> object) {
ReinitializeJSReceiver(object, JS_OBJECT_TYPE, JSObject::kHeaderSize);
}
void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
ReinitializeJSReceiver(object, JS_FUNCTION_TYPE, JSFunction::kSize);
}
Handle<FixedArray> Factory::NewTypeFeedbackVector(int slot_count) {
// Ensure we can skip the write barrier
ASSERT_EQ(isolate()->heap()->uninitialized_symbol(),
*TypeFeedbackInfo::UninitializedSentinel(isolate()));
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateFixedArrayWithFiller(
slot_count,
TENURED,
*TypeFeedbackInfo::UninitializedSentinel(isolate())),
FixedArray);
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<String> name,
int number_of_literals,
bool is_generator,
Handle<Code> code,
Handle<ScopeInfo> scope_info,
Handle<FixedArray> feedback_vector) {
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name, code);
shared->set_scope_info(*scope_info);
shared->set_feedback_vector(*feedback_vector);
int literals_array_size = number_of_literals;
// If the function contains object, regexp or array literals,
// allocate extra space for a literals array prefix containing the
// context.
if (number_of_literals > 0) {
literals_array_size += JSFunction::kLiteralsPrefixSize;
}
shared->set_num_literals(literals_array_size);
if (is_generator) {
shared->set_instance_class_name(isolate()->heap()->Generator_string());
shared->DisableOptimization(kGenerator);
}
return shared;
}
Handle<JSMessageObject> Factory::NewJSMessageObject(
Handle<String> type,
Handle<JSArray> arguments,
int start_position,
int end_position,
Handle<Object> script,
Handle<Object> stack_frames) {
Handle<Map> map = message_object_map();
Handle<JSMessageObject> message = New<JSMessageObject>(map, NEW_SPACE);
message->set_properties(*empty_fixed_array(), SKIP_WRITE_BARRIER);
message->initialize_elements();
message->set_elements(*empty_fixed_array(), SKIP_WRITE_BARRIER);
message->set_type(*type);
message->set_arguments(*arguments);
message->set_start_position(start_position);
message->set_end_position(end_position);
message->set_script(*script);
message->set_stack_frames(*stack_frames);
return message;
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<String> name,
MaybeHandle<Code> maybe_code) {
Handle<Map> map = shared_function_info_map();
Handle<SharedFunctionInfo> share = New<SharedFunctionInfo>(map,
OLD_POINTER_SPACE);
// Set pointer fields.
share->set_name(*name);
Handle<Code> code;
if (!maybe_code.ToHandle(&code)) {
code = handle(isolate()->builtins()->builtin(Builtins::kIllegal));
}
share->set_code(*code);
share->set_optimized_code_map(Smi::FromInt(0));
share->set_scope_info(ScopeInfo::Empty(isolate()));
Code* construct_stub =
isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric);
share->set_construct_stub(construct_stub);
share->set_instance_class_name(*Object_string());
share->set_function_data(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_inferred_name(*empty_string(), SKIP_WRITE_BARRIER);
share->set_feedback_vector(*empty_fixed_array(), SKIP_WRITE_BARRIER);
share->set_profiler_ticks(0);
share->set_ast_node_count(0);
share->set_counters(0);
// Set integer fields (smi or int, depending on the architecture).
share->set_length(0);
share->set_formal_parameter_count(0);
share->set_expected_nof_properties(0);
share->set_num_literals(0);
share->set_start_position_and_type(0);
share->set_end_position(0);
share->set_function_token_position(0);
// All compiler hints default to false or 0.
share->set_compiler_hints(0);
share->set_opt_count_and_bailout_reason(0);
return share;
}
static inline int NumberCacheHash(Handle<FixedArray> cache,
Handle<Object> number) {
int mask = (cache->length() >> 1) - 1;
if (number->IsSmi()) {
return Handle<Smi>::cast(number)->value() & mask;
} else {
DoubleRepresentation rep(number->Number());
return
(static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) & mask;
}
}
Handle<Object> Factory::GetNumberStringCache(Handle<Object> number) {
DisallowHeapAllocation no_gc;
int hash = NumberCacheHash(number_string_cache(), number);
Object* key = number_string_cache()->get(hash * 2);
if (key == *number || (key->IsHeapNumber() && number->IsHeapNumber() &&
key->Number() == number->Number())) {
return Handle<String>(
String::cast(number_string_cache()->get(hash * 2 + 1)), isolate());
}
return undefined_value();
}
void Factory::SetNumberStringCache(Handle<Object> number,
Handle<String> string) {
int hash = NumberCacheHash(number_string_cache(), number);
if (number_string_cache()->get(hash * 2) != *undefined_value()) {
int full_size = isolate()->heap()->FullSizeNumberStringCacheLength();
if (number_string_cache()->length() != full_size) {
// The first time we have a hash collision, we move to the full sized
// number string cache. The idea is to have a small number string
// cache in the snapshot to keep boot-time memory usage down.
// If we expand the number string cache already while creating
// the snapshot then that didn't work out.
ASSERT(!isolate()->serializer_enabled() || FLAG_extra_code != NULL);
Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED);
isolate()->heap()->set_number_string_cache(*new_cache);
return;
}
}
number_string_cache()->set(hash * 2, *number);
number_string_cache()->set(hash * 2 + 1, *string);
}
Handle<String> Factory::NumberToString(Handle<Object> number,
bool check_number_string_cache) {
isolate()->counters()->number_to_string_runtime()->Increment();
if (check_number_string_cache) {
Handle<Object> cached = GetNumberStringCache(number);
if (!cached->IsUndefined()) return Handle<String>::cast(cached);
}
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str;
if (number->IsSmi()) {
int num = Handle<Smi>::cast(number)->value();
str = IntToCString(num, buffer);
} else {
double num = Handle<HeapNumber>::cast(number)->value();
str = DoubleToCString(num, buffer);
}
// We tenure the allocated string since it is referenced from the
// number-string cache which lives in the old space.
Handle<String> js_string = NewStringFromAsciiChecked(str, TENURED);
SetNumberStringCache(number, js_string);
return js_string;
}
Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
// Get the original code of the function.
Handle<Code> code(shared->code());
// Create a copy of the code before allocating the debug info object to avoid
// allocation while setting up the debug info object.
Handle<Code> original_code(*Factory::CopyCode(code));
// Allocate initial fixed array for active break points before allocating the
// debug info object to avoid allocation while setting up the debug info
// object.
Handle<FixedArray> break_points(
NewFixedArray(DebugInfo::kEstimatedNofBreakPointsInFunction));
// Create and set up the debug info object. Debug info contains function, a
// copy of the original code, the executing code and initial fixed array for
// active break points.
Handle<DebugInfo> debug_info =
Handle<DebugInfo>::cast(NewStruct(DEBUG_INFO_TYPE));
debug_info->set_shared(*shared);
debug_info->set_original_code(*original_code);
debug_info->set_code(*code);
debug_info->set_break_points(*break_points);
// Link debug info to function.
shared->set_debug_info(*debug_info);
return debug_info;
}
Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
int length) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateArgumentsObject(*callee, length), JSObject);
}
Handle<JSFunction> Factory::CreateApiFunction(
Handle<FunctionTemplateInfo> obj,
Handle<Object> prototype,
ApiInstanceType instance_type) {
Handle<Code> code = isolate()->builtins()->HandleApiCall();
Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
Handle<JSFunction> result;
if (obj->remove_prototype()) {
result = NewFunctionWithoutPrototype(empty_string(), code);
} else {
int internal_field_count = 0;
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
internal_field_count =
Smi::cast(instance_template->internal_field_count())->value();
}
// TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
// JSObject::GetHeaderSize.
int instance_size = kPointerSize * internal_field_count;
InstanceType type;
switch (instance_type) {
case JavaScriptObject:
type = JS_OBJECT_TYPE;
instance_size += JSObject::kHeaderSize;
break;
case InnerGlobalObject:
type = JS_GLOBAL_OBJECT_TYPE;
instance_size += JSGlobalObject::kSize;
break;
case OuterGlobalObject:
type = JS_GLOBAL_PROXY_TYPE;
instance_size += JSGlobalProxy::kSize;
break;
default:
UNREACHABLE();
type = JS_OBJECT_TYPE; // Keep the compiler happy.
break;
}
result = NewFunction(empty_string(), code, prototype, type,
instance_size, obj->read_only_prototype());
}
result->shared()->set_length(obj->length());
Handle<Object> class_name(obj->class_name(), isolate());
if (class_name->IsString()) {
result->shared()->set_instance_class_name(*class_name);
result->shared()->set_name(*class_name);
}
result->shared()->set_function_data(*obj);
result->shared()->set_construct_stub(*construct_stub);
result->shared()->DontAdaptArguments();
if (obj->remove_prototype()) {
ASSERT(result->shared()->IsApiFunction());
ASSERT(!result->has_initial_map());
ASSERT(!result->has_prototype());
return result;
}
if (prototype->IsTheHole()) {
#ifdef DEBUG
LookupIterator it(handle(JSObject::cast(result->prototype())),
constructor_string(),
LookupIterator::CHECK_OWN_REAL);
MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
ASSERT(it.IsFound());
ASSERT(maybe_prop.ToHandleChecked().is_identical_to(result));
#endif
} else {
JSObject::AddProperty(handle(JSObject::cast(result->prototype())),
constructor_string(), result, DONT_ENUM);
}
// Down from here is only valid for API functions that can be used as a
// constructor (don't set the "remove prototype" flag).
Handle<Map> map(result->initial_map());
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
}
// Mark as hidden for the __proto__ accessor if needed.
if (obj->hidden_prototype()) {
map->set_is_hidden_prototype();
}
// Mark as needs_access_check if needed.
if (obj->needs_access_check()) {
map->set_is_access_check_needed(true);
}
// Set interceptor information in the map.
if (!obj->named_property_handler()->IsUndefined()) {
map->set_has_named_interceptor();
}
if (!obj->indexed_property_handler()->IsUndefined()) {
map->set_has_indexed_interceptor();
}
// Set instance call-as-function information in the map.
if (!obj->instance_call_handler()->IsUndefined()) {
map->set_has_instance_call_handler();
}
// Recursively copy parent instance templates' accessors,
// 'data' may be modified.
int max_number_of_additional_properties = 0;
int max_number_of_static_properties = 0;
FunctionTemplateInfo* info = *obj;
while (true) {
if (!info->instance_template()->IsUndefined()) {
Object* props =
ObjectTemplateInfo::cast(
info->instance_template())->property_accessors();
if (!props->IsUndefined()) {
Handle<Object> props_handle(props, isolate());
NeanderArray props_array(props_handle);
max_number_of_additional_properties += props_array.length();
}
}
if (!info->property_accessors()->IsUndefined()) {
Object* props = info->property_accessors();
if (!props->IsUndefined()) {
Handle<Object> props_handle(props, isolate());
NeanderArray props_array(props_handle);
max_number_of_static_properties += props_array.length();
}
}
Object* parent = info->parent_template();
if (parent->IsUndefined()) break;
info = FunctionTemplateInfo::cast(parent);
}
Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
// Use a temporary FixedArray to acculumate static accessors
int valid_descriptors = 0;
Handle<FixedArray> array;
if (max_number_of_static_properties > 0) {
array = NewFixedArray(max_number_of_static_properties);
}
while (true) {
// Install instance descriptors
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()), isolate());
Handle<Object> props = Handle<Object>(instance->property_accessors(),
isolate());
if (!props->IsUndefined()) {
Map::AppendCallbackDescriptors(map, props);
}
}
// Accumulate static accessors
if (!obj->property_accessors()->IsUndefined()) {
Handle<Object> props = Handle<Object>(obj->property_accessors(),
isolate());
valid_descriptors =
AccessorInfo::AppendUnique(props, array, valid_descriptors);
}
// Climb parent chain
Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate());
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
// Install accumulated static accessors
for (int i = 0; i < valid_descriptors; i++) {
Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
JSObject::SetAccessor(result, accessor).Assert();
}
ASSERT(result->shared()->IsApiFunction());
return result;
}
Handle<MapCache> Factory::AddToMapCache(Handle<Context> context,
Handle<FixedArray> keys,
Handle<Map> map) {
Handle<MapCache> map_cache = handle(MapCache::cast(context->map_cache()));
Handle<MapCache> result = MapCache::Put(map_cache, keys, map);
context->set_map_cache(*result);
return result;
}
Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context,
Handle<FixedArray> keys) {
if (context->map_cache()->IsUndefined()) {
// Allocate the new map cache for the native context.
Handle<MapCache> new_cache = MapCache::New(isolate(), 24);
context->set_map_cache(*new_cache);
}
// Check to see whether there is a matching element in the cache.
Handle<MapCache> cache =
Handle<MapCache>(MapCache::cast(context->map_cache()));
Handle<Object> result = Handle<Object>(cache->Lookup(*keys), isolate());
if (result->IsMap()) return Handle<Map>::cast(result);
// Create a new map and add it to the cache.
Handle<Map> map = Map::Create(
handle(context->object_function()), keys->length());
AddToMapCache(context, keys, map);
return map;
}
void Factory::SetRegExpAtomData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
Handle<Object> data) {
Handle<FixedArray> store = NewFixedArray(JSRegExp::kAtomDataSize);
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
store->set(JSRegExp::kAtomPatternIndex, *data);
regexp->set_data(*store);
}
void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
int capture_count) {
Handle<FixedArray> store = NewFixedArray(JSRegExp::kIrregexpDataSize);
Smi* uninitialized = Smi::FromInt(JSRegExp::kUninitializedValue);
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
store->set(JSRegExp::kIrregexpASCIICodeIndex, uninitialized);
store->set(JSRegExp::kIrregexpUC16CodeIndex, uninitialized);
store->set(JSRegExp::kIrregexpASCIICodeSavedIndex, uninitialized);
store->set(JSRegExp::kIrregexpUC16CodeSavedIndex, uninitialized);
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::FromInt(0));
store->set(JSRegExp::kIrregexpCaptureCountIndex,
Smi::FromInt(capture_count));
regexp->set_data(*store);
}
MaybeHandle<FunctionTemplateInfo> Factory::ConfigureInstance(
Handle<FunctionTemplateInfo> desc, Handle<JSObject> instance) {
// Configure the instance by adding the properties specified by the
// instance template.
Handle<Object> instance_template(desc->instance_template(), isolate());
if (!instance_template->IsUndefined()) {
RETURN_ON_EXCEPTION(
isolate(),
Execution::ConfigureInstance(isolate(), instance, instance_template),
FunctionTemplateInfo);
}
return desc;
}
Handle<Object> Factory::GlobalConstantFor(Handle<String> name) {
if (String::Equals(name, undefined_string())) return undefined_value();
if (String::Equals(name, nan_string())) return nan_value();
if (String::Equals(name, infinity_string())) return infinity_value();
return Handle<Object>::null();
}
Handle<Object> Factory::ToBoolean(bool value) {
return value ? true_value() : false_value();
}
ES6: Add support for Map/Set forEach This implements MapIterator and SetIterator which matches the same constructs in the ES6 spec. However, these 2 iterators are not exposed to user code yet. They are only used internally to implement Map.prototype.forEach and Set.prototype.forEach. Each iterator has a reference to the OrderedHashTable where it directly accesses the hash table's entries. The OrderedHashTable has a reference to the newest iterator and each iterator has a reference to the next and previous iterator, effectively creating a double linked list. When the OrderedHashTable is mutated (or replaced) all the iterators are updated. When the iterator iterates passed the end of the data table it closes itself. Closed iterators no longer have a reference to the OrderedHashTable and they are removed from the double linked list. In the case of Map/Set forEach, we manually call Close on the iterator in case an exception was thrown so that the iterator never reached the end. At this point the OrderedHashTable keeps all the non finished iterators alive but since the only thing we currently expose is forEach there are no unfinished iterators outside a forEach call. Once we expose the iterators to user code we will need to make the references from the OrderedHashTable to the iterators weak and have some mechanism to close an iterator when it is garbage collected. BUG=1793, 2323 LOG=Y R=adamk@chromium.org TBR=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/238063009 Patch from Erik Arvidsson <arv@chromium.org>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20857 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-04-17 17:45:32 +00:00
} } // namespace v8::internal