Version 3.17.7
Limited recursion in regexp compilation by a budget. (Chromium issue 178790)
ES6 symbols: Implemented Symbol intrinsic and basic functionality (issue 2158)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@13808 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 68b4a83..4bcf89e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-03-04: Version 3.17.7
+
+ Limited recursion in regexp compilation by a budget.
+ (Chromium issue 178790)
+
+ ES6 symbols: Implemented Symbol intrinsic and basic functionality
+ (issue 2158)
+
+ Performance and stability improvements on all platforms.
+
+
2013-02-28: Version 3.17.6
Fixed materialization of arguments objects with unknown values.
diff --git a/include/v8.h b/include/v8.h
index e7f73d1..1426f57 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -4221,7 +4221,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptySymbolRootIndex = 119;
+ static const int kEmptyStringRootIndex = 119;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
@@ -4231,10 +4231,10 @@
static const int kNodeIsIndependentShift = 4;
static const int kNodeIsPartiallyDependentShift = 5;
- static const int kJSObjectType = 0xad;
+ static const int kJSObjectType = 0xae;
static const int kFirstNonstringType = 0x80;
- static const int kOddballType = 0x82;
- static const int kForeignType = 0x85;
+ static const int kOddballType = 0x83;
+ static const int kForeignType = 0x86;
static const int kUndefinedOddballKind = 5;
static const int kNullOddballKind = 3;
@@ -4671,7 +4671,7 @@
typedef internal::Object* S;
typedef internal::Internals I;
if (!I::IsInitialized(isolate)) return Empty();
- S* slot = I::GetRoot(isolate, I::kEmptySymbolRootIndex);
+ S* slot = I::GetRoot(isolate, I::kEmptyStringRootIndex);
return Local<String>(reinterpret_cast<String*>(slot));
}
diff --git a/src/SConscript b/src/SConscript
index d04fe09..772ac4e 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -327,6 +327,7 @@
EXPERIMENTAL_LIBRARY_FILES = '''
+symbol.js
proxy.js
collection.js
'''.split()
diff --git a/src/accessors.cc b/src/accessors.cc
index 3dcf422..57062be 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -103,7 +103,7 @@
// causes an infinite loop.
if (!object->IsJSArray()) {
return object->SetLocalPropertyIgnoreAttributes(
- isolate->heap()->length_symbol(), value, NONE);
+ isolate->heap()->length_string(), value, NONE);
}
value = FlattenNumber(value);
@@ -475,7 +475,7 @@
if (function_raw == NULL) return heap->undefined_value();
if (!function_raw->should_have_prototype()) {
// Since we hit this accessor, object will have no prototype property.
- return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
+ return object->SetLocalPropertyIgnoreAttributes(heap->prototype_string(),
value_raw,
NONE);
}
@@ -503,7 +503,7 @@
if (is_observed && !old_value->SameValue(*value)) {
JSObject::EnqueueChangeRecord(
- function, "updated", isolate->factory()->prototype_symbol(), old_value);
+ function, "updated", isolate->factory()->prototype_string(), old_value);
}
return *function;
@@ -630,7 +630,7 @@
// If there is an arguments variable in the stack, we return that.
Handle<ScopeInfo> scope_info(function->shared()->scope_info());
int index = scope_info->StackSlotIndex(
- isolate->heap()->arguments_symbol());
+ isolate->heap()->arguments_string());
if (index >= 0) {
Handle<Object> arguments(frame->GetExpression(index), isolate);
if (!arguments->IsArgumentsMarker()) return *arguments;
@@ -826,7 +826,7 @@
isolate);
if (!new_value->SameValue(*old_value)) {
JSObject::EnqueueChangeRecord(receiver, "prototype",
- isolate->factory()->Proto_symbol(),
+ isolate->factory()->proto_string(),
old_value);
}
return *hresult;
diff --git a/src/api.cc b/src/api.cc
index 96a3c82..e5135a2 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1785,7 +1785,7 @@
if (!raw_obj->IsJSObject()) return v8::Local<Value>();
i::HandleScope scope(isolate_);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
- i::Handle<i::String> name = isolate_->factory()->stack_symbol();
+ i::Handle<i::String> name = isolate_->factory()->stack_string();
if (!obj->HasProperty(*name)) return v8::Local<Value>();
i::Handle<i::Object> value = i::GetProperty(isolate_, obj, name);
if (value.is_null()) return v8::Local<Value>();
@@ -1899,7 +1899,8 @@
i::Handle<i::Object> argv[],
bool* has_pending_exception) {
i::Isolate* isolate = i::Isolate::Current();
- i::Handle<i::String> fmt_str = isolate->factory()->LookupUtf8Symbol(name);
+ i::Handle<i::String> fmt_str =
+ isolate->factory()->InternalizeUtf8String(name);
i::Object* object_fun =
isolate->js_builtins_object()->GetPropertyNoExceptionThrown(*fmt_str);
i::Handle<i::JSFunction> fun =
@@ -2292,7 +2293,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsDate()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(isolate->heap()->Date_symbol());
+ return obj->HasSpecificClassOf(isolate->heap()->Date_string());
}
@@ -2300,7 +2301,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsStringObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(isolate->heap()->String_symbol());
+ return obj->HasSpecificClassOf(isolate->heap()->String_string());
}
@@ -2308,16 +2309,16 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsNumberObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(isolate->heap()->Number_symbol());
+ return obj->HasSpecificClassOf(isolate->heap()->Number_string());
}
static i::Object* LookupBuiltin(i::Isolate* isolate,
const char* builtin_name) {
- i::Handle<i::String> symbol =
- isolate->factory()->LookupUtf8Symbol(builtin_name);
+ i::Handle<i::String> string =
+ isolate->factory()->InternalizeUtf8String(builtin_name);
i::Handle<i::JSBuiltinsObject> builtins = isolate->js_builtins_object();
- return builtins->GetPropertyNoExceptionThrown(*symbol);
+ return builtins->GetPropertyNoExceptionThrown(*string);
}
@@ -2355,7 +2356,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsBooleanObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return obj->HasSpecificClassOf(isolate->heap()->Boolean_symbol());
+ return obj->HasSpecificClassOf(isolate->heap()->Boolean_string());
}
@@ -2547,7 +2548,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Date::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Date_symbol()),
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Date_string()),
"v8::Date::Cast()",
"Could not convert to date");
}
@@ -2557,7 +2558,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::StringObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->HasSpecificClassOf(isolate->heap()->String_symbol()),
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->String_string()),
"v8::StringObject::Cast()",
"Could not convert to StringObject");
}
@@ -2567,7 +2568,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::NumberObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Number_symbol()),
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Number_string()),
"v8::NumberObject::Cast()",
"Could not convert to NumberObject");
}
@@ -2577,7 +2578,7 @@
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::BooleanObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Boolean_symbol()),
+ ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Boolean_string()),
"v8::BooleanObject::Cast()",
"Could not convert to BooleanObject");
}
@@ -3367,10 +3368,11 @@
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- i::Handle<i::String> key_symbol = isolate->factory()->LookupSymbol(key_obj);
+ i::Handle<i::String> key_string =
+ isolate->factory()->InternalizeString(key_obj);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
i::Handle<i::Object> result =
- i::JSObject::SetHiddenProperty(self, key_symbol, value_obj);
+ i::JSObject::SetHiddenProperty(self, key_string, value_obj);
return *result == *self;
}
@@ -3382,8 +3384,8 @@
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
- i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol), isolate);
+ i::Handle<i::String> key_string = FACTORY->InternalizeString(key_obj);
+ i::Handle<i::Object> result(self->GetHiddenProperty(*key_string), isolate);
if (result->IsUndefined()) return v8::Local<v8::Value>();
return Utils::ToLocal(result);
}
@@ -3396,8 +3398,8 @@
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
- i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
- self->DeleteHiddenProperty(*key_symbol);
+ i::Handle<i::String> key_string = FACTORY->InternalizeString(key_obj);
+ self->DeleteHiddenProperty(*key_string);
return true;
}
@@ -4827,7 +4829,7 @@
return v8::Local<String>();
}
LOG_API(isolate, "String::Empty()");
- return Utils::ToLocal(isolate->factory()->empty_symbol());
+ return Utils::ToLocal(isolate->factory()->empty_string());
}
@@ -4952,7 +4954,7 @@
}
CHECK(resource && resource->data());
bool result = obj->MakeExternal(resource);
- if (result && !obj->IsSymbol()) {
+ if (result && !obj->IsInternalizedString()) {
isolate->heap()->external_string_table()->AddString(*obj);
}
return result;
@@ -4989,7 +4991,7 @@
}
CHECK(resource && resource->data());
bool result = obj->MakeExternal(resource);
- if (result && !obj->IsSymbol()) {
+ if (result && !obj->IsInternalizedString()) {
isolate->heap()->external_string_table()->AddString(*obj);
}
return result;
@@ -5127,8 +5129,9 @@
i::HandleScope scope(isolate);
// Get the function ResetDateCache (defined in date.js).
- i::Handle<i::String> func_name_str = isolate->factory()->LookupOneByteSymbol(
- STATIC_ASCII_VECTOR("ResetDateCache"));
+ i::Handle<i::String> func_name_str =
+ isolate->factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("ResetDateCache"));
i::MaybeObject* result =
isolate->js_builtins_object()->GetProperty(*func_name_str);
i::Object* object_func;
@@ -5158,7 +5161,7 @@
if ((flags & RegExp::kMultiline) != 0) flags_buf[num_flags++] = 'm';
if ((flags & RegExp::kIgnoreCase) != 0) flags_buf[num_flags++] = 'i';
ASSERT(num_flags <= static_cast<int>(ARRAY_SIZE(flags_buf)));
- return FACTORY->LookupOneByteSymbol(
+ return FACTORY->InternalizeOneByteString(
i::Vector<const uint8_t>(flags_buf, num_flags));
}
@@ -5263,7 +5266,7 @@
LOG_API(isolate, "String::NewSymbol(char)");
ENTER_V8(isolate);
if (length == -1) length = i::StrLength(data);
- i::Handle<i::String> result = isolate->factory()->LookupUtf8Symbol(
+ i::Handle<i::String> result = isolate->factory()->InternalizeUtf8String(
i::Vector<const char>(data, length));
return Utils::ToLocal(result);
}
@@ -5975,7 +5978,7 @@
i::Debug* isolate_debug = isolate->debug();
isolate_debug->Load();
i::Handle<i::JSObject> debug(isolate_debug->debug_context()->global_object());
- i::Handle<i::String> name = isolate->factory()->LookupOneByteSymbol(
+ i::Handle<i::String> name = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("MakeMirror"));
i::Handle<i::Object> fun_obj = i::GetProperty(isolate, debug, name);
i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(fun_obj);
@@ -6038,11 +6041,11 @@
const i::CodeEntry* entry = node->entry();
if (!entry->has_name_prefix()) {
return Handle<String>(ToApi<String>(
- isolate->factory()->LookupUtf8Symbol(entry->name())));
+ isolate->factory()->InternalizeUtf8String(entry->name())));
} else {
return Handle<String>(ToApi<String>(isolate->factory()->NewConsString(
- isolate->factory()->LookupUtf8Symbol(entry->name_prefix()),
- isolate->factory()->LookupUtf8Symbol(entry->name()))));
+ isolate->factory()->InternalizeUtf8String(entry->name_prefix()),
+ isolate->factory()->InternalizeUtf8String(entry->name()))));
}
}
@@ -6051,7 +6054,7 @@
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfileNode::GetScriptResourceName");
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
- return Handle<String>(ToApi<String>(isolate->factory()->LookupUtf8Symbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->InternalizeUtf8String(
node->entry()->resource_name())));
}
@@ -6137,7 +6140,7 @@
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::CpuProfile::GetTitle");
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
- return Handle<String>(ToApi<String>(isolate->factory()->LookupUtf8Symbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->InternalizeUtf8String(
profile->title())));
}
@@ -6234,12 +6237,12 @@
case i::HeapGraphEdge::kInternal:
case i::HeapGraphEdge::kProperty:
case i::HeapGraphEdge::kShortcut:
- return Handle<String>(ToApi<String>(isolate->factory()->LookupUtf8Symbol(
- edge->name())));
+ return Handle<String>(ToApi<String>(
+ isolate->factory()->InternalizeUtf8String(edge->name())));
case i::HeapGraphEdge::kElement:
case i::HeapGraphEdge::kHidden:
- return Handle<Number>(ToApi<Number>(isolate->factory()->NewNumberFromInt(
- edge->index())));
+ return Handle<Number>(ToApi<Number>(
+ isolate->factory()->NewNumberFromInt(edge->index())));
default: UNREACHABLE();
}
return v8::Undefined();
@@ -6278,7 +6281,7 @@
Handle<String> HeapGraphNode::GetName() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapGraphNode::GetName");
- return Handle<String>(ToApi<String>(isolate->factory()->LookupUtf8Symbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->InternalizeUtf8String(
ToInternal(this)->name())));
}
@@ -6357,7 +6360,7 @@
Handle<String> HeapSnapshot::GetTitle() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetTitle");
- return Handle<String>(ToApi<String>(isolate->factory()->LookupUtf8Symbol(
+ return Handle<String>(ToApi<String>(isolate->factory()->InternalizeUtf8String(
ToInternal(this)->title())));
}
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 00bc367..466c890 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -542,31 +542,65 @@
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
+ // -- r2 : type info cell
// -- lr : return address
// -- sp[...]: constructor arguments
// -----------------------------------
- Label generic_constructor;
if (FLAG_debug_code) {
// The array construct code is only set for the builtin and internal
// Array functions which always have a map.
// Initial map for the builtin Array function should be a map.
- __ ldr(r2, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
- __ tst(r2, Operand(kSmiTagMask));
+ __ ldr(r3, FieldMemOperand(r1, JSFunction::kPrototypeOrInitialMapOffset));
+ __ tst(r3, Operand(kSmiTagMask));
__ Assert(ne, "Unexpected initial map for Array function");
- __ CompareObjectType(r2, r3, r4, MAP_TYPE);
+ __ CompareObjectType(r1, r3, r4, MAP_TYPE);
__ Assert(eq, "Unexpected initial map for Array function");
+
+ if (FLAG_optimize_constructed_arrays) {
+ // We should either have undefined in r2 or a valid jsglobalpropertycell
+ Label okay_here;
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->heap()->undefined_value(), masm->isolate());
+ Handle<Map> global_property_cell_map(
+ masm->isolate()->heap()->global_property_cell_map());
+ __ cmp(r2, Operand(undefined_sentinel));
+ __ b(eq, &okay_here);
+ __ ldr(r3, FieldMemOperand(r2, 0));
+ __ cmp(r3, Operand(global_property_cell_map));
+ __ Assert(eq, "Expected property cell in register ebx");
+ __ bind(&okay_here);
+ }
}
- // Run the native code for the Array function called as a constructor.
- ArrayNativeCode(masm, &generic_constructor);
+ if (FLAG_optimize_constructed_arrays) {
+ Label not_zero_case, not_one_case;
+ __ tst(r0, r0);
+ __ b(ne, ¬_zero_case);
+ ArrayNoArgumentConstructorStub no_argument_stub;
+ __ TailCallStub(&no_argument_stub);
- // Jump to the generic construct code in case the specialized code cannot
- // handle the construction.
- __ bind(&generic_constructor);
- Handle<Code> generic_construct_stub =
- masm->isolate()->builtins()->JSConstructStubGeneric();
- __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ __ bind(¬_zero_case);
+ __ cmp(r0, Operand(1));
+ __ b(gt, ¬_one_case);
+ ArraySingleArgumentConstructorStub single_argument_stub;
+ __ TailCallStub(&single_argument_stub);
+
+ __ bind(¬_one_case);
+ ArrayNArgumentsConstructorStub n_argument_stub;
+ __ TailCallStub(&n_argument_stub);
+ } else {
+ Label generic_constructor;
+ // Run the native code for the Array function called as a constructor.
+ ArrayNativeCode(masm, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
+ __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ }
}
@@ -682,7 +716,7 @@
// Load the empty string into r2, remove the receiver from the
// stack, and jump back to the case where the argument is a string.
__ bind(&no_arguments);
- __ LoadRoot(argument, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(argument, Heap::kempty_stringRootIndex);
__ Drop(1);
__ b(&argument_is_string);
@@ -1044,9 +1078,13 @@
// If the type of the result (stored in its map) is less than
// FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
- __ CompareObjectType(r0, r3, r3, FIRST_SPEC_OBJECT_TYPE);
+ __ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE);
__ b(ge, &exit);
+ // Symbols are "objects".
+ __ CompareInstanceType(r1, r3, SYMBOL_TYPE);
+ __ b(eq, &exit);
+
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
@@ -1141,6 +1179,10 @@
// Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3));
if (is_construct) {
+ // No type feedback cell is available
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->heap()->undefined_value(), masm->isolate());
+ __ mov(r2, Operand(undefined_sentinel));
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ CallStub(&stub);
} else {
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 32759b4..fa8e57b 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -73,6 +73,44 @@
}
+static void InitializeArrayConstructorDescriptor(Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ // register state
+ // r1 -- constructor function
+ // r2 -- type info cell with elements kind
+ // r0 -- number of arguments to the constructor function
+ static Register registers[] = { r1, r2 };
+ descriptor->register_param_count_ = 2;
+ // stack param count needs (constructor pointer, and single argument)
+ descriptor->stack_parameter_count_ = &r0;
+ descriptor->register_params_ = registers;
+ descriptor->extra_expression_stack_count_ = 1;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ArrayConstructor_StubFailure);
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
#define __ ACCESS_MASM(masm)
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
@@ -1505,12 +1543,13 @@
__ cmp(r3, Operand(ODDBALL_TYPE));
__ b(eq, &return_not_equal);
- // Now that we have the types we might as well check for symbol-symbol.
- // Ensure that no non-strings have the symbol bit set.
- STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
- STATIC_ASSERT(kSymbolTag != 0);
+ // Now that we have the types we might as well check for
+ // internalized-internalized.
+ // Ensure that no non-strings have the internalized bit set.
+ STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(r2, r2, Operand(r3));
- __ tst(r2, Operand(kIsSymbolMask));
+ __ tst(r2, Operand(kIsInternalizedMask));
__ b(ne, &return_not_equal);
}
@@ -1547,29 +1586,29 @@
}
-// Fast negative check for symbol-to-symbol equality.
-static void EmitCheckForSymbolsOrObjects(MacroAssembler* masm,
- Register lhs,
- Register rhs,
- Label* possible_strings,
- Label* not_both_strings) {
+// Fast negative check for internalized-to-internalized equality.
+static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
+ Register lhs,
+ Register rhs,
+ Label* possible_strings,
+ Label* not_both_strings) {
ASSERT((lhs.is(r0) && rhs.is(r1)) ||
(lhs.is(r1) && rhs.is(r0)));
// r2 is object type of rhs.
- // Ensure that no non-strings have the symbol bit set.
+ // Ensure that no non-strings have the internalized bit set.
Label object_test;
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ tst(r2, Operand(kIsNotStringMask));
__ b(ne, &object_test);
- __ tst(r2, Operand(kIsSymbolMask));
+ __ tst(r2, Operand(kIsInternalizedMask));
__ b(eq, possible_strings);
__ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE);
__ b(ge, not_both_strings);
- __ tst(r3, Operand(kIsSymbolMask));
+ __ tst(r3, Operand(kIsInternalizedMask));
__ b(eq, possible_strings);
- // Both are symbols. We already checked they weren't the same pointer
+ // Both are internalized. We already checked they weren't the same pointer
// so they are not equal.
__ mov(r0, Operand(NOT_EQUAL));
__ Ret();
@@ -1716,7 +1755,7 @@
__ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
DONT_DO_SMI_CHECK);
}
- // We could be strict about symbol/string here, but as long as
+ // We could be strict about internalized/non-internalized here, but as long as
// hydrogen doesn't care, the stub doesn't have to care either.
__ bind(&ok);
}
@@ -1814,27 +1853,29 @@
EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
}
- Label check_for_symbols;
+ Label check_for_internalized_strings;
Label flat_string_check;
// Check for heap-number-heap-number comparison. Can jump to slow case,
// or load both doubles into r0, r1, r2, r3 and jump to the code that handles
- // that case. If the inputs are not doubles then jumps to check_for_symbols.
+ // that case. If the inputs are not doubles then jumps to
+ // check_for_internalized_strings.
// In this case r2 will contain the type of rhs_. Never falls through.
EmitCheckForTwoHeapNumbers(masm,
lhs,
rhs,
&both_loaded_as_doubles,
- &check_for_symbols,
+ &check_for_internalized_strings,
&flat_string_check);
- __ bind(&check_for_symbols);
+ __ bind(&check_for_internalized_strings);
// In the strict case the EmitStrictTwoHeapObjectCompare already took care of
- // symbols.
+ // internalized strings.
if (cc == eq && !strict()) {
- // Returns an answer for two symbols or two detectable objects.
+ // Returns an answer for two internalized strings or two detectable objects.
// Otherwise jumps to string case or not both strings case.
// Assumes that r2 is the type of rhs_ on entry.
- EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check, &slow);
+ EmitCheckForInternalizedStringsOrObjects(
+ masm, lhs, rhs, &flat_string_check, &slow);
}
// Check for both being sequential ASCII strings, and inline if that is the
@@ -4501,7 +4542,7 @@
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
- __ cmp(r0, Operand(masm->isolate()->factory()->length_symbol()));
+ __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
__ b(ne, &miss);
receiver = r1;
} else {
@@ -4530,7 +4571,7 @@
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
- __ cmp(r0, Operand(masm->isolate()->factory()->prototype_symbol()));
+ __ cmp(r0, Operand(masm->isolate()->factory()->prototype_string()));
__ b(ne, &miss);
receiver = r1;
} else {
@@ -4559,7 +4600,7 @@
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
- __ cmp(r0, Operand(masm->isolate()->factory()->length_symbol()));
+ __ cmp(r0, Operand(masm->isolate()->factory()->length_string()));
__ b(ne, &miss);
receiver = r1;
} else {
@@ -4597,7 +4638,7 @@
// -- r1 : key
// -- r2 : receiver
// -----------------------------------
- __ cmp(r1, Operand(masm->isolate()->factory()->length_symbol()));
+ __ cmp(r1, Operand(masm->isolate()->factory()->length_string()));
__ b(ne, &miss);
receiver = r2;
value = r0;
@@ -4657,6 +4698,12 @@
Register InstanceofStub::right() { return r1; }
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, r0, reg_, inobject_, index_);
+ __ Ret();
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The displacement is the offset of the last parameter (if any)
// relative to the frame pointer.
@@ -5159,7 +5206,7 @@
// (3) Cons string. Check that it's flat.
// Replace subject with first string and reload instance type.
__ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset));
- __ CompareRoot(r0, Heap::kEmptyStringRootIndex);
+ __ CompareRoot(r0, Heap::kempty_stringRootIndex);
__ b(ne, &runtime);
__ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
@@ -5543,12 +5590,13 @@
}
-static void GenerateRecordCallTarget(MacroAssembler* masm) {
+static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// r1 : the function to call
// r2 : cache cell for call target
+ ASSERT(!FLAG_optimize_constructed_arrays);
Label done;
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
@@ -5582,6 +5630,82 @@
}
+static void GenerateRecordCallTarget(MacroAssembler* masm) {
+ // Cache the called function in a global property cell. Cache states
+ // are uninitialized, monomorphic (indicated by a JSFunction), and
+ // megamorphic.
+ // r1 : the function to call
+ // r2 : cache cell for call target
+ ASSERT(FLAG_optimize_constructed_arrays);
+ Label initialize, done, miss, megamorphic, not_array_function;
+
+ ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
+ masm->isolate()->heap()->undefined_value());
+ ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
+ masm->isolate()->heap()->the_hole_value());
+
+ // Load the cache state into r3.
+ __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+
+ // A monomorphic cache hit or an already megamorphic state: invoke the
+ // function without changing the state.
+ __ cmp(r3, r1);
+ __ b(eq, &done);
+ __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
+ __ b(eq, &done);
+
+ // Special handling of the Array() function, which caches not only the
+ // monomorphic Array function but the initial ElementsKind with special
+ // sentinels
+ Handle<Object> terminal_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
+ LAST_FAST_ELEMENTS_KIND);
+ __ cmp(r3, Operand(terminal_kind_sentinel));
+ __ b(ne, &miss);
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(r3);
+ __ cmp(r1, r3);
+ __ b(ne, &megamorphic);
+ __ jmp(&done);
+
+ __ bind(&miss);
+
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+ // megamorphic.
+ __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+ __ b(eq, &initialize);
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no
+ // write-barrier is needed.
+ __ bind(&megamorphic);
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+
+ // An uninitialized cache is patched with the function or sentinel to
+ // indicate the ElementsKind if function is the Array constructor.
+ __ bind(&initialize);
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(r3);
+ __ cmp(r1, r3);
+ __ b(ne, ¬_array_function);
+
+ // The target function is the Array constructor, install a sentinel value in
+ // the constructor's type info cell that will track the initial ElementsKind
+ // that should be used for the array when its constructed.
+ Handle<Object> initial_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
+ GetInitialFastElementsKind());
+ __ mov(r3, Operand(initial_kind_sentinel));
+ __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+ __ b(&done);
+
+ __ bind(¬_array_function);
+ __ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
+ // No need for a write barrier here - cells are rescanned.
+
+ __ bind(&done);
+}
+
+
void CallFunctionStub::Generate(MacroAssembler* masm) {
// r1 : the function to call
// r2 : cache cell for call target
@@ -5614,7 +5738,11 @@
__ b(ne, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Fast-case: Invoke the function now.
@@ -5689,13 +5817,19 @@
__ b(ne, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Jump to the function-specific construct stub.
- __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
- __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset));
- __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
+ Register jmp_reg = FLAG_optimize_constructed_arrays ? r3 : r2;
+ __ ldr(jmp_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(jmp_reg, FieldMemOperand(jmp_reg,
+ SharedFunctionInfo::kConstructStubOffset));
+ __ add(pc, jmp_reg, Operand(Code::kHeaderSize - kHeapObjectTag));
// r0: number of arguments
// r1: called object
@@ -6029,7 +6163,7 @@
}
-void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
@@ -6042,7 +6176,7 @@
Register scratch = scratch3;
// Make sure that both characters are not digits as such strings has a
- // different hash algorithm. Don't try to look for these in the symbol table.
+ // different hash algorithm. Don't try to look for these in the string table.
Label not_array_index;
__ sub(scratch, c1, Operand(static_cast<int>('0')));
__ cmp(scratch, Operand(static_cast<int>('9' - '0')));
@@ -6070,43 +6204,43 @@
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string.
- // Load symbol table
- // Load address of first element of the symbol table.
- Register symbol_table = c2;
- __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
+ // Load string table
+ // Load address of first element of the string table.
+ Register string_table = c2;
+ __ LoadRoot(string_table, Heap::kStringTableRootIndex);
Register undefined = scratch4;
__ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
- // Calculate capacity mask from the symbol table capacity.
+ // Calculate capacity mask from the string table capacity.
Register mask = scratch2;
- __ ldr(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset));
+ __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
__ mov(mask, Operand(mask, ASR, 1));
__ sub(mask, mask, Operand(1));
- // Calculate untagged address of the first element of the symbol table.
- Register first_symbol_table_element = symbol_table;
- __ add(first_symbol_table_element, symbol_table,
- Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag));
+ // Calculate untagged address of the first element of the string table.
+ Register first_string_table_element = string_table;
+ __ add(first_string_table_element, string_table,
+ Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
// Registers
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string
// mask: capacity mask
- // first_symbol_table_element: address of the first element of
- // the symbol table
+ // first_string_table_element: address of the first element of
+ // the string table
// undefined: the undefined object
// scratch: -
- // Perform a number of probes in the symbol table.
+ // Perform a number of probes in the string table.
const int kProbes = 4;
- Label found_in_symbol_table;
+ Label found_in_string_table;
Label next_probe[kProbes];
Register candidate = scratch5; // Scratch register contains candidate.
for (int i = 0; i < kProbes; i++) {
- // Calculate entry in symbol table.
+ // Calculate entry in string table.
if (i > 0) {
- __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i)));
+ __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
} else {
__ mov(candidate, hash);
}
@@ -6114,9 +6248,9 @@
__ and_(candidate, candidate, Operand(mask));
// Load the entry from the symble table.
- STATIC_ASSERT(SymbolTable::kEntrySize == 1);
+ STATIC_ASSERT(StringTable::kEntrySize == 1);
__ ldr(candidate,
- MemOperand(first_symbol_table_element,
+ MemOperand(first_string_table_element,
candidate,
LSL,
kPointerSizeLog2));
@@ -6132,7 +6266,7 @@
if (FLAG_debug_code) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(ip, candidate);
- __ Assert(eq, "oddball in symbol table is not undefined or the hole");
+ __ Assert(eq, "oddball in string table is not undefined or the hole");
}
__ jmp(&next_probe[i]);
@@ -6152,7 +6286,7 @@
// Assumes that word load is little endian.
__ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
__ cmp(chars, scratch);
- __ b(eq, &found_in_symbol_table);
+ __ b(eq, &found_in_string_table);
__ bind(&next_probe[i]);
}
@@ -6161,7 +6295,7 @@
// Scratch register contains result when we fall through to here.
Register result = candidate;
- __ bind(&found_in_symbol_table);
+ __ bind(&found_in_string_table);
__ Move(r0, result);
}
@@ -6290,7 +6424,7 @@
__ b(ne, &sliced_string);
// Cons string. Check whether it is flat, then fetch first part.
__ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
- __ CompareRoot(r5, Heap::kEmptyStringRootIndex);
+ __ CompareRoot(r5, Heap::kempty_stringRootIndex);
__ b(ne, &runtime);
__ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
// Update instance type.
@@ -6663,8 +6797,8 @@
// Adding two lengths can't overflow.
STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
__ add(r6, r2, Operand(r3));
- // Use the symbol table when adding two one character strings, as it
- // helps later optimizations to return a symbol here.
+ // Use the string table when adding two one character strings, as it
+ // helps later optimizations to return a string here.
__ cmp(r6, Operand(2));
__ b(ne, &longer_than_two);
@@ -6682,10 +6816,10 @@
__ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
__ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize));
- // Try to lookup two character string in symbol table. If it is not found
+ // Try to lookup two character string in string table. If it is not found
// just allocate a new one.
Label make_two_character_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
+ StringHelper::GenerateTwoCharacterStringTableProbe(
masm, r2, r3, r6, r7, r4, r5, r9, &make_two_character_string);
__ IncrementCounter(counters->string_add_native(), 1, r2, r3);
__ add(sp, sp, Operand(2 * kPointerSize));
@@ -7026,8 +7160,8 @@
}
-void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
- ASSERT(state_ == CompareIC::SYMBOL);
+void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
Label miss;
// Registers containing left and right operands respectively.
@@ -7039,17 +7173,68 @@
// Check that both operands are heap objects.
__ JumpIfEitherSmi(left, right, &miss);
- // Check that both operands are symbols.
+ // Check that both operands are internalized strings.
__ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
__ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
__ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
__ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp1, Operand(tmp2));
- __ tst(tmp1, Operand(kIsSymbolMask));
+ __ tst(tmp1, Operand(kIsInternalizedMask));
__ b(eq, &miss);
- // Symbols are compared by identity.
+ // Internalized strings are compared by identity.
+ __ cmp(left, right);
+ // Make sure r0 is non-zero. At this point input operands are
+ // guaranteed to be non-zero.
+ ASSERT(right.is(r0));
+ STATIC_ASSERT(EQUAL == 0);
+ STATIC_ASSERT(kSmiTag == 0);
+ __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
+ __ Ret();
+
+ __ bind(&miss);
+ GenerateMiss(masm);
+}
+
+
+void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::UNIQUE_NAME);
+ ASSERT(GetCondition() == eq);
+ Label miss;
+
+ // Registers containing left and right operands respectively.
+ Register left = r1;
+ Register right = r0;
+ Register tmp1 = r2;
+ Register tmp2 = r3;
+
+ // Check that both operands are heap objects.
+ __ JumpIfEitherSmi(left, right, &miss);
+
+ // Check that both operands are unique names. This leaves the instance
+ // types loaded in tmp1 and tmp2.
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset));
+ __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
+ __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset));
+ __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset));
+
+ Label succeed1;
+ __ tst(tmp1, Operand(kIsInternalizedMask));
+ __ b(ne, &succeed1);
+ __ cmp(tmp1, Operand(SYMBOL_TYPE));
+ __ b(ne, &miss);
+ __ bind(&succeed1);
+
+ Label succeed2;
+ __ tst(tmp2, Operand(kIsInternalizedMask));
+ __ b(ne, &succeed2);
+ __ cmp(tmp2, Operand(SYMBOL_TYPE));
+ __ b(ne, &miss);
+ __ bind(&succeed2);
+
+ // Unique names are compared by identity.
__ cmp(left, right);
// Make sure r0 is non-zero. At this point input operands are
// guaranteed to be non-zero.
@@ -7101,13 +7286,13 @@
// Handle not identical strings.
- // Check that both strings are symbols. If they are, we're done
+ // Check that both strings are internalized strings. If they are, we're done
// because we already know they are not identical.
if (equality) {
ASSERT(GetCondition() == eq);
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp3, tmp1, Operand(tmp2));
- __ tst(tmp3, Operand(kIsSymbolMask));
+ __ tst(tmp3, Operand(kIsInternalizedMask));
// Make sure r0 is non-zero. At this point input operands are
// guaranteed to be non-zero.
ASSERT(right.is(r0));
@@ -7290,11 +7475,11 @@
__ cmp(entity_name, tmp);
__ b(eq, &the_hole);
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
__ ldrb(entity_name,
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
- __ tst(entity_name, Operand(kIsSymbolMask));
+ __ tst(entity_name, Operand(kIsInternalizedMask));
__ b(eq, miss);
__ bind(&the_hole);
@@ -7463,11 +7648,11 @@
__ b(eq, &in_dictionary);
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
__ ldrb(entry_key,
FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
- __ tst(entry_key, Operand(kIsSymbolMask));
+ __ tst(entry_key, Operand(kIsInternalizedMask));
__ b(eq, &maybe_in_dictionary);
}
}
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 8b7b5ce..f952756 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -172,14 +172,14 @@
int flags);
- // Probe the symbol table for a two character string. If the string is
+ // Probe the string table for a two character string. If the string is
// not found by probing a jump to the label not_found is performed. This jump
- // does not guarantee that the string is not in the symbol table. If the
+ // does not guarantee that the string is not in the string table. If the
// string is found the code falls through with the string in register r0.
// Contents of both c1 and c2 registers are modified. At the exit c1 is
// guaranteed to contain halfword with low and high bytes equal to
// initial contents of c1 and c2 respectively.
- static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 69a2c9c..6e3c635 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -468,7 +468,7 @@
// the string.
__ bind(&cons_string);
__ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
- __ CompareRoot(result, Heap::kEmptyStringRootIndex);
+ __ CompareRoot(result, Heap::kempty_stringRootIndex);
__ b(ne, call_runtime);
// Get the first of the two strings and load its instance type.
__ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 6c49dca..2e1e3e3 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -356,102 +356,6 @@
}
-void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
- int frame_index) {
- JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (FLAG_trace_deopt) {
- PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
- }
-
- unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
-
- // Arguments adaptor can not be topmost or bottommost.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous
- // frame's top and this frame's size.
- uint32_t top_address;
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = height;
- unsigned output_offset = output_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // A marker value is used in place of the context.
- output_offset -= kPointerSize;
- intptr_t context = reinterpret_cast<intptr_t>(
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- output_frame->SetFrameSlot(output_offset, context);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
- top_address + output_offset, output_offset, context);
- }
-
- // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(function);
- output_frame->SetFrameSlot(output_offset, value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Number of incoming arguments.
- output_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
- output_frame->SetFrameSlot(output_offset, value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
- top_address + output_offset, output_offset, value, height - 1);
- }
-
- ASSERT(0 == output_offset);
-
- Builtins* builtins = isolate_->builtins();
- Code* adaptor_trampoline =
- builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
- uint32_t pc = reinterpret_cast<uint32_t>(
- adaptor_trampoline->instruction_start() +
- isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
- output_frame->SetPc(pc);
-}
-
-
void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index) {
//
@@ -755,124 +659,6 @@
}
-void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
- int frame_index,
- bool is_setter_stub_frame) {
- JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver (and the implicit return value, if any) are expected in
- // registers by the LoadIC/StoreIC, so they don't belong to the output stack
- // frame. This means that we have to use a height of 0.
- unsigned height = 0;
- unsigned height_in_bytes = height * kPointerSize;
- const char* kind = is_setter_stub_frame ? "setter" : "getter";
- if (trace_) {
- PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
- }
-
- // We need 5 stack entries from StackFrame::INTERNAL (lr, fp, cp, frame type,
- // code object, see MacroAssembler::EnterFrame). For a setter stub frames we
- // need one additional entry for the implicit return value, see
- // StoreStubCompiler::CompileStoreViaSetter.
- unsigned fixed_frame_entries = 5 + (is_setter_stub_frame ? 1 : 0);
- unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, accessor);
- output_frame->SetFrameType(StackFrame::INTERNAL);
-
- // A frame for an accessor stub can not be the topmost or bottommost one.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous frame's top and
- // this frame's size.
- uint32_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- unsigned output_offset = output_frame_size;
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // The context can be gotten from the previous frame.
- output_offset -= kPointerSize;
- value = output_[frame_index - 1]->GetContext();
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // A marker value is used in place of the function.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; function (%s sentinel)\n",
- top_address + output_offset, output_offset, value, kind);
- }
-
- // Get Code object from accessor stub.
- output_offset -= kPointerSize;
- Builtins::Name name = is_setter_stub_frame ?
- Builtins::kStoreIC_Setter_ForDeopt :
- Builtins::kLoadIC_Getter_ForDeopt;
- Code* accessor_stub = isolate_->builtins()->builtin(name);
- value = reinterpret_cast<intptr_t>(accessor_stub);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; code object\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Skip receiver.
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- iterator->Skip(Translation::NumberOfOperandsFor(opcode));
-
- if (is_setter_stub_frame) {
- // The implicit return value was part of the artificial setter stub
- // environment.
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- ASSERT(0 == output_offset);
-
- Smi* offset = is_setter_stub_frame ?
- isolate_->heap()->setter_stub_deopt_pc_offset() :
- isolate_->heap()->getter_stub_deopt_pc_offset();
- intptr_t pc = reinterpret_cast<intptr_t>(
- accessor_stub->instruction_start() + offset->value());
- output_frame->SetPc(pc);
-}
-
-
// This code is very similar to ia32 code, but relies on register names (fp, sp)
// and how the frame is laid out.
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index f5f26e7..04634d6 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1631,7 +1631,7 @@
ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
- if (key->handle()->IsSymbol()) {
+ if (key->handle()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
__ mov(r2, Operand(key->handle()));
@@ -2691,7 +2691,7 @@
__ cmp(r2, ip);
__ b(eq, if_false);
- // Look for valueOf symbol in the descriptor array, and indicate false if
+ // Look for valueOf name in the descriptor array, and indicate false if
// found. Since we omit an enumeration index check, if it is added via a
// transition that shares its descriptor array, this is a false positive.
Label entry, loop, done;
@@ -2716,10 +2716,10 @@
__ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
// Loop through all the keys in the descriptor array. If one of these is the
- // symbol valueOf the result is false.
- // The use of ip to store the valueOf symbol asumes that it is not otherwise
+ // string "valueOf" the result is false.
+ // The use of ip to store the valueOf string assumes that it is not otherwise
// used in the loop below.
- __ mov(ip, Operand(FACTORY->value_of_symbol()));
+ __ mov(ip, Operand(FACTORY->value_of_string()));
__ jmp(&entry);
__ bind(&loop);
__ ldr(r3, MemOperand(r4, 0));
@@ -2754,6 +2754,28 @@
}
+void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ __ JumpIfSmi(r0, if_false);
+ __ CompareObjectType(r0, r1, r2, SYMBOL_TYPE);
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(eq, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -2954,12 +2976,12 @@
// Functions have class 'Function'.
__ bind(&function);
- __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex);
+ __ LoadRoot(r0, Heap::kfunction_class_stringRootIndex);
__ jmp(&done);
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ LoadRoot(r0, Heap::kObject_symbolRootIndex);
+ __ LoadRoot(r0, Heap::kObject_stringRootIndex);
__ jmp(&done);
// Non-JS objects have class null.
@@ -3324,7 +3346,7 @@
__ bind(&index_out_of_range);
// When the index is out of range, the spec requires us to return
// the empty string.
- __ LoadRoot(result, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(result, Heap::kempty_stringRootIndex);
__ jmp(&done);
__ bind(&need_conversion);
@@ -3633,7 +3655,7 @@
__ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
__ SmiUntag(array_length, SetCC);
__ b(ne, &non_trivial_array);
- __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(r0, Heap::kempty_stringRootIndex);
__ b(&done);
__ bind(&non_trivial_array);
@@ -4246,13 +4268,13 @@
}
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- if (check->Equals(isolate()->heap()->number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_string())) {
__ JumpIfSmi(r0, if_true);
__ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(r0, ip);
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_string())) {
__ JumpIfSmi(r0, if_false);
// Check for undetectable objects => false.
__ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
@@ -4260,16 +4282,16 @@
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
+ } else if (check->Equals(isolate()->heap()->boolean_string())) {
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
__ b(eq, if_true);
__ CompareRoot(r0, Heap::kFalseValueRootIndex);
Split(eq, if_true, if_false, fall_through);
} else if (FLAG_harmony_typeof &&
- check->Equals(isolate()->heap()->null_symbol())) {
+ check->Equals(isolate()->heap()->null_string())) {
__ CompareRoot(r0, Heap::kNullValueRootIndex);
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
+ } else if (check->Equals(isolate()->heap()->undefined_string())) {
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
__ b(eq, if_true);
__ JumpIfSmi(r0, if_false);
@@ -4279,19 +4301,23 @@
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(ne, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_string())) {
__ JumpIfSmi(r0, if_false);
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE);
__ b(eq, if_true);
__ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE));
Split(eq, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_string())) {
__ JumpIfSmi(r0, if_false);
if (!FLAG_harmony_typeof) {
__ CompareRoot(r0, Heap::kNullValueRootIndex);
__ b(eq, if_true);
}
+ if (FLAG_harmony_symbols) {
+ __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
+ __ b(eq, if_true);
+ }
// Check for JS objects => true.
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(lt, if_false);
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 4a5d920..e8d0fab 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -303,30 +303,30 @@
}
-// Checks whether a key is an array index string or a symbol string.
-// Falls through if a key is a symbol.
+// Checks whether a key is an array index string or an internalized string.
+// Falls through if a key is an internalized string.
static void GenerateKeyStringCheck(MacroAssembler* masm,
Register key,
Register map,
Register hash,
Label* index_string,
- Label* not_symbol) {
+ Label* not_internalized) {
// The key is not a smi.
// Is it a string?
__ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
- __ b(ge, not_symbol);
+ __ b(ge, not_internalized);
// Is the string an array index, with cached numeric value?
__ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
__ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
__ b(eq, index_string);
- // Is the string a symbol?
+ // Is the string internalized?
// map: key map
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
- STATIC_ASSERT(kSymbolTag != 0);
- __ tst(hash, Operand(kIsSymbolMask));
- __ b(eq, not_symbol);
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ tst(hash, Operand(kIsInternalizedMask));
+ __ b(eq, not_internalized);
}
@@ -585,7 +585,7 @@
__ bind(&check_string);
GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
- // The key is known to be a symbol.
+ // The key is known to be internalized.
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
@@ -613,7 +613,7 @@
__ bind(&slow_call);
// This branch is taken if:
// - the receiver requires boxing or access check,
- // - the key is neither smi nor symbol,
+ // - the key is neither smi nor an internalized string,
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
@@ -656,8 +656,8 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags =
- Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r0, r2, r3, r4, r5, r6);
@@ -987,7 +987,7 @@
int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
__ And(r3, r3, Operand(mask));
- // Load the key (consisting of map and symbol) from the cache and
+ // Load the key (consisting of map and internalized string) from the cache and
// check for match.
Label load_in_object_property;
static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
@@ -1004,13 +1004,13 @@
__ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
__ cmp(r2, r5);
__ b(ne, &try_next_entry);
- __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load symbol
+ __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load string
__ cmp(r0, r5);
__ b(eq, &hit_on_nth_entry[i]);
__ bind(&try_next_entry);
}
- // Last entry: Load map and move r4 to symbol.
+ // Last entry: Load map and move r4 to string.
__ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
__ cmp(r2, r5);
__ b(ne, &slow);
@@ -1072,8 +1072,8 @@
GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
// Load the property to r0.
GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
- __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
- 1, r2, r3);
+ __ IncrementCounter(
+ isolate->counters()->keyed_load_generic_symbol(), 1, r2, r3);
__ Ret();
__ bind(&index_string);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index bab398c..d957594 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -355,6 +355,17 @@
}
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+ stream->Add("= ");
+ constructor()->PrintTo(stream);
+ stream->Add(" #%d / ", arity());
+ ASSERT(hydrogen()->property_cell()->value()->IsSmi());
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(hydrogen()->property_cell()->value())->value());
+ stream->Add(" (%s) ", ElementsKindToString(kind));
+}
+
+
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
stream->Add(" length ");
@@ -1139,6 +1150,14 @@
}
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+ LOperand* constructor = UseFixed(instr->constructor(), r1);
+ argument_count_ -= instr->argument_count();
+ LCallNewArray* result = new(zone()) LCallNewArray(constructor);
+ return MarkAsCall(DefineFixed(result, r0), instr);
+}
+
+
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* function = UseFixed(instr->function(), r1);
argument_count_ -= instr->argument_count();
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index e81734e..ecc77a8 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -68,6 +68,7 @@
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
@@ -1817,6 +1818,23 @@
};
+class LCallNewArray: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCallNewArray(LOperand* constructor) {
+ inputs_[0] = constructor;
+ }
+
+ LOperand* constructor() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+ DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 5bbaae8..8887391 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2680,12 +2680,12 @@
__ ldr(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
__ ldr(temp, FieldMemOperand(temp,
SharedFunctionInfo::kInstanceClassNameOffset));
- // The class name we are testing against is a symbol because it's a literal.
- // The name in the constructor is a symbol because of the way the context is
- // booted. This routine isn't expected to work for random API-created
+ // The class name we are testing against is internalized since it's a literal.
+ // The name in the constructor is internalized because of the way the context
+ // is booted. This routine isn't expected to work for random API-created
// classes and it doesn't have to because you can't access it with natives
- // syntax. Since both sides are symbols it is sufficient to use an identity
- // comparison.
+ // syntax. Since both sides are internalized it is sufficient to use an
+ // identity comparison.
__ cmp(temp, Operand(class_name));
// End with the answer in flags.
}
@@ -4295,12 +4295,32 @@
ASSERT(ToRegister(instr->constructor()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
- CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ mov(r0, Operand(instr->arity()));
+ if (FLAG_optimize_constructed_arrays) {
+ // No cell in r2 for construct type feedback in optimized code
+ Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
+ isolate());
+ __ mov(r2, Operand(undefined_value));
+ }
+ CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+ ASSERT(ToRegister(instr->constructor()).is(r1));
+ ASSERT(ToRegister(instr->result()).is(r0));
+ ASSERT(FLAG_optimize_constructed_arrays);
+
+ __ mov(r0, Operand(instr->arity()));
+ __ mov(r2, Operand(instr->hydrogen()->property_cell()));
+ Handle<Code> array_construct_code =
+ isolate()->builtins()->ArrayConstructCode();
+
+ CallCode(array_construct_code, RelocInfo::CONSTRUCT_CALL, instr);
+}
+
+
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
CallRuntime(instr->function(), instr->arity(), instr);
}
@@ -6042,14 +6062,14 @@
Handle<String> type_name) {
Condition final_branch_condition = kNoCondition;
Register scratch = scratch0();
- if (type_name->Equals(heap()->number_symbol())) {
+ if (type_name->Equals(heap()->number_string())) {
__ JumpIfSmi(input, true_label);
__ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
__ cmp(input, Operand(ip));
final_branch_condition = eq;
- } else if (type_name->Equals(heap()->string_symbol())) {
+ } else if (type_name->Equals(heap()->string_string())) {
__ JumpIfSmi(input, false_label);
__ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE);
__ b(ge, false_label);
@@ -6057,17 +6077,17 @@
__ tst(ip, Operand(1 << Map::kIsUndetectable));
final_branch_condition = eq;
- } else if (type_name->Equals(heap()->boolean_symbol())) {
+ } else if (type_name->Equals(heap()->boolean_string())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = eq;
- } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
__ CompareRoot(input, Heap::kNullValueRootIndex);
final_branch_condition = eq;
- } else if (type_name->Equals(heap()->undefined_symbol())) {
+ } else if (type_name->Equals(heap()->undefined_string())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ b(eq, true_label);
__ JumpIfSmi(input, false_label);
@@ -6077,7 +6097,7 @@
__ tst(ip, Operand(1 << Map::kIsUndetectable));
final_branch_condition = ne;
- } else if (type_name->Equals(heap()->function_symbol())) {
+ } else if (type_name->Equals(heap()->function_string())) {
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ JumpIfSmi(input, false_label);
__ CompareObjectType(input, scratch, input, JS_FUNCTION_TYPE);
@@ -6085,14 +6105,21 @@
__ cmp(input, Operand(JS_FUNCTION_PROXY_TYPE));
final_branch_condition = eq;
- } else if (type_name->Equals(heap()->object_symbol())) {
+ } else if (type_name->Equals(heap()->object_string())) {
__ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ b(eq, true_label);
}
- __ CompareObjectType(input, input, scratch,
- FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+ if (FLAG_harmony_symbols) {
+ __ CompareObjectType(input, input, scratch, SYMBOL_TYPE);
+ __ b(eq, true_label);
+ __ CompareInstanceType(input, scratch,
+ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+ } else {
+ __ CompareObjectType(input, input, scratch,
+ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+ }
__ b(lt, false_label);
__ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ b(gt, false_label);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index bc3c786..326f555 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -3076,6 +3076,19 @@
}
+void MacroAssembler::LoadArrayFunction(Register function) {
+ // Load the global or builtins object from the current context.
+ ldr(function,
+ MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+ // Load the global context from the global or builtins object.
+ ldr(function,
+ FieldMemOperand(function, GlobalObject::kGlobalContextOffset));
+ // Load the array function from the native context.
+ ldr(function,
+ MemOperand(function, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
+
+
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map,
Register scratch) {
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index d26eda7..0826b7d 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -514,6 +514,7 @@
bool can_have_holes);
void LoadGlobalFunction(int index, Register function);
+ void LoadArrayFunction(Register function);
// Load the initial map from the global function. The registers
// function and map can be the same, function is then overwritten.
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 354956d..03aa359 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -130,14 +130,14 @@
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
-// Name must be a symbol and receiver must be a heap object.
+// Name must be internalized and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<String> name,
Register scratch0,
Register scratch1) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
__ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
@@ -328,23 +328,24 @@
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ ldr(dst, FieldMemOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ ldr(dst, FieldMemOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
- __ ldr(dst, FieldMemOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ ldr(dst, FieldMemOperand(src, offset));
}
@@ -1066,6 +1067,11 @@
#define __ ACCESS_MASM(masm())
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
@@ -1074,7 +1080,9 @@
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -1102,8 +1110,8 @@
if (!current->HasFastProperties() &&
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
- if (!name->IsSymbol()) {
- name = factory()->LookupSymbol(name);
+ if (!name->IsInternalizedString()) {
+ name = factory()->InternalizeString(name);
}
ASSERT(current->property_dictionary()->FindEntry(*name) ==
StringDictionary::kNotFound);
@@ -1115,9 +1123,15 @@
reg = holder_reg; // From now on the object will be in holder_reg.
__ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else {
- Handle<Map> current_map(current->map());
- __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
- ALLOW_ELEMENT_TRANSITION_MAPS);
+ Register map_reg = scratch1;
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ Handle<Map> current_map(current->map());
+ // CheckMap implicitly loads the map of |reg| into |map_reg|.
+ __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ } else {
+ __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
@@ -1130,7 +1144,7 @@
if (heap()->InNewSpace(*prototype)) {
// The prototype is in new space; we cannot store a reference to it
// in the code. Load it from the map.
- __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+ __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
} else {
// The prototype is in old space; load it directly.
__ mov(reg, Operand(prototype));
@@ -1148,9 +1162,11 @@
// Log the check depth.
LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
- DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
+ DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1170,9 +1186,11 @@
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ b(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ b(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
@@ -1182,12 +1200,10 @@
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
@@ -1233,8 +1249,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1995,7 +2010,7 @@
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
- __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(r0, Heap::kempty_stringRootIndex);
__ Drop(argc + 1);
__ Ret();
}
@@ -2422,7 +2437,7 @@
break;
case STRING_CHECK:
- // Check that the object is a two-byte string or a symbol.
+ // Check that the object is a string.
__ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
__ b(ge, &miss);
// Check that the maps starting from the prototype haven't changed.
@@ -2433,6 +2448,12 @@
r0, holder, r3, r1, r4, name, &miss);
break;
+ case SYMBOL_CHECK:
+ // Check that the object is a symbol.
+ __ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
+ __ b(ne, &miss);
+ break;
+
case NUMBER_CHECK: {
Label fast;
// Check that the object is a smi or a heap number.
@@ -2856,7 +2877,7 @@
__ Ret();
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
@@ -2927,8 +2948,10 @@
bool is_dont_delete) {
Label success, miss;
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(
+ receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(cell));
@@ -2950,7 +2973,7 @@
__ Ret();
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
@@ -2978,35 +3001,40 @@
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- lr : return address
- // -- r0 : key
- // -- r1 : receiver
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(r1, &miss);
+
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
int receiver_count = receiver_maps->length();
- __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
__ mov(ip, Operand(receiver_maps->at(current)));
- __ cmp(r2, ip);
- __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET, eq);
+ __ cmp(map_reg, ip);
+ __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
}
__ bind(&miss);
- Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
- __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
diff --git a/src/ast.cc b/src/ast.cc
index 627e65a..02c815c 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -97,7 +97,7 @@
position_(position),
interface_(interface) {
// Names must be canonicalized for fast equality checks.
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
}
@@ -182,8 +182,8 @@
key_ = key;
value_ = value;
Object* k = *key->handle();
- if (k->IsSymbol() &&
- isolate->heap()->Proto_symbol()->Equals(String::cast(k))) {
+ if (k->IsInternalizedString() &&
+ isolate->heap()->proto_string()->Equals(String::cast(k))) {
kind_ = PROTOTYPE;
} else if (value_->AsMaterializedLiteral() != NULL) {
kind_ = MATERIALIZED_LITERAL;
@@ -483,9 +483,9 @@
if (info.IsUninitialized()) info = TypeInfo::Unknown();
if (info.IsSmi()) {
compare_type_ = SMI_ONLY;
- } else if (info.IsSymbol()) {
- compare_type_ = SYMBOL_ONLY;
- } else if (info.IsNonSymbol()) {
+ } else if (info.IsInternalizedString()) {
+ compare_type_ = NAME_ONLY;
+ } else if (info.IsNonInternalizedString()) {
compare_type_ = STRING_ONLY;
} else if (info.IsNonPrimitive()) {
compare_type_ = OBJECT_ONLY;
@@ -605,6 +605,7 @@
is_monomorphic_ = oracle->CallNewIsMonomorphic(this);
if (is_monomorphic_) {
target_ = oracle->GetCallNewTarget(this);
+ elements_kind_ = oracle->GetCallNewElementsKind(this);
}
}
diff --git a/src/ast.h b/src/ast.h
index a0a7a73..66b4dd4 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -968,7 +968,7 @@
TypeFeedbackId CompareId() { return compare_id_; }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
- bool IsSymbolCompare() { return compare_type_ == SYMBOL_ONLY; }
+ bool IsNameCompare() { return compare_type_ == NAME_ONLY; }
bool IsStringCompare() { return compare_type_ == STRING_ONLY; }
bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
@@ -980,7 +980,7 @@
enum CompareTypeFeedback {
NONE,
SMI_ONLY,
- SYMBOL_ONLY,
+ NAME_ONLY,
STRING_ONLY,
OBJECT_ONLY
};
@@ -1171,7 +1171,7 @@
DECLARE_NODE_TYPE(Literal)
virtual bool IsPropertyName() {
- if (handle_->IsSymbol()) {
+ if (handle_->IsInternalizedString()) {
uint32_t ignored;
return !String::cast(*handle_)->AsArrayIndex(&ignored);
}
@@ -1595,6 +1595,7 @@
Handle<JSFunction> target() { return target_; }
BailoutId ReturnId() const { return return_id_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
protected:
CallNew(Isolate* isolate,
@@ -1606,7 +1607,8 @@
arguments_(arguments),
pos_(pos),
is_monomorphic_(false),
- return_id_(GetNextId(isolate)) { }
+ return_id_(GetNextId(isolate)),
+ elements_kind_(GetInitialFastElementsKind()) { }
private:
Expression* expression_;
@@ -1617,6 +1619,7 @@
Handle<JSFunction> target_;
const BailoutId return_id_;
+ ElementsKind elements_kind_;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index b2c8c77..fcb1de9 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -360,11 +360,11 @@
bool is_ecma_native) {
Isolate* isolate = target->GetIsolate();
Factory* factory = isolate->factory();
- Handle<String> symbol = factory->LookupUtf8Symbol(name);
+ Handle<String> internalized_name = factory->InternalizeUtf8String(name);
Handle<Code> call_code = Handle<Code>(isolate->builtins()->builtin(call));
Handle<JSFunction> function = prototype.is_null() ?
- factory->NewFunctionWithoutPrototype(symbol, call_code) :
- factory->NewFunctionWithPrototype(symbol,
+ factory->NewFunctionWithoutPrototype(internalized_name, call_code) :
+ factory->NewFunctionWithPrototype(internalized_name,
type,
instance_size,
prototype,
@@ -379,9 +379,9 @@
}
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
- target, symbol, function, attributes));
+ target, internalized_name, function, attributes));
if (is_ecma_native) {
- function->shared()->set_instance_class_name(*symbol);
+ function->shared()->set_instance_class_name(*internalized_name);
}
function->shared()->set_native(true);
return function;
@@ -407,19 +407,19 @@
map->set_instance_descriptors(*descriptors);
{ // Add length.
- CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
+ CallbacksDescriptor d(*factory()->length_string(), *length, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add name.
- CallbacksDescriptor d(*factory()->name_symbol(), *name, attribs);
+ CallbacksDescriptor d(*factory()->name_string(), *name, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
- CallbacksDescriptor d(*factory()->arguments_symbol(), *args, attribs);
+ CallbacksDescriptor d(*factory()->arguments_string(), *args, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add caller.
- CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs);
+ CallbacksDescriptor d(*factory()->caller_string(), *caller, attribs);
map->AppendDescriptor(&d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
@@ -427,7 +427,7 @@
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
}
- CallbacksDescriptor d(*factory()->prototype_symbol(), *prototype, attribs);
+ CallbacksDescriptor d(*factory()->prototype_string(), *prototype, attribs);
map->AppendDescriptor(&d, witness);
}
}
@@ -472,7 +472,7 @@
Factory* factory = isolate->factory();
Heap* heap = isolate->heap();
- Handle<String> object_name = Handle<String>(heap->Object_symbol());
+ Handle<String> object_name = Handle<String>(heap->Object_string());
{ // --- O b j e c t ---
Handle<JSFunction> object_fun =
@@ -498,7 +498,7 @@
object_prototype_map->set_instance_descriptors(*prototype_descriptors);
{ // Add __proto__.
- CallbacksDescriptor d(heap->Proto_symbol(), *object_prototype, attribs);
+ CallbacksDescriptor d(heap->proto_string(), *object_prototype, attribs);
object_prototype_map->AppendDescriptor(&d, witness);
}
@@ -511,10 +511,10 @@
// Allocate the empty function as the prototype for function ECMAScript
// 262 15.3.4.
- Handle<String> symbol =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("Empty"));
+ Handle<String> empty_string =
+ factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("Empty"));
Handle<JSFunction> empty_function =
- factory->NewFunctionWithoutPrototype(symbol, CLASSIC_MODE);
+ factory->NewFunctionWithoutPrototype(empty_string, CLASSIC_MODE);
// --- E m p t y ---
Handle<Code> code =
@@ -566,19 +566,19 @@
map->set_instance_descriptors(*descriptors);
{ // Add length.
- CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
+ CallbacksDescriptor d(*factory()->length_string(), *length, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add name.
- CallbacksDescriptor d(*factory()->name_symbol(), *name, attribs);
+ CallbacksDescriptor d(*factory()->name_string(), *name, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add arguments.
- CallbacksDescriptor d(*factory()->arguments_symbol(), *arguments, attribs);
+ CallbacksDescriptor d(*factory()->arguments_string(), *arguments, attribs);
map->AppendDescriptor(&d, witness);
}
{ // Add caller.
- CallbacksDescriptor d(*factory()->caller_symbol(), *caller, attribs);
+ CallbacksDescriptor d(*factory()->caller_string(), *caller, attribs);
map->AppendDescriptor(&d, witness);
}
if (prototypeMode != DONT_ADD_PROTOTYPE) {
@@ -586,7 +586,7 @@
if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs | READ_ONLY);
}
- CallbacksDescriptor d(*factory()->prototype_symbol(), *prototype, attribs);
+ CallbacksDescriptor d(*factory()->prototype_string(), *prototype, attribs);
map->AppendDescriptor(&d, witness);
}
}
@@ -595,7 +595,7 @@
// ECMAScript 5th Edition, 13.2.3
Handle<JSFunction> Genesis::GetThrowTypeErrorFunction() {
if (throw_type_error_function.is_null()) {
- Handle<String> name = factory()->LookupOneByteSymbol(
+ Handle<String> name = factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("ThrowTypeError"));
throw_type_error_function =
factory()->NewFunctionWithoutPrototype(name, CLASSIC_MODE);
@@ -671,8 +671,8 @@
void Genesis::PoisonArgumentsAndCaller(Handle<Map> map) {
- SetAccessors(map, factory()->arguments_symbol(), GetThrowTypeErrorFunction());
- SetAccessors(map, factory()->caller_symbol(), GetThrowTypeErrorFunction());
+ SetAccessors(map, factory()->arguments_string(), GetThrowTypeErrorFunction());
+ SetAccessors(map, factory()->caller_string(), GetThrowTypeErrorFunction());
}
@@ -748,7 +748,7 @@
}
if (js_global_template.is_null()) {
- Handle<String> name = Handle<String>(heap()->empty_symbol());
+ Handle<String> name = Handle<String>(heap()->empty_string());
Handle<Code> code = Handle<Code>(isolate()->builtins()->builtin(
Builtins::kIllegal));
js_global_function =
@@ -761,7 +761,7 @@
JSObject::cast(js_global_function->instance_prototype()));
CHECK_NOT_EMPTY_HANDLE(isolate(),
JSObject::SetLocalPropertyIgnoreAttributes(
- prototype, factory()->constructor_symbol(),
+ prototype, factory()->constructor_string(),
isolate()->object_function(), NONE));
} else {
Handle<FunctionTemplateInfo> js_global_constructor(
@@ -782,7 +782,7 @@
// Step 2: create or re-initialize the global proxy object.
Handle<JSFunction> global_proxy_function;
if (global_template.IsEmpty()) {
- Handle<String> name = Handle<String>(heap()->empty_symbol());
+ Handle<String> name = Handle<String>(heap()->empty_string());
Handle<Code> code = Handle<Code>(isolate()->builtins()->builtin(
Builtins::kIllegal));
global_proxy_function =
@@ -798,7 +798,7 @@
factory()->OuterGlobalObject);
}
- Handle<String> global_name = factory()->LookupOneByteSymbol(
+ Handle<String> global_name = factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("global"));
global_proxy_function->shared()->set_instance_class_name(*global_name);
global_proxy_function->initial_map()->set_is_access_check_needed(true);
@@ -839,7 +839,7 @@
static const PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
ForceSetProperty(builtins_global,
- factory()->LookupOneByteSymbol(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("global")),
inner_global,
attributes);
@@ -871,7 +871,7 @@
Factory* factory = isolate->factory();
Heap* heap = isolate->heap();
- Handle<String> object_name = Handle<String>(heap->Object_symbol());
+ Handle<String> object_name = Handle<String>(heap->Object_string());
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
inner_global, object_name,
@@ -907,7 +907,7 @@
initial_map->set_instance_descriptors(*array_descriptors);
{ // Add length.
- CallbacksDescriptor d(*factory->length_symbol(), *array_length, attribs);
+ CallbacksDescriptor d(*factory->length_string(), *array_length, attribs);
array_function->initial_map()->AppendDescriptor(&d, witness);
}
@@ -956,7 +956,7 @@
string_map->set_instance_descriptors(*string_descriptors);
{ // Add length.
- CallbacksDescriptor d(*factory->length_symbol(), *string_length, attribs);
+ CallbacksDescriptor d(*factory->length_string(), *string_length, attribs);
string_map->AppendDescriptor(&d, witness);
}
}
@@ -993,28 +993,28 @@
{
// ECMA-262, section 15.10.7.1.
- FieldDescriptor field(heap->source_symbol(),
+ FieldDescriptor field(heap->source_string(),
JSRegExp::kSourceFieldIndex,
final);
initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.2.
- FieldDescriptor field(heap->global_symbol(),
+ FieldDescriptor field(heap->global_string(),
JSRegExp::kGlobalFieldIndex,
final);
initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.3.
- FieldDescriptor field(heap->ignore_case_symbol(),
+ FieldDescriptor field(heap->ignore_case_string(),
JSRegExp::kIgnoreCaseFieldIndex,
final);
initial_map->AppendDescriptor(&field, witness);
}
{
// ECMA-262, section 15.10.7.4.
- FieldDescriptor field(heap->multiline_symbol(),
+ FieldDescriptor field(heap->multiline_string(),
JSRegExp::kMultilineFieldIndex,
final);
initial_map->AppendDescriptor(&field, witness);
@@ -1023,7 +1023,7 @@
// ECMA-262, section 15.10.7.5.
PropertyAttributes writable =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
- FieldDescriptor field(heap->last_index_symbol(),
+ FieldDescriptor field(heap->last_index_string(),
JSRegExp::kLastIndexFieldIndex,
writable);
initial_map->AppendDescriptor(&field, witness);
@@ -1041,7 +1041,7 @@
proto_map->set_prototype(native_context()->initial_object_prototype());
Handle<JSObject> proto = factory->NewJSObjectFromMap(proto_map);
proto->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex,
- heap->query_colon_symbol());
+ heap->query_colon_string());
proto->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex,
heap->false_value());
proto->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex,
@@ -1078,7 +1078,7 @@
// Make sure we can recognize argument objects at runtime.
// This is done by introducing an anonymous function with
// class_name equals 'Arguments'.
- Handle<String> symbol = factory->LookupOneByteSymbol(
+ Handle<String> arguments_string = factory->InternalizeOneByteString(
STATIC_ASCII_VECTOR("Arguments"));
Handle<Code> code = Handle<Code>(
isolate->builtins()->builtin(Builtins::kIllegal));
@@ -1087,14 +1087,14 @@
JSObject::cast(native_context()->object_function()->prototype()));
Handle<JSFunction> function =
- factory->NewFunctionWithPrototype(symbol,
+ factory->NewFunctionWithPrototype(arguments_string,
JS_OBJECT_TYPE,
JSObject::kHeaderSize,
prototype,
code,
false);
ASSERT(!function->has_initial_map());
- function->shared()->set_instance_class_name(*symbol);
+ function->shared()->set_instance_class_name(*arguments_string);
function->shared()->set_expected_nof_properties(2);
Handle<JSObject> result = factory->NewJSObject(function);
@@ -1103,20 +1103,20 @@
// callee must be added as the second property.
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
- result, factory->length_symbol(),
+ result, factory->length_string(),
factory->undefined_value(), DONT_ENUM));
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
- result, factory->callee_symbol(),
+ result, factory->callee_string(),
factory->undefined_value(), DONT_ENUM));
#ifdef DEBUG
LookupResult lookup(isolate);
- result->LocalLookup(heap->callee_symbol(), &lookup);
+ result->LocalLookup(heap->callee_string(), &lookup);
ASSERT(lookup.IsField());
ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsCalleeIndex);
- result->LocalLookup(heap->length_symbol(), &lookup);
+ result->LocalLookup(heap->length_string(), &lookup);
ASSERT(lookup.IsField());
ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
@@ -1177,17 +1177,17 @@
map->set_instance_descriptors(*descriptors);
{ // length
- FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
+ FieldDescriptor d(*factory->length_string(), 0, DONT_ENUM);
map->AppendDescriptor(&d, witness);
}
{ // callee
- CallbacksDescriptor d(*factory->callee_symbol(),
+ CallbacksDescriptor d(*factory->callee_string(),
*callee,
attributes);
map->AppendDescriptor(&d, witness);
}
{ // caller
- CallbacksDescriptor d(*factory->caller_symbol(),
+ CallbacksDescriptor d(*factory->caller_string(),
*caller,
attributes);
map->AppendDescriptor(&d, witness);
@@ -1209,12 +1209,12 @@
// Add length property only for strict mode boilerplate.
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
- result, factory->length_symbol(),
+ result, factory->length_string(),
factory->undefined_value(), DONT_ENUM));
#ifdef DEBUG
LookupResult lookup(isolate);
- result->LocalLookup(heap->length_symbol(), &lookup);
+ result->LocalLookup(heap->length_string(), &lookup);
ASSERT(lookup.IsField());
ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
@@ -1231,14 +1231,14 @@
Handle<Code> code = Handle<Code>(
isolate->builtins()->builtin(Builtins::kIllegal));
Handle<JSFunction> context_extension_fun =
- factory->NewFunction(factory->empty_symbol(),
+ factory->NewFunction(factory->empty_string(),
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
JSObject::kHeaderSize,
code,
true);
- Handle<String> name =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("context_extension"));
+ Handle<String> name = factory->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("context_extension"));
context_extension_fun->shared()->set_instance_class_name(*name);
native_context()->set_context_extension_function(*context_extension_fun);
}
@@ -1250,7 +1250,7 @@
Handle<Code>(isolate->builtins()->builtin(
Builtins::kHandleApiCallAsFunction));
Handle<JSFunction> delegate =
- factory->NewFunction(factory->empty_symbol(), JS_OBJECT_TYPE,
+ factory->NewFunction(factory->empty_string(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
native_context()->set_call_as_function_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
@@ -1262,7 +1262,7 @@
Handle<Code>(isolate->builtins()->builtin(
Builtins::kHandleApiCallAsConstructor));
Handle<JSFunction> delegate =
- factory->NewFunction(factory->empty_symbol(), JS_OBJECT_TYPE,
+ factory->NewFunction(factory->empty_string(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, code, true);
native_context()->set_call_as_constructor_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
@@ -1418,7 +1418,7 @@
#define INSTALL_NATIVE(Type, name, var) \
Handle<String> var##_name = \
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR(name)); \
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR(name)); \
Object* var##_native = \
native_context()->builtins()->GetPropertyNoExceptionThrown( \
*var##_name); \
@@ -1446,6 +1446,9 @@
}
void Genesis::InstallExperimentalNativeFunctions() {
+ if (FLAG_harmony_symbols) {
+ INSTALL_NATIVE(JSObject, "SymbolDelegate", symbol_delegate);
+ }
if (FLAG_harmony_proxies) {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
@@ -1484,8 +1487,14 @@
factory()->NewJSObject(isolate()->object_function(), TENURED);
SetPrototype(array_function, prototype);
+ // TODO(mvstanton): For performance reasons, this code would have to
+ // be changed to successfully run with FLAG_optimize_constructed_arrays.
+ // The next checkin to enable FLAG_optimize_constructed_arrays by
+ // default will address this.
+ CHECK(!FLAG_optimize_constructed_arrays);
array_function->shared()->set_construct_stub(
isolate()->builtins()->builtin(Builtins::kArrayConstructCode));
+
array_function->shared()->DontAdaptArguments();
MaybeObject* maybe_map = array_function->initial_map()->Copy();
@@ -1508,7 +1517,7 @@
{ // Add length.
CallbacksDescriptor d(
- *factory()->length_symbol(), *array_length, attribs);
+ *factory()->length_string(), *array_length, attribs);
array_function->initial_map()->AppendDescriptor(&d, witness);
}
@@ -1525,12 +1534,12 @@
Handle<Code> code = Handle<Code>(
isolate()->builtins()->builtin(Builtins::kIllegal));
Handle<JSFunction> builtins_fun =
- factory()->NewFunction(factory()->empty_symbol(),
+ factory()->NewFunction(factory()->empty_string(),
JS_BUILTINS_OBJECT_TYPE,
JSBuiltinsObject::kSize, code, true);
Handle<String> name =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("builtins"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("builtins"));
builtins_fun->shared()->set_instance_class_name(*name);
builtins_fun->initial_map()->set_dictionary_map(true);
builtins_fun->initial_map()->set_prototype(heap()->null_value());
@@ -1549,12 +1558,12 @@
// global object.
static const PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
- Handle<String> global_symbol =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("global"));
+ Handle<String> global_string =
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("global"));
Handle<Object> global_obj(native_context()->global_object(), isolate());
CHECK_NOT_EMPTY_HANDLE(isolate(),
JSObject::SetLocalPropertyIgnoreAttributes(
- builtins, global_symbol, global_obj, attributes));
+ builtins, global_string, global_obj, attributes));
// Set up the reference from the global object to the builtins object.
JSGlobalObject::cast(native_context()->global_object())->
@@ -1562,7 +1571,7 @@
// Create a bridge function that has context in the native context.
Handle<JSFunction> bridge =
- factory()->NewFunction(factory()->empty_symbol(),
+ factory()->NewFunction(factory()->empty_string(),
factory()->undefined_value());
ASSERT(bridge->context() == *isolate()->native_context());
@@ -1593,48 +1602,51 @@
Handle<Foreign> script_source(
factory()->NewForeign(&Accessors::ScriptSource));
Handle<Foreign> script_name(factory()->NewForeign(&Accessors::ScriptName));
- Handle<String> id_symbol(factory()->LookupOneByteSymbol(
+ Handle<String> id_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("id")));
Handle<Foreign> script_id(factory()->NewForeign(&Accessors::ScriptId));
- Handle<String> line_offset_symbol(
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("line_offset")));
+ Handle<String> line_offset_string(
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("line_offset")));
Handle<Foreign> script_line_offset(
factory()->NewForeign(&Accessors::ScriptLineOffset));
- Handle<String> column_offset_symbol(
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("column_offset")));
+ Handle<String> column_offset_string(
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("column_offset")));
Handle<Foreign> script_column_offset(
factory()->NewForeign(&Accessors::ScriptColumnOffset));
- Handle<String> data_symbol(factory()->LookupOneByteSymbol(
+ Handle<String> data_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("data")));
Handle<Foreign> script_data(factory()->NewForeign(&Accessors::ScriptData));
- Handle<String> type_symbol(factory()->LookupOneByteSymbol(
+ Handle<String> type_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("type")));
Handle<Foreign> script_type(factory()->NewForeign(&Accessors::ScriptType));
- Handle<String> compilation_type_symbol(
- factory()->LookupOneByteSymbol(
+ Handle<String> compilation_type_string(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("compilation_type")));
Handle<Foreign> script_compilation_type(
factory()->NewForeign(&Accessors::ScriptCompilationType));
- Handle<String> line_ends_symbol(factory()->LookupOneByteSymbol(
+ Handle<String> line_ends_string(factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("line_ends")));
Handle<Foreign> script_line_ends(
factory()->NewForeign(&Accessors::ScriptLineEnds));
- Handle<String> context_data_symbol(
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("context_data")));
+ Handle<String> context_data_string(
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("context_data")));
Handle<Foreign> script_context_data(
factory()->NewForeign(&Accessors::ScriptContextData));
- Handle<String> eval_from_script_symbol(
- factory()->LookupOneByteSymbol(
+ Handle<String> eval_from_script_string(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("eval_from_script")));
Handle<Foreign> script_eval_from_script(
factory()->NewForeign(&Accessors::ScriptEvalFromScript));
- Handle<String> eval_from_script_position_symbol(
- factory()->LookupOneByteSymbol(
+ Handle<String> eval_from_script_position_string(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("eval_from_script_position")));
Handle<Foreign> script_eval_from_script_position(
factory()->NewForeign(&Accessors::ScriptEvalFromScriptPosition));
- Handle<String> eval_from_function_name_symbol(
- factory()->LookupOneByteSymbol(
+ Handle<String> eval_from_function_name_string(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("eval_from_function_name")));
Handle<Foreign> script_eval_from_function_name(
factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName));
@@ -1644,67 +1656,67 @@
{
CallbacksDescriptor d(
- *factory()->source_symbol(), *script_source, attribs);
+ *factory()->source_string(), *script_source, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*factory()->name_symbol(), *script_name, attribs);
+ CallbacksDescriptor d(*factory()->name_string(), *script_name, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*id_symbol, *script_id, attribs);
+ CallbacksDescriptor d(*id_string, *script_id, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*line_offset_symbol, *script_line_offset, attribs);
+ CallbacksDescriptor d(*line_offset_string, *script_line_offset, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
CallbacksDescriptor d(
- *column_offset_symbol, *script_column_offset, attribs);
+ *column_offset_string, *script_column_offset, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*data_symbol, *script_data, attribs);
+ CallbacksDescriptor d(*data_string, *script_data, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*type_symbol, *script_type, attribs);
+ CallbacksDescriptor d(*type_string, *script_type, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
CallbacksDescriptor d(
- *compilation_type_symbol, *script_compilation_type, attribs);
+ *compilation_type_string, *script_compilation_type, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
- CallbacksDescriptor d(*line_ends_symbol, *script_line_ends, attribs);
+ CallbacksDescriptor d(*line_ends_string, *script_line_ends, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
CallbacksDescriptor d(
- *context_data_symbol, *script_context_data, attribs);
+ *context_data_string, *script_context_data, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
CallbacksDescriptor d(
- *eval_from_script_symbol, *script_eval_from_script, attribs);
+ *eval_from_script_string, *script_eval_from_script, attribs);
script_map->AppendDescriptor(&d, witness);
}
{
CallbacksDescriptor d(
- *eval_from_script_position_symbol,
+ *eval_from_script_position_string,
*script_eval_from_script_position,
attribs);
script_map->AppendDescriptor(&d, witness);
@@ -1712,7 +1724,7 @@
{
CallbacksDescriptor d(
- *eval_from_function_name_symbol,
+ *eval_from_function_name_string,
*script_eval_from_function_name,
attribs);
script_map->AppendDescriptor(&d, witness);
@@ -1738,7 +1750,6 @@
native_context()->set_opaque_reference_function(*opaque_reference_fun);
}
-
// InternalArrays should not use Smi-Only array optimizations. There are too
// many places in the C++ runtime code (e.g. RegEx) that assume that
// elements in InternalArrays can be set to non-Smi values without going
@@ -1784,7 +1795,7 @@
HeapObject::cast(string_function->initial_map()->prototype())->map());
// Install Function.prototype.call and apply.
- { Handle<String> key = factory()->function_class_symbol();
+ { Handle<String> key = factory()->function_class_string();
Handle<JSFunction> function =
Handle<JSFunction>::cast(
GetProperty(isolate(), isolate()->global_object(), key));
@@ -1848,7 +1859,7 @@
JSFunction* array_function = native_context()->array_function();
Handle<DescriptorArray> array_descriptors(
array_function->initial_map()->instance_descriptors());
- String* length = heap()->length_symbol();
+ String* length = heap()->length_string();
int old = array_descriptors->SearchWithCache(
length, array_function->initial_map());
ASSERT(old != DescriptorArray::kNotFound);
@@ -1858,14 +1869,14 @@
initial_map->AppendDescriptor(&desc, witness);
}
{
- FieldDescriptor index_field(heap()->index_symbol(),
+ FieldDescriptor index_field(heap()->index_string(),
JSRegExpResult::kIndexIndex,
NONE);
initial_map->AppendDescriptor(&index_field, witness);
}
{
- FieldDescriptor input_field(heap()->input_symbol(),
+ FieldDescriptor input_field(heap()->input_string(),
JSRegExpResult::kInputIndex,
NONE);
initial_map->AppendDescriptor(&input_field, witness);
@@ -1890,6 +1901,11 @@
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount();
i++) {
+ if (FLAG_harmony_symbols &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native symbol.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
if (FLAG_harmony_proxies &&
strcmp(ExperimentalNatives::GetScriptName(i).start(),
"native proxy.js") == 0) {
@@ -1921,14 +1937,14 @@
Handle<GlobalObject> global(native_context->global_object());
const char* period_pos = strchr(holder_expr, '.');
if (period_pos == NULL) {
- return Handle<JSObject>::cast(
- GetProperty(isolate, global, factory->LookupUtf8Symbol(holder_expr)));
+ return Handle<JSObject>::cast(GetProperty(
+ isolate, global, factory->InternalizeUtf8String(holder_expr)));
}
ASSERT_EQ(".prototype", period_pos);
Vector<const char> property(holder_expr,
static_cast<int>(period_pos - holder_expr));
Handle<JSFunction> function = Handle<JSFunction>::cast(
- GetProperty(isolate, global, factory->LookupUtf8Symbol(property)));
+ GetProperty(isolate, global, factory->InternalizeUtf8String(property)));
return Handle<JSObject>(JSObject::cast(function->prototype()));
}
@@ -1937,7 +1953,7 @@
const char* function_name,
BuiltinFunctionId id) {
Factory* factory = holder->GetIsolate()->factory();
- Handle<String> name = factory->LookupUtf8Symbol(function_name);
+ Handle<String> name = factory->InternalizeUtf8String(function_name);
Object* function_object = holder->GetProperty(*name)->ToObjectUnchecked();
Handle<JSFunction> function(JSFunction::cast(function_object));
function->shared()->set_function_data(Smi::FromInt(id));
@@ -2027,7 +2043,8 @@
native_context->global_object()));
// Expose the natives in global if a name for it is specified.
if (FLAG_expose_natives_as != NULL && strlen(FLAG_expose_natives_as) != 0) {
- Handle<String> natives = factory->LookupUtf8Symbol(FLAG_expose_natives_as);
+ Handle<String> natives =
+ factory->InternalizeUtf8String(FLAG_expose_natives_as);
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
global, natives,
@@ -2037,10 +2054,10 @@
Handle<Object> Error = GetProperty(global, "Error");
if (Error->IsJSObject()) {
- Handle<String> name =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("stackTraceLimit"));
- Handle<Smi> stack_trace_limit(Smi::FromInt(FLAG_stack_trace_limit),
- isolate);
+ Handle<String> name = factory->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("stackTraceLimit"));
+ Handle<Smi> stack_trace_limit(
+ Smi::FromInt(FLAG_stack_trace_limit), isolate);
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
Handle<JSObject>::cast(Error), name,
@@ -2061,9 +2078,9 @@
native_context->security_token());
Handle<String> debug_string =
- factory->LookupUtf8Symbol(FLAG_expose_debug_as);
- Handle<Object> global_proxy(debug->debug_context()->global_proxy(),
- isolate);
+ factory->InternalizeUtf8String(FLAG_expose_debug_as);
+ Handle<Object> global_proxy(
+ debug->debug_context()->global_proxy(), isolate);
CHECK_NOT_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
global, debug_string, global_proxy, DONT_ENUM));
@@ -2205,7 +2222,8 @@
HandleScope scope(isolate());
for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
- Handle<String> name = factory()->LookupUtf8Symbol(Builtins::GetName(id));
+ Handle<String> name =
+ factory()->InternalizeUtf8String(Builtins::GetName(id));
Object* function_object = builtins->GetPropertyNoExceptionThrown(*name);
Handle<JSFunction> function
= Handle<JSFunction>(JSFunction::cast(function_object));
diff --git a/src/builtins.cc b/src/builtins.cc
index 279594e..aa69203 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -186,9 +186,67 @@
}
+#define CONVERT_ARG_STUB_CALLER_ARGS(name) \
+ Arguments* name = reinterpret_cast<Arguments*>(args[0]);
+
+
+RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) {
+ CONVERT_ARG_STUB_CALLER_ARGS(caller_args);
+ // ASSERT(args.length() == 3);
+ Handle<JSFunction> function = args.at<JSFunction>(1);
+ Handle<Object> type_info = args.at<Object>(2);
+
+ JSArray* array = NULL;
+ bool holey = false;
+ if (caller_args->length() == 1 && (*caller_args)[0]->IsSmi()) {
+ int value = Smi::cast((*caller_args)[0])->value();
+ holey = (value > 0 && value < JSObject::kInitialMaxFastElementArray);
+ }
+
+ ASSERT(function->has_initial_map());
+ ElementsKind kind = function->initial_map()->elements_kind();
+ if (holey) {
+ kind = GetHoleyElementsKind(kind);
+ }
+
+ MaybeObject* maybe_array;
+ if (*type_info != isolate->heap()->undefined_value()) {
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(*type_info);
+ if (cell->value()->IsSmi()) {
+ Smi* smi = Smi::cast(cell->value());
+ ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
+ if (holey && !IsFastHoleyElementsKind(to_kind)) {
+ to_kind = GetHoleyElementsKind(to_kind);
+ // Update the allocation site info to reflect the advice alteration.
+ cell->set_value(Smi::FromInt(to_kind));
+ }
+
+ AllocationSiteMode mode = AllocationSiteInfo::GetMode(to_kind);
+ if (mode == TRACK_ALLOCATION_SITE) {
+ maybe_array = isolate->heap()->AllocateEmptyJSArrayWithAllocationSite(
+ kind, type_info);
+ } else {
+ maybe_array = isolate->heap()->AllocateEmptyJSArray(kind);
+ }
+ if (!maybe_array->To(&array)) return maybe_array;
+ }
+ }
+
+ if (array == NULL) {
+ maybe_array = isolate->heap()->AllocateEmptyJSArray(kind);
+ if (!maybe_array->To(&array)) return maybe_array;
+ }
+
+ maybe_array = ArrayConstructInitializeElements(array, caller_args);
+ if (maybe_array->IsFailure()) return maybe_array;
+ return array;
+}
+
+
static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
Isolate* isolate,
JSFunction* constructor) {
+ ASSERT(args->length() >= 1);
Heap* heap = isolate->heap();
isolate->counters()->array_function_runtime()->Increment();
@@ -197,8 +255,29 @@
array = JSArray::cast((*args)[0]);
// Initialize elements and length in case later allocations fail so that the
// array object is initialized in a valid state.
- array->set_length(Smi::FromInt(0));
- array->set_elements(heap->empty_fixed_array());
+ MaybeObject* maybe_array = array->Initialize(0);
+ if (maybe_array->IsFailure()) return maybe_array;
+
+ if (FLAG_optimize_constructed_arrays) {
+ AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(array);
+ ElementsKind to_kind = array->GetElementsKind();
+ if (info != NULL && info->GetElementsKindPayload(&to_kind)) {
+ if (IsMoreGeneralElementsKindTransition(array->GetElementsKind(),
+ to_kind)) {
+ // We have advice that we should change the elements kind
+ if (FLAG_trace_track_allocation_sites) {
+ PrintF("AllocationSiteInfo: pre-transitioning array %p(%s->%s)\n",
+ reinterpret_cast<void*>(array),
+ ElementsKindToString(array->GetElementsKind()),
+ ElementsKindToString(to_kind));
+ }
+
+ maybe_array = array->TransitionElementsKind(to_kind);
+ if (maybe_array->IsFailure()) return maybe_array;
+ }
+ }
+ }
+
if (!FLAG_smi_only_arrays) {
Context* native_context = isolate->context()->native_context();
if (array->GetElementsKind() == GetInitialFastElementsKind() &&
@@ -215,97 +294,10 @@
if (!maybe_obj->To(&array)) return maybe_obj;
}
- // Optimize the case where there is one argument and the argument is a
- // small smi.
- if (args->length() == 2) {
- Object* obj = (*args)[1];
- if (obj->IsSmi()) {
- int len = Smi::cast(obj)->value();
- if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
- Object* fixed_array;
- { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
- if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
- }
- ElementsKind elements_kind = array->GetElementsKind();
- if (!IsFastHoleyElementsKind(elements_kind)) {
- elements_kind = GetHoleyElementsKind(elements_kind);
- MaybeObject* maybe_array =
- array->TransitionElementsKind(elements_kind);
- if (maybe_array->IsFailure()) return maybe_array;
- }
- // We do not use SetContent to skip the unnecessary elements type check.
- array->set_elements(FixedArray::cast(fixed_array));
- array->set_length(Smi::cast(obj));
- return array;
- }
- }
- // Take the argument as the length.
- { MaybeObject* maybe_obj = array->Initialize(0);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- return array->SetElementsLength((*args)[1]);
- }
-
- // Optimize the case where there are no parameters passed.
- if (args->length() == 1) {
- return array->Initialize(JSArray::kPreallocatedArrayElements);
- }
-
- // Set length and elements on the array.
- int number_of_elements = args->length() - 1;
- MaybeObject* maybe_object =
- array->EnsureCanContainElements(args, 1, number_of_elements,
- ALLOW_CONVERTED_DOUBLE_ELEMENTS);
- if (maybe_object->IsFailure()) return maybe_object;
-
- // Allocate an appropriately typed elements array.
- MaybeObject* maybe_elms;
- ElementsKind elements_kind = array->GetElementsKind();
- if (IsFastDoubleElementsKind(elements_kind)) {
- maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
- number_of_elements);
- } else {
- maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
- }
- FixedArrayBase* elms;
- if (!maybe_elms->To(&elms)) return maybe_elms;
-
- // Fill in the content
- switch (array->GetElementsKind()) {
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_SMI_ELEMENTS: {
- FixedArray* smi_elms = FixedArray::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
- }
- break;
- }
- case FAST_HOLEY_ELEMENTS:
- case FAST_ELEMENTS: {
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
- FixedArray* object_elms = FixedArray::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- object_elms->set(index, (*args)[index+1], mode);
- }
- break;
- }
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS: {
- FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
- for (int index = 0; index < number_of_elements; index++) {
- double_elms->set(index, (*args)[index+1]->Number());
- }
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
-
- array->set_elements(elms);
- array->set_length(Smi::FromInt(number_of_elements));
- return array;
+ Arguments adjusted_arguments(args->length() - 1, args->arguments() - 1);
+ ASSERT(adjusted_arguments.length() < 1 ||
+ adjusted_arguments[0] == (*args)[1]);
+ return ArrayConstructInitializeElements(array, &adjusted_arguments);
}
diff --git a/src/builtins.h b/src/builtins.h
index cb0c9c5..15abeb1 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -133,7 +133,7 @@
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
Code::kNoExtraICState) \
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
+ Code::IC_FRAGMENT) \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, \
@@ -272,6 +272,7 @@
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)
+MaybeObject* ArrayConstructor_StubFailure(Arguments args, Isolate* isolate);
class BuiltinFunctionTable;
class ObjectVisitor;
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index d02715f..491e255 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -171,7 +171,7 @@
HInstruction* value =
AddInstruction(new(zone) HLoadNamedField(boilerplate, true, i));
AddInstruction(new(zone) HStoreNamedField(object,
- factory->empty_symbol(),
+ factory->empty_string(),
value,
true, i));
AddSimulate(BailoutId::StubEntry());
@@ -290,14 +290,14 @@
to_kind, array_length);
AddInstruction(new(zone) HStoreNamedField(js_array,
- factory->elements_field_symbol(),
+ factory->elements_field_string(),
new_elements, true,
JSArray::kElementsOffset));
AddSimulate(BailoutId::StubEntry());
if_builder.End();
- AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_symbol(),
+ AddInstruction(new(zone) HStoreNamedField(js_array, factory->length_string(),
map, true, JSArray::kMapOffset));
AddSimulate(BailoutId::StubEntry());
@@ -306,6 +306,33 @@
}
+template <>
+void CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
+ HInstruction* deopt = new(zone()) HSoftDeoptimize();
+ AddInstruction(deopt);
+ current_block()->MarkAsDeoptimizing();
+ HReturn* ret = new(zone()) HReturn(GetParameter(0), context());
+ current_block()->Finish(ret);
+}
+
+
+Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() {
+ CodeStubGraphBuilder<ArrayNoArgumentConstructorStub> builder(this);
+ LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+ return chunk->Codegen(Code::COMPILED_STUB);
+}
+
+
+template <>
+void CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::BuildCodeStub() {
+ HInstruction* deopt = new(zone()) HSoftDeoptimize();
+ AddInstruction(deopt);
+ current_block()->MarkAsDeoptimizing();
+ HReturn* ret = new(zone()) HReturn(GetParameter(0), context());
+ current_block()->Finish(ret);
+}
+
+
Handle<Code> TransitionElementsKindStub::GenerateCode() {
CodeStubGraphBuilder<TransitionElementsKindStub> builder(this);
LChunk* chunk = OptimizeGraph(builder.CreateGraph());
@@ -313,4 +340,27 @@
}
+Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {
+ CodeStubGraphBuilder<ArraySingleArgumentConstructorStub> builder(this);
+ LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+ return chunk->Codegen(Code::COMPILED_STUB);
+}
+
+
+template <>
+void CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
+ HInstruction* deopt = new(zone()) HSoftDeoptimize();
+ AddInstruction(deopt);
+ current_block()->MarkAsDeoptimizing();
+ HReturn* ret = new(zone()) HReturn(GetParameter(0), context());
+ current_block()->Finish(ret);
+}
+
+
+Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() {
+ CodeStubGraphBuilder<ArrayNArgumentsConstructorStub> builder(this);
+ LChunk* chunk = OptimizeGraph(builder.CreateGraph());
+ return chunk->Codegen(Code::COMPILED_STUB);
+}
+
} } // namespace v8::internal
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index dacd525..4a401cd 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -98,7 +98,10 @@
// Copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
- static_cast<Code::Kind>(GetCodeKind()), GetICState(), GetExtraICState());
+ static_cast<Code::Kind>(GetCodeKind()),
+ GetICState(),
+ GetExtraICState(),
+ GetStubType());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
return new_object;
@@ -295,8 +298,8 @@
Factory* factory = isolate->factory();
return Map::UpdateCodeCache(known_map_,
strict() ?
- factory->strict_compare_ic_symbol() :
- factory->compare_ic_symbol(),
+ factory->strict_compare_ic_string() :
+ factory->compare_ic_string(),
new_object);
}
@@ -307,10 +310,13 @@
static_cast<Code::Kind>(GetCodeKind()),
UNINITIALIZED);
ASSERT(op_ == Token::EQ || op_ == Token::EQ_STRICT);
- String* symbol = strict() ?
- *factory->strict_compare_ic_symbol() :
- *factory->compare_ic_symbol();
- Handle<Object> probe(known_map_->FindInCodeCache(symbol, flags), isolate);
+ Handle<Object> probe(
+ known_map_->FindInCodeCache(
+ strict() ?
+ *factory->strict_compare_ic_string() :
+ *factory->compare_ic_string(),
+ flags),
+ isolate);
if (probe->IsCode()) {
*code_out = Code::cast(*probe);
#ifdef DEBUG
@@ -370,8 +376,11 @@
case CompareIC::STRING:
GenerateStrings(masm);
break;
- case CompareIC::SYMBOL:
- GenerateSymbols(masm);
+ case CompareIC::INTERNALIZED_STRING:
+ GenerateInternalizedStrings(masm);
+ break;
+ case CompareIC::UNIQUE_NAME:
+ GenerateUniqueNames(masm);
break;
case CompareIC::OBJECT:
GenerateObjects(masm);
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 06e2836..f7a4eaa 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -73,6 +73,9 @@
V(CEntry) \
V(JSEntry) \
V(KeyedLoadElement) \
+ V(ArrayNoArgumentConstructor) \
+ V(ArraySingleArgumentConstructor) \
+ V(ArrayNArgumentsConstructor) \
V(KeyedStoreElement) \
V(DebuggerStatement) \
V(StringDictionaryLookup) \
@@ -80,7 +83,9 @@
V(TransitionElementsKind) \
V(StoreArrayLiteralElement) \
V(StubFailureTrampoline) \
- V(ProfileEntryHook)
+ V(ProfileEntryHook) \
+ /* IC Handler stubs */ \
+ V(LoadField)
// List of code stubs only used on ARM platforms.
#ifdef V8_TARGET_ARCH_ARM
@@ -185,6 +190,9 @@
virtual Code::ExtraICState GetExtraICState() {
return Code::kNoExtraICState;
}
+ virtual Code::StubType GetStubType() {
+ return Code::NORMAL;
+ }
// Returns whether the code generated for this stub needs to be allocated as
// a fixed (non-moveable) code object.
@@ -608,6 +616,7 @@
virtual void Generate(MacroAssembler* masm);
private:
+ STATIC_ASSERT(KindBits::kSize == 4);
class WrapperModeBits: public BitField<bool, 4, 1> {};
virtual CodeStub::Major MajorKey() { return StringLength; }
virtual int MinorKey() {
@@ -629,6 +638,7 @@
}
private:
+ STATIC_ASSERT(KindBits::kSize == 4);
class StrictModeBits: public BitField<bool, 4, 1> {};
virtual int MinorKey() {
return KindBits::encode(kind()) | StrictModeBits::encode(strict_mode_);
@@ -649,6 +659,48 @@
};
+class HandlerStub: public ICStub {
+ public:
+ explicit HandlerStub(Code::Kind kind) : ICStub(kind) { }
+
+ protected:
+ virtual Code::ExtraICState GetExtraICState() {
+ return Code::HANDLER_FRAGMENT;
+ }
+};
+
+
+class LoadFieldStub: public HandlerStub {
+ public:
+ LoadFieldStub(Register reg, bool inobject, int index)
+ : HandlerStub(Code::LOAD_IC),
+ reg_(reg),
+ inobject_(inobject),
+ index_(index) { }
+ virtual void Generate(MacroAssembler* masm);
+
+ protected:
+ virtual Code::StubType GetStubType() { return Code::FIELD; }
+
+ private:
+ STATIC_ASSERT(KindBits::kSize == 4);
+ class RegisterBits: public BitField<int, 4, 6> {};
+ class InobjectBits: public BitField<bool, 10, 1> {};
+ class IndexBits: public BitField<int, 11, 11> {};
+ virtual CodeStub::Major MajorKey() { return LoadField; }
+ virtual int MinorKey() {
+ return KindBits::encode(kind())
+ | RegisterBits::encode(reg_.code())
+ | InobjectBits::encode(inobject_)
+ | IndexBits::encode(index_);
+ }
+
+ Register reg_;
+ bool inobject_;
+ int index_;
+};
+
+
class BinaryOpStub: public PlatformCodeStub {
public:
BinaryOpStub(Token::Value op, OverwriteMode mode)
@@ -794,9 +846,9 @@
private:
class OpField: public BitField<int, 0, 3> { };
- class LeftStateField: public BitField<int, 3, 3> { };
- class RightStateField: public BitField<int, 6, 3> { };
- class HandlerStateField: public BitField<int, 9, 3> { };
+ class LeftStateField: public BitField<int, 3, 4> { };
+ class RightStateField: public BitField<int, 7, 4> { };
+ class HandlerStateField: public BitField<int, 11, 4> { };
virtual void FinishCode(Handle<Code> code) {
code->set_stub_info(MinorKey());
@@ -809,8 +861,9 @@
void GenerateSmis(MacroAssembler* masm);
void GenerateNumbers(MacroAssembler* masm);
- void GenerateSymbols(MacroAssembler* masm);
+ void GenerateInternalizedStrings(MacroAssembler* masm);
void GenerateStrings(MacroAssembler* masm);
+ void GenerateUniqueNames(MacroAssembler* masm);
void GenerateObjects(MacroAssembler* masm);
void GenerateMiss(MacroAssembler* masm);
void GenerateKnownObjects(MacroAssembler* masm);
@@ -1288,6 +1341,63 @@
};
+class ArrayNoArgumentConstructorStub : public HydrogenCodeStub {
+ public:
+ ArrayNoArgumentConstructorStub() {
+ }
+
+ Major MajorKey() { return ArrayNoArgumentConstructor; }
+ int MinorKey() { return 0; }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ArrayNoArgumentConstructorStub);
+};
+
+
+class ArraySingleArgumentConstructorStub : public HydrogenCodeStub {
+ public:
+ ArraySingleArgumentConstructorStub() {
+ }
+
+ Major MajorKey() { return ArraySingleArgumentConstructor; }
+ int MinorKey() { return 0; }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ArraySingleArgumentConstructorStub);
+};
+
+
+class ArrayNArgumentsConstructorStub : public HydrogenCodeStub {
+ public:
+ ArrayNArgumentsConstructorStub() {
+ }
+
+ Major MajorKey() { return ArrayNArgumentsConstructor; }
+ int MinorKey() { return 0; }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ArrayNArgumentsConstructorStub);
+};
+
+
class KeyedStoreElementStub : public PlatformCodeStub {
public:
KeyedStoreElementStub(bool is_js_array,
diff --git a/src/contexts.h b/src/contexts.h
index 745ba65..cd7ed6a 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -156,6 +156,7 @@
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
+ V(SYMBOL_DELEGATE_INDEX, JSObject, symbol_delegate) \
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
to_complete_property_descriptor) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
@@ -286,6 +287,7 @@
EMBEDDER_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
+ SYMBOL_DELEGATE_INDEX,
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index 1b53912..7edaf22 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -481,9 +481,9 @@
sign = NEGATIVE;
}
- static const char kInfinitySymbol[] = "Infinity";
- if (*current == kInfinitySymbol[0]) {
- if (!SubStringEquals(¤t, end, kInfinitySymbol)) {
+ static const char kInfinityString[] = "Infinity";
+ if (*current == kInfinityString[0]) {
+ if (!SubStringEquals(¤t, end, kInfinityString)) {
return JunkStringValue();
}
diff --git a/src/d8.cc b/src/d8.cc
index 3ef0d54..2d30a1c 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -123,26 +123,12 @@
};
-LineEditor *LineEditor::first_ = NULL;
+LineEditor *LineEditor::current_ = NULL;
LineEditor::LineEditor(Type type, const char* name)
- : type_(type),
- name_(name),
- next_(first_) {
- first_ = this;
-}
-
-
-LineEditor* LineEditor::Get() {
- LineEditor* current = first_;
- LineEditor* best = current;
- while (current != NULL) {
- if (current->type_ > best->type_)
- best = current;
- current = current->next_;
- }
- return best;
+ : type_(type), name_(name) {
+ if (current_ == NULL || current_->type_ < type) current_ = this;
}
diff --git a/src/d8.h b/src/d8.h
index 1c3ce0a..f3b3fa1 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -128,12 +128,11 @@
virtual void AddHistory(const char* str) { }
const char* name() { return name_; }
- static LineEditor* Get();
+ static LineEditor* Get() { return current_; }
private:
Type type_;
const char* name_;
- LineEditor* next_;
- static LineEditor* first_;
+ static LineEditor* current_;
};
diff --git a/src/debug.cc b/src/debug.cc
index 8940edd..2821578 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -842,7 +842,7 @@
isolate_->set_context(*context);
// Expose the builtins object in the debugger context.
- Handle<String> key = isolate_->factory()->LookupOneByteSymbol(
+ Handle<String> key = isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("builtins"));
Handle<GlobalObject> global = Handle<GlobalObject>(context->global_object());
RETURN_IF_EMPTY_HANDLE_VALUE(
@@ -1109,13 +1109,13 @@
if (!break_point_object->IsJSObject()) return true;
// Get the function IsBreakPointTriggered (defined in debug-debugger.js).
- Handle<String> is_break_point_triggered_symbol =
- factory->LookupOneByteSymbol(
+ Handle<String> is_break_point_triggered_string =
+ factory->InternalizeOneByteString(
STATIC_ASCII_VECTOR("IsBreakPointTriggered"));
Handle<JSFunction> check_break_point =
Handle<JSFunction>(JSFunction::cast(
debug_context()->global_object()->GetPropertyNoExceptionThrown(
- *is_break_point_triggered_symbol)));
+ *is_break_point_triggered_string)));
// Get the break id as an object.
Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
@@ -2441,7 +2441,7 @@
ASSERT(isolate_->context() == *Debug::debug_context());
// Clear the mirror cache.
- Handle<String> function_name = isolate_->factory()->LookupOneByteSymbol(
+ Handle<String> function_name = isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("ClearMirrorCache"));
Handle<Object> fun(
isolate_->global_object()->GetPropertyNoExceptionThrown(*function_name),
@@ -2570,7 +2570,7 @@
// Create the execution state object.
Handle<String> constructor_str =
- isolate_->factory()->LookupUtf8Symbol(constructor_name);
+ isolate_->factory()->InternalizeUtf8String(constructor_name);
Handle<Object> constructor(
isolate_->global_object()->GetPropertyNoExceptionThrown(*constructor_str),
isolate_);
@@ -2800,13 +2800,13 @@
// script. Make sure that these break points are set.
// Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
- Handle<String> update_script_break_points_symbol =
- isolate_->factory()->LookupOneByteSymbol(
+ Handle<String> update_script_break_points_string =
+ isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("UpdateScriptBreakPoints"));
Handle<Object> update_script_break_points =
Handle<Object>(
debug->debug_context()->global_object()->GetPropertyNoExceptionThrown(
- *update_script_break_points_symbol),
+ *update_script_break_points_string),
isolate_);
if (!update_script_break_points->IsJSFunction()) {
return;
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 7267b05..c0b5945 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -821,6 +821,226 @@
}
+void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ unsigned height = iterator->Next();
+ unsigned height_in_bytes = height * kPointerSize;
+ if (trace_) {
+ PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
+ }
+
+ unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, function);
+ output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
+
+ // Arguments adaptor can not be topmost or bottommost.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous
+ // frame's top and this frame's size.
+ intptr_t top_address;
+ top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ // Compute the incoming parameter translation.
+ int parameter_count = height;
+ unsigned output_offset = output_frame_size;
+ for (int i = 0; i < parameter_count; ++i) {
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+ }
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // A marker value is used in place of the context.
+ output_offset -= kPointerSize;
+ intptr_t context = reinterpret_cast<intptr_t>(
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ output_frame->SetFrameSlot(output_offset, context);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; context (adaptor sentinel)\n",
+ top_address + output_offset, output_offset, context);
+ }
+
+ // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(function);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; function\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Number of incoming arguments.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; argc (%d)\n",
+ top_address + output_offset, output_offset, value, height - 1);
+ }
+
+ ASSERT(0 == output_offset);
+
+ Builtins* builtins = isolate_->builtins();
+ Code* adaptor_trampoline =
+ builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
+ intptr_t pc_value = reinterpret_cast<intptr_t>(
+ adaptor_trampoline->instruction_start() +
+ isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
+ output_frame->SetPc(pc_value);
+}
+
+
+void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
+ int frame_index,
+ bool is_setter_stub_frame) {
+ JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ // The receiver (and the implicit return value, if any) are expected in
+ // registers by the LoadIC/StoreIC, so they don't belong to the output stack
+ // frame. This means that we have to use a height of 0.
+ unsigned height = 0;
+ unsigned height_in_bytes = height * kPointerSize;
+ const char* kind = is_setter_stub_frame ? "setter" : "getter";
+ if (trace_) {
+ PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
+ }
+
+ // We need 1 stack entry for the return address + 4 stack entries from
+ // StackFrame::INTERNAL (FP, context, frame type, code object, see
+ // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
+ // entry for the implicit return value, see
+ // StoreStubCompiler::CompileStoreViaSetter.
+ unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
+ unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, accessor);
+ output_frame->SetFrameType(StackFrame::INTERNAL);
+
+ // A frame for an accessor stub can not be the topmost or bottommost one.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous frame's top and
+ // this frame's size.
+ intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ unsigned output_offset = output_frame_size;
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // The context can be gotten from the previous frame.
+ output_offset -= kPointerSize;
+ value = output_[frame_index - 1]->GetContext();
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; context\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // A marker value is used in place of the function.
+ output_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; function (%s sentinel)\n",
+ top_address + output_offset, output_offset, value, kind);
+ }
+
+ // Get Code object from accessor stub.
+ output_offset -= kPointerSize;
+ Builtins::Name name = is_setter_stub_frame ?
+ Builtins::kStoreIC_Setter_ForDeopt :
+ Builtins::kLoadIC_Getter_ForDeopt;
+ Code* accessor_stub = isolate_->builtins()->builtin(name);
+ value = reinterpret_cast<intptr_t>(accessor_stub);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
+ " ; code object\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Skip receiver.
+ Translation::Opcode opcode =
+ static_cast<Translation::Opcode>(iterator->Next());
+ iterator->Skip(Translation::NumberOfOperandsFor(opcode));
+
+ if (is_setter_stub_frame) {
+ // The implicit return value was part of the artificial setter stub
+ // environment.
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+ }
+
+ ASSERT(0 == output_offset);
+
+ Smi* offset = is_setter_stub_frame ?
+ isolate_->heap()->setter_stub_deopt_pc_offset() :
+ isolate_->heap()->getter_stub_deopt_pc_offset();
+ intptr_t pc = reinterpret_cast<intptr_t>(
+ accessor_stub->instruction_start() + offset->value());
+ output_frame->SetPc(pc);
+}
+
+
void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ASSERT_NE(DEBUGGER, bailout_type_);
diff --git a/src/elements.cc b/src/elements.cc
index e37ae58..9deef60 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -27,6 +27,7 @@
#include "v8.h"
+#include "arguments.h"
#include "objects.h"
#include "elements.h"
#include "utils.h"
@@ -1973,4 +1974,100 @@
}
+MUST_USE_RESULT MaybeObject* ArrayConstructInitializeElements(
+ JSArray* array, Arguments* args) {
+ Heap* heap = array->GetIsolate()->heap();
+
+ // Optimize the case where there is one argument and the argument is a
+ // small smi.
+ if (args->length() == 1) {
+ Object* obj = (*args)[0];
+ if (obj->IsSmi()) {
+ int len = Smi::cast(obj)->value();
+ if (len > 0 && len < JSObject::kInitialMaxFastElementArray) {
+ ElementsKind elements_kind = array->GetElementsKind();
+ MaybeObject* maybe_array = array->Initialize(len, len);
+ if (maybe_array->IsFailure()) return maybe_array;
+
+ if (!IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = GetHoleyElementsKind(elements_kind);
+ maybe_array = array->TransitionElementsKind(elements_kind);
+ if (maybe_array->IsFailure()) return maybe_array;
+ }
+
+ return array;
+ } else if (len == 0) {
+ return array->Initialize(JSArray::kPreallocatedArrayElements);
+ }
+ }
+
+ // Take the argument as the length.
+ MaybeObject* maybe_obj = array->Initialize(0);
+ if (!maybe_obj->To(&obj)) return maybe_obj;
+
+ return array->SetElementsLength((*args)[0]);
+ }
+
+ // Optimize the case where there are no parameters passed.
+ if (args->length() == 0) {
+ return array->Initialize(JSArray::kPreallocatedArrayElements);
+ }
+
+ // Set length and elements on the array.
+ int number_of_elements = args->length();
+ MaybeObject* maybe_object =
+ array->EnsureCanContainElements(args, 0, number_of_elements,
+ ALLOW_CONVERTED_DOUBLE_ELEMENTS);
+ if (maybe_object->IsFailure()) return maybe_object;
+
+ // Allocate an appropriately typed elements array.
+ MaybeObject* maybe_elms;
+ ElementsKind elements_kind = array->GetElementsKind();
+ if (IsFastDoubleElementsKind(elements_kind)) {
+ maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
+ number_of_elements);
+ } else {
+ maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
+ }
+ FixedArrayBase* elms;
+ if (!maybe_elms->To(&elms)) return maybe_elms;
+
+ // Fill in the content
+ switch (array->GetElementsKind()) {
+ case FAST_HOLEY_SMI_ELEMENTS:
+ case FAST_SMI_ELEMENTS: {
+ FixedArray* smi_elms = FixedArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER);
+ }
+ break;
+ }
+ case FAST_HOLEY_ELEMENTS:
+ case FAST_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ FixedArray* object_elms = FixedArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ object_elms->set(index, (*args)[index], mode);
+ }
+ break;
+ }
+ case FAST_HOLEY_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS: {
+ FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
+ for (int index = 0; index < number_of_elements; index++) {
+ double_elms->set(index, (*args)[index]->Number());
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ array->set_elements(elms);
+ array->set_length(Smi::FromInt(number_of_elements));
+ return array;
+}
+
} } // namespace v8::internal
diff --git a/src/elements.h b/src/elements.h
index e31ceb4..6353aae 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -200,6 +200,9 @@
void CheckArrayAbuse(JSObject* obj, const char* op, uint32_t key,
bool allow_appending = false);
+MUST_USE_RESULT MaybeObject* ArrayConstructInitializeElements(
+ JSArray* array, Arguments* args);
+
} } // namespace v8::internal
#endif // V8_ELEMENTS_H_
diff --git a/src/execution.cc b/src/execution.cc
index ba01ae5..705faa5 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -683,10 +683,8 @@
return factory->undefined_value();
}
- Handle<Object> char_at =
- GetProperty(isolate,
- isolate->js_builtins_object(),
- factory->char_at_symbol());
+ Handle<Object> char_at = GetProperty(
+ isolate, isolate->js_builtins_object(), factory->char_at_string());
if (!char_at->IsJSFunction()) {
return factory->undefined_value();
}
@@ -787,7 +785,7 @@
args,
&caught_exception);
if (caught_exception || !result->IsString()) {
- return isolate->factory()->empty_symbol();
+ return isolate->factory()->empty_string();
}
return Handle<String>::cast(result);
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index 614c243..76d2030 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -99,7 +99,7 @@
SimpleAsciiStringResource* resource = new SimpleAsciiStringResource(
reinterpret_cast<char*>(data), string->length());
result = string->MakeExternal(resource);
- if (result && !string->IsSymbol()) {
+ if (result && !string->IsInternalizedString()) {
HEAP->external_string_table()->AddString(*string);
}
if (!result) delete resource;
@@ -109,7 +109,7 @@
SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
data, string->length());
result = string->MakeExternal(resource);
- if (result && !string->IsSymbol()) {
+ if (result && !string->IsInternalizedString()) {
HEAP->external_string_table()->AddString(*string);
}
if (!result) delete resource;
diff --git a/src/factory.cc b/src/factory.cc
index 6a4235e..bb0e85f 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -157,41 +157,39 @@
}
-// Symbols are created in the old generation (data space).
-Handle<String> Factory::LookupUtf8Symbol(Vector<const char> string) {
+// Internalized strings are created in the old generation (data space).
+Handle<String> Factory::InternalizeUtf8String(Vector<const char> string) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupUtf8Symbol(string),
+ isolate()->heap()->InternalizeUtf8String(string),
String);
}
-// Symbols are created in the old generation (data space).
-Handle<String> Factory::LookupSymbol(Handle<String> string) {
+// Internalized strings are created in the old generation (data space).
+Handle<String> Factory::InternalizeString(Handle<String> string) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupSymbol(*string),
+ isolate()->heap()->InternalizeString(*string),
String);
}
-Handle<String> Factory::LookupOneByteSymbol(Vector<const uint8_t> string) {
+Handle<String> Factory::InternalizeOneByteString(Vector<const uint8_t> string) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupOneByteSymbol(string),
+ isolate()->heap()->InternalizeOneByteString(string),
String);
}
-Handle<String> Factory::LookupOneByteSymbol(Handle<SeqOneByteString> string,
- int from,
- int length) {
+Handle<String> Factory::InternalizeOneByteString(
+ Handle<SeqOneByteString> string, int from, int length) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupOneByteSymbol(string,
- from,
- length),
+ isolate()->heap()->InternalizeOneByteString(
+ string, from, length),
String);
}
-Handle<String> Factory::LookupTwoByteSymbol(Vector<const uc16> string) {
+Handle<String> Factory::InternalizeTwoByteString(Vector<const uc16> string) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupTwoByteSymbol(string),
+ isolate()->heap()->InternalizeTwoByteString(string),
String);
}
@@ -285,6 +283,14 @@
}
+Handle<Symbol> Factory::NewSymbol() {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateSymbol(),
+ Symbol);
+}
+
+
Handle<Context> Factory::NewNativeContext() {
CALL_HEAP_FUNCTION(
isolate(),
@@ -751,7 +757,7 @@
Handle<Object> Factory::NewError(const char* maker,
const char* type,
Handle<JSArray> args) {
- Handle<String> make_str = LookupUtf8Symbol(maker);
+ Handle<String> make_str = InternalizeUtf8String(maker);
Handle<Object> fun_obj(
isolate()->js_builtins_object()->GetPropertyNoExceptionThrown(*make_str),
isolate());
@@ -761,7 +767,7 @@
return EmergencyNewError(type, args);
}
Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
- Handle<Object> type_obj = LookupUtf8Symbol(type);
+ Handle<Object> type_obj = InternalizeUtf8String(type);
Handle<Object> argv[] = { type_obj, args };
// Invoke the JavaScript factory method. If an exception is thrown while
@@ -783,7 +789,7 @@
Handle<Object> Factory::NewError(const char* constructor,
Handle<String> message) {
- Handle<String> constr = LookupUtf8Symbol(constructor);
+ Handle<String> constr = InternalizeUtf8String(constructor);
Handle<JSFunction> fun = Handle<JSFunction>(
JSFunction::cast(isolate()->js_builtins_object()->
GetPropertyNoExceptionThrown(*constr)));
@@ -861,7 +867,7 @@
// Currently safe because it is only invoked from Genesis.
CHECK_NOT_EMPTY_HANDLE(isolate(),
JSObject::SetLocalPropertyIgnoreAttributes(
- prototype, constructor_symbol(),
+ prototype, constructor_string(),
function, DONT_ENUM));
return function;
}
@@ -919,9 +925,9 @@
}
-Handle<String> Factory::SymbolFromString(Handle<String> value) {
+Handle<String> Factory::InternalizedStringFromString(Handle<String> value) {
CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->LookupSymbol(*value), String);
+ isolate()->heap()->InternalizeString(*value), String);
}
@@ -1267,7 +1273,7 @@
ASSERT(type != INVALID_TYPE);
Handle<JSFunction> result =
- NewFunction(Factory::empty_symbol(),
+ NewFunction(Factory::empty_string(),
type,
instance_size,
code,
@@ -1452,9 +1458,9 @@
Handle<Object> Factory::GlobalConstantFor(Handle<String> name) {
Heap* h = isolate()->heap();
- if (name->Equals(h->undefined_symbol())) return undefined_value();
- if (name->Equals(h->nan_symbol())) return nan_value();
- if (name->Equals(h->infinity_symbol())) return infinity_value();
+ if (name->Equals(h->undefined_string())) return undefined_value();
+ if (name->Equals(h->nan_string())) return nan_value();
+ if (name->Equals(h->infinity_string())) return infinity_value();
return Handle<Object>::null();
}
diff --git a/src/factory.h b/src/factory.h
index f58008e..3651d36 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -79,16 +79,16 @@
Handle<TypeFeedbackInfo> NewTypeFeedbackInfo();
- Handle<String> LookupUtf8Symbol(Vector<const char> str);
- Handle<String> LookupUtf8Symbol(const char* str) {
- return LookupUtf8Symbol(CStrVector(str));
+ Handle<String> InternalizeUtf8String(Vector<const char> str);
+ Handle<String> InternalizeUtf8String(const char* str) {
+ return InternalizeUtf8String(CStrVector(str));
}
- Handle<String> LookupSymbol(Handle<String> str);
- Handle<String> LookupOneByteSymbol(Vector<const uint8_t> str);
- Handle<String> LookupOneByteSymbol(Handle<SeqOneByteString>,
+ Handle<String> InternalizeString(Handle<String> str);
+ Handle<String> InternalizeOneByteString(Vector<const uint8_t> str);
+ Handle<String> InternalizeOneByteString(Handle<SeqOneByteString>,
int from,
int length);
- Handle<String> LookupTwoByteSymbol(Vector<const uc16> str);
+ Handle<String> InternalizeTwoByteString(Vector<const uc16> str);
// String creation functions. Most of the string creation functions take
@@ -166,6 +166,9 @@
Handle<String> NewExternalStringFromTwoByte(
const ExternalTwoByteString::Resource* resource);
+ // Create a symbol.
+ Handle<Symbol> NewSymbol();
+
// Create a global (but otherwise uninitialized) context.
Handle<Context> NewNativeContext();
@@ -195,8 +198,8 @@
Handle<Context> previous,
Handle<ScopeInfo> scope_info);
- // Return the Symbol matching the passed in string.
- Handle<String> SymbolFromString(Handle<String> value);
+ // Return the internalized version of the passed in string.
+ Handle<String> InternalizedStringFromString(Handle<String> value);
// Allocate a new struct. The struct is pretenured (allocated directly in
// the old generation).
@@ -434,16 +437,16 @@
ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR_ACCESSOR
-#define SYMBOL_ACCESSOR(name, str) \
+#define STRING_ACCESSOR(name, str) \
inline Handle<String> name() { \
return Handle<String>(BitCast<String**>( \
&isolate()->heap()->roots_[Heap::k##name##RootIndex])); \
}
- SYMBOL_LIST(SYMBOL_ACCESSOR)
-#undef SYMBOL_ACCESSOR
+ INTERNALIZED_STRING_LIST(STRING_ACCESSOR)
+#undef STRING_ACCESSOR
- Handle<String> hidden_symbol() {
- return Handle<String>(&isolate()->heap()->hidden_symbol_);
+ Handle<String> hidden_string() {
+ return Handle<String>(&isolate()->heap()->hidden_string_);
}
Handle<SharedFunctionInfo> NewSharedFunctionInfo(
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index eb5f1d0..dcc6c2c 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -141,6 +141,8 @@
DEFINE_bool(harmony_scoping, false, "enable harmony block scoping")
DEFINE_bool(harmony_modules, false,
"enable harmony modules (implies block scoping)")
+DEFINE_bool(harmony_symbols, false,
+ "enable harmony symbols (a.k.a. private names)")
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_collections, false,
"enable harmony collections (sets, maps, and weak maps)")
@@ -149,6 +151,7 @@
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules)
+DEFINE_implication(harmony, harmony_symbols)
DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections)
DEFINE_implication(harmony, harmony_observation)
@@ -219,6 +222,8 @@
"eliminate unreachable code (hidden behind soft deopts)")
DEFINE_bool(track_allocation_sites, true,
"Use allocation site info to reduce transitions")
+DEFINE_bool(optimize_constructed_arrays, false,
+ "Use allocation site info on constructed arrays")
DEFINE_bool(trace_osr, false, "trace on-stack replacement")
DEFINE_int(stress_runs, 0, "number of stress runs")
DEFINE_bool(optimize_closures, true, "optimize closures")
diff --git a/src/func-name-inferrer.cc b/src/func-name-inferrer.cc
index 2dd0bbc..84d3bf0 100644
--- a/src/func-name-inferrer.cc
+++ b/src/func-name-inferrer.cc
@@ -55,14 +55,14 @@
void FuncNameInferrer::PushLiteralName(Handle<String> name) {
- if (IsOpen() && !isolate()->heap()->prototype_symbol()->Equals(*name)) {
+ if (IsOpen() && !isolate()->heap()->prototype_string()->Equals(*name)) {
names_stack_.Add(Name(name, kLiteralName), zone());
}
}
void FuncNameInferrer::PushVariableName(Handle<String> name) {
- if (IsOpen() && !isolate()->heap()->result_symbol()->Equals(*name)) {
+ if (IsOpen() && !isolate()->heap()->result_string()->Equals(*name)) {
names_stack_.Add(Name(name, kVariableName), zone());
}
}
@@ -85,7 +85,7 @@
if (prev->length() > 0) {
Factory* factory = isolate()->factory();
Handle<String> curr = factory->NewConsString(
- factory->dot_symbol(), names_stack_.at(pos).name);
+ factory->dot_string(), names_stack_.at(pos).name);
return MakeNameFromStackHelper(pos + 1,
factory->NewConsString(prev, curr));
} else {
diff --git a/src/handles.cc b/src/handles.cc
index 5de9b6c..7496cc1 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -276,7 +276,7 @@
Handle<Object> GetProperty(Handle<JSReceiver> obj,
const char* name) {
Isolate* isolate = obj->GetIsolate();
- Handle<String> str = isolate->factory()->LookupUtf8Symbol(name);
+ Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
}
@@ -603,7 +603,7 @@
Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) {
Isolate* isolate = script->GetIsolate();
Handle<String> name_or_source_url_key =
- isolate->factory()->LookupOneByteSymbol(
+ isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("nameOrSourceURL"));
Handle<JSValue> script_wrapper = GetScriptWrapper(script);
Handle<Object> property = GetProperty(isolate,
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 7b64a3b..916a6a2 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -112,32 +112,33 @@
}
-MaybeObject* Heap::AllocateSymbolFromUtf8(Vector<const char> str,
- int chars,
- uint32_t hash_field) {
+MaybeObject* Heap::AllocateInternalizedStringFromUtf8(
+ Vector<const char> str, int chars, uint32_t hash_field) {
if (IsOneByte(str, chars)) {
- return AllocateOneByteSymbol(Vector<const uint8_t>::cast(str), hash_field);
+ return AllocateOneByteInternalizedString(
+ Vector<const uint8_t>::cast(str), hash_field);
}
- return AllocateInternalSymbol<false>(str, chars, hash_field);
+ return AllocateInternalizedStringImpl<false>(str, chars, hash_field);
}
template<typename T>
-MaybeObject* Heap::AllocateInternalSymbol(T t, int chars, uint32_t hash_field) {
+MaybeObject* Heap::AllocateInternalizedStringImpl(
+ T t, int chars, uint32_t hash_field) {
if (IsOneByte(t, chars)) {
- return AllocateInternalSymbol<true>(t, chars, hash_field);
+ return AllocateInternalizedStringImpl<true>(t, chars, hash_field);
}
- return AllocateInternalSymbol<false>(t, chars, hash_field);
+ return AllocateInternalizedStringImpl<false>(t, chars, hash_field);
}
-MaybeObject* Heap::AllocateOneByteSymbol(Vector<const uint8_t> str,
- uint32_t hash_field) {
+MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
+ uint32_t hash_field) {
if (str.length() > SeqOneByteString::kMaxLength) {
return Failure::OutOfMemoryException(0x2);
}
// Compute map and object size.
- Map* map = ascii_symbol_map();
+ Map* map = ascii_internalized_string_map();
int size = SeqOneByteString::SizeFor(str.length());
// Allocate string.
@@ -165,13 +166,13 @@
}
-MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str,
- uint32_t hash_field) {
+MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
+ uint32_t hash_field) {
if (str.length() > SeqTwoByteString::kMaxLength) {
return Failure::OutOfMemoryException(0x3);
}
// Compute map and object size.
- Map* map = symbol_map();
+ Map* map = internalized_string_map();
int size = SeqTwoByteString::SizeFor(str.length());
// Allocate string.
@@ -455,6 +456,15 @@
}
+MaybeObject* Heap::AllocateEmptyJSArrayWithAllocationSite(
+ ElementsKind elements_kind,
+ Handle<Object> allocation_site_payload) {
+ return AllocateJSArrayAndStorageWithAllocationSite(elements_kind, 0, 0,
+ allocation_site_payload,
+ DONT_INITIALIZE_ARRAY_ELEMENTS);
+}
+
+
bool Heap::CollectGarbage(AllocationSpace space, const char* gc_reason) {
const char* collector_reason = NULL;
GarbageCollector collector = SelectGarbageCollector(space, &collector_reason);
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index a18fb63..9e96685 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -1019,7 +1019,7 @@
ExtractElementReferences(js_obj, entry);
ExtractInternalReferences(js_obj, entry);
SetPropertyReference(
- obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype());
+ obj, entry, heap_->proto_string(), js_obj->GetPrototype());
if (obj->IsJSFunction()) {
JSFunction* js_fun = JSFunction::cast(js_obj);
Object* proto_or_map = js_fun->prototype_or_initial_map();
@@ -1027,13 +1027,13 @@
if (!proto_or_map->IsMap()) {
SetPropertyReference(
obj, entry,
- heap_->prototype_symbol(), proto_or_map,
+ heap_->prototype_string(), proto_or_map,
NULL,
JSFunction::kPrototypeOrInitialMapOffset);
} else {
SetPropertyReference(
obj, entry,
- heap_->prototype_symbol(), js_fun->prototype());
+ heap_->prototype_string(), js_fun->prototype());
}
}
SharedFunctionInfo* shared_info = js_fun->shared();
@@ -1323,7 +1323,7 @@
String* k = descs->GetKey(i);
if (index < js_obj->map()->inobject_properties()) {
Object* value = js_obj->InObjectPropertyAt(index);
- if (k != heap_->hidden_symbol()) {
+ if (k != heap_->hidden_string()) {
SetPropertyReference(
js_obj, entry,
k, value,
@@ -1338,7 +1338,7 @@
}
} else {
Object* value = js_obj->FastPropertyAt(index);
- if (k != heap_->hidden_symbol()) {
+ if (k != heap_->hidden_string()) {
SetPropertyReference(js_obj, entry, k, value);
} else {
TagObject(value, "(hidden properties)");
@@ -1388,7 +1388,7 @@
Object* value = target->IsJSGlobalPropertyCell()
? JSGlobalPropertyCell::cast(target)->value()
: target;
- if (k != heap_->hidden_symbol()) {
+ if (k != heap_->hidden_string()) {
SetPropertyReference(js_obj, entry, String::cast(k), value);
} else {
TagObject(value, "(hidden properties)");
@@ -1438,15 +1438,15 @@
String* V8HeapExplorer::GetConstructorName(JSObject* object) {
Heap* heap = object->GetHeap();
- if (object->IsJSFunction()) return heap->closure_symbol();
+ if (object->IsJSFunction()) return heap->closure_string();
String* constructor_name = object->constructor_name();
- if (constructor_name == heap->Object_symbol()) {
+ if (constructor_name == heap->Object_string()) {
// Look up an immediate "constructor" property, if it is a function,
// return its name. This is for instances of binding objects, which
// have prototype constructor type "Object".
Object* constructor_prop = NULL;
LookupResult result(heap->isolate());
- object->LocalLookupRealNamedProperty(heap->constructor_symbol(), &result);
+ object->LocalLookupRealNamedProperty(heap->constructor_string(), &result);
if (!result.IsFound()) return object->constructor_name();
constructor_prop = result.GetLazyValue();
@@ -1768,9 +1768,9 @@
#define STRUCT_MAP_NAME(NAME, Name, name) NAME_ENTRY(name##_map)
STRUCT_LIST(STRUCT_MAP_NAME)
#undef STRUCT_MAP_NAME
-#define SYMBOL_NAME(name, str) NAME_ENTRY(name)
- SYMBOL_LIST(SYMBOL_NAME)
-#undef SYMBOL_NAME
+#define STRING_NAME(name, str) NAME_ENTRY(name)
+ INTERNALIZED_STRING_LIST(STRING_NAME)
+#undef STRING_NAME
#undef NAME_ENTRY
CHECK(!strong_gc_subroot_names_.is_empty());
}
diff --git a/src/heap.cc b/src/heap.cc
index a698339..7ce9263 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -127,7 +127,7 @@
amount_of_external_allocated_memory_at_last_global_gc_(0),
old_gen_exhausted_(false),
store_buffer_rebuilder_(store_buffer()),
- hidden_symbol_(NULL),
+ hidden_string_(NULL),
global_gc_prologue_callback_(NULL),
global_gc_epilogue_callback_(NULL),
gc_safe_size_of_old_object_(NULL),
@@ -492,10 +492,10 @@
isolate_->counters()->alive_after_last_gc()->Set(
static_cast<int>(SizeOfObjects()));
- isolate_->counters()->symbol_table_capacity()->Set(
- symbol_table()->Capacity());
+ isolate_->counters()->string_table_capacity()->Set(
+ string_table()->Capacity());
isolate_->counters()->number_of_symbols()->Set(
- symbol_table()->NumberOfElements());
+ string_table()->NumberOfElements());
if (CommittedMemory() > 0) {
isolate_->counters()->external_fragmentation_total()->AddSample(
@@ -704,24 +704,25 @@
#ifdef VERIFY_HEAP
-// Helper class for verifying the symbol table.
-class SymbolTableVerifier : public ObjectVisitor {
+// Helper class for verifying the string table.
+class StringTableVerifier : public ObjectVisitor {
public:
void VisitPointers(Object** start, Object** end) {
// Visit all HeapObject pointers in [start, end).
for (Object** p = start; p < end; p++) {
if ((*p)->IsHeapObject()) {
- // Check that the symbol is actually a symbol.
- CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
+ // Check that the string is actually internalized.
+ CHECK((*p)->IsTheHole() || (*p)->IsUndefined() ||
+ (*p)->IsInternalizedString());
}
}
}
};
-static void VerifySymbolTable() {
- SymbolTableVerifier verifier;
- HEAP->symbol_table()->IterateElements(&verifier);
+static void VerifyStringTable() {
+ StringTableVerifier verifier;
+ HEAP->string_table()->IterateElements(&verifier);
}
#endif // VERIFY_HEAP
@@ -876,7 +877,7 @@
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
- VerifySymbolTable();
+ VerifyStringTable();
}
#endif
@@ -1001,7 +1002,7 @@
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
- VerifySymbolTable();
+ VerifyStringTable();
}
#endif
@@ -1618,10 +1619,11 @@
void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
AssertNoAllocation no_allocation;
- // Both the external string table and the symbol table may contain
+ // Both the external string table and the string table may contain
// external strings, but neither lists them exhaustively, nor is the
// intersection set empty. Therefore we iterate over the external string
- // table first, ignoring symbols, and then over the symbol table.
+ // table first, ignoring internalized strings, and then over the
+ // internalized string table.
class ExternalStringTableVisitorAdapter : public ObjectVisitor {
public:
@@ -1629,9 +1631,9 @@
v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
virtual void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
- // Visit non-symbol external strings,
- // since symbols are listed in the symbol table.
- if (!(*p)->IsSymbol()) {
+ // Visit non-internalized external strings,
+ // since internalized strings are listed in the string table.
+ if (!(*p)->IsInternalizedString()) {
ASSERT((*p)->IsExternalString());
visitor_->VisitExternalString(Utils::ToLocal(
Handle<String>(String::cast(*p))));
@@ -1644,14 +1646,14 @@
external_string_table_.Iterate(&external_string_table_visitor);
- class SymbolTableVisitorAdapter : public ObjectVisitor {
+ class StringTableVisitorAdapter : public ObjectVisitor {
public:
- explicit SymbolTableVisitorAdapter(
+ explicit StringTableVisitorAdapter(
v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
virtual void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
if ((*p)->IsExternalString()) {
- ASSERT((*p)->IsSymbol());
+ ASSERT((*p)->IsInternalizedString());
visitor_->VisitExternalString(Utils::ToLocal(
Handle<String>(String::cast(*p))));
}
@@ -1659,9 +1661,9 @@
}
private:
v8::ExternalResourceVisitor* visitor_;
- } symbol_table_visitor(visitor);
+ } string_table_visitor(visitor);
- symbol_table()->IterateElements(&symbol_table_visitor);
+ string_table()->IterateElements(&string_table_visitor);
}
@@ -2271,11 +2273,11 @@
};
-const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
-#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
+const Heap::ConstantStringTable Heap::constant_string_table[] = {
+#define CONSTANT_STRING_ELEMENT(name, contents) \
{contents, k##name##RootIndex},
- SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
-#undef CONSTANT_SYMBOL_ELEMENT
+ INTERNALIZED_STRING_LIST(CONSTANT_STRING_ELEMENT)
+#undef CONSTANT_STRING_ELEMENT
};
@@ -2378,6 +2380,11 @@
}
set_heap_number_map(Map::cast(obj));
+ { MaybeObject* maybe_obj = AllocateMap(SYMBOL_TYPE, Symbol::kSize);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_symbol_map(Map::cast(obj));
+
{ MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
@@ -2738,17 +2745,17 @@
set_infinity_value(HeapNumber::cast(obj));
// The hole has not been created yet, but we want to put something
- // predictable in the gaps in the symbol table, so lets make that Smi zero.
+ // predictable in the gaps in the string table, so lets make that Smi zero.
set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
- // Allocate initial symbol table.
- { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
+ // Allocate initial string table.
+ { MaybeObject* maybe_obj = StringTable::Allocate(kInitialStringTableSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
- // Don't use set_symbol_table() due to asserts.
- roots_[kSymbolTableRootIndex] = obj;
+ // Don't use set_string_table() due to asserts.
+ roots_[kStringTableRootIndex] = obj;
- // Finish initializing oddballs after creating symboltable.
+ // Finish initializing oddballs after creating the string table.
{ MaybeObject* maybe_obj =
undefined_value()->Initialize("undefined",
nan_value(),
@@ -2804,31 +2811,25 @@
}
set_termination_exception(obj);
- // Allocate the empty string.
- { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
- if (!maybe_obj->ToObject(&obj)) return false;
- }
- set_empty_string(String::cast(obj));
-
- for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
+ for (unsigned i = 0; i < ARRAY_SIZE(constant_string_table); i++) {
{ MaybeObject* maybe_obj =
- LookupUtf8Symbol(constant_symbol_table[i].contents);
+ InternalizeUtf8String(constant_string_table[i].contents);
if (!maybe_obj->ToObject(&obj)) return false;
}
- roots_[constant_symbol_table[i].index] = String::cast(obj);
+ roots_[constant_string_table[i].index] = String::cast(obj);
}
- // Allocate the hidden symbol which is used to identify the hidden properties
+ // Allocate the hidden string which is used to identify the hidden properties
// in JSObjects. The hash code has a special value so that it will not match
// the empty string when searching for the property. It cannot be part of the
// loop above because it needs to be allocated manually with the special
- // hash code in place. The hash code for the hidden_symbol is zero to ensure
+ // hash code in place. The hash code for the hidden_string is zero to ensure
// that it will always be at the first entry in property descriptors.
- { MaybeObject* maybe_obj =
- AllocateOneByteSymbol(OneByteVector("", 0), String::kEmptyStringHash);
+ { MaybeObject* maybe_obj = AllocateOneByteInternalizedString(
+ OneByteVector("", 0), String::kEmptyStringHash);
if (!maybe_obj->ToObject(&obj)) return false;
}
- hidden_symbol_ = String::cast(obj);
+ hidden_string_ = String::cast(obj);
// Allocate the foreign for __proto__.
{ MaybeObject* maybe_obj =
@@ -2950,7 +2951,7 @@
kConstructStubDeoptPCOffsetRootIndex,
kGetterStubDeoptPCOffsetRootIndex,
kSetterStubDeoptPCOffsetRootIndex,
- kSymbolTableRootIndex,
+ kStringTableRootIndex,
};
for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
@@ -2966,10 +2967,10 @@
Object* key_pattern,
ResultsCacheType type) {
FixedArray* cache;
- if (!key_string->IsSymbol()) return Smi::FromInt(0);
+ if (!key_string->IsInternalizedString()) return Smi::FromInt(0);
if (type == STRING_SPLIT_SUBSTRINGS) {
ASSERT(key_pattern->IsString());
- if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
+ if (!key_pattern->IsInternalizedString()) return Smi::FromInt(0);
cache = heap->string_split_cache();
} else {
ASSERT(type == REGEXP_MULTIPLE_INDICES);
@@ -3000,10 +3001,10 @@
FixedArray* value_array,
ResultsCacheType type) {
FixedArray* cache;
- if (!key_string->IsSymbol()) return;
+ if (!key_string->IsInternalizedString()) return;
if (type == STRING_SPLIT_SUBSTRINGS) {
ASSERT(key_pattern->IsString());
- if (!key_pattern->IsSymbol()) return;
+ if (!key_pattern->IsInternalizedString()) return;
cache = heap->string_split_cache();
} else {
ASSERT(type == REGEXP_MULTIPLE_INDICES);
@@ -3035,14 +3036,14 @@
}
}
// If the array is a reasonably short list of substrings, convert it into a
- // list of symbols.
+ // list of internalized strings.
if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
for (int i = 0; i < value_array->length(); i++) {
String* str = String::cast(value_array->get(i));
- Object* symbol;
- MaybeObject* maybe_symbol = heap->LookupSymbol(str);
- if (maybe_symbol->ToObject(&symbol)) {
- value_array->set(i, symbol);
+ Object* internalized_str;
+ MaybeObject* maybe_string = heap->InternalizeString(str);
+ if (maybe_string->ToObject(&internalized_str)) {
+ value_array->set(i, internalized_str);
}
}
}
@@ -3275,7 +3276,7 @@
Code* construct_stub =
isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
share->set_construct_stub(construct_stub);
- share->set_instance_class_name(Object_symbol());
+ 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);
@@ -3341,12 +3342,12 @@
Heap* heap,
uint16_t c1,
uint16_t c2) {
- String* symbol;
+ String* result;
// Numeric strings have a different hash algorithm not known by
- // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
+ // LookupTwoCharsStringIfExists, so we skip this step for such strings.
if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
- heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
- return symbol;
+ heap->string_table()->LookupTwoCharsStringIfExists(c1, c2, &result)) {
+ return result;
// Now we know the length is 2, we might as well make use of that fact
// when building the new string.
} else if (static_cast<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) {
@@ -3387,7 +3388,7 @@
int length = first_length + second_length;
// Optimization for 2-byte strings often used as keys in a decompression
- // dictionary. Check whether we already have the string in the symbol
+ // dictionary. Check whether we already have the string in the string
// table to prevent creation of many unneccesary strings.
if (length == 2) {
uint16_t c1 = first->Get(0);
@@ -3502,8 +3503,8 @@
return LookupSingleCharacterStringFromCode(buffer->Get(start));
} else 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 symbol
- // table to prevent creation of many unneccesary strings.
+ // dictionary. Check whether we already have the string in the string
+ // table to prevent creation of many unnecessary strings.
uint16_t c1 = buffer->Get(start);
uint16_t c2 = buffer->Get(start + 1);
return MakeOrFindTwoCharacterString(this, c1, c2);
@@ -3650,7 +3651,7 @@
buffer[0] = static_cast<uint8_t>(code);
Object* result;
MaybeObject* maybe_result =
- LookupOneByteSymbol(Vector<const uint8_t>(buffer, 1));
+ InternalizeOneByteString(Vector<const uint8_t>(buffer, 1));
if (!maybe_result->ToObject(&result)) return maybe_result;
single_character_string_cache()->set(code, result);
@@ -3903,6 +3904,28 @@
}
+MaybeObject* Heap::AllocateWithAllocationSite(Map* map, AllocationSpace space,
+ Handle<Object> allocation_site_info_payload) {
+ ASSERT(gc_state_ == NOT_IN_GC);
+ ASSERT(map->instance_type() != MAP_TYPE);
+ // If allocation failures are disallowed, we may allocate in a different
+ // space when new space is full and the object is not a large object.
+ AllocationSpace retry_space =
+ (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
+ int size = map->instance_size() + AllocationSiteInfo::kSize;
+ Object* result;
+ MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ // No need for write barrier since object is white and map is in old space.
+ HeapObject::cast(result)->set_map_no_write_barrier(map);
+ AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
+ reinterpret_cast<Address>(result) + map->instance_size());
+ alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+ alloc_info->set_payload(*allocation_site_info_payload, SKIP_WRITE_BARRIER);
+ return result;
+}
+
+
MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
ASSERT(gc_state_ == NOT_IN_GC);
ASSERT(map->instance_type() != MAP_TYPE);
@@ -3910,11 +3933,10 @@
// space when new space is full and the object is not a large object.
AllocationSpace retry_space =
(space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
+ int size = map->instance_size();
Object* result;
- { MaybeObject* maybe_result =
- AllocateRaw(map->instance_size(), space, retry_space);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
// No need for write barrier since object is white and map is in old space.
HeapObject::cast(result)->set_map_no_write_barrier(map);
return result;
@@ -3959,7 +3981,7 @@
// constructor to the function.
MaybeObject* maybe_failure =
JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
- constructor_symbol(), function, DONT_ENUM);
+ constructor_string(), function, DONT_ENUM);
if (maybe_failure->IsFailure()) return maybe_failure;
return prototype;
@@ -4098,7 +4120,7 @@
DescriptorArray::WhitenessWitness witness(descriptors);
for (int i = 0; i < count; i++) {
String* name = fun->shared()->GetThisPropertyAssignmentName(i);
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
FieldDescriptor field(name, i, NONE, i + 1);
descriptors->Set(i, &field, witness);
}
@@ -4182,10 +4204,48 @@
(pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
Object* obj;
- { MaybeObject* maybe_obj = Allocate(map, space);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ MaybeObject* maybe_obj = Allocate(map, space);
+ if (!maybe_obj->To(&obj)) return maybe_obj;
+
+ // Initialize the JSObject.
+ InitializeJSObjectFromMap(JSObject::cast(obj),
+ FixedArray::cast(properties),
+ map);
+ ASSERT(JSObject::cast(obj)->HasFastElements());
+ return obj;
+}
+
+
+MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map,
+ Handle<Object> allocation_site_info_payload) {
+ // JSFunctions should be allocated using AllocateFunction to be
+ // properly initialized.
+ ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
+
+ // Both types of global objects should be allocated using
+ // AllocateGlobalObject to be properly initialized.
+ ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
+ ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
+
+ // Allocate the backing storage for the properties.
+ int prop_size =
+ map->pre_allocated_property_fields() +
+ map->unused_property_fields() -
+ map->inobject_properties();
+ ASSERT(prop_size >= 0);
+ Object* properties;
+ { MaybeObject* maybe_properties = AllocateFixedArray(prop_size);
+ if (!maybe_properties->ToObject(&properties)) return maybe_properties;
}
+ // Allocate the JSObject.
+ AllocationSpace space = NEW_SPACE;
+ if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
+ Object* obj;
+ MaybeObject* maybe_obj = AllocateWithAllocationSite(map, space,
+ allocation_site_info_payload);
+ if (!maybe_obj->To(&obj)) return maybe_obj;
+
// Initialize the JSObject.
InitializeJSObjectFromMap(JSObject::cast(obj),
FixedArray::cast(properties),
@@ -4218,6 +4278,51 @@
}
+MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
+ Handle<Object> allocation_site_info_payload) {
+ // Allocate the initial map if absent.
+ if (!constructor->has_initial_map()) {
+ Object* initial_map;
+ { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
+ if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
+ }
+ constructor->set_initial_map(Map::cast(initial_map));
+ Map::cast(initial_map)->set_constructor(constructor);
+ }
+ // Allocate the object based on the constructors initial map, or the payload
+ // advice
+ Map* initial_map = constructor->initial_map();
+
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(
+ *allocation_site_info_payload);
+ Smi* smi = Smi::cast(cell->value());
+ ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
+ AllocationSiteMode mode = TRACK_ALLOCATION_SITE;
+ if (to_kind != initial_map->elements_kind()) {
+ MaybeObject* maybe_new_map = constructor->GetElementsTransitionMap(
+ isolate(), to_kind);
+ if (!maybe_new_map->To(&initial_map)) return maybe_new_map;
+ // Possibly alter the mode, since we found an updated elements kind
+ // in the type info cell.
+ mode = AllocationSiteInfo::GetMode(to_kind);
+ }
+
+ MaybeObject* result;
+ if (mode == TRACK_ALLOCATION_SITE) {
+ result = AllocateJSObjectFromMapWithAllocationSite(initial_map,
+ allocation_site_info_payload);
+ } else {
+ result = AllocateJSObjectFromMap(initial_map, NOT_TENURED);
+ }
+#ifdef DEBUG
+ // Make sure result is NOT a global object if valid.
+ Object* non_failure;
+ ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
+#endif
+ return result;
+}
+
+
MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
// Allocate a fresh map. Modules do not have a prototype.
Map* map;
@@ -4239,11 +4344,14 @@
int capacity,
ArrayStorageAllocationMode mode,
PretenureFlag pretenure) {
- ASSERT(capacity >= length);
MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
JSArray* array;
if (!maybe_array->To(&array)) return maybe_array;
+ // TODO(mvstanton): this body of code is duplicate with AllocateJSArrayStorage
+ // for performance reasons.
+ ASSERT(capacity >= length);
+
if (capacity == 0) {
array->set_length(Smi::FromInt(0));
array->set_elements(empty_fixed_array());
@@ -4276,6 +4384,60 @@
}
+MaybeObject* Heap::AllocateJSArrayAndStorageWithAllocationSite(
+ ElementsKind elements_kind,
+ int length,
+ int capacity,
+ Handle<Object> allocation_site_payload,
+ ArrayStorageAllocationMode mode) {
+ MaybeObject* maybe_array = AllocateJSArrayWithAllocationSite(elements_kind,
+ allocation_site_payload);
+ JSArray* array;
+ if (!maybe_array->To(&array)) return maybe_array;
+ return AllocateJSArrayStorage(array, length, capacity, mode);
+}
+
+
+MaybeObject* Heap::AllocateJSArrayStorage(
+ 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 array;
+ }
+
+ FixedArrayBase* elms;
+ MaybeObject* maybe_elms = NULL;
+ ElementsKind elements_kind = array->GetElementsKind();
+ if (IsFastDoubleElementsKind(elements_kind)) {
+ if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
+ maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
+ } else {
+ ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
+ maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
+ }
+ } else {
+ ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
+ if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
+ maybe_elms = AllocateUninitializedFixedArray(capacity);
+ } else {
+ ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
+ maybe_elms = AllocateFixedArrayWithHoles(capacity);
+ }
+ }
+ if (!maybe_elms->To(&elms)) return maybe_elms;
+
+ array->set_elements(elms);
+ array->set_length(Smi::FromInt(length));
+ return array;
+}
+
+
MaybeObject* Heap::AllocateJSArrayWithElements(
FixedArrayBase* elements,
ElementsKind elements_kind,
@@ -4406,8 +4568,7 @@
}
-MaybeObject* Heap::CopyJSObject(JSObject* source,
- AllocationSiteMode mode) {
+MaybeObject* Heap::CopyJSObject(JSObject* source) {
// Never used to copy functions. If functions need to be copied we
// have to be careful to clear the literals array.
SLOW_ASSERT(!source->IsJSFunction());
@@ -4417,25 +4578,13 @@
int object_size = map->instance_size();
Object* clone;
- bool track_origin = mode == TRACK_ALLOCATION_SITE &&
- map->CanTrackAllocationSite();
-
WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
// If we're forced to always allocate, we use the general allocation
// functions which may leave us with an object in old space.
- int adjusted_object_size = object_size;
if (always_allocate()) {
- // We'll only track origin if we are certain to allocate in new space
- if (track_origin) {
- const int kMinFreeNewSpaceAfterGC = InitialSemiSpaceSize() * 3/4;
- if ((object_size + AllocationSiteInfo::kSize) < kMinFreeNewSpaceAfterGC) {
- adjusted_object_size += AllocationSiteInfo::kSize;
- }
- }
-
{ MaybeObject* maybe_clone =
- AllocateRaw(adjusted_object_size, NEW_SPACE, OLD_POINTER_SPACE);
+ AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
if (!maybe_clone->ToObject(&clone)) return maybe_clone;
}
Address clone_address = HeapObject::cast(clone)->address();
@@ -4448,10 +4597,107 @@
(object_size - JSObject::kHeaderSize) / kPointerSize);
} else {
wb_mode = SKIP_WRITE_BARRIER;
- if (track_origin) {
+
+ { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
+ if (!maybe_clone->ToObject(&clone)) return maybe_clone;
+ }
+ SLOW_ASSERT(InNewSpace(clone));
+ // Since we know the clone is allocated in new space, we can copy
+ // the contents without worrying about updating the write barrier.
+ CopyBlock(HeapObject::cast(clone)->address(),
+ source->address(),
+ object_size);
+ }
+
+ SLOW_ASSERT(
+ JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
+ FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
+ FixedArray* properties = FixedArray::cast(source->properties());
+ // Update elements if necessary.
+ if (elements->length() > 0) {
+ Object* elem;
+ { MaybeObject* maybe_elem;
+ if (elements->map() == fixed_cow_array_map()) {
+ maybe_elem = FixedArray::cast(elements);
+ } else if (source->HasFastDoubleElements()) {
+ maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
+ } else {
+ maybe_elem = CopyFixedArray(FixedArray::cast(elements));
+ }
+ if (!maybe_elem->ToObject(&elem)) return maybe_elem;
+ }
+ JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
+ }
+ // Update properties if necessary.
+ if (properties->length() > 0) {
+ Object* prop;
+ { MaybeObject* maybe_prop = CopyFixedArray(properties);
+ if (!maybe_prop->ToObject(&prop)) return maybe_prop;
+ }
+ JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
+ }
+ // Return the new clone.
+ return clone;
+}
+
+
+MaybeObject* Heap::CopyJSObjectWithAllocationSite(JSObject* source) {
+ // Never used to copy functions. If functions need to be copied we
+ // have to be careful to clear the literals array.
+ SLOW_ASSERT(!source->IsJSFunction());
+
+ // Make the clone.
+ Map* map = source->map();
+ int object_size = map->instance_size();
+ Object* clone;
+
+ ASSERT(map->CanTrackAllocationSite());
+ ASSERT(map->instance_type() == JS_ARRAY_TYPE);
+ WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
+
+ // If we're forced to always allocate, we use the general allocation
+ // functions which may leave us with an object in old space.
+ int adjusted_object_size = object_size;
+ if (always_allocate()) {
+ // We'll only track origin if we are certain to allocate in new space
+ const int kMinFreeNewSpaceAfterGC = InitialSemiSpaceSize() * 3/4;
+ if ((object_size + AllocationSiteInfo::kSize) < kMinFreeNewSpaceAfterGC) {
adjusted_object_size += AllocationSiteInfo::kSize;
}
+ { MaybeObject* maybe_clone =
+ AllocateRaw(adjusted_object_size, NEW_SPACE, OLD_POINTER_SPACE);
+ if (!maybe_clone->ToObject(&clone)) return maybe_clone;
+ }
+ Address clone_address = HeapObject::cast(clone)->address();
+ CopyBlock(clone_address,
+ source->address(),
+ object_size);
+ // Update write barrier for all fields that lie beyond the header.
+ int write_barrier_offset = adjusted_object_size > object_size
+ ? JSArray::kSize + AllocationSiteInfo::kSize
+ : JSObject::kHeaderSize;
+ if (((object_size - write_barrier_offset) / kPointerSize) > 0) {
+ RecordWrites(clone_address,
+ write_barrier_offset,
+ (object_size - write_barrier_offset) / kPointerSize);
+ }
+
+ // Track allocation site information, if we failed to allocate it inline.
+ if (InNewSpace(clone) &&
+ adjusted_object_size == object_size) {
+ MaybeObject* maybe_alloc_info =
+ AllocateStruct(ALLOCATION_SITE_INFO_TYPE);
+ AllocationSiteInfo* alloc_info;
+ if (maybe_alloc_info->To(&alloc_info)) {
+ alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+ alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
+ }
+ }
+ } else {
+ wb_mode = SKIP_WRITE_BARRIER;
+ adjusted_object_size += AllocationSiteInfo::kSize;
+
{ MaybeObject* maybe_clone = new_space_.AllocateRaw(adjusted_object_size);
if (!maybe_clone->ToObject(&clone)) return maybe_clone;
}
@@ -4466,8 +4712,8 @@
if (adjusted_object_size > object_size) {
AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
reinterpret_cast<Address>(clone) + object_size);
- alloc_info->set_map(allocation_site_info_map());
- alloc_info->set_payload(source);
+ alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+ alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
}
SLOW_ASSERT(
@@ -4528,7 +4774,8 @@
SharedFunctionInfo* shared = NULL;
if (type == JS_FUNCTION_TYPE) {
String* name;
- maybe = LookupOneByteSymbol(STATIC_ASCII_VECTOR("<freezing call trap>"));
+ maybe =
+ InternalizeOneByteString(STATIC_ASCII_VECTOR("<freezing call trap>"));
if (!maybe->To<String>(&name)) return maybe;
maybe = AllocateSharedFunctionInfo(name);
if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
@@ -4662,25 +4909,27 @@
}
-Map* Heap::SymbolMapForString(String* string) {
- // If the string is in new space it cannot be used as a symbol.
+Map* Heap::InternalizedStringMapForString(String* string) {
+ // If the string is in new space it cannot be used as internalized.
if (InNewSpace(string)) return NULL;
- // Find the corresponding symbol map for strings.
+ // Find the corresponding internalized string map for strings.
switch (string->map()->instance_type()) {
- case STRING_TYPE: return symbol_map();
- case ASCII_STRING_TYPE: return ascii_symbol_map();
- case CONS_STRING_TYPE: return cons_symbol_map();
- case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
- case EXTERNAL_STRING_TYPE: return external_symbol_map();
- case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
+ case STRING_TYPE: return internalized_string_map();
+ case ASCII_STRING_TYPE: return ascii_internalized_string_map();
+ case CONS_STRING_TYPE: return cons_internalized_string_map();
+ case CONS_ASCII_STRING_TYPE: return cons_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_ASCII_DATA_TYPE:
- return external_symbol_with_ascii_data_map();
- case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
+ return external_internalized_string_with_ascii_data_map();
+ case SHORT_EXTERNAL_STRING_TYPE:
+ return short_external_internalized_string_map();
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
- return short_external_ascii_symbol_map();
+ return short_external_ascii_internalized_string_map();
case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
- return short_external_symbol_with_ascii_data_map();
+ return short_external_internalized_string_with_ascii_data_map();
default: return NULL; // No match found.
}
}
@@ -4734,9 +4983,8 @@
template<bool is_one_byte, typename T>
-MaybeObject* Heap::AllocateInternalSymbol(T t,
- int chars,
- uint32_t hash_field) {
+MaybeObject* Heap::AllocateInternalizedStringImpl(
+ T t, int chars, uint32_t hash_field) {
ASSERT(chars >= 0);
// Compute map and object size.
int size;
@@ -4746,13 +4994,13 @@
if (chars > SeqOneByteString::kMaxLength) {
return Failure::OutOfMemoryException(0x9);
}
- map = ascii_symbol_map();
+ map = ascii_internalized_string_map();
size = SeqOneByteString::SizeFor(chars);
} else {
if (chars > SeqTwoByteString::kMaxLength) {
return Failure::OutOfMemoryException(0xa);
}
- map = symbol_map();
+ map = internalized_string_map();
size = SeqTwoByteString::SizeFor(chars);
}
@@ -4783,13 +5031,13 @@
// Need explicit instantiations.
template
-MaybeObject* Heap::AllocateInternalSymbol<true>(String*, int, uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<true>(String*, int, uint32_t);
template
-MaybeObject* Heap::AllocateInternalSymbol<false>(String*, int, uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<false>(
+ String*, int, uint32_t);
template
-MaybeObject* Heap::AllocateInternalSymbol<false>(Vector<const char>,
- int,
- uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<false>(
+ Vector<const char>, int, uint32_t);
MaybeObject* Heap::AllocateRawOneByteString(int length,
@@ -4897,6 +5145,25 @@
}
+MaybeObject* Heap::AllocateJSArrayWithAllocationSite(
+ ElementsKind elements_kind,
+ Handle<Object> allocation_site_info_payload) {
+ Context* native_context = isolate()->context()->native_context();
+ JSFunction* array_function = native_context->array_function();
+ Map* map = array_function->initial_map();
+ Object* maybe_map_array = native_context->js_array_maps();
+ if (!maybe_map_array->IsUndefined()) {
+ Object* maybe_transitioned_map =
+ FixedArray::cast(maybe_map_array)->get(elements_kind);
+ if (!maybe_transitioned_map->IsUndefined()) {
+ map = Map::cast(maybe_transitioned_map);
+ }
+ }
+ return AllocateJSObjectFromMapWithAllocationSite(map,
+ allocation_site_info_payload);
+}
+
+
MaybeObject* Heap::AllocateEmptyFixedArray() {
int size = FixedArray::SizeFor(0);
Object* result;
@@ -5167,6 +5434,34 @@
}
+MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) {
+ // Statically ensure that it is safe to allocate symbols in paged spaces.
+ STATIC_ASSERT(Symbol::kSize <= Page::kNonCodeObjectAreaSize);
+ AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+
+ Object* result;
+ MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_DATA_SPACE);
+ if (!maybe->ToObject(&result)) return maybe;
+
+ HeapObject::cast(result)->set_map_no_write_barrier(symbol_map());
+
+ // Generate a random hash value.
+ int hash;
+ int attempts = 0;
+ do {
+ hash = V8::RandomPrivate(isolate()) & Name::kHashBitMask;
+ attempts++;
+ } while (hash == 0 && attempts < 30);
+ if (hash == 0) hash = 1; // never return 0
+
+ Symbol::cast(result)->set_hash_field(
+ Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
+
+ ASSERT(result->IsSymbol());
+ return result;
+}
+
+
MaybeObject* Heap::AllocateNativeContext() {
Object* result;
{ MaybeObject* maybe_result =
@@ -5661,93 +5956,93 @@
#endif
-MaybeObject* Heap::LookupUtf8Symbol(Vector<const char> string) {
- Object* symbol = NULL;
+MaybeObject* Heap::InternalizeUtf8String(Vector<const char> string) {
+ Object* result = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
- symbol_table()->LookupUtf8Symbol(string, &symbol);
+ string_table()->LookupUtf8String(string, &result);
if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
}
- // Can't use set_symbol_table because SymbolTable::cast knows that
- // SymbolTable is a singleton and checks for identity.
- roots_[kSymbolTableRootIndex] = new_table;
- ASSERT(symbol != NULL);
- return symbol;
+ // Can't use set_string_table because StringTable::cast knows that
+ // StringTable is a singleton and checks for identity.
+ roots_[kStringTableRootIndex] = new_table;
+ ASSERT(result != NULL);
+ return result;
}
-MaybeObject* Heap::LookupOneByteSymbol(Vector<const uint8_t> string) {
- Object* symbol = NULL;
+MaybeObject* Heap::InternalizeOneByteString(Vector<const uint8_t> string) {
+ Object* result = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
- symbol_table()->LookupOneByteSymbol(string, &symbol);
+ string_table()->LookupOneByteString(string, &result);
if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
}
- // Can't use set_symbol_table because SymbolTable::cast knows that
- // SymbolTable is a singleton and checks for identity.
- roots_[kSymbolTableRootIndex] = new_table;
- ASSERT(symbol != NULL);
- return symbol;
+ // Can't use set_string_table because StringTable::cast knows that
+ // StringTable is a singleton and checks for identity.
+ roots_[kStringTableRootIndex] = new_table;
+ ASSERT(result != NULL);
+ return result;
}
-MaybeObject* Heap::LookupOneByteSymbol(Handle<SeqOneByteString> string,
+MaybeObject* Heap::InternalizeOneByteString(Handle<SeqOneByteString> string,
int from,
int length) {
- Object* symbol = NULL;
+ Object* result = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
- symbol_table()->LookupSubStringOneByteSymbol(string,
+ string_table()->LookupSubStringOneByteString(string,
from,
length,
- &symbol);
+ &result);
if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
}
- // Can't use set_symbol_table because SymbolTable::cast knows that
- // SymbolTable is a singleton and checks for identity.
- roots_[kSymbolTableRootIndex] = new_table;
- ASSERT(symbol != NULL);
- return symbol;
+ // Can't use set_string_table because StringTable::cast knows that
+ // StringTable is a singleton and checks for identity.
+ roots_[kStringTableRootIndex] = new_table;
+ ASSERT(result != NULL);
+ return result;
}
-MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
- Object* symbol = NULL;
+MaybeObject* Heap::InternalizeTwoByteString(Vector<const uc16> string) {
+ Object* result = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
- symbol_table()->LookupTwoByteSymbol(string, &symbol);
+ string_table()->LookupTwoByteString(string, &result);
if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
}
- // Can't use set_symbol_table because SymbolTable::cast knows that
- // SymbolTable is a singleton and checks for identity.
- roots_[kSymbolTableRootIndex] = new_table;
- ASSERT(symbol != NULL);
- return symbol;
+ // Can't use set_string_table because StringTable::cast knows that
+ // StringTable is a singleton and checks for identity.
+ roots_[kStringTableRootIndex] = new_table;
+ ASSERT(result != NULL);
+ return result;
}
-MaybeObject* Heap::LookupSymbol(String* string) {
- if (string->IsSymbol()) return string;
- Object* symbol = NULL;
+MaybeObject* Heap::InternalizeString(String* string) {
+ if (string->IsInternalizedString()) return string;
+ Object* result = NULL;
Object* new_table;
{ MaybeObject* maybe_new_table =
- symbol_table()->LookupString(string, &symbol);
+ string_table()->LookupString(string, &result);
if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
}
- // Can't use set_symbol_table because SymbolTable::cast knows that
- // SymbolTable is a singleton and checks for identity.
- roots_[kSymbolTableRootIndex] = new_table;
- ASSERT(symbol != NULL);
- return symbol;
+ // Can't use set_string_table because StringTable::cast knows that
+ // StringTable is a singleton and checks for identity.
+ roots_[kStringTableRootIndex] = new_table;
+ ASSERT(result != NULL);
+ return result;
}
-bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
- if (string->IsSymbol()) {
- *symbol = string;
+bool Heap::InternalizeStringIfExists(String* string, String** result) {
+ if (string->IsInternalizedString()) {
+ *result = string;
return true;
}
- return symbol_table()->LookupSymbolIfExists(string, symbol);
+ return string_table()->LookupStringIfExists(string, result);
}
@@ -5975,8 +6270,8 @@
void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
- v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
- v->Synchronize(VisitorSynchronization::kSymbolTable);
+ v->VisitPointer(reinterpret_cast<Object**>(&roots_[kStringTableRootIndex]));
+ v->Synchronize(VisitorSynchronization::kStringTable);
if (mode != VISIT_ALL_IN_SCAVENGE &&
mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
// Scavenge collections have special processing for this.
@@ -5991,8 +6286,8 @@
v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
v->Synchronize(VisitorSynchronization::kStrongRootList);
- v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
- v->Synchronize(VisitorSynchronization::kSymbol);
+ v->VisitPointer(BitCast<Object**>(&hidden_string_));
+ v->Synchronize(VisitorSynchronization::kInternalizedString);
isolate_->bootstrapper()->Iterate(v);
v->Synchronize(VisitorSynchronization::kBootstrapper);
@@ -7169,9 +7464,9 @@
void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
- String* symbol;
- if (HEAP->LookupSymbolIfExists(name, &symbol)) {
- int index = (Hash(map, symbol) & kHashMask);
+ String* internalized_name;
+ if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
+ int index = (Hash(map, internalized_name) & kHashMask);
// After a GC there will be free slots, so we use them in order (this may
// help to get the most frequently used one in position 0).
for (int i = 0; i< kEntriesPerBucket; i++) {
@@ -7179,7 +7474,7 @@
Object* free_entry_indicator = NULL;
if (key.map == free_entry_indicator) {
key.map = map;
- key.name = symbol;
+ key.name = internalized_name;
field_offsets_[index + i] = field_offset;
return;
}
@@ -7196,7 +7491,7 @@
// Write the new first entry.
Key& key = keys_[index];
key.map = map;
- key.name = symbol;
+ key.name = internalized_name;
field_offsets_[index] = field_offset;
}
}
@@ -7329,7 +7624,7 @@
if (nested_ || list_.is_empty() || isolate->has_pending_exception()) return;
nested_ = true;
HandleScope scope(isolate);
- Handle<String> stack_key = isolate->factory()->stack_symbol();
+ Handle<String> stack_key = isolate->factory()->stack_string();
int write_index = 0;
int budget = kBudgetPerGC;
for (int i = 0; i < list_.length(); i++) {
@@ -7353,7 +7648,7 @@
Object* getter_obj = AccessorPair::cast(callback)->getter();
if (!getter_obj->IsJSFunction()) continue;
getter_fun = JSFunction::cast(getter_obj);
- String* key = isolate->heap()->hidden_stack_trace_symbol();
+ String* key = isolate->heap()->hidden_stack_trace_string();
if (key != getter_fun->GetHiddenProperty(key)) continue;
}
diff --git a/src/heap.h b/src/heap.h
index 3c599ed..a5ff86e 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -61,8 +61,6 @@
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
V(Map, shared_function_info_map, SharedFunctionInfoMap) \
V(Map, meta_map, MetaMap) \
- V(Map, ascii_symbol_map, AsciiSymbolMap) \
- V(Map, ascii_string_map, AsciiStringMap) \
V(Map, heap_number_map, HeapNumberMap) \
V(Map, native_context_map, NativeContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
@@ -74,7 +72,6 @@
V(Map, hash_table_map, HashTableMap) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \
- V(String, empty_string, EmptyString) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Smi, stack_limit, StackLimit) \
V(Oddball, arguments_marker, ArgumentsMarker) \
@@ -90,29 +87,42 @@
V(FixedArray, regexp_multiple_cache, RegExpMultipleCache) \
V(Object, termination_exception, TerminationException) \
V(Smi, hash_seed, HashSeed) \
- V(Map, string_map, StringMap) \
V(Map, symbol_map, SymbolMap) \
+ V(Map, string_map, StringMap) \
+ V(Map, ascii_string_map, AsciiStringMap) \
V(Map, cons_string_map, ConsStringMap) \
V(Map, cons_ascii_string_map, ConsAsciiStringMap) \
V(Map, sliced_string_map, SlicedStringMap) \
V(Map, sliced_ascii_string_map, SlicedAsciiStringMap) \
- V(Map, cons_symbol_map, ConsSymbolMap) \
- V(Map, cons_ascii_symbol_map, ConsAsciiSymbolMap) \
- V(Map, external_symbol_map, ExternalSymbolMap) \
- V(Map, external_symbol_with_ascii_data_map, ExternalSymbolWithAsciiDataMap) \
- V(Map, external_ascii_symbol_map, ExternalAsciiSymbolMap) \
V(Map, external_string_map, ExternalStringMap) \
V(Map, external_string_with_ascii_data_map, ExternalStringWithAsciiDataMap) \
V(Map, external_ascii_string_map, ExternalAsciiStringMap) \
- V(Map, short_external_symbol_map, ShortExternalSymbolMap) \
- V(Map, \
- short_external_symbol_with_ascii_data_map, \
- ShortExternalSymbolWithAsciiDataMap) \
- V(Map, short_external_ascii_symbol_map, ShortExternalAsciiSymbolMap) \
V(Map, short_external_string_map, ShortExternalStringMap) \
V(Map, \
short_external_string_with_ascii_data_map, \
ShortExternalStringWithAsciiDataMap) \
+ V(Map, internalized_string_map, InternalizedStringMap) \
+ V(Map, ascii_internalized_string_map, AsciiInternalizedStringMap) \
+ V(Map, cons_internalized_string_map, ConsInternalizedStringMap) \
+ V(Map, cons_ascii_internalized_string_map, ConsAsciiInternalizedStringMap) \
+ V(Map, \
+ external_internalized_string_map, \
+ ExternalInternalizedStringMap) \
+ V(Map, \
+ external_internalized_string_with_ascii_data_map, \
+ ExternalInternalizedStringWithAsciiDataMap) \
+ V(Map, \
+ external_ascii_internalized_string_map, \
+ ExternalAsciiInternalizedStringMap) \
+ V(Map, \
+ short_external_internalized_string_map, \
+ ShortExternalInternalizedStringMap) \
+ V(Map, \
+ short_external_internalized_string_with_ascii_data_map, \
+ ShortExternalInternalizedStringWithAsciiDataMap) \
+ V(Map, \
+ short_external_ascii_internalized_string_map, \
+ ShortExternalAsciiInternalizedStringMap) \
V(Map, short_external_ascii_string_map, ShortExternalAsciiStringMap) \
V(Map, undetectable_string_map, UndetectableStringMap) \
V(Map, undetectable_ascii_string_map, UndetectableAsciiStringMap) \
@@ -160,103 +170,103 @@
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
- V(SymbolTable, symbol_table, SymbolTable)
+ V(StringTable, string_table, StringTable)
-#define SYMBOL_LIST(V) \
- V(Array_symbol, "Array") \
- V(Object_symbol, "Object") \
- V(Proto_symbol, "__proto__") \
- V(StringImpl_symbol, "StringImpl") \
- V(arguments_symbol, "arguments") \
- V(Arguments_symbol, "Arguments") \
- V(call_symbol, "call") \
- V(apply_symbol, "apply") \
- V(caller_symbol, "caller") \
- V(boolean_symbol, "boolean") \
- V(Boolean_symbol, "Boolean") \
- V(callee_symbol, "callee") \
- V(constructor_symbol, "constructor") \
- V(code_symbol, ".code") \
- V(result_symbol, ".result") \
- V(dot_for_symbol, ".for.") \
- V(catch_var_symbol, ".catch-var") \
- V(empty_symbol, "") \
- V(eval_symbol, "eval") \
- V(function_symbol, "function") \
- V(length_symbol, "length") \
- V(module_symbol, "module") \
- V(name_symbol, "name") \
- V(native_symbol, "native") \
- V(null_symbol, "null") \
- V(number_symbol, "number") \
- V(Number_symbol, "Number") \
- V(nan_symbol, "NaN") \
- V(RegExp_symbol, "RegExp") \
- V(source_symbol, "source") \
- V(global_symbol, "global") \
- V(ignore_case_symbol, "ignoreCase") \
- V(multiline_symbol, "multiline") \
- V(input_symbol, "input") \
- V(index_symbol, "index") \
- V(last_index_symbol, "lastIndex") \
- V(object_symbol, "object") \
- V(prototype_symbol, "prototype") \
- V(string_symbol, "string") \
- V(String_symbol, "String") \
- V(Date_symbol, "Date") \
- V(this_symbol, "this") \
- V(to_string_symbol, "toString") \
- V(char_at_symbol, "CharAt") \
- V(undefined_symbol, "undefined") \
- V(value_of_symbol, "valueOf") \
- V(stack_symbol, "stack") \
- V(InitializeVarGlobal_symbol, "InitializeVarGlobal") \
- V(InitializeConstGlobal_symbol, "InitializeConstGlobal") \
- V(KeyedLoadElementMonomorphic_symbol, \
+#define INTERNALIZED_STRING_LIST(V) \
+ V(Array_string, "Array") \
+ V(Object_string, "Object") \
+ V(proto_string, "__proto__") \
+ V(StringImpl_string, "StringImpl") \
+ V(arguments_string, "arguments") \
+ V(Arguments_string, "Arguments") \
+ V(call_string, "call") \
+ V(apply_string, "apply") \
+ V(caller_string, "caller") \
+ V(boolean_string, "boolean") \
+ V(Boolean_string, "Boolean") \
+ V(callee_string, "callee") \
+ V(constructor_string, "constructor") \
+ V(code_string, ".code") \
+ V(result_string, ".result") \
+ V(dot_for_string, ".for.") \
+ V(catch_var_string, ".catch-var") \
+ V(empty_string, "") \
+ V(eval_string, "eval") \
+ V(function_string, "function") \
+ V(length_string, "length") \
+ V(module_string, "module") \
+ V(name_string, "name") \
+ V(native_string, "native") \
+ V(null_string, "null") \
+ V(number_string, "number") \
+ V(Number_string, "Number") \
+ V(nan_string, "NaN") \
+ V(RegExp_string, "RegExp") \
+ V(source_string, "source") \
+ V(global_string, "global") \
+ V(ignore_case_string, "ignoreCase") \
+ V(multiline_string, "multiline") \
+ V(input_string, "input") \
+ V(index_string, "index") \
+ V(last_index_string, "lastIndex") \
+ V(object_string, "object") \
+ V(prototype_string, "prototype") \
+ V(string_string, "string") \
+ V(String_string, "String") \
+ V(Date_string, "Date") \
+ V(this_string, "this") \
+ V(to_string_string, "toString") \
+ V(char_at_string, "CharAt") \
+ V(undefined_string, "undefined") \
+ V(value_of_string, "valueOf") \
+ V(stack_string, "stack") \
+ V(InitializeVarGlobal_string, "InitializeVarGlobal") \
+ V(InitializeConstGlobal_string, "InitializeConstGlobal") \
+ V(KeyedLoadElementMonomorphic_string, \
"KeyedLoadElementMonomorphic") \
- V(KeyedStoreElementMonomorphic_symbol, \
+ V(KeyedStoreElementMonomorphic_string, \
"KeyedStoreElementMonomorphic") \
- V(KeyedStoreAndGrowElementMonomorphic_symbol, \
+ V(KeyedStoreAndGrowElementMonomorphic_string, \
"KeyedStoreAndGrowElementMonomorphic") \
- V(stack_overflow_symbol, "kStackOverflowBoilerplate") \
- V(illegal_access_symbol, "illegal access") \
- V(out_of_memory_symbol, "out-of-memory") \
- V(illegal_execution_state_symbol, "illegal execution state") \
- V(get_symbol, "get") \
- V(set_symbol, "set") \
- V(map_field_symbol, "%map") \
- V(elements_field_symbol, "%elements") \
- V(length_field_symbol, "%length") \
- V(function_class_symbol, "Function") \
- V(illegal_argument_symbol, "illegal argument") \
- V(MakeReferenceError_symbol, "MakeReferenceError") \
- V(MakeSyntaxError_symbol, "MakeSyntaxError") \
- V(MakeTypeError_symbol, "MakeTypeError") \
- V(invalid_lhs_in_assignment_symbol, "invalid_lhs_in_assignment") \
- V(invalid_lhs_in_for_in_symbol, "invalid_lhs_in_for_in") \
- V(invalid_lhs_in_postfix_op_symbol, "invalid_lhs_in_postfix_op") \
- V(invalid_lhs_in_prefix_op_symbol, "invalid_lhs_in_prefix_op") \
- V(illegal_return_symbol, "illegal_return") \
- V(illegal_break_symbol, "illegal_break") \
- V(illegal_continue_symbol, "illegal_continue") \
- V(unknown_label_symbol, "unknown_label") \
- V(redeclaration_symbol, "redeclaration") \
- V(failure_symbol, "<failure>") \
- V(space_symbol, " ") \
- V(exec_symbol, "exec") \
- V(zero_symbol, "0") \
- V(global_eval_symbol, "GlobalEval") \
- V(identity_hash_symbol, "v8::IdentityHash") \
- V(closure_symbol, "(closure)") \
- V(use_strict, "use strict") \
- V(dot_symbol, ".") \
- V(anonymous_function_symbol, "(anonymous function)") \
- V(compare_ic_symbol, "==") \
- V(strict_compare_ic_symbol, "===") \
- V(infinity_symbol, "Infinity") \
- V(minus_infinity_symbol, "-Infinity") \
- V(hidden_stack_trace_symbol, "v8::hidden_stack_trace") \
- V(query_colon_symbol, "(?:)")
+ V(stack_overflow_string, "kStackOverflowBoilerplate") \
+ V(illegal_access_string, "illegal access") \
+ V(out_of_memory_string, "out-of-memory") \
+ V(illegal_execution_state_string, "illegal execution state") \
+ V(get_string, "get") \
+ V(set_string, "set") \
+ V(map_field_string, "%map") \
+ V(elements_field_string, "%elements") \
+ V(length_field_string, "%length") \
+ V(function_class_string, "Function") \
+ V(illegal_argument_string, "illegal argument") \
+ V(MakeReferenceError_string, "MakeReferenceError") \
+ V(MakeSyntaxError_string, "MakeSyntaxError") \
+ V(MakeTypeError_string, "MakeTypeError") \
+ V(invalid_lhs_in_assignment_string, "invalid_lhs_in_assignment") \
+ V(invalid_lhs_in_for_in_string, "invalid_lhs_in_for_in") \
+ V(invalid_lhs_in_postfix_op_string, "invalid_lhs_in_postfix_op") \
+ V(invalid_lhs_in_prefix_op_string, "invalid_lhs_in_prefix_op") \
+ V(illegal_return_string, "illegal_return") \
+ V(illegal_break_string, "illegal_break") \
+ V(illegal_continue_string, "illegal_continue") \
+ V(unknown_label_string, "unknown_label") \
+ V(redeclaration_string, "redeclaration") \
+ V(failure_string, "<failure>") \
+ V(space_string, " ") \
+ V(exec_string, "exec") \
+ V(zero_string, "0") \
+ V(global_eval_string, "GlobalEval") \
+ V(identity_hash_string, "v8::IdentityHash") \
+ V(closure_string, "(closure)") \
+ V(use_strict_string, "use strict") \
+ V(dot_string, ".") \
+ V(anonymous_function_string, "(anonymous function)") \
+ V(compare_ic_string, "==") \
+ V(strict_compare_ic_string, "===") \
+ V(infinity_string, "Infinity") \
+ V(minus_infinity_string, "-Infinity") \
+ V(hidden_stack_trace_string, "v8::hidden_stack_trace") \
+ V(query_colon_string, "(?:)") \
// Forward declarations.
class GCTracer;
@@ -591,7 +601,12 @@
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateJSObject(
- JSFunction* constructor, PretenureFlag pretenure = NOT_TENURED);
+ JSFunction* constructor,
+ PretenureFlag pretenure = NOT_TENURED);
+
+ MUST_USE_RESULT MaybeObject* AllocateJSObjectWithAllocationSite(
+ JSFunction* constructor,
+ Handle<Object> allocation_site_info_payload);
MUST_USE_RESULT MaybeObject* AllocateJSModule(Context* context,
ScopeInfo* scope_info);
@@ -605,6 +620,10 @@
pretenure);
}
+ inline MUST_USE_RESULT MaybeObject* AllocateEmptyJSArrayWithAllocationSite(
+ ElementsKind elements_kind,
+ Handle<Object> allocation_site_payload);
+
// Allocate a JSArray with a specified length but elements that are left
// uninitialized.
MUST_USE_RESULT MaybeObject* AllocateJSArrayAndStorage(
@@ -614,6 +633,19 @@
ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS,
PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateJSArrayAndStorageWithAllocationSite(
+ ElementsKind elements_kind,
+ int length,
+ int capacity,
+ Handle<Object> allocation_site_payload,
+ ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS);
+
+ MUST_USE_RESULT MaybeObject* AllocateJSArrayStorage(
+ JSArray* array,
+ int length,
+ int capacity,
+ ArrayStorageAllocationMode mode = DONT_INITIALIZE_ARRAY_ELEMENTS);
+
// Allocate a JSArray with no elements
MUST_USE_RESULT MaybeObject* AllocateJSArrayWithElements(
FixedArrayBase* array_base,
@@ -630,9 +662,9 @@
// Returns a deep copy of the JavaScript object.
// Properties and elements are copied too.
// Returns failure if allocation failed.
- MUST_USE_RESULT MaybeObject* CopyJSObject(
- JSObject* source,
- AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE);
+ MUST_USE_RESULT MaybeObject* CopyJSObject(JSObject* source);
+
+ MUST_USE_RESULT MaybeObject* CopyJSObjectWithAllocationSite(JSObject* source);
// Allocates the function prototype.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
@@ -675,12 +707,18 @@
MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMap(
Map* map, PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateJSObjectFromMapWithAllocationSite(
+ Map* map, Handle<Object> allocation_site_info_payload);
+
// Allocates a heap object based on the map.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* Allocate(Map* map, AllocationSpace space);
+ MUST_USE_RESULT MaybeObject* AllocateWithAllocationSite(Map* map,
+ AllocationSpace space, Handle<Object> allocation_site_info_payload);
+
// Allocates a JS Map in the heap.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
@@ -763,20 +801,20 @@
Vector<const uc16> str,
PretenureFlag pretenure = NOT_TENURED);
- // Allocates a symbol in old space based on the character stream.
- // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
- // failed.
+ // Allocates an internalized string in old space based on the character
+ // stream. Returns Failure::RetryAfterGC(requested_bytes, space) if the
+ // allocation failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT inline MaybeObject* AllocateSymbolFromUtf8(
+ MUST_USE_RESULT inline MaybeObject* AllocateInternalizedStringFromUtf8(
Vector<const char> str,
int chars,
uint32_t hash_field);
- MUST_USE_RESULT inline MaybeObject* AllocateOneByteSymbol(
+ MUST_USE_RESULT inline MaybeObject* AllocateOneByteInternalizedString(
Vector<const uint8_t> str,
uint32_t hash_field);
- MUST_USE_RESULT inline MaybeObject* AllocateTwoByteSymbol(
+ MUST_USE_RESULT inline MaybeObject* AllocateTwoByteInternalizedString(
Vector<const uc16> str,
uint32_t hash_field);
@@ -784,11 +822,11 @@
static inline bool IsOneByte(T t, int chars);
template<typename T>
- MUST_USE_RESULT inline MaybeObject* AllocateInternalSymbol(
+ MUST_USE_RESULT inline MaybeObject* AllocateInternalizedStringImpl(
T t, int chars, uint32_t hash_field);
template<bool is_one_byte, typename T>
- MUST_USE_RESULT MaybeObject* AllocateInternalSymbol(
+ MUST_USE_RESULT MaybeObject* AllocateInternalizedStringImpl(
T t, int chars, uint32_t hash_field);
// Allocates and partially initializes a String. There are two String
@@ -835,6 +873,13 @@
void* external_pointer,
PretenureFlag pretenure);
+ // Allocate a symbol.
+ // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+ // failed.
+ // Please note this does not perform a garbage collection.
+ MUST_USE_RESULT MaybeObject* AllocateSymbol(
+ PretenureFlag pretenure = NOT_TENURED);
+
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
@@ -1085,27 +1130,28 @@
// the provided data as the relocation information.
MUST_USE_RESULT MaybeObject* CopyCode(Code* code, Vector<byte> reloc_info);
- // Finds the symbol for string in the symbol table.
- // If not found, a new symbol is added to the table and returned.
+ // Finds the internalized copy for string in the string table.
+ // If not found, a new string is added to the table and returned.
// Returns Failure::RetryAfterGC(requested_bytes, space) if allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* LookupUtf8Symbol(Vector<const char> str);
- MUST_USE_RESULT MaybeObject* LookupUtf8Symbol(const char* str) {
- return LookupUtf8Symbol(CStrVector(str));
+ MUST_USE_RESULT MaybeObject* InternalizeUtf8String(Vector<const char> str);
+ MUST_USE_RESULT MaybeObject* InternalizeUtf8String(const char* str) {
+ return InternalizeUtf8String(CStrVector(str));
}
- MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const uint8_t> str);
- MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str);
- MUST_USE_RESULT MaybeObject* LookupSymbol(String* str);
- MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(
+ MUST_USE_RESULT MaybeObject* InternalizeOneByteString(
+ Vector<const uint8_t> str);
+ MUST_USE_RESULT MaybeObject* InternalizeTwoByteString(Vector<const uc16> str);
+ MUST_USE_RESULT MaybeObject* InternalizeString(String* str);
+ MUST_USE_RESULT MaybeObject* InternalizeOneByteString(
Handle<SeqOneByteString> string, int from, int length);
- bool LookupSymbolIfExists(String* str, String** symbol);
- bool LookupTwoCharsSymbolIfExists(String* str, String** symbol);
+ bool InternalizeStringIfExists(String* str, String** result);
+ bool InternalizeTwoCharsStringIfExists(String* str, String** result);
- // Compute the matching symbol map for a string if possible.
+ // Compute the matching internalized string map for a string if possible.
// NULL is returned if string is in new space or not flattened.
- Map* SymbolMapForString(String* str);
+ Map* InternalizedStringMapForString(String* str);
// Tries to flatten a string before compare operation.
//
@@ -1233,15 +1279,15 @@
STRUCT_LIST(STRUCT_MAP_ACCESSOR)
#undef STRUCT_MAP_ACCESSOR
-#define SYMBOL_ACCESSOR(name, str) String* name() { \
+#define STRING_ACCESSOR(name, str) String* name() { \
return String::cast(roots_[k##name##RootIndex]); \
}
- SYMBOL_LIST(SYMBOL_ACCESSOR)
-#undef SYMBOL_ACCESSOR
+ INTERNALIZED_STRING_LIST(STRING_ACCESSOR)
+#undef STRING_ACCESSOR
- // The hidden_symbol is special because it is the empty string, but does
+ // The hidden_string is special because it is the empty string, but does
// not match the empty string.
- String* hidden_symbol() { return hidden_symbol_; }
+ String* hidden_string() { return hidden_string_; }
void set_native_contexts_list(Object* object) {
native_contexts_list_ = object;
@@ -1367,13 +1413,13 @@
// Print short heap statistics.
void PrintShortHeapStatistics();
- // Makes a new symbol object
+ // Makes a new internalized string object
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- MUST_USE_RESULT MaybeObject* CreateSymbol(
+ MUST_USE_RESULT MaybeObject* CreateInternalizedString(
const char* str, int length, int hash);
- MUST_USE_RESULT MaybeObject* CreateSymbol(String* str);
+ MUST_USE_RESULT MaybeObject* CreateInternalizedString(String* str);
// Write barrier support for address[offset] = o.
INLINE(void RecordWrite(Address address, int offset));
@@ -1490,17 +1536,17 @@
STRONG_ROOT_LIST(ROOT_INDEX_DECLARATION)
#undef ROOT_INDEX_DECLARATION
-#define SYMBOL_INDEX_DECLARATION(name, str) k##name##RootIndex,
- SYMBOL_LIST(SYMBOL_INDEX_DECLARATION)
-#undef SYMBOL_DECLARATION
+#define STRING_INDEX_DECLARATION(name, str) k##name##RootIndex,
+ INTERNALIZED_STRING_LIST(STRING_INDEX_DECLARATION)
+#undef STRING_DECLARATION
// Utility type maps
#define DECLARE_STRUCT_MAP(NAME, Name, name) k##Name##MapRootIndex,
STRUCT_LIST(DECLARE_STRUCT_MAP)
#undef DECLARE_STRUCT_MAP
- kSymbolTableRootIndex,
- kStrongRootListLength = kSymbolTableRootIndex,
+ kStringTableRootIndex,
+ kStrongRootListLength = kStringTableRootIndex,
kRootListLength
};
@@ -1508,7 +1554,7 @@
STATIC_CHECK(kNullValueRootIndex == Internals::kNullValueRootIndex);
STATIC_CHECK(kTrueValueRootIndex == Internals::kTrueValueRootIndex);
STATIC_CHECK(kFalseValueRootIndex == Internals::kFalseValueRootIndex);
- STATIC_CHECK(kempty_symbolRootIndex == Internals::kEmptySymbolRootIndex);
+ STATIC_CHECK(kempty_stringRootIndex == Internals::kEmptyStringRootIndex);
// Generated code can embed direct references to non-writable roots if
// they are in new space.
@@ -1914,7 +1960,7 @@
RootListIndex index;
};
- struct ConstantSymbolTable {
+ struct ConstantStringTable {
const char* contents;
RootListIndex index;
};
@@ -1926,12 +1972,12 @@
};
static const StringTypeTable string_type_table[];
- static const ConstantSymbolTable constant_symbol_table[];
+ static const ConstantStringTable constant_string_table[];
static const StructTable struct_table[];
- // The special hidden symbol which is an empty string, but does not match
+ // The special hidden string which is an empty string, but does not match
// any string when looked up in properties.
- String* hidden_symbol_;
+ String* hidden_string_;
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
@@ -2017,6 +2063,10 @@
ElementsKind elements_kind,
PretenureFlag pretenure = NOT_TENURED);
+ MUST_USE_RESULT MaybeObject* AllocateJSArrayWithAllocationSite(
+ ElementsKind elements_kind,
+ Handle<Object> allocation_site_info_payload);
+
// Allocate empty fixed array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();
@@ -2173,7 +2223,7 @@
void ClearObjectStats(bool clear_last_time_stats = false);
- static const int kInitialSymbolTableSize = 2048;
+ static const int kInitialStringTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
static const int kInitialNumberStringCacheSize = 256;
@@ -2509,7 +2559,7 @@
// Lookup descriptor index for (map, name).
// If absent, kAbsent is returned.
int Lookup(Map* source, String* name) {
- if (!StringShape(name).IsSymbol()) return kAbsent;
+ if (!StringShape(name).IsInternalized()) return kAbsent;
int index = Hash(source, name);
Key& key = keys_[index];
if ((key.source == source) && (key.name == name)) return results_[index];
@@ -2519,7 +2569,7 @@
// Update an element in the cache.
void Update(Map* source, String* name, int result) {
ASSERT(result != kAbsent);
- if (StringShape(name).IsSymbol()) {
+ if (StringShape(name).IsInternalized()) {
int index = Hash(source, name);
Key& key = keys_[index];
key.source = source;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index aef227f..4b54c21 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1303,10 +1303,11 @@
return NULL;
}
- if (check_ == IS_SYMBOL && value()->IsConstant()) {
- // Dereferencing is safe here: a symbol cannot become a non-symbol.
+ if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) {
+ // Dereferencing is safe here:
+ // an internalized string cannot become non-internalized.
AllowHandleDereference allow_handle_deref(isolate());
- if (HConstant::cast(value())->handle()->IsSymbol()) return NULL;
+ if (HConstant::cast(value())->handle()->IsInternalizedString()) return NULL;
}
return this;
}
@@ -1336,9 +1337,9 @@
*mask = kIsNotStringMask;
*tag = kStringTag;
return;
- case IS_SYMBOL:
- *mask = kIsSymbolMask;
- *tag = kSymbolTag;
+ case IS_INTERNALIZED_STRING:
+ *mask = kIsInternalizedMask;
+ *tag = kInternalizedTag;
return;
default:
UNREACHABLE();
@@ -1396,7 +1397,7 @@
case IS_SPEC_OBJECT: return "object";
case IS_JS_ARRAY: return "array";
case IS_STRING: return "string";
- case IS_SYMBOL: return "symbol";
+ case IS_INTERNALIZED_STRING: return "internalized_string";
}
UNREACHABLE();
return "";
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index d2b3fc5..cef8a54 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -83,6 +83,7 @@
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(Change) \
@@ -2210,6 +2211,25 @@
};
+class HCallNewArray: public HCallNew {
+ public:
+ HCallNewArray(HValue* context, HValue* constructor, int argument_count,
+ Handle<JSGlobalPropertyCell> type_cell)
+ : HCallNew(context, constructor, argument_count),
+ type_cell_(type_cell) {
+ }
+
+ Handle<JSGlobalPropertyCell> property_cell() const {
+ return type_cell_;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
+
+ private:
+ Handle<JSGlobalPropertyCell> type_cell_;
+};
+
+
class HCallRuntime: public HCall<1> {
public:
HCallRuntime(HValue* context,
@@ -2652,8 +2672,9 @@
static HCheckInstanceType* NewIsString(HValue* value, Zone* zone) {
return new(zone) HCheckInstanceType(value, IS_STRING);
}
- static HCheckInstanceType* NewIsSymbol(HValue* value, Zone* zone) {
- return new(zone) HCheckInstanceType(value, IS_SYMBOL);
+ static HCheckInstanceType* NewIsInternalizedString(
+ HValue* value, Zone* zone) {
+ return new(zone) HCheckInstanceType(value, IS_INTERNALIZED_STRING);
}
virtual void PrintDataTo(StringStream* stream);
@@ -2684,7 +2705,7 @@
IS_SPEC_OBJECT,
IS_JS_ARRAY,
IS_STRING,
- IS_SYMBOL,
+ IS_INTERNALIZED_STRING,
LAST_INTERVAL_CHECK = IS_JS_ARRAY
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 4d9bc9b..2754fa3 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1075,7 +1075,7 @@
BuildStoreMap(elements, map, BailoutId::StubEntry());
Handle<String> fixed_array_length_field_name =
- isolate->factory()->length_field_symbol();
+ isolate->factory()->length_field_string();
HInstruction* store_length =
new(zone) HStoreNamedField(elements, fixed_array_length_field_name,
capacity, true, FixedArray::kLengthOffset);
@@ -1092,7 +1092,7 @@
Zone* zone = this->zone();
Isolate* isolate = graph()->isolate();
Factory* factory = isolate->factory();
- Handle<String> map_field_name = factory->map_field_symbol();
+ Handle<String> map_field_name = factory->map_field_string();
HInstruction* store_map =
new(zone) HStoreNamedField(object, map_field_name, map,
true, JSObject::kMapOffset);
@@ -4753,7 +4753,19 @@
typecheck->SetSuccessorAt(1, not_spec_object);
current_block()->Finish(typecheck);
if_spec_object->AddLeaveInlined(return_value, state);
- not_spec_object->AddLeaveInlined(receiver, state);
+ if (!FLAG_harmony_symbols) {
+ not_spec_object->AddLeaveInlined(receiver, state);
+ } else {
+ HHasInstanceTypeAndBranch* symbolcheck =
+ new(zone()) HHasInstanceTypeAndBranch(return_value, SYMBOL_TYPE);
+ HBasicBlock* is_symbol = graph()->CreateBasicBlock();
+ HBasicBlock* not_symbol = graph()->CreateBasicBlock();
+ symbolcheck->SetSuccessorAt(0, is_symbol);
+ symbolcheck->SetSuccessorAt(1, not_symbol);
+ not_spec_object->Finish(symbolcheck);
+ is_symbol->AddLeaveInlined(return_value, state);
+ not_symbol->AddLeaveInlined(receiver, state);
+ }
}
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
// Return from an inlined setter call. The returned value is never used, the
@@ -5752,7 +5764,7 @@
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
- if (key->handle()->IsSymbol()) {
+ if (key->handle()->IsInternalizedString()) {
if (property->emit_store()) {
property->RecordTypeFeedback(oracle());
CHECK_ALIVE(VisitForValue(value));
@@ -8478,8 +8490,21 @@
CHECK_ALIVE(VisitArgument(expr->expression()));
HValue* constructor = HPushArgument::cast(Top())->argument();
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- HInstruction* call =
- new(zone()) HCallNew(context, constructor, argument_count);
+ HCallNew* call;
+ if (FLAG_optimize_constructed_arrays &&
+ !(expr->target().is_null()) &&
+ *(expr->target()) == isolate()->global_context()->array_function()) {
+ Handle<Object> feedback = oracle()->GetInfo(expr->CallNewFeedbackId());
+ ASSERT(feedback->IsSmi());
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(feedback);
+ AddInstruction(new(zone()) HCheckFunction(constructor,
+ Handle<JSFunction>(isolate()->global_context()->array_function())));
+ call = new(zone()) HCallNewArray(context, constructor, argument_count,
+ cell);
+ } else {
+ call = new(zone()) HCallNew(context, constructor, argument_count);
+ }
Drop(argument_count);
call->set_position(expr->position());
return ast_context()->ReturnInstruction(call, expr->id());
@@ -9437,11 +9462,12 @@
default:
return Bailout("Unsupported non-primitive compare");
}
- } else if (overall_type_info.IsSymbol() && Token::IsEqualityOp(op)) {
+ } else if (overall_type_info.IsInternalizedString() &&
+ Token::IsEqualityOp(op)) {
AddInstruction(new(zone()) HCheckNonSmi(left));
- AddInstruction(HCheckInstanceType::NewIsSymbol(left, zone()));
+ AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
AddInstruction(new(zone()) HCheckNonSmi(right));
- AddInstruction(HCheckInstanceType::NewIsSymbol(right, zone()));
+ AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone()));
HCompareObjectEqAndBranch* result =
new(zone()) HCompareObjectEqAndBranch(left, right);
result->set_position(expr->position());
@@ -9662,6 +9688,16 @@
}
+void HOptimizedGraphBuilder::GenerateIsSymbol(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ HHasInstanceTypeAndBranch* result =
+ new(zone()) HHasInstanceTypeAndBranch(value, SYMBOL_TYPE);
+ return ast_context()->ReturnControl(result, call->id());
+}
+
+
void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
@@ -9871,7 +9907,7 @@
// Create in-object property store to kValueOffset.
set_current_block(if_js_value);
- Handle<String> name = isolate()->factory()->undefined_symbol();
+ Handle<String> name = isolate()->factory()->undefined_string();
AddInstruction(new(zone()) HStoreNamedField(object,
name,
value,
@@ -10475,11 +10511,13 @@
void HTracer::TraceLithium(const char* name, LChunk* chunk) {
+ AllowHandleDereference allow_handle_deref(chunk->graph()->isolate());
Trace(name, chunk->graph(), chunk);
}
void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
+ AllowHandleDereference allow_handle_deref(graph->isolate());
Trace(name, graph, NULL);
}
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index c689afb..e3b2b7b 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -383,6 +383,10 @@
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
__ j(above_equal, &exit);
+ // Symbols are "objects".
+ __ CmpInstanceType(ecx, SYMBOL_TYPE);
+ __ j(equal, &exit);
+
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
@@ -1475,34 +1479,66 @@
void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc
+ // -- ebx : type info cell
// -- edi : constructor
// -- esp[0] : return address
// -- esp[4] : last argument
// -----------------------------------
- Label generic_constructor;
-
if (FLAG_debug_code) {
// The array construct code is only set for the global and natives
// builtin Array functions which always have maps.
// Initial map for the builtin Array function should be a map.
- __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi.
- __ test(ebx, Immediate(kSmiTagMask));
+ __ test(ecx, Immediate(kSmiTagMask));
__ Assert(not_zero, "Unexpected initial map for Array function");
- __ CmpObjectType(ebx, MAP_TYPE, ecx);
+ __ CmpObjectType(ecx, MAP_TYPE, ecx);
__ Assert(equal, "Unexpected initial map for Array function");
+
+ if (FLAG_optimize_constructed_arrays) {
+ // We should either have undefined in ebx or a valid jsglobalpropertycell
+ Label okay_here;
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->heap()->undefined_value(), masm->isolate());
+ Handle<Map> global_property_cell_map(
+ masm->isolate()->heap()->global_property_cell_map());
+ __ cmp(ebx, Immediate(undefined_sentinel));
+ __ j(equal, &okay_here);
+ __ cmp(FieldOperand(ebx, 0), Immediate(global_property_cell_map));
+ __ Assert(equal, "Expected property cell in register ebx");
+ __ bind(&okay_here);
+ }
}
- // Run the native code for the Array function called as constructor.
- ArrayNativeCode(masm, true, &generic_constructor);
+ if (FLAG_optimize_constructed_arrays) {
+ Label not_zero_case, not_one_case;
+ __ test(eax, eax);
+ __ j(not_zero, ¬_zero_case);
+ ArrayNoArgumentConstructorStub no_argument_stub;
+ __ TailCallStub(&no_argument_stub);
- // Jump to the generic construct code in case the specialized code cannot
- // handle the construction.
- __ bind(&generic_constructor);
- Handle<Code> generic_construct_stub =
- masm->isolate()->builtins()->JSConstructStubGeneric();
- __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
+ __ bind(¬_zero_case);
+ __ cmp(eax, 1);
+ __ j(greater, ¬_one_case);
+ ArraySingleArgumentConstructorStub single_argument_stub;
+ __ TailCallStub(&single_argument_stub);
+
+ __ bind(¬_one_case);
+ ArrayNArgumentsConstructorStub n_argument_stub;
+ __ TailCallStub(&n_argument_stub);
+ } else {
+ Label generic_constructor;
+ // Run the native code for the Array function called as constructor.
+ ArrayNativeCode(masm, true, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
+ __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
+ }
}
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index f753fb8..1329a3e 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -37,6 +37,7 @@
#include "runtime.h"
#include "stub-cache.h"
#include "codegen.h"
+#include "runtime.h"
namespace v8 {
namespace internal {
@@ -60,6 +61,7 @@
static Register registers[] = { edx, ecx };
descriptor->register_param_count_ = 2;
descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
}
@@ -76,6 +78,44 @@
}
+static void InitializeArrayConstructorDescriptor(Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ // register state
+ // edi -- constructor function
+ // ebx -- type info cell with elements kind
+ // eax -- number of arguments to the constructor function
+ static Register registers[] = { edi, ebx };
+ descriptor->register_param_count_ = 2;
+ // stack param count needs (constructor pointer, and single argument)
+ descriptor->stack_parameter_count_ = &eax;
+ descriptor->register_params_ = registers;
+ descriptor->extra_expression_stack_count_ = 1;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ArrayConstructor_StubFailure);
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
#define __ ACCESS_MASM(masm)
void ToNumberStub::Generate(MacroAssembler* masm) {
@@ -3255,7 +3295,7 @@
Label miss;
if (kind() == Code::KEYED_LOAD_IC) {
- __ cmp(ecx, Immediate(masm->isolate()->factory()->length_symbol()));
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
__ j(not_equal, &miss);
}
@@ -3274,7 +3314,7 @@
Label miss;
if (kind() == Code::KEYED_LOAD_IC) {
- __ cmp(ecx, Immediate(masm->isolate()->factory()->prototype_symbol()));
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->prototype_string()));
__ j(not_equal, &miss);
}
@@ -3293,7 +3333,7 @@
Label miss;
if (kind() == Code::KEYED_LOAD_IC) {
- __ cmp(ecx, Immediate(masm->isolate()->factory()->length_symbol()));
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
__ j(not_equal, &miss);
}
@@ -3324,7 +3364,7 @@
Register scratch = ebx;
if (kind() == Code::KEYED_LOAD_IC) {
- __ cmp(ecx, Immediate(masm->isolate()->factory()->length_symbol()));
+ __ cmp(ecx, Immediate(masm->isolate()->factory()->length_string()));
__ j(not_equal, &miss);
}
@@ -3368,6 +3408,12 @@
}
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, eax, reg_, inobject_, index_);
+ __ ret(0);
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in edx and the parameter count is in eax.
@@ -4435,21 +4481,21 @@
Immediate(masm->isolate()->factory()->heap_number_map()));
__ j(not_equal, fail);
}
- // We could be strict about symbol/string here, but as long as
+ // We could be strict about internalized/non-internalized here, but as long as
// hydrogen doesn't care, the stub doesn't have to care either.
__ bind(&ok);
}
-static void BranchIfNonSymbol(MacroAssembler* masm,
- Label* label,
- Register object,
- Register scratch) {
+static void BranchIfNotInternalizedString(MacroAssembler* masm,
+ Label* label,
+ Register object,
+ Register scratch) {
__ JumpIfSmi(object, label);
__ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
- __ and_(scratch, kIsSymbolMask | kIsNotStringMask);
- __ cmp(scratch, kSymbolTag | kStringTag);
+ __ and_(scratch, kIsInternalizedMask | kIsNotStringMask);
+ __ cmp(scratch, kInternalizedTag | kStringTag);
__ j(not_equal, label);
}
@@ -4677,14 +4723,14 @@
// The number comparison code did not provide a valid result.
__ bind(&non_number_comparison);
- // Fast negative check for symbol-to-symbol equality.
+ // Fast negative check for internalized-to-internalized equality.
Label check_for_strings;
if (cc == equal) {
- BranchIfNonSymbol(masm, &check_for_strings, eax, ecx);
- BranchIfNonSymbol(masm, &check_for_strings, edx, ecx);
+ BranchIfNotInternalizedString(masm, &check_for_strings, eax, ecx);
+ BranchIfNotInternalizedString(masm, &check_for_strings, edx, ecx);
// We've already checked for object identity, so if both operands
- // are symbols they aren't equal. Register eax already holds a
+ // are internalized they aren't equal. Register eax already holds a
// non-zero value, which indicates not equal, so just return.
__ ret(0);
}
@@ -4787,12 +4833,13 @@
}
-static void GenerateRecordCallTarget(MacroAssembler* masm) {
+static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// ebx : cache cell for call target
// edi : the function to call
+ ASSERT(!FLAG_optimize_constructed_arrays);
Isolate* isolate = masm->isolate();
Label initialize, done;
@@ -4825,6 +4872,82 @@
}
+static void GenerateRecordCallTarget(MacroAssembler* masm) {
+ // Cache the called function in a global property cell. Cache states
+ // are uninitialized, monomorphic (indicated by a JSFunction), and
+ // megamorphic.
+ // ebx : cache cell for call target
+ // edi : the function to call
+ ASSERT(FLAG_optimize_constructed_arrays);
+ Isolate* isolate = masm->isolate();
+ Label initialize, done, miss, megamorphic, not_array_function;
+
+ // Load the cache state into ecx.
+ __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
+
+ // A monomorphic cache hit or an already megamorphic state: invoke the
+ // function without changing the state.
+ __ cmp(ecx, edi);
+ __ j(equal, &done);
+ __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
+ __ j(equal, &done);
+
+ // Special handling of the Array() function, which caches not only the
+ // monomorphic Array function but the initial ElementsKind with special
+ // sentinels
+ Handle<Object> terminal_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(isolate,
+ LAST_FAST_ELEMENTS_KIND);
+ __ cmp(ecx, Immediate(terminal_kind_sentinel));
+ __ j(above, &miss);
+ // Load the global or builtins object from the current context
+ __ LoadGlobalContext(ecx);
+ // Make sure the function is the Array() function
+ __ cmp(edi, Operand(ecx,
+ Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+ __ j(not_equal, &megamorphic);
+ __ jmp(&done);
+
+ __ bind(&miss);
+
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+ // megamorphic.
+ __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
+ __ j(equal, &initialize);
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no
+ // write-barrier is needed.
+ __ bind(&megamorphic);
+ __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
+ Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
+ __ jmp(&done, Label::kNear);
+
+ // An uninitialized cache is patched with the function or sentinel to
+ // indicate the ElementsKind if function is the Array constructor.
+ __ bind(&initialize);
+ __ LoadGlobalContext(ecx);
+ // Make sure the function is the Array() function
+ __ cmp(edi, Operand(ecx,
+ Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+ __ j(not_equal, ¬_array_function);
+
+ // The target function is the Array constructor, install a sentinel value in
+ // the constructor's type info cell that will track the initial ElementsKind
+ // that should be used for the array when its constructed.
+ Handle<Object> initial_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(isolate,
+ GetInitialFastElementsKind());
+ __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
+ Immediate(initial_kind_sentinel));
+ __ jmp(&done);
+
+ __ bind(¬_array_function);
+ __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi);
+ // No need for a write barrier here - cells are rescanned.
+
+ __ bind(&done);
+}
+
+
void CallFunctionStub::Generate(MacroAssembler* masm) {
// ebx : cache cell for call target
// edi : the function to call
@@ -4856,7 +4979,11 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Fast-case: Just invoke the function.
@@ -4929,14 +5056,20 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Jump to the function-specific construct stub.
- __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
- __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
- __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
- __ jmp(ebx);
+ Register jmp_reg = FLAG_optimize_constructed_arrays ? ecx : ebx;
+ __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+ __ mov(jmp_reg, FieldOperand(jmp_reg,
+ SharedFunctionInfo::kConstructStubOffset));
+ __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize));
+ __ jmp(jmp_reg);
// edi: called object
// eax: number of arguments
@@ -5748,8 +5881,8 @@
STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength);
// Handle exceptionally long strings in the runtime system.
__ j(overflow, &call_runtime);
- // Use the symbol table when adding two one character strings, as it
- // helps later optimizations to return a symbol here.
+ // Use the string table when adding two one character strings, as it
+ // helps later optimizations to return an internalized string here.
__ cmp(ebx, Immediate(Smi::FromInt(2)));
__ j(not_equal, &longer_than_two);
@@ -5760,10 +5893,10 @@
__ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize));
__ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize));
- // Try to lookup two character string in symbol table. If it is not found
+ // Try to lookup two character string in string table. If it is not found
// just allocate a new one.
Label make_two_character_string, make_two_character_string_no_reload;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
+ StringHelper::GenerateTwoCharacterStringTableProbe(
masm, ebx, ecx, eax, edx, edi,
&make_two_character_string_no_reload, &make_two_character_string);
__ IncrementCounter(counters->string_add_native(), 1);
@@ -6109,7 +6242,7 @@
}
-void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
@@ -6121,7 +6254,7 @@
Register scratch = scratch3;
// Make sure that both characters are not digits as such strings has a
- // different hash algorithm. Don't try to look for these in the symbol table.
+ // different hash algorithm. Don't try to look for these in the string table.
Label not_array_index;
__ mov(scratch, c1);
__ sub(scratch, Immediate(static_cast<int>('0')));
@@ -6147,47 +6280,47 @@
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string.
- // Load the symbol table.
- Register symbol_table = c2;
+ // Load the string table.
+ Register string_table = c2;
ExternalReference roots_array_start =
ExternalReference::roots_array_start(masm->isolate());
- __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex));
- __ mov(symbol_table,
+ __ mov(scratch, Immediate(Heap::kStringTableRootIndex));
+ __ mov(string_table,
Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
- // Calculate capacity mask from the symbol table capacity.
+ // Calculate capacity mask from the string table capacity.
Register mask = scratch2;
- __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
+ __ mov(mask, FieldOperand(string_table, StringTable::kCapacityOffset));
__ SmiUntag(mask);
__ sub(mask, Immediate(1));
// Registers
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string
- // symbol_table: symbol table
+ // string_table: string table
// mask: capacity mask
// scratch: -
- // Perform a number of probes in the symbol table.
+ // Perform a number of probes in the string table.
static const int kProbes = 4;
- Label found_in_symbol_table;
+ Label found_in_string_table;
Label next_probe[kProbes], next_probe_pop_mask[kProbes];
Register candidate = scratch; // Scratch register contains candidate.
for (int i = 0; i < kProbes; i++) {
- // Calculate entry in symbol table.
+ // Calculate entry in string table.
__ mov(scratch, hash);
if (i > 0) {
- __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
+ __ add(scratch, Immediate(StringTable::GetProbeOffset(i)));
}
__ and_(scratch, mask);
- // Load the entry from the symbol table.
- STATIC_ASSERT(SymbolTable::kEntrySize == 1);
+ // Load the entry from the string table.
+ STATIC_ASSERT(StringTable::kEntrySize == 1);
__ mov(candidate,
- FieldOperand(symbol_table,
+ FieldOperand(string_table,
scratch,
times_pointer_size,
- SymbolTable::kElementsStartOffset));
+ StringTable::kElementsStartOffset));
// If entry is undefined no string with this hash can be found.
Factory* factory = masm->isolate()->factory();
@@ -6216,7 +6349,7 @@
__ mov(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize));
__ and_(temp, 0x0000ffff);
__ cmp(chars, temp);
- __ j(equal, &found_in_symbol_table);
+ __ j(equal, &found_in_string_table);
__ bind(&next_probe_pop_mask[i]);
__ pop(mask);
__ bind(&next_probe[i]);
@@ -6227,7 +6360,7 @@
// Scratch register contains result when we fall through to here.
Register result = candidate;
- __ bind(&found_in_symbol_table);
+ __ bind(&found_in_string_table);
__ pop(mask); // Pop saved mask from the stack.
if (!result.is(eax)) {
__ mov(eax, result);
@@ -6840,8 +6973,8 @@
}
-void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
- ASSERT(state_ == CompareIC::SYMBOL);
+void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
ASSERT(GetCondition() == equal);
// Registers containing left and right operands respectively.
@@ -6857,17 +6990,74 @@
__ and_(tmp1, right);
__ JumpIfSmi(tmp1, &miss, Label::kNear);
- // Check that both operands are symbols.
+ // Check that both operands are internalized strings.
__ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
__ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
__ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp2);
- __ test(tmp1, Immediate(kIsSymbolMask));
+ __ test(tmp1, Immediate(kIsInternalizedMask));
__ j(zero, &miss, Label::kNear);
- // Symbols are compared by identity.
+ // Internalized strings are compared by identity.
+ Label done;
+ __ cmp(left, right);
+ // Make sure eax is non-zero. At this point input operands are
+ // guaranteed to be non-zero.
+ ASSERT(right.is(eax));
+ __ j(not_equal, &done, Label::kNear);
+ STATIC_ASSERT(EQUAL == 0);
+ STATIC_ASSERT(kSmiTag == 0);
+ __ Set(eax, Immediate(Smi::FromInt(EQUAL)));
+ __ bind(&done);
+ __ ret(0);
+
+ __ bind(&miss);
+ GenerateMiss(masm);
+}
+
+
+void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::UNIQUE_NAME);
+ ASSERT(GetCondition() == equal);
+
+ // Registers containing left and right operands respectively.
+ Register left = edx;
+ Register right = eax;
+ Register tmp1 = ecx;
+ Register tmp2 = ebx;
+
+ // Check that both operands are heap objects.
+ Label miss;
+ __ mov(tmp1, left);
+ STATIC_ASSERT(kSmiTag == 0);
+ __ and_(tmp1, right);
+ __ JumpIfSmi(tmp1, &miss, Label::kNear);
+
+ // Check that both operands are unique names. This leaves the instance
+ // types loaded in tmp1 and tmp2.
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
+ __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
+ __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
+ __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
+
+ Label succeed1;
+ __ test(tmp1, Immediate(kIsInternalizedMask));
+ __ j(not_zero, &succeed1);
+ __ cmpb(tmp1, static_cast<uint8_t>(SYMBOL_TYPE));
+ __ j(not_equal, &miss);
+ __ bind(&succeed1);
+
+ Label succeed2;
+ __ test(tmp2, Immediate(kIsInternalizedMask));
+ __ j(not_zero, &succeed2);
+ __ cmpb(tmp2, static_cast<uint8_t>(SYMBOL_TYPE));
+ __ j(not_equal, &miss);
+ __ bind(&succeed2);
+
+ // Unique names are compared by identity.
Label done;
__ cmp(left, right);
// Make sure eax is non-zero. At this point input operands are
@@ -6928,14 +7118,14 @@
// Handle not identical strings.
__ bind(¬_same);
- // Check that both strings are symbols. If they are, we're done
+ // Check that both strings are internalized. If they are, we're done
// because we already know they are not identical. But in the case of
// non-equality compare, we still need to determine the order.
if (equality) {
Label do_compare;
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp2);
- __ test(tmp1, Immediate(kIsSymbolMask));
+ __ test(tmp1, Immediate(kIsInternalizedMask));
__ j(zero, &do_compare, Label::kNear);
// Make sure eax is non-zero. At this point input operands are
// guaranteed to be non-zero.
@@ -7043,14 +7233,14 @@
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
-// Name must be a symbol and receiver must be a heap object.
+// Name must be an internalized string and receiver must be a heap object.
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register properties,
Handle<String> name,
Register r0) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
// If names of slots in range from 1 to kProbes - 1 for the hash value are
// not equal to the name and kProbes-th slot is not used (its name is the
@@ -7087,10 +7277,10 @@
__ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
__ j(equal, &the_hole, Label::kNear);
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
__ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- kIsSymbolMask);
+ kIsInternalizedMask);
__ j(zero, miss);
__ bind(&the_hole);
}
@@ -7225,14 +7415,14 @@
__ j(equal, &in_dictionary);
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
- // If we hit a non symbol key during negative lookup
- // we have to bailout as this key might be equal to the
+ // If we hit a key that is not an internalized string during negative
+ // lookup we have to bailout as this key might be equal to the
// key we are looking for.
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
__ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
- kIsSymbolMask);
+ kIsInternalizedMask);
__ j(zero, &maybe_in_dictionary);
}
}
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index bbb1df4..e6bb38a 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -177,15 +177,15 @@
Register scratch, // Neither of above.
bool ascii);
- // Probe the symbol table for a two character string. If the string
+ // Probe the string table for a two character string. If the string
// requires non-standard hashing a jump to the label not_probed is
// performed and registers c1 and c2 are preserved. In all other
// cases they are clobbered. If the string is not found by probing a
// jump to the label not_found is performed. This jump does not
- // guarantee that the string is not in the symbol table. If the
+ // guarantee that the string is not in the string table. If the
// string is found the code falls through with the string in
// register eax.
- static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index c062fd7..e27ea4c 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -463,102 +463,6 @@
}
-void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
- int frame_index) {
- JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
- }
-
- unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
-
- // Arguments adaptor can not be topmost or bottommost.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous
- // frame's top and this frame's size.
- uint32_t top_address;
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = height;
- unsigned output_offset = output_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // A marker value is used in place of the context.
- output_offset -= kPointerSize;
- intptr_t context = reinterpret_cast<intptr_t>(
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- output_frame->SetFrameSlot(output_offset, context);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
- top_address + output_offset, output_offset, context);
- }
-
- // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(function);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Number of incoming arguments.
- output_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
- top_address + output_offset, output_offset, value, height - 1);
- }
-
- ASSERT(0 == output_offset);
-
- Builtins* builtins = isolate_->builtins();
- Code* adaptor_trampoline =
- builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
- uint32_t pc = reinterpret_cast<uint32_t>(
- adaptor_trampoline->instruction_start() +
- isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
- output_frame->SetPc(pc);
-}
-
-
void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index) {
//
@@ -852,125 +756,6 @@
}
-void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
- int frame_index,
- bool is_setter_stub_frame) {
- JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver (and the implicit return value, if any) are expected in
- // registers by the LoadIC/StoreIC, so they don't belong to the output stack
- // frame. This means that we have to use a height of 0.
- unsigned height = 0;
- unsigned height_in_bytes = height * kPointerSize;
- const char* kind = is_setter_stub_frame ? "setter" : "getter";
- if (trace_) {
- PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
- }
-
- // We need 1 stack entry for the return address + 4 stack entries from
- // StackFrame::INTERNAL (FP, context, frame type, code object, see
- // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
- // entry for the implicit return value, see
- // StoreStubCompiler::CompileStoreViaSetter.
- unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
- unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, accessor);
- output_frame->SetFrameType(StackFrame::INTERNAL);
-
- // A frame for an accessor stub can not be the topmost or bottommost one.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous frame's top and
- // this frame's size.
- intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- unsigned output_offset = output_frame_size;
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // The context can be gotten from the previous frame.
- output_offset -= kPointerSize;
- value = output_[frame_index - 1]->GetContext();
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // A marker value is used in place of the function.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; function (%s sentinel)\n",
- top_address + output_offset, output_offset, value, kind);
- }
-
- // Get Code object from accessor stub.
- output_offset -= kPointerSize;
- Builtins::Name name = is_setter_stub_frame ?
- Builtins::kStoreIC_Setter_ForDeopt :
- Builtins::kLoadIC_Getter_ForDeopt;
- Code* accessor_stub = isolate_->builtins()->builtin(name);
- value = reinterpret_cast<intptr_t>(accessor_stub);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; code object\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Skip receiver.
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- iterator->Skip(Translation::NumberOfOperandsFor(opcode));
-
- if (is_setter_stub_frame) {
- // The implicit return value was part of the artificial setter stub
- // environment.
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- ASSERT(0 == output_offset);
-
- Smi* offset = is_setter_stub_frame ?
- isolate_->heap()->setter_stub_deopt_pc_offset() :
- isolate_->heap()->getter_stub_deopt_pc_offset();
- intptr_t pc = reinterpret_cast<intptr_t>(
- accessor_stub->instruction_start() + offset->value());
- output_frame->SetPc(pc);
-}
-
-
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
int frame_index) {
BailoutId node_id = BailoutId(iterator->Next());
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index c68fa9c..1428dfe 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1586,7 +1586,7 @@
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
- if (key->handle()->IsSymbol()) {
+ if (key->handle()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
__ mov(ecx, Immediate(key->handle()));
@@ -2560,6 +2560,7 @@
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
+ // TODO(rossberg): incorporate symbols.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -2634,7 +2635,7 @@
__ cmp(ecx, FACTORY->hash_table_map());
__ j(equal, if_false);
- // Look for valueOf symbol in the descriptor array, and indicate false if
+ // Look for valueOf string in the descriptor array, and indicate false if
// found. Since we omit an enumeration index check, if it is added via a
// transition that shares its descriptor array, this is a false positive.
Label entry, loop, done;
@@ -2656,11 +2657,11 @@
// Calculate location of the first key name.
__ add(ebx, Immediate(DescriptorArray::kFirstOffset));
// Loop through all the keys in the descriptor array. If one of these is the
- // symbol valueOf the result is false.
+ // internalized string "valueOf" the result is false.
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, FieldOperand(ebx, 0));
- __ cmp(edx, FACTORY->value_of_symbol());
+ __ cmp(edx, FACTORY->value_of_string());
__ j(equal, if_false);
__ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
@@ -2695,6 +2696,28 @@
}
+void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ __ JumpIfSmi(eax, if_false);
+ __ CmpObjectType(eax, SYMBOL_TYPE, ebx);
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -2897,12 +2920,12 @@
// Functions have class 'Function'.
__ bind(&function);
- __ mov(eax, isolate()->factory()->function_class_symbol());
+ __ mov(eax, isolate()->factory()->function_class_string());
__ jmp(&done);
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ mov(eax, isolate()->factory()->Object_symbol());
+ __ mov(eax, isolate()->factory()->Object_string());
__ jmp(&done);
// Non-JS objects have class null.
@@ -4232,12 +4255,12 @@
}
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- if (check->Equals(isolate()->heap()->number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_string())) {
__ JumpIfSmi(eax, if_true);
__ cmp(FieldOperand(eax, HeapObject::kMapOffset),
isolate()->factory()->heap_number_map());
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_string())) {
__ JumpIfSmi(eax, if_false);
__ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
__ j(above_equal, if_false);
@@ -4245,16 +4268,16 @@
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
Split(zero, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
+ } else if (check->Equals(isolate()->heap()->boolean_string())) {
__ cmp(eax, isolate()->factory()->true_value());
__ j(equal, if_true);
__ cmp(eax, isolate()->factory()->false_value());
Split(equal, if_true, if_false, fall_through);
} else if (FLAG_harmony_typeof &&
- check->Equals(isolate()->heap()->null_symbol())) {
+ check->Equals(isolate()->heap()->null_string())) {
__ cmp(eax, isolate()->factory()->null_value());
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
+ } else if (check->Equals(isolate()->heap()->undefined_string())) {
__ cmp(eax, isolate()->factory()->undefined_value());
__ j(equal, if_true);
__ JumpIfSmi(eax, if_false);
@@ -4263,19 +4286,23 @@
__ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
__ test(ecx, Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_string())) {
__ JumpIfSmi(eax, if_false);
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
__ j(equal, if_true);
__ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_string())) {
__ JumpIfSmi(eax, if_false);
if (!FLAG_harmony_typeof) {
__ cmp(eax, isolate()->factory()->null_value());
__ j(equal, if_true);
}
+ if (FLAG_harmony_symbols) {
+ __ CmpObjectType(eax, SYMBOL_TYPE, edx);
+ __ j(equal, if_true);
+ }
__ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
__ j(below, if_false);
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 3c7b285..428d830 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -100,7 +100,7 @@
// storage. This function may fail to load a property even though it is
// in the dictionary, so code at miss_label must always call a backup
// property load that is complete. This function is safe to call if
-// name is not a symbol, and will jump to the miss_label in that
+// name is not internalized, and will jump to the miss_label in that
// case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm,
@@ -157,7 +157,7 @@
// storage. This function may fail to store a property eventhough it
// is in the dictionary, so code at miss_label must always call a
// backup property store that is complete. This function is safe to
-// call if name is not a symbol, and will jump to the miss_label in
+// call if name is not internalized, and will jump to the miss_label in
// that case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm,
@@ -292,31 +292,31 @@
}
-// Checks whether a key is an array index string or a symbol string.
-// Falls through if the key is a symbol.
+// Checks whether a key is an array index string or an internalized string.
+// Falls through if the key is an internalized string.
static void GenerateKeyStringCheck(MacroAssembler* masm,
Register key,
Register map,
Register hash,
Label* index_string,
- Label* not_symbol) {
+ Label* not_internalized) {
// Register use:
// key - holds the key and is unchanged. Assumed to be non-smi.
// Scratch registers:
// map - used to hold the map of the key.
// hash - used to hold the hash of the key.
__ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
- __ j(above_equal, not_symbol);
+ __ j(above_equal, not_internalized);
// Is the string an array index, with cached numeric value?
__ mov(hash, FieldOperand(key, String::kHashFieldOffset));
__ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
__ j(zero, index_string);
- // Is the string a symbol?
- STATIC_ASSERT(kSymbolTag != 0);
- __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
- __ j(zero, not_symbol);
+ // Is the string internalized?
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsInternalizedMask);
+ __ j(zero, not_internalized);
}
@@ -484,7 +484,7 @@
__ xor_(eax, edi);
__ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
- // Load the key (consisting of map and symbol) from the cache and
+ // Load the key (consisting of map and internalized string) from the cache and
// check for match.
Label load_in_object_property;
static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
@@ -1198,7 +1198,7 @@
__ bind(&check_string);
GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
- // The key is known to be a symbol.
+ // The key is known to be an internalized string.
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
@@ -1224,7 +1224,7 @@
__ bind(&slow_call);
// This branch is taken if:
// - the receiver requires boxing or access check,
- // - the key is neither smi nor symbol,
+ // - the key is neither smi nor an internalized string,
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
@@ -1295,9 +1295,10 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
- eax);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, edx, ecx, ebx, eax);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 58bdc89..0f2d32b 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2509,12 +2509,12 @@
__ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
__ mov(temp, FieldOperand(temp,
SharedFunctionInfo::kInstanceClassNameOffset));
- // The class name we are testing against is a symbol because it's a literal.
- // The name in the constructor is a symbol because of the way the context is
- // booted. This routine isn't expected to work for random API-created
+ // The class name we are testing against is internalized since it's a literal.
+ // The name in the constructor is internalized because of the way the context
+ // is booted. This routine isn't expected to work for random API-created
// classes and it doesn't have to because you can't access it with natives
- // syntax. Since both sides are symbols it is sufficient to use an identity
- // comparison.
+ // syntax. Since both sides are internalized it is sufficient to use an
+ // identity comparison.
__ cmp(temp, class_name);
// End with the answer in the z flag.
}
@@ -3733,77 +3733,64 @@
}
}
-void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathRound(LMathRound* instr) {
CpuFeatures::Scope scope(SSE2);
Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->value());
XMMRegister xmm_scratch = xmm0;
+ XMMRegister input_temp = ToDoubleRegister(instr->temp());
ExternalReference one_half = ExternalReference::address_of_one_half();
ExternalReference minus_one_half =
ExternalReference::address_of_minus_one_half();
- bool minus_zero_check =
- instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+ Label done, round_to_zero, below_one_half, do_not_compensate;
__ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
+ __ ucomisd(xmm_scratch, input_reg);
+ __ j(above, &below_one_half);
- if (CpuFeatures::IsSupported(SSE4_1) && !minus_zero_check) {
- CpuFeatures::Scope scope(SSE4_1);
+ // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
+ __ addsd(xmm_scratch, input_reg);
+ __ cvttsd2si(output_reg, Operand(xmm_scratch));
+ // Overflow is signalled with minint.
+ __ cmp(output_reg, 0x80000000u);
+ __ RecordComment("D2I conversion overflow");
+ DeoptimizeIf(equal, instr->environment());
+ __ jmp(&done);
- __ addsd(xmm_scratch, input_reg);
- __ roundsd(xmm_scratch, xmm_scratch, Assembler::kRoundDown);
- __ cvttsd2si(output_reg, Operand(xmm_scratch));
- // Overflow is signalled with minint.
- __ cmp(output_reg, 0x80000000u);
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
- } else {
- Label done, round_to_zero, below_one_half, do_not_compensate;
- __ ucomisd(xmm_scratch, input_reg);
- __ j(above, &below_one_half);
+ __ bind(&below_one_half);
+ __ movdbl(xmm_scratch, Operand::StaticVariable(minus_one_half));
+ __ ucomisd(xmm_scratch, input_reg);
+ __ j(below_equal, &round_to_zero);
- // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
- __ addsd(xmm_scratch, input_reg);
- __ cvttsd2si(output_reg, Operand(xmm_scratch));
- // Overflow is signalled with minint.
- __ cmp(output_reg, 0x80000000u);
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
- __ jmp(&done);
+ // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
+ // compare and compensate.
+ __ movsd(input_temp, input_reg); // Do not alter input_reg.
+ __ subsd(input_temp, xmm_scratch);
+ __ cvttsd2si(output_reg, Operand(input_temp));
+ // Catch minint due to overflow, and to prevent overflow when compensating.
+ __ cmp(output_reg, 0x80000000u);
+ __ RecordComment("D2I conversion overflow");
+ DeoptimizeIf(equal, instr->environment());
- __ bind(&below_one_half);
- __ movdbl(xmm_scratch, Operand::StaticVariable(minus_one_half));
- __ ucomisd(xmm_scratch, input_reg);
- __ j(below_equal, &round_to_zero);
+ __ cvtsi2sd(xmm_scratch, output_reg);
+ __ ucomisd(xmm_scratch, input_temp);
+ __ j(equal, &done);
+ __ sub(output_reg, Immediate(1));
+ // No overflow because we already ruled out minint.
+ __ jmp(&done);
- // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
- // compare and compensate.
- __ subsd(input_reg, xmm_scratch);
- __ cvttsd2si(output_reg, Operand(input_reg));
- // Catch minint due to overflow, and to prevent overflow when compensating.
- __ cmp(output_reg, 0x80000000u);
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
-
- __ cvtsi2sd(xmm_scratch, output_reg);
- __ ucomisd(xmm_scratch, input_reg);
- __ j(equal, &done);
- __ sub(output_reg, Immediate(1));
- // No overflow because we already ruled out minint.
- __ jmp(&done);
-
- __ bind(&round_to_zero);
- // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
- // we can ignore the difference between a result of -0 and +0.
- if (minus_zero_check) {
- // If the sign is positive, we return +0.
- __ movmskpd(output_reg, input_reg);
- __ test(output_reg, Immediate(1));
- __ RecordComment("Minus zero");
- DeoptimizeIf(not_zero, instr->environment());
- }
- __ Set(output_reg, Immediate(0));
- __ bind(&done);
+ __ bind(&round_to_zero);
+ // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
+ // we can ignore the difference between a result of -0 and +0.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ // If the sign is positive, we return +0.
+ __ movmskpd(output_reg, input_reg);
+ __ test(output_reg, Immediate(1));
+ __ RecordComment("Minus zero");
+ DeoptimizeIf(not_zero, instr->environment());
}
+ __ Set(output_reg, Immediate(0));
+ __ bind(&done);
}
@@ -4035,9 +4022,6 @@
case kMathFloor:
DoMathFloor(instr);
break;
- case kMathRound:
- DoMathRound(instr);
- break;
case kMathSqrt:
DoMathSqrt(instr);
break;
@@ -4146,12 +4130,32 @@
ASSERT(ToRegister(instr->constructor()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
+ if (FLAG_optimize_constructed_arrays) {
+ // No cell in ebx for construct type feedback in optimized code
+ Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
+ isolate());
+ __ mov(ebx, Immediate(undefined_value));
+ }
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ Set(eax, Immediate(instr->arity()));
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+ ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->constructor()).is(edi));
+ ASSERT(ToRegister(instr->result()).is(eax));
+ ASSERT(FLAG_optimize_constructed_arrays);
+
+ __ mov(ebx, instr->hydrogen()->property_cell());
+ Handle<Code> array_construct_code =
+ isolate()->builtins()->ArrayConstructCode();
+ __ Set(eax, Immediate(instr->arity()));
+ CallCode(array_construct_code, RelocInfo::CONSTRUCT_CALL, instr);
+}
+
+
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
CallRuntime(instr->function(), instr->arity(), instr);
}
@@ -5920,13 +5924,13 @@
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- if (type_name->Equals(heap()->number_symbol())) {
+ if (type_name->Equals(heap()->number_string())) {
__ JumpIfSmi(input, true_label);
__ cmp(FieldOperand(input, HeapObject::kMapOffset),
factory()->heap_number_map());
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->string_symbol())) {
+ } else if (type_name->Equals(heap()->string_string())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
__ j(above_equal, false_label);
@@ -5934,17 +5938,17 @@
1 << Map::kIsUndetectable);
final_branch_condition = zero;
- } else if (type_name->Equals(heap()->boolean_symbol())) {
+ } else if (type_name->Equals(heap()->boolean_string())) {
__ cmp(input, factory()->true_value());
__ j(equal, true_label);
__ cmp(input, factory()->false_value());
final_branch_condition = equal;
- } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
__ cmp(input, factory()->null_value());
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->undefined_symbol())) {
+ } else if (type_name->Equals(heap()->undefined_string())) {
__ cmp(input, factory()->undefined_value());
__ j(equal, true_label);
__ JumpIfSmi(input, false_label);
@@ -5954,7 +5958,7 @@
1 << Map::kIsUndetectable);
final_branch_condition = not_zero;
- } else if (type_name->Equals(heap()->function_symbol())) {
+ } else if (type_name->Equals(heap()->function_string())) {
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
@@ -5962,13 +5966,19 @@
__ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->object_symbol())) {
+ } else if (type_name->Equals(heap()->object_string())) {
__ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ cmp(input, factory()->null_value());
__ j(equal, true_label);
}
- __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
+ if (FLAG_harmony_symbols) {
+ __ CmpObjectType(input, SYMBOL_TYPE, input);
+ __ j(equal, true_label);
+ __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+ } else {
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
+ }
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index c4fca1c..ab6779a 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -286,7 +286,6 @@
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
void DoMathAbs(LUnaryMathOperation* instr);
void DoMathFloor(LUnaryMathOperation* instr);
- void DoMathRound(LUnaryMathOperation* instr);
void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr);
void DoMathTan(LUnaryMathOperation* instr);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index d5cf125..69b1c97 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -314,6 +314,12 @@
}
+void LMathRound::PrintDataTo(StringStream* stream) {
+ stream->Add("/round ");
+ value()->PrintTo(stream);
+}
+
+
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -367,6 +373,19 @@
}
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+ stream->Add("= ");
+ context()->PrintTo(stream);
+ stream->Add(" ");
+ constructor()->PrintTo(stream);
+ stream->Add(" #%d / ", arity());
+ ASSERT(hydrogen()->property_cell()->value()->IsSmi());
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(hydrogen()->property_cell()->value())->value());
+ stream->Add(" (%s) ", ElementsKindToString(kind));
+}
+
+
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
@@ -1145,21 +1164,16 @@
input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
} else {
- LOperand* input;
- if (op == kMathRound &&
- (!CpuFeatures::IsSupported(SSE4_1) ||
- instr->CheckFlag(HValue::kBailoutOnMinusZero))) {
- // Math.round implemented without roundsd. Input may be overwritten.
- ASSERT(instr->value()->representation().IsDouble());
- input = UseTempRegister(instr->value());
- } else {
- input = UseRegisterAtStart(instr->value());
- }
+ LOperand* input = UseRegisterAtStart(instr->value());
LOperand* context = UseAny(instr->context()); // Deferred use by MathAbs.
if (op == kMathPowHalf) {
LOperand* temp = TempRegister();
LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
return DefineSameAsFirst(result);
+ } else if (op == kMathRound) {
+ LOperand* temp = FixedTemp(xmm4);
+ LMathRound* result = new(zone()) LMathRound(context, input, temp);
+ return AssignEnvironment(DefineAsRegister(result));
}
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
input);
@@ -1168,8 +1182,6 @@
return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
case kMathFloor:
return AssignEnvironment(DefineAsRegister(result));
- case kMathRound:
- return AssignEnvironment(DefineAsRegister(result));
case kMathSqrt:
return DefineSameAsFirst(result);
default:
@@ -1221,6 +1233,16 @@
}
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+ ASSERT(FLAG_optimize_constructed_arrays);
+ LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* constructor = UseFixed(instr->constructor(), edi);
+ argument_count_ -= instr->argument_count();
+ LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
+ return MarkAsCall(DefineFixed(result, eax), instr);
+}
+
+
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* function = UseFixed(instr->function(), edi);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index ff4c477..087eb74 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -62,6 +62,7 @@
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
@@ -132,6 +133,7 @@
V(MathFloorOfDiv) \
V(MathMinMax) \
V(MathPowHalf) \
+ V(MathRound) \
V(ModI) \
V(MulI) \
V(NumberTagD) \
@@ -700,6 +702,25 @@
};
+class LMathRound: public LTemplateInstruction<1, 2, 1> {
+ public:
+ LMathRound(LOperand* context, LOperand* value, LOperand* temp) {
+ inputs_[1] = context;
+ inputs_[0] = value;
+ temps_[0] = temp;
+ }
+
+ LOperand* context() { return inputs_[1]; }
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp() { return temps_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathRound, "math-round")
+ DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+
+ virtual void PrintDataTo(StringStream* stream);
+};
+
+
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
@@ -1847,6 +1868,25 @@
};
+class LCallNewArray: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LCallNewArray(LOperand* context, LOperand* constructor) {
+ inputs_[0] = context;
+ inputs_[1] = constructor;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+ LOperand* constructor() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+ DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
class LCallRuntime: public LTemplateInstruction<1, 1, 0> {
public:
explicit LCallRuntime(LOperand* context) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 5e4f211..587699f 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -2409,12 +2409,23 @@
}
+void MacroAssembler::LoadGlobalContext(Register global_context) {
+ // Load the global or builtins object from the current context.
+ mov(global_context,
+ Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+ // Load the native context from the global or builtins object.
+ mov(global_context,
+ FieldOperand(global_context, GlobalObject::kNativeContextOffset));
+}
+
+
void MacroAssembler::LoadGlobalFunction(int index, Register function) {
// Load the global or builtins object from the current context.
mov(function,
Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
// Load the native context from the global or builtins object.
- mov(function, FieldOperand(function, GlobalObject::kNativeContextOffset));
+ mov(function,
+ FieldOperand(function, GlobalObject::kNativeContextOffset));
// Load the function from the native context.
mov(function, Operand(function, Context::SlotOffset(index)));
}
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index 8c893dc..65899ce 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -249,6 +249,8 @@
Register map_out,
bool can_have_holes);
+ void LoadGlobalContext(Register global_context);
+
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index c242d3f..34ce36d 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -141,14 +141,14 @@
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
-// Name must be a symbol and receiver must be a heap object.
+// Name must be an internalized string and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<String> name,
Register r0,
Register r1) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1);
__ IncrementCounter(counters->negative_lookups_miss(), 1);
@@ -377,23 +377,24 @@
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ mov(dst, FieldOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ mov(dst, FieldOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ mov(dst, FieldOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ mov(dst, FieldOperand(src, offset));
}
@@ -936,6 +937,11 @@
#define __ ACCESS_MASM(masm())
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
@@ -944,7 +950,9 @@
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -972,8 +980,8 @@
if (!current->HasFastProperties() &&
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
- if (!name->IsSymbol()) {
- name = factory()->LookupSymbol(name);
+ if (!name->IsInternalizedString()) {
+ name = factory()->InternalizeString(name);
}
ASSERT(current->property_dictionary()->FindEntry(*name) ==
StringDictionary::kNotFound);
@@ -991,8 +999,10 @@
// Save the map in scratch1 for later.
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
- __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
- ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
@@ -1024,9 +1034,11 @@
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, Handle<Map>(holder->map()),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, Handle<Map>(holder->map()),
+ miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1046,9 +1058,11 @@
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ jmp(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
@@ -1058,12 +1072,10 @@
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
@@ -1122,8 +1134,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1162,7 +1173,7 @@
__ mov(scratch2(), esp);
ASSERT(!scratch2().is(reg));
__ push(reg); // holder
- // Push data from AccessorInfo.
+ // Push data from ExecutableAccessorInfo.
if (isolate()->heap()->InNewSpace(callback->data())) {
__ mov(scratch1(), Immediate(callback));
__ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
@@ -1171,8 +1182,8 @@
}
__ push(Immediate(reinterpret_cast<int>(isolate())));
- // Save a pointer to where we pushed the arguments pointer.
- // This will be passed as the const AccessorInfo& to the C++ callback.
+ // Save a pointer to where we pushed the arguments pointer. This will be
+ // passed as the const ExecutableAccessorInfo& to the C++ callback.
__ push(scratch2());
__ push(name()); // name
@@ -2355,7 +2366,7 @@
break;
case STRING_CHECK:
- // Check that the object is a string or a symbol.
+ // Check that the object is a string.
__ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
__ j(above_equal, &miss);
// Check that the maps starting from the prototype haven't changed.
@@ -2366,6 +2377,12 @@
eax, holder, ebx, edx, edi, name, &miss);
break;
+ case SYMBOL_CHECK:
+ // Check that the object is a symbol.
+ __ CmpObjectType(edx, SYMBOL_TYPE, eax);
+ __ j(not_equal, &miss);
+ break;
+
case NUMBER_CHECK: {
Label fast;
// Check that the object is a smi or a heap number.
@@ -2927,7 +2944,7 @@
__ ret(0);
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
@@ -2998,8 +3015,9 @@
bool is_dont_delete) {
Label success, miss;
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
if (Serializer::enabled()) {
__ mov(eax, Immediate(cell));
@@ -3026,7 +3044,7 @@
__ ret(0);
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
@@ -3054,34 +3072,38 @@
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(edx, &miss);
- Register map_reg = ebx;
- __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
+ __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
__ cmp(map_reg, receiver_maps->at(current));
- __ j(equal, handler_ics->at(current));
+ __ j(equal, handlers->at(current));
}
__ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
diff --git a/src/ic-inl.h b/src/ic-inl.h
index 11ab710..9439792 100644
--- a/src/ic-inl.h
+++ b/src/ic-inl.h
@@ -107,8 +107,9 @@
return GetCodeCacheForObject(JSObject::cast(object), holder);
}
// If the object is a value, we use the prototype map for the cache.
- ASSERT(object->IsString() || object->IsNumber() || object->IsBoolean());
- return PROTOTYPE_MAP;
+ ASSERT(object->IsString() || object->IsSymbol() ||
+ object->IsNumber() || object->IsBoolean());
+ return DELEGATE_MAP;
}
@@ -123,7 +124,7 @@
!object->HasFastProperties() &&
!object->IsJSGlobalProxy() &&
!object->IsJSGlobalObject()) {
- return PROTOTYPE_MAP;
+ return DELEGATE_MAP;
}
return OWN_MAP;
}
@@ -132,8 +133,7 @@
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
Object* object,
InlineCacheHolderFlag holder) {
- Object* map_owner =
- holder == OWN_MAP ? object : object->GetPrototype(isolate);
+ Object* map_owner = holder == OWN_MAP ? object : object->GetDelegate(isolate);
ASSERT(map_owner->IsJSObject());
return JSObject::cast(map_owner);
}
diff --git a/src/ic.cc b/src/ic.cc
index b31ea9a..7fdf6be 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -179,7 +179,7 @@
// The stub was generated for JSObject but called for non-JSObject.
// IC::GetCodeCacheHolder is not applicable.
return false;
- } else if (cache_holder == PROTOTYPE_MAP &&
+ } else if (cache_holder == DELEGATE_MAP &&
receiver->GetPrototype(isolate)->IsNull()) {
// IC::GetCodeCacheHolder is not applicable.
return false;
@@ -756,7 +756,7 @@
MaybeObject* KeyedCallIC::LoadFunction(State state,
Handle<Object> object,
Handle<Object> key) {
- if (key->IsSymbol()) {
+ if (key->IsInternalizedString()) {
return CallICBase::LoadFunction(state,
Code::kNoExtraICState,
object,
@@ -817,7 +817,7 @@
// objects is read-only and therefore always returns the length of
// the underlying string value. See ECMA-262 15.5.5.1.
if ((object->IsString() || object->IsStringWrapper()) &&
- name->Equals(isolate()->heap()->length_symbol())) {
+ name->Equals(isolate()->heap()->length_string())) {
Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
@@ -846,7 +846,7 @@
// Use specialized code for getting the length of arrays.
if (object->IsJSArray() &&
- name->Equals(isolate()->heap()->length_symbol())) {
+ name->Equals(isolate()->heap()->length_string())) {
Handle<Code> stub;
if (state == UNINITIALIZED) {
stub = pre_monomorphic_stub();
@@ -868,7 +868,7 @@
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
- name->Equals(isolate()->heap()->prototype_symbol()) &&
+ name->Equals(isolate()->heap()->prototype_string()) &&
Handle<JSFunction>::cast(object)->should_have_prototype()) {
Handle<Code> stub;
if (state == UNINITIALIZED) {
@@ -935,6 +935,71 @@
}
+static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
+ Handle<Map> new_receiver_map) {
+ ASSERT(!new_receiver_map.is_null());
+ for (int current = 0; current < receiver_maps->length(); ++current) {
+ if (!receiver_maps->at(current).is_null() &&
+ receiver_maps->at(current).is_identical_to(new_receiver_map)) {
+ return false;
+ }
+ }
+ receiver_maps->Add(new_receiver_map);
+ return true;
+}
+
+
+bool IC::UpdatePolymorphicIC(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code) {
+ if (code->type() == Code::NORMAL) return false;
+ if (target()->ic_state() == MONOMORPHIC &&
+ target()->type() == Code::NORMAL) {
+ return false;
+ }
+ MapHandleList receiver_maps;
+ CodeHandleList handlers;
+ target()->FindAllMaps(&receiver_maps);
+ int number_of_maps = receiver_maps.length();
+ if (number_of_maps == 0 || number_of_maps >= 4) return false;
+
+ target()->FindAllCode(&handlers, receiver_maps.length());
+
+ if (!AddOneReceiverMapIfMissing(&receiver_maps,
+ Handle<Map>(receiver->map()))) {
+ return false;
+ }
+
+ handlers.Add(code);
+ Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
+ &receiver_maps, &handlers, name);
+ set_target(*ic);
+ return true;
+}
+
+
+void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
+ receiver, handler, name);
+ set_target(*ic);
+}
+
+
+void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC(
+ receiver, handler, name);
+ set_target(*ic);
+}
+
+
void IC::PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
@@ -944,14 +1009,18 @@
case UNINITIALIZED:
case PREMONOMORPHIC:
case MONOMORPHIC_PROTOTYPE_FAILURE:
- set_target(*code);
+ UpdateMonomorphicIC(receiver, code, name);
break;
case MONOMORPHIC:
// Only move to megamorphic if the target changes.
if (target() != *code) {
- // We are transitioning from monomorphic to megamorphic case.
- // Place the current monomorphic stub and stub compiled for
- // the receiver into stub cache.
+ if (target()->is_load_stub()) {
+ if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ break;
+ }
+ }
+ // We are transitioning from monomorphic to megamorphic case. Place the
+ // stub compiled for the receiver into stub cache.
Map* map = target()->FindFirstMap();
if (map != NULL) {
UpdateMegamorphicCache(map, *name, target());
@@ -967,14 +1036,26 @@
UpdateMegamorphicCache(receiver->map(), *name, *code);
break;
case POLYMORPHIC:
- // When trying to patch a polymorphic stub with anything other than
- // another polymorphic stub, go generic.
- // TODO(verwaest): Currently we always go generic since no polymorphic
- // stubs enter this code path. Replace with proper updating once named
- // load/store can also be polymorphic.
- set_target((strict_mode == kStrictMode)
- ? *generic_stub_strict()
- : *generic_stub());
+ if (target()->is_load_stub()) {
+ if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ break;
+ }
+ MapHandleList receiver_maps;
+ CodeHandleList handlers;
+ target()->FindAllMaps(&receiver_maps);
+ target()->FindAllCode(&handlers, receiver_maps.length());
+ for (int i = 0; i < receiver_maps.length(); i++) {
+ UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
+ }
+ UpdateMegamorphicCache(receiver->map(), *name, *code);
+ set_target(*megamorphic_stub());
+ } else {
+ // When trying to patch a polymorphic keyed load/store element stub
+ // with anything other than another polymorphic stub, go generic.
+ set_target((strict_mode == kStrictMode)
+ ? *generic_stub_strict()
+ : *generic_stub());
+ }
break;
case DEBUG_STUB:
break;
@@ -985,6 +1066,42 @@
}
+static void GetReceiverMapsForStub(Handle<Code> stub,
+ MapHandleList* result) {
+ ASSERT(stub->is_inline_cache_stub());
+ switch (stub->ic_state()) {
+ case MONOMORPHIC: {
+ Map* map = stub->FindFirstMap();
+ if (map != NULL) {
+ result->Add(Handle<Map>(map));
+ }
+ break;
+ }
+ case POLYMORPHIC: {
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Handle<Object> object(info->target_object(), stub->GetIsolate());
+ if (object->IsString()) break;
+ ASSERT(object->IsMap());
+ AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+ }
+ break;
+ }
+ case MEGAMORPHIC:
+ break;
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case GENERIC:
+ case DEBUG_STUB:
+ UNREACHABLE();
+ break;
+ }
+}
+
+
void LoadIC::UpdateCaches(LookupResult* lookup,
State state,
Handle<Object> object,
@@ -1004,7 +1121,7 @@
// setting the monomorphic state.
code = pre_monomorphic_stub();
} else {
- code = ComputeLoadMonomorphic(lookup, receiver, name);
+ code = ComputeLoadHandler(lookup, receiver, name);
if (code.is_null()) return;
}
@@ -1020,9 +1137,9 @@
}
-Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
+Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
if (!lookup->IsProperty()) {
// Nonexistent property. The result is undefined.
return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
@@ -1051,7 +1168,7 @@
// property must be found in the receiver for the stub to be
// applicable.
if (!holder.is_identical_to(receiver)) break;
- return isolate()->stub_cache()->ComputeLoadNormal();
+ return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (callback->IsExecutableAccessorInfo()) {
@@ -1093,7 +1210,7 @@
if (key->IsHeapNumber()) {
double value = Handle<HeapNumber>::cast(key)->value();
if (isnan(value)) {
- key = isolate->factory()->nan_symbol();
+ key = isolate->factory()->nan_string();
} else {
int int_value = FastD2I(value);
if (value == int_value && Smi::IsValid(int_value)) {
@@ -1101,62 +1218,12 @@
}
}
} else if (key->IsUndefined()) {
- key = isolate->factory()->undefined_symbol();
+ key = isolate->factory()->undefined_string();
}
return key;
}
-static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
- Handle<Map> new_receiver_map) {
- ASSERT(!new_receiver_map.is_null());
- for (int current = 0; current < receiver_maps->length(); ++current) {
- if (!receiver_maps->at(current).is_null() &&
- receiver_maps->at(current).is_identical_to(new_receiver_map)) {
- return false;
- }
- }
- receiver_maps->Add(new_receiver_map);
- return true;
-}
-
-
-static void GetReceiverMapsForStub(Handle<Code> stub,
- MapHandleList* result) {
- ASSERT(stub->is_inline_cache_stub());
- ASSERT(stub->is_keyed_load_stub() || stub->is_keyed_store_stub());
- switch (stub->ic_state()) {
- case MONOMORPHIC: {
- Map* map = stub->FindFirstMap();
- if (map != NULL) {
- result->Add(Handle<Map>(map));
- }
- break;
- }
- case POLYMORPHIC: {
- AssertNoAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Handle<Object> object(info->target_object(), stub->GetIsolate());
- ASSERT(object->IsMap());
- AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
- }
- break;
- }
- case MEGAMORPHIC:
- break;
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- case GENERIC:
- case DEBUG_STUB:
- UNREACHABLE();
- break;
- }
-}
-
-
Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
State ic_state = target()->ic_state();
@@ -1226,11 +1293,11 @@
Handle<Object> object,
Handle<Object> key,
ICMissMode miss_mode) {
- // Check for values that can be converted into a symbol directly or
- // is representable as a smi.
+ // Check for values that can be converted into an internalized string directly
+ // or is representable as a smi.
key = TryConvertKey(key, isolate());
- if (key->IsSymbol()) {
+ if (key->IsInternalizedString()) {
return LoadIC::Load(state, object, Handle<String>::cast(key));
}
@@ -1268,9 +1335,9 @@
}
-Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
+Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
// Bail out if we didn't find a result.
if (!lookup->IsProperty()) return Handle<Code>::null();
@@ -1367,7 +1434,7 @@
// The length property of string values is read-only. Throw in strict mode.
if (strict_mode == kStrictMode && object->IsString() &&
- name->Equals(isolate()->heap()->length_symbol())) {
+ name->Equals(isolate()->heap()->length_string())) {
return TypeError("strict_read_only_property", object, name);
}
@@ -1396,7 +1463,7 @@
// property.
if (FLAG_use_ic &&
receiver->IsJSArray() &&
- name->Equals(isolate()->heap()->length_symbol()) &&
+ name->Equals(isolate()->heap()->length_string()) &&
Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
receiver->HasFastProperties()) {
Handle<Code> stub =
@@ -1723,11 +1790,11 @@
Handle<Object> key,
Handle<Object> value,
ICMissMode miss_mode) {
- // Check for values that can be converted into a symbol directly or
- // is representable as a smi.
+ // Check for values that can be converted into an internalized string directly
+ // or is representable as a smi.
key = TryConvertKey(key, isolate());
- if (key->IsSymbol()) {
+ if (key->IsInternalizedString()) {
return StoreIC::Store(state,
strict_mode,
object,
@@ -1936,7 +2003,7 @@
#ifdef DEBUG
// The length property has to be a writable callback property.
LookupResult debug_lookup(isolate);
- receiver->LocalLookup(isolate->heap()->length_symbol(), &debug_lookup);
+ receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
#endif
@@ -2376,8 +2443,9 @@
case UNINITIALIZED: return "UNINITIALIZED";
case SMI: return "SMI";
case NUMBER: return "NUMBER";
- case SYMBOL: return "SYMBOL";
+ case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
case STRING: return "STRING";
+ case UNIQUE_NAME: return "UNIQUE_NAME";
case OBJECT: return "OBJECT";
case KNOWN_OBJECT: return "KNOWN_OBJECT";
case GENERIC: return "GENERIC";
@@ -2394,8 +2462,9 @@
case CompareIC::UNINITIALIZED:
if (value->IsSmi()) return CompareIC::SMI;
if (value->IsHeapNumber()) return CompareIC::NUMBER;
- if (value->IsSymbol()) return CompareIC::SYMBOL;
+ if (value->IsInternalizedString()) return CompareIC::INTERNALIZED_STRING;
if (value->IsString()) return CompareIC::STRING;
+ if (value->IsSymbol()) return CompareIC::UNIQUE_NAME;
if (value->IsJSObject()) return CompareIC::OBJECT;
break;
case CompareIC::SMI:
@@ -2405,12 +2474,16 @@
case CompareIC::NUMBER:
if (value->IsNumber()) return CompareIC::NUMBER;
break;
- case CompareIC::SYMBOL:
- if (value->IsSymbol()) return CompareIC::SYMBOL;
+ case CompareIC::INTERNALIZED_STRING:
+ if (value->IsInternalizedString()) return CompareIC::INTERNALIZED_STRING;
if (value->IsString()) return CompareIC::STRING;
+ if (value->IsSymbol()) return CompareIC::UNIQUE_NAME;
break;
case CompareIC::STRING:
- if (value->IsSymbol() || value->IsString()) return CompareIC::STRING;
+ if (value->IsString()) return CompareIC::STRING;
+ break;
+ case CompareIC::UNIQUE_NAME:
+ if (value->IsUniqueName()) return CompareIC::UNIQUE_NAME;
break;
case CompareIC::OBJECT:
if (value->IsJSObject()) return CompareIC::OBJECT;
@@ -2443,13 +2516,14 @@
return NUMBER;
}
}
- if (x->IsSymbol() && y->IsSymbol()) {
- // We compare symbols as strings if we need to determine
+ if (x->IsInternalizedString() && y->IsInternalizedString()) {
+ // We compare internalized strings as plain ones if we need to determine
// the order in a non-equality compare.
- return Token::IsEqualityOp(op_) ? SYMBOL : STRING;
+ return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
}
if (x->IsString() && y->IsString()) return STRING;
if (!Token::IsEqualityOp(op_)) return GENERIC;
+ if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
if (x->IsJSObject() && y->IsJSObject()) {
if (Handle<JSObject>::cast(x)->map() ==
Handle<JSObject>::cast(y)->map()) {
@@ -2461,9 +2535,11 @@
return GENERIC;
case SMI:
return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
- case SYMBOL:
+ case INTERNALIZED_STRING:
ASSERT(Token::IsEqualityOp(op_));
- return x->IsString() && y->IsString() ? STRING : GENERIC;
+ if (x->IsString() && y->IsString()) return STRING;
+ if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
+ return GENERIC;
case NUMBER:
// If the failure was due to one side changing from smi to heap number,
// then keep the state (if other changed at the same time, we will get
@@ -2476,6 +2552,7 @@
if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
return GENERIC;
case STRING:
+ case UNIQUE_NAME:
case OBJECT:
case GENERIC:
return GENERIC;
diff --git a/src/ic.h b/src/ic.h
index f7ebdf2..78c3642 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -165,6 +165,16 @@
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ set_target(*handler);
+ }
+ bool UpdatePolymorphicIC(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code);
void PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
@@ -377,9 +387,12 @@
State state,
Handle<Object> object,
Handle<String> name);
- virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name);
private:
// Stub accessors.
@@ -448,9 +461,12 @@
}
// Update the inline cache.
- virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
private:
@@ -756,14 +772,15 @@
// UNINITIALIZED < ...
// ... < GENERIC
// SMI < NUMBER
- // SYMBOL < STRING
+ // INTERNALIZED_STRING < STRING
// KNOWN_OBJECT < OBJECT
enum State {
UNINITIALIZED,
SMI,
NUMBER,
- SYMBOL,
STRING,
+ INTERNALIZED_STRING,
+ UNIQUE_NAME, // Symbol or InternalizedString
OBJECT, // JSObject
KNOWN_OBJECT, // JSObject with specific map (faster check)
GENERIC
diff --git a/src/interface.cc b/src/interface.cc
index 1634a37..603dfe9 100644
--- a/src/interface.cc
+++ b/src/interface.cc
@@ -35,8 +35,8 @@
static bool Match(void* key1, void* key2) {
String* name1 = *static_cast<String**>(key1);
String* name2 = *static_cast<String**>(key2);
- ASSERT(name1->IsSymbol());
- ASSERT(name2->IsSymbol());
+ ASSERT(name1->IsInternalizedString());
+ ASSERT(name2->IsInternalizedString());
return name1 == name2;
}
diff --git a/src/isolate.cc b/src/isolate.cc
index c8e6f05..4970ec7 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -541,11 +541,11 @@
OS::PrintError(
"If you are lucky you may find a partial stack dump on stdout.\n\n");
incomplete_message_->OutputToStdOut();
- return factory()->empty_symbol();
+ return factory()->empty_string();
} else {
OS::Abort();
// Unreachable
- return factory()->empty_symbol();
+ return factory()->empty_string();
}
}
@@ -662,7 +662,7 @@
void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) {
if (capture_stack_trace_for_uncaught_exceptions_) {
// Capture stack trace for a detailed exception message.
- Handle<String> key = factory()->hidden_stack_trace_symbol();
+ Handle<String> key = factory()->hidden_stack_trace_string();
Handle<JSArray> stack_trace = CaptureCurrentStackTrace(
stack_trace_for_uncaught_exceptions_frame_limit_,
stack_trace_for_uncaught_exceptions_options_);
@@ -678,20 +678,20 @@
Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
Handle<String> column_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("column"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("column"));
Handle<String> line_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("lineNumber"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("lineNumber"));
Handle<String> script_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("scriptName"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("scriptName"));
Handle<String> script_name_or_source_url_key =
- factory()->LookupOneByteSymbol(
+ factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("scriptNameOrSourceURL"));
Handle<String> function_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("functionName"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("functionName"));
Handle<String> eval_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("isEval"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("isEval"));
Handle<String> constructor_key =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("isConstructor"));
+ factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("isConstructor"));
StackTraceFrameIterator it(this);
int frames_seen = 0;
@@ -934,7 +934,7 @@
// Skip checks for hidden properties access. Note, we do not
// require existence of a context in this case.
- if (key == heap_.hidden_symbol()) return true;
+ if (key == heap_.hidden_string()) return true;
// Check for compatibility between the security tokens in the
// current lexical context and the accessed object.
@@ -1030,7 +1030,7 @@
// At this point we cannot create an Error object using its javascript
// constructor. Instead, we copy the pre-constructed boilerplate and
// attach the stack trace as a hidden property.
- Handle<String> key = factory()->stack_overflow_symbol();
+ Handle<String> key = factory()->stack_overflow_string();
Handle<JSObject> boilerplate =
Handle<JSObject>::cast(GetProperty(this, js_builtins_object(), key));
Handle<JSObject> exception = Copy(boilerplate);
@@ -1047,7 +1047,7 @@
Handle<JSArray> stack_trace = CaptureSimpleStackTrace(
exception, factory()->undefined_value(), limit);
JSObject::SetHiddenProperty(exception,
- factory()->hidden_stack_trace_symbol(),
+ factory()->hidden_stack_trace_string(),
stack_trace);
return Failure::Exception();
}
@@ -1081,7 +1081,7 @@
Failure* Isolate::ThrowIllegalOperation() {
- return Throw(heap_.illegal_access_symbol());
+ return Throw(heap_.illegal_access_string());
}
@@ -1187,7 +1187,7 @@
if (!obj->IsJSObject()) return false;
String* error_key =
- *(factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("$Error")));
+ *(factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("$Error")));
Object* error_constructor =
js_builtins_object()->GetPropertyNoExceptionThrown(error_key);
@@ -1243,7 +1243,7 @@
if (capture_stack_trace_for_uncaught_exceptions_) {
if (IsErrorObject(exception_handle)) {
// We fetch the stack trace that corresponds to this error object.
- String* key = heap()->hidden_stack_trace_symbol();
+ String* key = heap()->hidden_stack_trace_string();
Object* stack_property =
JSObject::cast(*exception_handle)->GetHiddenProperty(key);
// Property lookup may have failed. In this case it's probably not
@@ -1268,8 +1268,8 @@
bool failed = false;
exception_arg = Execution::ToDetailString(exception_arg, &failed);
if (failed) {
- exception_arg =
- factory()->LookupOneByteSymbol(STATIC_ASCII_VECTOR("exception"));
+ exception_arg = factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("exception"));
}
}
Handle<Object> message_obj = MessageHandler::MakeMessageObject(
diff --git a/src/json-parser.h b/src/json-parser.h
index 8d9ddda..28ef8b3 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -102,10 +102,10 @@
Handle<String> ParseJsonString() {
return ScanJsonString<false>();
}
- Handle<String> ParseJsonSymbol() {
+ Handle<String> ParseJsonInternalizedString() {
return ScanJsonString<true>();
}
- template <bool is_symbol>
+ template <bool is_internalized>
Handle<String> ScanJsonString();
// Creates a new string and copies prefix[start..end] into the beginning
// of it. Then scans the rest of the string, adding characters after the
@@ -338,7 +338,7 @@
c0_ = '"';
#endif
- Handle<String> key = ParseJsonSymbol();
+ Handle<String> key = ParseJsonInternalizedString();
if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
AdvanceSkipWhitespace();
@@ -601,7 +601,7 @@
template <bool seq_ascii>
-template <bool is_symbol>
+template <bool is_internalized>
Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
ASSERT_EQ('"', c0_);
Advance();
@@ -610,10 +610,10 @@
return factory()->empty_string();
}
- if (seq_ascii && is_symbol) {
- // Fast path for existing symbols. If the the string being parsed is not
- // a known symbol, contains backslashes or unexpectedly reaches the end of
- // string, return with an empty handle.
+ if (seq_ascii && is_internalized) {
+ // Fast path for existing internalized strings. If the the string being
+ // parsed is not a known internalized string, contains backslashes or
+ // unexpectedly reaches the end of string, return with an empty handle.
uint32_t running_hash = isolate()->heap()->HashSeed();
int position = position_;
uc32 c0 = c0_;
@@ -647,12 +647,12 @@
? StringHasher::GetHashCore(running_hash) : length;
Vector<const uint8_t> string_vector(
seq_source_->GetChars() + position_, length);
- SymbolTable* symbol_table = isolate()->heap()->symbol_table();
- uint32_t capacity = symbol_table->Capacity();
- uint32_t entry = SymbolTable::FirstProbe(hash, capacity);
+ StringTable* string_table = isolate()->heap()->string_table();
+ uint32_t capacity = string_table->Capacity();
+ uint32_t entry = StringTable::FirstProbe(hash, capacity);
uint32_t count = 1;
while (true) {
- Object* element = symbol_table->KeyAt(entry);
+ Object* element = string_table->KeyAt(entry);
if (element == isolate()->heap()->undefined_value()) {
// Lookup failure.
break;
@@ -665,7 +665,7 @@
AdvanceSkipWhitespace();
return Handle<String>(String::cast(element), isolate());
}
- entry = SymbolTable::NextProbe(entry, count++, capacity);
+ entry = StringTable::NextProbe(entry, count++, capacity);
}
}
@@ -690,8 +690,8 @@
} while (c0_ != '"');
int length = position_ - beg_pos;
Handle<String> result;
- if (seq_ascii && is_symbol) {
- result = factory()->LookupOneByteSymbol(seq_source_, beg_pos, length);
+ if (seq_ascii && is_internalized) {
+ result = factory()->InternalizeOneByteString(seq_source_, beg_pos, length);
} else {
result = factory()->NewRawOneByteString(length, pretenure_);
uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index 3ea023d..e9121d4 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -165,7 +165,7 @@
// (indirect) handle to it in the outermost handle scope.
Handle<JSValue> accumulator_store_;
Handle<String> current_part_;
- Handle<String> tojson_symbol_;
+ Handle<String> tojson_string_;
Handle<JSArray> stack_;
int current_index_;
int part_length_;
@@ -251,8 +251,8 @@
factory_->ToObject(factory_->empty_string()));
part_length_ = kInitialPartLength;
current_part_ = factory_->NewRawOneByteString(kInitialPartLength);
- tojson_symbol_ =
- factory_->LookupOneByteSymbol(STATIC_ASCII_VECTOR("toJSON"));
+ tojson_string_ =
+ factory_->InternalizeOneByteString(STATIC_ASCII_VECTOR("toJSON"));
stack_ = factory_->NewJSArray(8);
}
@@ -297,11 +297,11 @@
Handle<Object> BasicJsonStringifier::ApplyToJsonFunction(
Handle<Object> object, Handle<Object> key) {
LookupResult lookup(isolate_);
- JSObject::cast(*object)->LookupRealNamedProperty(*tojson_symbol_, &lookup);
+ JSObject::cast(*object)->LookupRealNamedProperty(*tojson_string_, &lookup);
if (!lookup.IsProperty()) return object;
PropertyAttributes attr;
Handle<Object> fun =
- Object::GetProperty(object, object, &lookup, tojson_symbol_, &attr);
+ Object::GetProperty(object, object, &lookup, tojson_string_, &attr);
if (!fun->IsJSFunction()) return object;
// Call toJSON function.
@@ -434,17 +434,17 @@
Handle<JSValue> object) {
bool has_exception = false;
String* class_name = object->class_name();
- if (class_name == isolate_->heap()->String_symbol()) {
+ if (class_name == isolate_->heap()->String_string()) {
Handle<Object> value = Execution::ToString(object, &has_exception);
if (has_exception) return EXCEPTION;
SerializeString(Handle<String>::cast(value));
- } else if (class_name == isolate_->heap()->Number_symbol()) {
+ } else if (class_name == isolate_->heap()->Number_string()) {
Handle<Object> value = Execution::ToNumber(object, &has_exception);
if (has_exception) return EXCEPTION;
if (value->IsSmi()) return SerializeSmi(Smi::cast(*value));
SerializeHeapNumber(Handle<HeapNumber>::cast(value));
} else {
- ASSERT(class_name == isolate_->heap()->Boolean_symbol());
+ ASSERT(class_name == isolate_->heap()->Boolean_string());
Object* value = JSValue::cast(*object)->value();
ASSERT(value->IsBoolean());
AppendAscii(value->IsTrue() ? "true" : "false");
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 9b82da1..e73b1d4 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -2299,35 +2299,33 @@
int ActionNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+ if (budget <= 0) return 0;
if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input!
return on_success()->EatsAtLeast(still_to_find,
- recursion_depth + 1,
+ budget - 1,
not_at_start);
}
void ActionNode::FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
if (type_ == BEGIN_SUBMATCH) {
bm->SetRest(offset);
} else if (type_ != POSITIVE_SUBMATCH_SUCCESS) {
- on_success()->FillInBMInfo(
- offset, recursion_depth + 1, budget - 1, bm, not_at_start);
+ on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
}
SaveBMInfo(bm, not_at_start, offset);
}
int AssertionNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+ if (budget <= 0) return 0;
// If we know we are not at the start and we are asked "how many characters
// will you match if you succeed?" then we can answer anything since false
// implies false. So lets just return the max answer (still_to_find) since
@@ -2335,55 +2333,53 @@
// branches in the node graph.
if (type() == AT_START && not_at_start) return still_to_find;
return on_success()->EatsAtLeast(still_to_find,
- recursion_depth + 1,
+ budget - 1,
not_at_start);
}
void AssertionNode::FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
// Match the behaviour of EatsAtLeast on this node.
if (type() == AT_START && not_at_start) return;
- on_success()->FillInBMInfo(
- offset, recursion_depth + 1, budget - 1, bm, not_at_start);
+ on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
SaveBMInfo(bm, not_at_start, offset);
}
int BackReferenceNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+ if (budget <= 0) return 0;
return on_success()->EatsAtLeast(still_to_find,
- recursion_depth + 1,
+ budget - 1,
not_at_start);
}
int TextNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
int answer = Length();
if (answer >= still_to_find) return answer;
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return answer;
+ if (budget <= 0) return answer;
// We are not at start after this node so we set the last argument to 'true'.
return answer + on_success()->EatsAtLeast(still_to_find - answer,
- recursion_depth + 1,
+ budget - 1,
true);
}
int NegativeLookaheadChoiceNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+ if (budget <= 0) return 0;
// Alternative 0 is the negative lookahead, alternative 1 is what comes
// afterwards.
RegExpNode* node = alternatives_->at(1).node();
- return node->EatsAtLeast(still_to_find, recursion_depth + 1, not_at_start);
+ return node->EatsAtLeast(still_to_find, budget - 1, not_at_start);
}
@@ -2400,39 +2396,40 @@
int ChoiceNode::EatsAtLeastHelper(int still_to_find,
- int recursion_depth,
+ int budget,
RegExpNode* ignore_this_node,
bool not_at_start) {
- if (recursion_depth > RegExpCompiler::kMaxRecursion) return 0;
+ if (budget <= 0) return 0;
int min = 100;
int choice_count = alternatives_->length();
+ budget = (budget - 1) / choice_count;
for (int i = 0; i < choice_count; i++) {
RegExpNode* node = alternatives_->at(i).node();
if (node == ignore_this_node) continue;
- int node_eats_at_least = node->EatsAtLeast(still_to_find,
- recursion_depth + 1,
- not_at_start);
+ int node_eats_at_least =
+ node->EatsAtLeast(still_to_find, budget, not_at_start);
if (node_eats_at_least < min) min = node_eats_at_least;
+ if (min == 0) return 0;
}
return min;
}
int LoopChoiceNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
return EatsAtLeastHelper(still_to_find,
- recursion_depth,
+ budget - 1,
loop_node_,
not_at_start);
}
int ChoiceNode::EatsAtLeast(int still_to_find,
- int recursion_depth,
+ int budget,
bool not_at_start) {
return EatsAtLeastHelper(still_to_find,
- recursion_depth,
+ budget,
NULL,
not_at_start);
}
@@ -2988,19 +2985,15 @@
void LoopChoiceNode::FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
- if (body_can_be_zero_length_ ||
- recursion_depth > RegExpCompiler::kMaxRecursion ||
- budget <= 0) {
+ if (body_can_be_zero_length_ || budget <= 0) {
bm->SetRest(offset);
SaveBMInfo(bm, not_at_start, offset);
return;
}
- ChoiceNode::FillInBMInfo(
- offset, recursion_depth + 1, budget - 1, bm, not_at_start);
+ ChoiceNode::FillInBMInfo(offset, budget - 1, bm, not_at_start);
SaveBMInfo(bm, not_at_start, offset);
}
@@ -3097,12 +3090,13 @@
BoyerMooreLookahead* lookahead = bm_info(not_at_start);
if (lookahead == NULL) {
int eats_at_least =
- Min(kMaxLookaheadForBoyerMoore,
- EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start));
+ Min(kMaxLookaheadForBoyerMoore, EatsAtLeast(kMaxLookaheadForBoyerMoore,
+ kRecursionBudget,
+ not_at_start));
if (eats_at_least >= 1) {
BoyerMooreLookahead* bm =
new(zone()) BoyerMooreLookahead(eats_at_least, compiler, zone());
- FillInBMInfo(0, 0, kFillInBMBudget, bm, not_at_start);
+ FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
if (bm->at(0)->is_non_word()) next_is_word_character = Trace::FALSE;
if (bm->at(0)->is_word()) next_is_word_character = Trace::TRUE;
}
@@ -4034,16 +4028,17 @@
ASSERT(trace->is_trivial()); // This is the case on LoopChoiceNodes.
BoyerMooreLookahead* lookahead = bm_info(not_at_start);
if (lookahead == NULL) {
- eats_at_least =
- Min(kMaxLookaheadForBoyerMoore,
- EatsAtLeast(kMaxLookaheadForBoyerMoore, 0, not_at_start));
+ eats_at_least = Min(kMaxLookaheadForBoyerMoore,
+ EatsAtLeast(kMaxLookaheadForBoyerMoore,
+ kRecursionBudget,
+ not_at_start));
if (eats_at_least >= 1) {
BoyerMooreLookahead* bm =
new(zone()) BoyerMooreLookahead(eats_at_least,
compiler,
zone());
GuardedAlternative alt0 = alternatives_->at(0);
- alt0.node()->FillInBMInfo(0, 0, kFillInBMBudget, bm, not_at_start);
+ alt0.node()->FillInBMInfo(0, kRecursionBudget, bm, not_at_start);
skip_was_emitted = bm->EmitSkipInstructions(macro_assembler);
}
} else {
@@ -4055,7 +4050,8 @@
if (eats_at_least == kEatsAtLeastNotYetInitialized) {
// Save some time by looking at most one machine word ahead.
- eats_at_least = EatsAtLeast(compiler->ascii() ? 4 : 2, 0, not_at_start);
+ eats_at_least =
+ EatsAtLeast(compiler->ascii() ? 4 : 2, kRecursionBudget, not_at_start);
}
int preload_characters = CalculatePreloadCharacters(compiler, eats_at_least);
@@ -5811,7 +5807,6 @@
void BackReferenceNode::FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
@@ -5827,7 +5822,6 @@
void ChoiceNode::FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
@@ -5840,15 +5834,13 @@
SaveBMInfo(bm, not_at_start, offset);
return;
}
- alt.node()->FillInBMInfo(
- offset, recursion_depth + 1, budget, bm, not_at_start);
+ alt.node()->FillInBMInfo(offset, budget, bm, not_at_start);
}
SaveBMInfo(bm, not_at_start, offset);
}
void TextNode::FillInBMInfo(int initial_offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
@@ -5905,7 +5897,6 @@
return;
}
on_success()->FillInBMInfo(offset,
- recursion_depth + 1,
budget - 1,
bm,
true); // Not at start after a text node.
diff --git a/src/jsregexp.h b/src/jsregexp.h
index ae0e902..625f192 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -582,9 +582,7 @@
// used to indicate that we know we are not at the start of the input. In
// this case anchored branches will always fail and can be ignored when
// determining how many characters are consumed on success.
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start) = 0;
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start) = 0;
// Emits some quick code that checks whether the preloaded characters match.
// Falls through on certain failure, jumps to the label on possible success.
// If the node cannot make a quick check it does nothing and returns false.
@@ -616,9 +614,8 @@
// implementation. TODO(erikcorry): This should share more code with
// EatsAtLeast, GetQuickCheckDetails. The budget argument is used to limit
// the number of nodes we are willing to look at in order to create this data.
- static const int kFillInBMBudget = 200;
+ static const int kRecursionBudget = 200;
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
@@ -725,12 +722,10 @@
void set_on_success(RegExpNode* node) { on_success_ = node; }
virtual RegExpNode* FilterASCII(int depth, bool ignore_case);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
- on_success_->FillInBMInfo(
- offset, recursion_depth + 1, budget - 1, bm, not_at_start);
+ on_success_->FillInBMInfo(offset, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
@@ -773,9 +768,7 @@
RegExpNode* on_success);
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
@@ -784,7 +777,6 @@
details, compiler, filled_in, not_at_start);
}
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
@@ -843,9 +835,7 @@
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
@@ -856,7 +846,6 @@
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
@@ -911,15 +900,12 @@
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
@@ -960,7 +946,6 @@
return;
}
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
@@ -989,7 +974,6 @@
UNREACHABLE();
}
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
@@ -1075,11 +1059,9 @@
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
DispatchTable* GetTable(bool ignore_case);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
int EatsAtLeastHelper(int still_to_find,
- int recursion_depth,
+ int budget,
RegExpNode* ignore_this_node,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
@@ -1087,7 +1069,6 @@
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
@@ -1133,20 +1114,17 @@
AddAlternative(this_must_fail);
AddAlternative(then_do_this);
}
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
alternatives_->at(1).node()->FillInBMInfo(
- offset, recursion_depth + 1, budget - 1, bm, not_at_start);
+ offset, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
// For a negative lookahead we don't emit the quick check for the
@@ -1169,15 +1147,12 @@
void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
- virtual int EatsAtLeast(int still_to_find,
- int recursion_depth,
- bool not_at_start);
+ virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
- int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 7aaef15..382f209 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -966,14 +966,14 @@
rethrow_exception = Handle<JSObject>::cast(exception);
Factory* factory = isolate->factory();
- Handle<String> start_pos_key =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("startPosition"));
- Handle<String> end_pos_key =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("endPosition"));
- Handle<String> script_obj_key =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("scriptObject"));
- Handle<Smi> start_pos(Smi::FromInt(message_location.start_pos()),
- isolate);
+ Handle<String> start_pos_key = factory->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("startPosition"));
+ Handle<String> end_pos_key = factory->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("endPosition"));
+ Handle<String> script_obj_key = factory->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("scriptObject"));
+ Handle<Smi> start_pos(
+ Smi::FromInt(message_location.start_pos()), isolate);
Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
Handle<JSValue> script_obj = GetScriptWrapper(message_location.script());
JSReceiver::SetProperty(
diff --git a/src/log-utils.cc b/src/log-utils.cc
index d8d92cb..830c3da 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -262,7 +262,7 @@
Append(str->IsOneByteRepresentation() ? 'a' : '2');
if (StringShape(str).IsExternal())
Append('e');
- if (StringShape(str).IsSymbol())
+ if (StringShape(str).IsInternalized())
Append('#');
Append(":%i:", str->length());
}
diff --git a/src/log.h b/src/log.h
index 9532e8b..718dc02 100644
--- a/src/log.h
+++ b/src/log.h
@@ -135,6 +135,7 @@
V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC") \
V(LAZY_COMPILE_TAG, "LazyCompile") \
V(LOAD_IC_TAG, "LoadIC") \
+ V(LOAD_POLYMORPHIC_IC_TAG, "LoadPolymorphicIC") \
V(REG_EXP_TAG, "RegExp") \
V(SCRIPT_TAG, "Script") \
V(STORE_IC_TAG, "StoreIC") \
diff --git a/src/macros.py b/src/macros.py
index f871fc5..291a898 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -99,6 +99,7 @@
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
+macro IS_SYMBOL(arg) = (%_IsSymbol(arg));
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 47a66a8..366594f 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -1178,7 +1178,7 @@
static inline HeapObject* ShortCircuitConsString(Object** p) {
- // Optimization: If the heap object pointed to by p is a non-symbol
+ // Optimization: If the heap object pointed to by p is a non-internalized
// cons string whose right substring is HEAP->empty_string, update
// it in place to its left substring. Return the updated value.
//
@@ -1186,7 +1186,7 @@
// (i.e., the left substring of a cons string is always a heap object).
//
// The check performed is:
- // object->IsConsString() && !object->IsSymbol() &&
+ // object->IsConsString() && !object->IsInternalizedString() &&
// (ConsString::cast(object)->second() == HEAP->empty_string())
// except the maps for the object and its possible substrings might be
// marked.
@@ -1563,10 +1563,10 @@
static inline void Visit(Map* map, HeapObject* obj) {
Heap* heap = map->GetHeap();
FixedArray* fixed_array = FixedArray::cast(obj);
- if (fixed_array == heap->symbol_table()) {
+ if (fixed_array == heap->string_table()) {
heap->RecordObjectStats(
FIXED_ARRAY_TYPE,
- SYMBOL_TABLE_SUB_TYPE,
+ STRING_TABLE_SUB_TYPE,
fixed_array->Size());
}
ObjectStatsVisitBase(kVisitFixedArray, map, obj);
@@ -1747,10 +1747,10 @@
};
-// Helper class for pruning the symbol table.
-class SymbolTableCleaner : public ObjectVisitor {
+// Helper class for pruning the string table.
+class StringTableCleaner : public ObjectVisitor {
public:
- explicit SymbolTableCleaner(Heap* heap)
+ explicit StringTableCleaner(Heap* heap)
: heap_(heap), pointers_removed_(0) { }
virtual void VisitPointers(Object** start, Object** end) {
@@ -1759,8 +1759,8 @@
Object* o = *p;
if (o->IsHeapObject() &&
!Marking::MarkBitFrom(HeapObject::cast(o)).Get()) {
- // Check if the symbol being pruned is an external symbol. We need to
- // delete the associated external data as this symbol is going away.
+ // Check if the internalized string being pruned is external. We need to
+ // delete the associated external data as this string is going away.
// Since no objects have yet been moved we can safely access the map of
// the object.
@@ -1920,14 +1920,14 @@
}
-void MarkCompactCollector::MarkSymbolTable() {
- SymbolTable* symbol_table = heap()->symbol_table();
- // Mark the symbol table itself.
- MarkBit symbol_table_mark = Marking::MarkBitFrom(symbol_table);
- SetMark(symbol_table, symbol_table_mark);
+void MarkCompactCollector::MarkStringTable() {
+ StringTable* string_table = heap()->string_table();
+ // Mark the string table itself.
+ MarkBit string_table_mark = Marking::MarkBitFrom(string_table);
+ SetMark(string_table, string_table_mark);
// Explicitly mark the prefix.
MarkingVisitor marker(heap());
- symbol_table->IteratePrefix(&marker);
+ string_table->IteratePrefix(&marker);
ProcessMarkingDeque();
}
@@ -1937,8 +1937,8 @@
// etc., and all objects reachable from them.
heap()->IterateStrongRoots(visitor, VISIT_ONLY_STRONG);
- // Handle the symbol table specially.
- MarkSymbolTable();
+ // Handle the string table specially.
+ MarkStringTable();
// There may be overflowed objects in the heap. Visit them now.
while (marking_deque_.overflowed()) {
@@ -2176,19 +2176,19 @@
void MarkCompactCollector::AfterMarking() {
- // Object literal map caches reference symbols (cache keys) and maps
+ // Object literal map caches reference strings (cache keys) and maps
// (cache values). At this point still useful maps have already been
// marked. Mark the keys for the alive values before we process the
- // symbol table.
+ // string table.
ProcessMapCaches();
- // Prune the symbol table removing all symbols only pointed to by the
- // symbol table. Cannot use symbol_table() here because the symbol
+ // Prune the string table removing all strings only pointed to by the
+ // string table. Cannot use string_table() here because the string
// table is marked.
- SymbolTable* symbol_table = heap()->symbol_table();
- SymbolTableCleaner v(heap());
- symbol_table->IterateElements(&v);
- symbol_table->ElementsRemoved(v.PointersRemoved());
+ StringTable* string_table = heap()->string_table();
+ StringTableCleaner v(heap());
+ string_table->IterateElements(&v);
+ string_table->ElementsRemoved(v.PointersRemoved());
heap()->external_string_table_.Iterate(&v);
heap()->external_string_table_.CleanUp();
heap()->error_object_list_.RemoveUnmarked(heap());
@@ -3284,7 +3284,7 @@
// Update pointer from the native contexts list.
updating_visitor.VisitPointer(heap_->native_contexts_list_address());
- heap_->symbol_table()->Iterate(&updating_visitor);
+ heap_->string_table()->Iterate(&updating_visitor);
// Update pointers from external string table.
heap_->UpdateReferencesInExternalStringTable(
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 38ea4ed..b5d60fd 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -797,9 +797,9 @@
// Mark the heap roots and all objects reachable from them.
void MarkRoots(RootMarkingVisitor* visitor);
- // Mark the symbol table specially. References to symbols from the
- // symbol table are weak.
- void MarkSymbolTable();
+ // Mark the string table specially. References to internalized strings from
+ // the string table are weak.
+ void MarkStringTable();
// Mark objects in implicit references groups if their parent object
// is marked.
diff --git a/src/messages.cc b/src/messages.cc
index bc8c6a5..de18a4b 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -62,7 +62,7 @@
Vector< Handle<Object> > args,
Handle<String> stack_trace,
Handle<JSArray> stack_frames) {
- Handle<String> type_handle = FACTORY->LookupUtf8Symbol(type);
+ Handle<String> type_handle = FACTORY->InternalizeUtf8String(type);
Handle<FixedArray> arguments_elements =
FACTORY->NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
@@ -157,7 +157,7 @@
Handle<Object> data) {
Factory* factory = isolate->factory();
Handle<String> fmt_str =
- factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("FormatMessage"));
+ factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("FormatMessage"));
Handle<JSFunction> fun =
Handle<JSFunction>(
JSFunction::cast(
@@ -176,7 +176,7 @@
&caught_exception);
if (caught_exception || !result->IsString()) {
- return factory->LookupOneByteSymbol(STATIC_ASCII_VECTOR("<error>"));
+ return factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("<error>"));
}
Handle<String> result_string = Handle<String>::cast(result);
// A string that has been obtained from JS code in this way is
diff --git a/src/messages.js b/src/messages.js
index e274f50..14ba73f 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -820,7 +820,8 @@
%_CallFunction(this.receiver,
ownName,
ObjectLookupSetter) === this.fun ||
- %GetDataProperty(this.receiver, ownName) === this.fun)) {
+ (IS_OBJECT(this.receiver) &&
+ %GetDataProperty(this.receiver, ownName) === this.fun))) {
// To handle DontEnum properties we guess that the method has
// the same name as the function.
return ownName;
@@ -829,7 +830,8 @@
for (var prop in this.receiver) {
if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun ||
%_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun ||
- %GetDataProperty(this.receiver, prop) === this.fun) {
+ (IS_OBJECT(this.receiver) &&
+ %GetDataProperty(this.receiver, prop) === this.fun)) {
// If we find more than one match bail out to avoid confusion.
if (name) {
return null;
@@ -883,10 +885,9 @@
function CallSiteIsConstructor() {
var receiver = this.receiver;
- var constructor = receiver ? %GetDataProperty(receiver, "constructor") : null;
- if (!constructor) {
- return false;
- }
+ var constructor =
+ IS_OBJECT(receiver) ? %GetDataProperty(receiver, "constructor") : null;
+ if (!constructor) return false;
return this.fun === constructor;
}
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 0d710d6..4eba0fa 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -39,6 +39,18 @@
namespace internal {
+void FastCloneShallowObjectStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a3, a2, a1, a0 };
+ descriptor->register_param_count_ = 4;
+ descriptor->register_params_ = registers;
+ descriptor->stack_parameter_count_ = NULL;
+ descriptor->deoptimization_handler_ =
+ Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
+}
+
+
void KeyedLoadFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -498,49 +510,6 @@
}
-void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) {
- // Stack layout on entry:
- //
- // [sp]: object literal flags.
- // [sp + kPointerSize]: constant properties.
- // [sp + (2 * kPointerSize)]: literal index.
- // [sp + (3 * kPointerSize)]: literals array.
-
- // Load boilerplate object into a3 and check if we need to create a
- // boilerplate.
- Label slow_case;
- __ lw(a3, MemOperand(sp, 3 * kPointerSize));
- __ lw(a0, MemOperand(sp, 2 * kPointerSize));
- __ Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(a3, t0, a3);
- __ lw(a3, MemOperand(a3));
- __ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
- __ Branch(&slow_case, eq, a3, Operand(t0));
-
- // Check that the boilerplate contains only fast properties and we can
- // statically determine the instance size.
- int size = JSObject::kHeaderSize + length_ * kPointerSize;
- __ lw(a0, FieldMemOperand(a3, HeapObject::kMapOffset));
- __ lbu(a0, FieldMemOperand(a0, Map::kInstanceSizeOffset));
- __ Branch(&slow_case, ne, a0, Operand(size >> kPointerSizeLog2));
-
- // Allocate the JS object and copy header together with all in-object
- // properties from the boilerplate.
- __ AllocateInNewSpace(size, v0, a1, a2, &slow_case, TAG_OBJECT);
- for (int i = 0; i < size; i += kPointerSize) {
- __ lw(a1, FieldMemOperand(a3, i));
- __ sw(a1, FieldMemOperand(v0, i));
- }
-
- // Return and remove the on-stack parameters.
- __ DropAndRet(4);
-
- __ bind(&slow_case);
- __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1);
-}
-
-
// Takes a Smi and converts to an IEEE 64 bit floating point value in two
// registers. The format is 1 sign bit, 11 exponent bits (biased 1023) and
// 52 fraction bits (20 in the first word, 32 in the second). Zeros is a
@@ -1815,7 +1784,7 @@
Label ok;
if (expected == CompareIC::SMI) {
__ JumpIfNotSmi(input, fail);
- } else if (expected == CompareIC::HEAP_NUMBER) {
+ } else if (expected == CompareIC::NUMBER) {
__ JumpIfSmi(input, &ok);
__ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
DONT_DO_SMI_CHECK);
@@ -2174,8 +2143,8 @@
case UnaryOpIC::SMI:
GenerateSmiStub(masm);
break;
- case UnaryOpIC::HEAP_NUMBER:
- GenerateHeapNumberStub(masm);
+ case UnaryOpIC::NUMBER:
+ GenerateNumberStub(masm);
break;
case UnaryOpIC::GENERIC:
GenerateGenericStub(masm);
@@ -2255,13 +2224,13 @@
// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
+void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
switch (op_) {
case Token::SUB:
- GenerateHeapNumberStubSub(masm);
+ GenerateNumberStubSub(masm);
break;
case Token::BIT_NOT:
- GenerateHeapNumberStubBitNot(masm);
+ GenerateNumberStubBitNot(masm);
break;
default:
UNREACHABLE();
@@ -2269,7 +2238,7 @@
}
-void UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) {
+void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
Label non_smi, slow, call_builtin;
GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
__ bind(&non_smi);
@@ -2281,7 +2250,7 @@
}
-void UnaryOpStub::GenerateHeapNumberStubBitNot(MacroAssembler* masm) {
+void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) {
Label non_smi, slow;
GenerateSmiCodeBitNot(masm, &non_smi);
__ bind(&non_smi);
@@ -2696,8 +2665,7 @@
masm, right, destination, f14, f16, a2, a3, heap_number_map,
scratch1, scratch2, f2, miss);
} else {
- Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss
- : not_numbers;
+ Label* fail = (right_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
FloatingPointHelper::LoadNumber(
masm, destination, right, f14, a2, a3, heap_number_map,
scratch1, scratch2, fail);
@@ -2709,8 +2677,7 @@
masm, left, destination, f12, f16, a0, a1, heap_number_map,
scratch1, scratch2, f2, miss);
} else {
- Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss
- : not_numbers;
+ Label* fail = (left_type == BinaryOpIC::NUMBER) ? miss : not_numbers;
FloatingPointHelper::LoadNumber(
masm, destination, left, f12, a0, a1, heap_number_map,
scratch1, scratch2, fail);
@@ -3109,7 +3076,7 @@
__ bind(&return_heap_number);
// Return a heap number, or fall through to type transition or runtime
// call if we can't.
- if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER
+ if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::NUMBER
: BinaryOpIC::INT32)) {
// We are using FPU registers so s0 is available.
heap_number_result = s0;
@@ -3338,11 +3305,11 @@
}
__ bind(&done);
- GenerateHeapNumberStub(masm);
+ GenerateNumberStub(masm);
}
-void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
+void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
Label call_runtime, transition;
BinaryOpStub_GenerateFPOperation(
masm, left_type_, right_type_, false,
@@ -5144,8 +5111,7 @@
Isolate* isolate = masm->isolate();
- Label runtime, invoke_regexp;
-
+ Label runtime;
// Allocation of registers for this function. These are in callee save
// registers and will be preserved by the call to the native RegExp code, as
// this code is called using the normal C calling convention. When calling
@@ -5197,149 +5163,111 @@
// Check that the number of captures fit in the static offsets vector buffer.
__ lw(a2,
FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
- // Calculate number of capture registers (number_of_captures + 1) * 2. This
- // uses the asumption that smis are 2 * their untagged value.
+ // Check (number_of_captures + 1) * 2 <= offsets vector size
+ // Or number_of_captures * 2 <= offsets vector size - 2
+ // Multiplying by 2 comes for free since a2 is smi-tagged.
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
- __ Addu(a2, a2, Operand(2)); // a2 was a smi.
- // Check that the static offsets vector buffer is large enough.
+ STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
__ Branch(
- &runtime, hi, a2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize));
-
- // a2: Number of capture registers
- // regexp_data: RegExp data (FixedArray)
- // Check that the second argument is a string.
- __ lw(subject, MemOperand(sp, kSubjectOffset));
- __ JumpIfSmi(subject, &runtime);
- __ GetObjectType(subject, a0, a0);
- __ And(a0, a0, Operand(kIsNotStringMask));
- STATIC_ASSERT(kStringTag == 0);
- __ Branch(&runtime, ne, a0, Operand(zero_reg));
-
- // Get the length of the string to r3.
- __ lw(a3, FieldMemOperand(subject, String::kLengthOffset));
-
- // a2: Number of capture registers
- // a3: Length of subject string as a smi
- // subject: Subject string
- // regexp_data: RegExp data (FixedArray)
- // Check that the third argument is a positive smi less than the subject
- // string length. A negative value will be greater (unsigned comparison).
- __ lw(a0, MemOperand(sp, kPreviousIndexOffset));
- __ JumpIfNotSmi(a0, &runtime);
- __ Branch(&runtime, ls, a3, Operand(a0));
-
- // a2: Number of capture registers
- // subject: Subject string
- // regexp_data: RegExp data (FixedArray)
- // Check that the fourth object is a JSArray object.
- __ lw(a0, MemOperand(sp, kLastMatchInfoOffset));
- __ JumpIfSmi(a0, &runtime);
- __ GetObjectType(a0, a1, a1);
- __ Branch(&runtime, ne, a1, Operand(JS_ARRAY_TYPE));
- // Check that the JSArray is in fast case.
- __ lw(last_match_info_elements,
- FieldMemOperand(a0, JSArray::kElementsOffset));
- __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
- __ Branch(&runtime, ne, a0, Operand(
- isolate->factory()->fixed_array_map()));
- // Check that the last match info has space for the capture registers and the
- // additional information.
- __ lw(a0,
- FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
- __ Addu(a2, a2, Operand(RegExpImpl::kLastMatchOverhead));
- __ sra(at, a0, kSmiTagSize); // Untag length for comparison.
- __ Branch(&runtime, gt, a2, Operand(at));
+ &runtime, hi, a2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2));
// Reset offset for possibly sliced string.
__ mov(t0, zero_reg);
- // subject: Subject string
- // regexp_data: RegExp data (FixedArray)
- // Check the representation and encoding of the subject string.
- Label seq_string;
+ __ lw(subject, MemOperand(sp, kSubjectOffset));
+ __ JumpIfSmi(subject, &runtime);
+ __ mov(a3, subject); // Make a copy of the original subject string.
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
- // First check for flat string. None of the following string type tests will
- // succeed if subject is not a string or a short external string.
+ // subject: subject string
+ // a3: subject string
+ // a0: subject string instance type
+ // regexp_data: RegExp data (FixedArray)
+ // Handle subject string according to its encoding and representation:
+ // (1) Sequential string? If yes, go to (5).
+ // (2) Anything but sequential or cons? If yes, go to (6).
+ // (3) Cons string. If the string is flat, replace subject with first string.
+ // Otherwise bailout.
+ // (4) Is subject external? If yes, go to (7).
+ // (5) Sequential string. Load regexp code according to encoding.
+ // (E) Carry on.
+ /// [...]
+
+ // Deferred code at the end of the stub:
+ // (6) Not a long external string? If yes, go to (8).
+ // (7) External string. Make it, offset-wise, look like a sequential string.
+ // Go to (5).
+ // (8) Short external string or not a string? If yes, bail out to runtime.
+ // (9) Sliced string. Replace subject with parent. Go to (4).
+
+ Label seq_string /* 5 */, external_string /* 7 */,
+ check_underlying /* 4 */, not_seq_nor_cons /* 6 */,
+ not_long_external /* 8 */;
+
+ // (1) Sequential string? If yes, go to (5).
__ And(a1,
a0,
Operand(kIsNotStringMask |
kStringRepresentationMask |
kShortExternalStringMask));
STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
- __ Branch(&seq_string, eq, a1, Operand(zero_reg));
+ __ Branch(&seq_string, eq, a1, Operand(zero_reg)); // Go to (5).
- // subject: Subject string
- // a0: instance type if Subject string
- // regexp_data: RegExp data (FixedArray)
- // a1: whether subject is a string and if yes, its string representation
- // Check for flat cons string or sliced string.
- // A flat cons string is a cons string where the second part is the empty
- // string. In that case the subject string is just the first part of the cons
- // string. Also in this case the first part of the cons string is known to be
- // a sequential string or an external string.
- // In the case of a sliced string its offset has to be taken into account.
- Label cons_string, external_string, check_encoding;
+ // (2) Anything but sequential or cons? If yes, go to (6).
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
- __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag));
- __ Branch(&external_string, eq, a1, Operand(kExternalStringTag));
+ // Go to (6).
+ __ Branch(¬_seq_nor_cons, ge, a1, Operand(kExternalStringTag));
- // Catch non-string subject or short external string.
- STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
- __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask));
- __ Branch(&runtime, ne, at, Operand(zero_reg));
-
- // String is sliced.
- __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
- __ sra(t0, t0, kSmiTagSize);
- __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
- // t5: offset of sliced string, smi-tagged.
- __ jmp(&check_encoding);
- // String is a cons string, check whether it is flat.
- __ bind(&cons_string);
+ // (3) Cons string. Check that it's flat.
+ // Replace subject with first string and reload instance type.
__ lw(a0, FieldMemOperand(subject, ConsString::kSecondOffset));
__ LoadRoot(a1, Heap::kEmptyStringRootIndex);
__ Branch(&runtime, ne, a0, Operand(a1));
__ lw(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
- // Is first part of cons or parent of slice a flat string?
- __ bind(&check_encoding);
+
+ // (4) Is subject external? If yes, go to (7).
+ __ bind(&check_underlying);
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
STATIC_ASSERT(kSeqStringTag == 0);
__ And(at, a0, Operand(kStringRepresentationMask));
- __ Branch(&external_string, ne, at, Operand(zero_reg));
+ // The underlying external string is never a short external string.
+ STATIC_CHECK(ExternalString::kMaxShortLength < ConsString::kMinLength);
+ STATIC_CHECK(ExternalString::kMaxShortLength < SlicedString::kMinLength);
+ __ Branch(&external_string, ne, at, Operand(zero_reg)); // Go to (7).
+ // (5) Sequential string. Load regexp code according to encoding.
__ bind(&seq_string);
- // subject: Subject string
- // regexp_data: RegExp data (FixedArray)
- // a0: Instance type of subject string
+ // subject: sequential subject string (or look-alike, external string)
+ // a3: original subject string
+ // Load previous index and check range before a3 is overwritten. We have to
+ // use a3 instead of subject here because subject might have been only made
+ // to look like a sequential string when it actually is an external string.
+ __ lw(a1, MemOperand(sp, kPreviousIndexOffset));
+ __ JumpIfNotSmi(a1, &runtime);
+ __ lw(a3, FieldMemOperand(a3, String::kLengthOffset));
+ __ Branch(&runtime, ls, a3, Operand(a1));
+ __ sra(a1, a1, kSmiTagSize); // Untag the Smi.
+
STATIC_ASSERT(kStringEncodingMask == 4);
STATIC_ASSERT(kOneByteStringTag == 4);
STATIC_ASSERT(kTwoByteStringTag == 0);
- // Find the code object based on the assumptions above.
__ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII.
__ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset));
__ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below).
__ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
__ Movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
+ // (E) Carry on. String handling is done.
+ // t9: irregexp code
// Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it contains
// a smi (code flushing support).
__ JumpIfSmi(t9, &runtime);
- // a3: encoding of subject string (1 if ASCII, 0 if two_byte);
- // t9: code
- // subject: Subject string
- // regexp_data: RegExp data (FixedArray)
- // Load used arguments before starting to push arguments for call to native
- // RegExp code to avoid handling changing stack height.
- __ lw(a1, MemOperand(sp, kPreviousIndexOffset));
- __ sra(a1, a1, kSmiTagSize); // Untag the Smi.
-
// a1: previous index
// a3: encoding of subject string (1 if ASCII, 0 if two_byte);
// t9: code
@@ -5434,9 +5362,7 @@
// subject: subject string (callee saved)
// regexp_data: RegExp data (callee saved)
// last_match_info_elements: Last match info elements (callee saved)
-
// Check the result.
-
Label success;
__ Branch(&success, eq, v0, Operand(1));
// We expect exactly one result since we force the called regexp to behave
@@ -5477,10 +5403,29 @@
__ lw(a1,
FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset));
// Calculate number of capture registers (number_of_captures + 1) * 2.
+ // Multiplying by 2 comes for free since r1 is smi-tagged.
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
__ Addu(a1, a1, Operand(2)); // a1 was a smi.
+ __ lw(a0, MemOperand(sp, kLastMatchInfoOffset));
+ __ JumpIfSmi(a0, &runtime);
+ __ GetObjectType(a0, a2, a2);
+ __ Branch(&runtime, ne, a2, Operand(JS_ARRAY_TYPE));
+ // Check that the JSArray is in fast case.
+ __ lw(last_match_info_elements,
+ FieldMemOperand(a0, JSArray::kElementsOffset));
+ __ lw(a0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ Branch(&runtime, ne, a0, Operand(at));
+ // Check that the last match info has space for the capture registers and the
+ // additional information.
+ __ lw(a0,
+ FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset));
+ __ Addu(a2, a1, Operand(RegExpImpl::kLastMatchOverhead));
+ __ sra(at, a0, kSmiTagSize);
+ __ Branch(&runtime, gt, a2, Operand(at));
+
// a1: number of capture registers
// subject: subject string
// Store the capture count.
@@ -5494,10 +5439,11 @@
__ mov(a2, subject);
__ RecordWriteField(last_match_info_elements,
RegExpImpl::kLastSubjectOffset,
- a2,
+ subject,
t3,
kRAHasNotBeenSaved,
kDontSaveFPRegs);
+ __ mov(subject, a2);
__ sw(subject,
FieldMemOperand(last_match_info_elements,
RegExpImpl::kLastInputOffset));
@@ -5539,8 +5485,17 @@
__ lw(v0, MemOperand(sp, kLastMatchInfoOffset));
__ DropAndRet(4);
- // External string. Short external strings have already been ruled out.
- // a0: scratch
+ // Do the runtime call to execute the regexp.
+ __ bind(&runtime);
+ __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
+
+ // Deferred code for string handling.
+ // (6) Not a long external string? If yes, go to (8).
+ __ bind(¬_seq_nor_cons);
+ // Go to (8).
+ __ Branch(¬_long_external, gt, a1, Operand(kExternalStringTag));
+
+ // (7) External string. Make it, offset-wise, look like a sequential string.
__ bind(&external_string);
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
@@ -5560,11 +5515,20 @@
__ Subu(subject,
subject,
SeqTwoByteString::kHeaderSize - kHeapObjectTag);
- __ jmp(&seq_string);
+ __ jmp(&seq_string); // Go to (5).
- // Do the runtime call to execute the regexp.
- __ bind(&runtime);
- __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
+ // (8) Short external string or not a string? If yes, bail out to runtime.
+ __ bind(¬_long_external);
+ STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
+ __ And(at, a1, Operand(kIsNotStringMask | kShortExternalStringMask));
+ __ Branch(&runtime, ne, at, Operand(zero_reg));
+
+ // (9) Sliced string. Replace subject with parent. Go to (4).
+ // Load offset into t0 and replace subject string with parent.
+ __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
+ __ sra(t0, t0, kSmiTagSize);
+ __ lw(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
+ __ jmp(&check_underlying); // Go to (4).
#endif // V8_INTERPRETED_REGEXP
}
@@ -6125,7 +6089,7 @@
}
-void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
@@ -6175,41 +6139,41 @@
// Load symbol table.
// Load address of first element of the symbol table.
- Register symbol_table = c2;
- __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
+ Register string_table = c2;
+ __ LoadRoot(string_table, Heap::kStringTableRootIndex);
Register undefined = scratch4;
__ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
// Calculate capacity mask from the symbol table capacity.
Register mask = scratch2;
- __ lw(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset));
+ __ lw(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
__ sra(mask, mask, 1);
__ Addu(mask, mask, -1);
// Calculate untagged address of the first element of the symbol table.
- Register first_symbol_table_element = symbol_table;
- __ Addu(first_symbol_table_element, symbol_table,
- Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag));
+ Register first_string_table_element = string_table;
+ __ Addu(first_string_table_element, string_table,
+ Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
// Registers.
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string
// mask: capacity mask
- // first_symbol_table_element: address of the first element of
+ // first_string_table_element: address of the first element of
// the symbol table
// undefined: the undefined object
// scratch: -
// Perform a number of probes in the symbol table.
const int kProbes = 4;
- Label found_in_symbol_table;
+ Label found_in_string_table;
Label next_probe[kProbes];
Register candidate = scratch5; // Scratch register contains candidate.
for (int i = 0; i < kProbes; i++) {
// Calculate entry in symbol table.
if (i > 0) {
- __ Addu(candidate, hash, Operand(SymbolTable::GetProbeOffset(i)));
+ __ Addu(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
} else {
__ mov(candidate, hash);
}
@@ -6217,9 +6181,9 @@
__ And(candidate, candidate, Operand(mask));
// Load the entry from the symble table.
- STATIC_ASSERT(SymbolTable::kEntrySize == 1);
+ STATIC_ASSERT(StringTable::kEntrySize == 1);
__ sll(scratch, candidate, kPointerSizeLog2);
- __ Addu(scratch, scratch, first_symbol_table_element);
+ __ Addu(scratch, scratch, first_string_table_element);
__ lw(candidate, MemOperand(scratch));
// If entry is undefined no string with this hash can be found.
@@ -6250,7 +6214,7 @@
// Check if the two characters match.
// Assumes that word load is little endian.
__ lhu(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
- __ Branch(&found_in_symbol_table, eq, chars, Operand(scratch));
+ __ Branch(&found_in_string_table, eq, chars, Operand(scratch));
__ bind(&next_probe[i]);
}
@@ -6259,7 +6223,7 @@
// Scratch register contains result when we fall through to here.
Register result = candidate;
- __ bind(&found_in_symbol_table);
+ __ bind(&found_in_string_table);
__ mov(v0, result);
}
@@ -6796,7 +6760,7 @@
// Try to lookup two character string in symbol table. If it is not found
// just allocate a new one.
Label make_two_character_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
+ StringHelper::GenerateTwoCharacterStringTableProbe(
masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string);
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
__ DropAndRet(2);
@@ -7042,8 +7006,8 @@
}
-void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
- ASSERT(state_ == CompareIC::HEAP_NUMBER);
+void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::NUMBER);
Label generic_stub;
Label unordered, maybe_undefined1, maybe_undefined2;
@@ -7643,7 +7607,6 @@
static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
// Used in RegExpExecStub.
{ REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET },
- { REG(s2), REG(a2), REG(t3), EMIT_REMEMBERED_SET },
// Used in CompileArrayPushCall.
// Also used in StoreIC::GenerateNormal via GenerateDictionaryStore.
// Also used in KeyedStoreIC::GenerateGeneric.
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index ac0b0ff..7647916 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -180,7 +180,7 @@
// Contents of both c1 and c2 registers are modified. At the exit c1 is
// guaranteed to contain halfword with low and high bytes equal to
// initial contents of c1 and c2 respectively.
- static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 00c7ece..8e96cd5 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -349,104 +349,8 @@
}
-void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
- int frame_index) {
- JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (FLAG_trace_deopt) {
- PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
- }
-
- unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
-
- // Arguments adaptor can not be topmost or bottommost.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous
- // frame's top and this frame's size.
- uint32_t top_address;
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = height;
- unsigned output_offset = output_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // A marker value is used in place of the context.
- output_offset -= kPointerSize;
- intptr_t context = reinterpret_cast<intptr_t>(
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- output_frame->SetFrameSlot(output_offset, context);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
- top_address + output_offset, output_offset, context);
- }
-
- // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(function);
- output_frame->SetFrameSlot(output_offset, value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Number of incoming arguments.
- output_offset -= kPointerSize;
- value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
- output_frame->SetFrameSlot(output_offset, value);
- if (FLAG_trace_deopt) {
- PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
- top_address + output_offset, output_offset, value, height - 1);
- }
-
- ASSERT(0 == output_offset);
-
- Builtins* builtins = isolate_->builtins();
- Code* adaptor_trampoline =
- builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
- uint32_t pc = reinterpret_cast<uint32_t>(
- adaptor_trampoline->instruction_start() +
- isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
- output_frame->SetPc(pc);
-}
-
-
-void Deoptimizer::DoCompiledStubFrame(TranslationIterator* iterator,
- int frame_index) {
+void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
+ int frame_index) {
//
// FROM TO
// | .... | | .... |
@@ -459,9 +363,9 @@
// v +-------------------------+ +-------------------------|
// | COMPILED_STUB marker | | STUB_FAILURE marker |
// +-------------------------+ +-------------------------+
- // | | | caller args.length_ |
- // | ... | +-------------------------+
// | | | caller args.arguments_ |
+ // | ... | +-------------------------+
+ // | | | caller args.length_ |
// |-------------------------|<-sp +-------------------------+
// | caller args pointer |
// +-------------------------+
@@ -483,58 +387,77 @@
isolate_->code_stub_interface_descriptor(major_key);
// The output frame must have room for all pushed register parameters
- // and the standard stack frame slots.
- int output_frame_size = StandardFrameConstants::kFixedFrameSize +
- kPointerSize * descriptor->register_param_count_;
+ // and the standard stack frame slots. Include space for an argument
+ // object to the callee and optionally the space to pass the argument
+ // object to the stub failure handler.
+ int height_in_bytes = kPointerSize * descriptor->register_param_count_ +
+ sizeof(Arguments) + kPointerSize;
+ int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
+ int input_frame_size = input_->GetFrameSize();
+ int output_frame_size = height_in_bytes + fixed_frame_size;
+ if (trace_) {
+ PrintF(" translating %s => StubFailureTrampolineStub, height=%d\n",
+ CodeStub::MajorName(static_cast<CodeStub::Major>(major_key), false),
+ height_in_bytes);
+ }
- // Include space for an argument object to the callee and optionally
- // the space to pass the argument object to the stub failure handler.
- output_frame_size += sizeof(Arguments) + kPointerSize;
+ // The stub failure trampoline is a single frame.
FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, 0);
+ new(output_frame_size) FrameDescription(output_frame_size, NULL);
+ output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE);
ASSERT(frame_index == 0);
output_[frame_index] = output_frame;
- Code* notify_failure =
- isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
- output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
- output_frame->SetContinuation(
- reinterpret_cast<intptr_t>(notify_failure->entry()));
+ // The top address for the output frame can be computed from the input
+ // frame pointer and the output frame's height. Subtract space for the
+ // context and function slots.
+ intptr_t top_address = input_->GetRegister(fp.code()) - (2 * kPointerSize) -
+ height_in_bytes;
+ output_frame->SetTop(top_address);
- Code* trampoline = NULL;
- int extra = descriptor->extra_expression_stack_count_;
- StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
- ASSERT(trampoline != NULL);
- output_frame->SetPc(reinterpret_cast<intptr_t>(
- trampoline->instruction_start()));
- unsigned input_frame_size = input_->GetFrameSize();
-
- intptr_t frame_ptr = input_->GetRegister(fp.code());
-
- // JSFunction continuation
+ // Read caller's PC (JSFunction continuation) from the input frame.
intptr_t input_frame_offset = input_frame_size - kPointerSize;
intptr_t output_frame_offset = output_frame_size - kPointerSize;
intptr_t value = input_->GetFrameSlot(input_frame_offset);
output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
- // saved frame ptr
+ // Read caller's FP from the input frame, and set this frame's FP.
input_frame_offset -= kPointerSize;
value = input_->GetFrameSlot(input_frame_offset);
output_frame_offset -= kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
+ intptr_t frame_ptr = input_->GetRegister(fp.code());
+ output_frame->SetRegister(fp.code(), frame_ptr);
+ output_frame->SetFp(frame_ptr);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
- // Restore context
+ // The context can be gotten from the input frame.
input_frame_offset -= kPointerSize;
value = input_->GetFrameSlot(input_frame_offset);
output_frame->SetRegister(cp.code(), value);
output_frame_offset -= kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
- // Internal frame markers
+ // A marker value is used in place of the function.
output_frame_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(
Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE));
output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function (stub fail sentinel)\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
int caller_arg_count = 0;
if (descriptor->stack_parameter_count_ != NULL) {
@@ -547,15 +470,27 @@
value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
(caller_arg_count - 1) * kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; args.arguments\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
- output_frame->SetFrameSlot(output_frame_offset, value);
output_frame_offset -= kPointerSize;
- output_frame->SetFrameSlot(output_frame_offset, caller_arg_count);
+ value = caller_arg_count;
+ output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; args.length\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
+ output_frame_offset -= kPointerSize;
value = frame_ptr - (output_frame_size - output_frame_offset) -
- StandardFrameConstants::kMarkerOffset;
- output_frame_offset -= kPointerSize;
+ StandardFrameConstants::kMarkerOffset + kPointerSize;
output_frame->SetFrameSlot(output_frame_offset, value);
+ if (trace_) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; args*\n",
+ top_address + output_frame_offset, output_frame_offset, value);
+ }
// Copy the register parameters to the failure frame.
for (int i = 0; i < descriptor->register_param_count_; ++i) {
@@ -563,14 +498,13 @@
DoTranslateCommand(iterator, 0, output_frame_offset);
}
+ ASSERT(0 == output_frame_offset);
+
for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
double double_value = input_->GetDoubleRegister(i);
output_frame->SetDoubleRegister(i, double_value);
}
- output_frame->SetRegister(fp.code(), frame_ptr);
- output_frame->SetFp(frame_ptr);
-
ApiFunction function(descriptor->deoptimization_handler_);
ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
@@ -581,6 +515,19 @@
output_frame->SetRegister(s0.code(), params);
output_frame->SetRegister(s1.code(), (params - 1) * kPointerSize);
output_frame->SetRegister(s2.code(), handler);
+
+ // Compute this frame's PC, state, and continuation.
+ Code* trampoline = NULL;
+ int extra = descriptor->extra_expression_stack_count_;
+ StubFailureTrampolineStub(extra).FindCodeInCache(&trampoline, isolate_);
+ ASSERT(trampoline != NULL);
+ output_frame->SetPc(reinterpret_cast<intptr_t>(
+ trampoline->instruction_start()));
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
+ Code* notify_failure =
+ isolate_->builtins()->builtin(Builtins::kNotifyStubFailure);
+ output_frame->SetContinuation(
+ reinterpret_cast<intptr_t>(notify_failure->entry()));
}
@@ -706,124 +653,6 @@
}
-void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
- int frame_index,
- bool is_setter_stub_frame) {
- JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver (and the implicit return value, if any) are expected in
- // registers by the LoadIC/StoreIC, so they don't belong to the output stack
- // frame. This means that we have to use a height of 0.
- unsigned height = 0;
- unsigned height_in_bytes = height * kPointerSize;
- const char* kind = is_setter_stub_frame ? "setter" : "getter";
- if (trace_) {
- PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
- }
-
- // We need 5 stack entries from StackFrame::INTERNAL (ra, fp, cp, frame type,
- // code object, see MacroAssembler::EnterFrame). For a setter stub frame we
- // need one additional entry for the implicit return value, see
- // StoreStubCompiler::CompileStoreViaSetter.
- unsigned fixed_frame_entries = 5 + (is_setter_stub_frame ? 1 : 0);
- unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, accessor);
- output_frame->SetFrameType(StackFrame::INTERNAL);
-
- // A frame for an accessor stub can not be the topmost or bottommost one.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous frame's top and
- // this frame's size.
- uint32_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- unsigned output_offset = output_frame_size;
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's pc\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // The context can be gotten from the previous frame.
- output_offset -= kPointerSize;
- value = output_[frame_index - 1]->GetContext();
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // A marker value is used in place of the function.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; function (%s sentinel)\n",
- top_address + output_offset, output_offset, value, kind);
- }
-
- // Get Code object from accessor stub.
- output_offset -= kPointerSize;
- Builtins::Name name = is_setter_stub_frame ?
- Builtins::kStoreIC_Setter_ForDeopt :
- Builtins::kLoadIC_Getter_ForDeopt;
- Code* accessor_stub = isolate_->builtins()->builtin(name);
- value = reinterpret_cast<intptr_t>(accessor_stub);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; code object\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Skip receiver.
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- iterator->Skip(Translation::NumberOfOperandsFor(opcode));
-
- if (is_setter_stub_frame) {
- // The implicit return value was part of the artificial setter stub
- // environment.
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- ASSERT(0 == output_offset);
-
- Smi* offset = is_setter_stub_frame ?
- isolate_->heap()->setter_stub_deopt_pc_offset() :
- isolate_->heap()->getter_stub_deopt_pc_offset();
- intptr_t pc = reinterpret_cast<intptr_t>(
- accessor_stub->instruction_start() + offset->value());
- output_frame->SetPc(pc);
-}
-
-
// This code is very similar to ia32/arm code, but relies on register names
// (fp, sp) and how the frame is laid out.
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 03f2774..5f44e539 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -1587,7 +1587,7 @@
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Handle<FixedArray> constant_properties = expr->constant_properties();
- __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(expr->literal_index())));
__ li(a1, Operand(constant_properties));
@@ -1598,12 +1598,13 @@
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ li(a0, Operand(Smi::FromInt(flags)));
- __ Push(a3, a2, a1, a0);
int properties_count = constant_properties->length() / 2;
if (expr->depth() > 1) {
+ __ Push(a3, a2, a1, a0);
__ CallRuntime(Runtime::kCreateObjectLiteral, 4);
- } else if (flags != ObjectLiteral::kFastElements ||
+ } else if (Serializer::enabled() || flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
+ __ Push(a3, a2, a1, a0);
__ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
} else {
FastCloneShallowObjectStub stub(properties_count);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index ccbc9c9..a44c943 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -573,8 +573,8 @@
void LCodeGen::WriteTranslation(LEnvironment* environment,
Translation* translation,
- int* arguments_index,
- int* arguments_count) {
+ int* pushed_arguments_index,
+ int* pushed_arguments_count) {
if (environment == NULL) return;
// The translation includes one command per value in the environment.
@@ -586,13 +586,13 @@
// arguments index points to the first element of a sequence of tagged
// values on the stack that represent the arguments. This needs to be
// kept in sync with the LArgumentsElements implementation.
- *arguments_index = -environment->parameter_count();
- *arguments_count = environment->parameter_count();
+ *pushed_arguments_index = -environment->parameter_count();
+ *pushed_arguments_count = environment->parameter_count();
WriteTranslation(environment->outer(),
translation,
- arguments_index,
- arguments_count);
+ pushed_arguments_index,
+ pushed_arguments_count);
bool has_closure_id = !info()->closure().is_null() &&
*info()->closure() != *environment->closure();
int closure_id = has_closure_id
@@ -625,13 +625,20 @@
}
// Inlined frames which push their arguments cause the index to be
- // bumped and a new stack area to be used for materialization.
- if (environment->entry() != NULL &&
- environment->entry()->arguments_pushed()) {
- *arguments_index = *arguments_index < 0
- ? GetStackSlotCount()
- : *arguments_index + *arguments_count;
- *arguments_count = environment->entry()->arguments_count() + 1;
+ // bumped and another stack area to be used for materialization,
+ // otherwise actual argument values are unknown for inlined frames.
+ bool arguments_known = true;
+ int arguments_index = *pushed_arguments_index;
+ int arguments_count = *pushed_arguments_count;
+ if (environment->entry() != NULL) {
+ arguments_known = environment->entry()->arguments_pushed();
+ arguments_index = arguments_index < 0
+ ? GetStackSlotCount() : arguments_index + arguments_count;
+ arguments_count = environment->entry()->arguments_count() + 1;
+ if (environment->entry()->arguments_pushed()) {
+ *pushed_arguments_index = arguments_index;
+ *pushed_arguments_count = arguments_count;
+ }
}
for (int i = 0; i < translation_size; ++i) {
@@ -646,8 +653,9 @@
environment->spilled_registers()[value->index()],
environment->HasTaggedValueAt(i),
environment->HasUint32ValueAt(i),
- *arguments_index,
- *arguments_count);
+ arguments_known,
+ arguments_index,
+ arguments_count);
} else if (
value->IsDoubleRegister() &&
environment->spilled_double_registers()[value->index()] != NULL) {
@@ -657,8 +665,9 @@
environment->spilled_double_registers()[value->index()],
false,
false,
- *arguments_index,
- *arguments_count);
+ arguments_known,
+ arguments_index,
+ arguments_count);
}
}
@@ -666,8 +675,9 @@
value,
environment->HasTaggedValueAt(i),
environment->HasUint32ValueAt(i),
- *arguments_index,
- *arguments_count);
+ arguments_known,
+ arguments_index,
+ arguments_count);
}
}
@@ -676,13 +686,15 @@
LOperand* op,
bool is_tagged,
bool is_uint32,
+ bool arguments_known,
int arguments_index,
int arguments_count) {
if (op == NULL) {
// TODO(twuerthinger): Introduce marker operands to indicate that this value
// is not present and must be reconstructed from the deoptimizer. Currently
// this is only used for the arguments object.
- translation->StoreArgumentsObject(arguments_index, arguments_count);
+ translation->StoreArgumentsObject(
+ arguments_known, arguments_index, arguments_count);
} else if (op->IsStackSlot()) {
if (is_tagged) {
translation->StoreStackSlot(op->index());
@@ -2496,6 +2508,14 @@
}
+void LCodeGen::DoInstanceSize(LInstanceSize* instr) {
+ Register object = ToRegister(instr->object());
+ Register result = ToRegister(instr->result());
+ __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
+ __ lbu(result, FieldMemOperand(result, Map::kInstanceSizeOffset));
+}
+
+
void LCodeGen::DoCmpT(LCmpT* instr) {
Token::Value op = instr->op();
@@ -5275,26 +5295,31 @@
DeferredAllocate* deferred =
new(zone()) DeferredAllocate(this, instr);
- Register size = ToRegister(instr->size());
Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->temp1());
Register scratch2 = ToRegister(instr->temp2());
- HAllocate* original_instr = instr->hydrogen();
- if (original_instr->size()->IsConstant()) {
- UNREACHABLE();
- } else {
- // Allocate memory for the object.
- AllocationFlags flags = TAG_OBJECT;
- if (original_instr->MustAllocateDoubleAligned()) {
- flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
- }
+ // Allocate memory for the object.
+ AllocationFlags flags = TAG_OBJECT;
+ if (instr->hydrogen()->MustAllocateDoubleAligned()) {
+ flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
+ }
+ if (instr->size()->IsConstantOperand()) {
+ int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
__ AllocateInNewSpace(size,
result,
scratch,
scratch2,
deferred->entry(),
- TAG_OBJECT);
+ flags);
+ } else {
+ Register size = ToRegister(instr->size());
+ __ AllocateInNewSpace(size,
+ result,
+ scratch,
+ scratch2,
+ deferred->entry(),
+ flags);
}
__ bind(deferred->exit());
@@ -5545,21 +5570,22 @@
instr->hydrogen()->constant_properties();
// Set up the parameters to the stub/runtime call.
- __ LoadHeapObject(t0, literals);
- __ li(a3, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
- __ li(a2, Operand(constant_properties));
+ __ LoadHeapObject(a3, literals);
+ __ li(a2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
+ __ li(a1, Operand(constant_properties));
int flags = instr->hydrogen()->fast_elements()
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
- __ li(a1, Operand(Smi::FromInt(flags)));
- __ Push(t0, a3, a2, a1);
+ __ li(a0, Operand(Smi::FromInt(flags)));
// Pick the right runtime function or stub to call.
int properties_count = constant_properties->length() / 2;
if (instr->hydrogen()->depth() > 1) {
+ __ Push(a3, a2, a1, a0);
CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
} else if (flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
+ __ Push(a3, a2, a1, a0);
CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
} else {
FastCloneShallowObjectStub stub(properties_count);
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 3de3244..b4476c4 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -274,6 +274,7 @@
LOperand* op,
bool is_tagged,
bool is_uint32,
+ bool arguments_known,
int arguments_index,
int arguments_count);
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index a6d7f1d..cc5c10d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -971,6 +971,12 @@
}
+LInstruction* LChunkBuilder::DoInstanceSize(HInstanceSize* instr) {
+ LOperand* object = UseRegisterAtStart(instr->object());
+ return DefineAsRegister(new(zone()) LInstanceSize(object));
+}
+
+
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
LOperand* receiver = UseRegisterAtStart(instr->receiver());
LOperand* function = UseRegisterAtStart(instr->function());
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 738a464..db235e4 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -108,6 +108,7 @@
V(In) \
V(InstanceOf) \
V(InstanceOfKnownGlobal) \
+ V(InstanceSize) \
V(InstructionGap) \
V(Integer32ToDouble) \
V(Uint32ToDouble) \
@@ -959,6 +960,19 @@
};
+class LInstanceSize: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LInstanceSize(LOperand* object) {
+ inputs_[0] = object;
+ }
+
+ LOperand* object() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(InstanceSize, "instance-size")
+ DECLARE_HYDROGEN_ACCESSOR(InstanceSize)
+};
+
+
class LBoundsCheck: public LTemplateInstruction<0, 2, 0> {
public:
LBoundsCheck(LOperand* index, LOperand* length) {
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 649751f..dd5681b 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1104,7 +1104,7 @@
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
if (!name->IsSymbol()) {
- name = factory()->LookupSymbol(name);
+ name = factory()->InternalizeString(name);
}
ASSERT(current->property_dictionary()->FindEntry(*name) ==
StringDictionary::kNotFound);
@@ -1168,130 +1168,128 @@
}
-void StubCompiler::GenerateLoadField(Handle<JSObject> object,
- Handle<JSObject> holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- PropertyIndex index,
- Handle<String> name,
- Label* miss) {
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
+void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
+ Label* miss) {
+ __ Branch(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+}
- // Check that the maps haven't changed.
- Register reg = CheckPrototypes(
- object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
+
+Register BaseLoadStubCompiler::CallbackHandlerFrontend(
+ Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<String> name,
+ Label* success,
+ FrontendCheckType check,
+ Handle<ExecutableAccessorInfo> callback) {
+ Label miss;
+
+ Register reg = HandlerFrontendHeader(
+ object, object_reg, holder, name, &miss, check);
+
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ ASSERT(!reg.is(scratch2()));
+ ASSERT(!reg.is(scratch3()));
+ ASSERT(!reg.is(scratch4()));
+
+ // Load the properties dictionary.
+ Register dictionary = scratch4();
+ __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ &miss,
+ &probe_done,
+ dictionary,
+ this->name(),
+ scratch2(),
+ scratch3());
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, scratch3 contains the
+ // pointer into the dictionary. Check that the value is the callback.
+ Register pointer = scratch3();
+ const int kElementsStartOffset = StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset));
+ __ Branch(&miss, ne, scratch2(), Operand(callback));
+ }
+
+ HandlerFrontendFooter(success, &miss);
+ return reg;
+}
+
+
+void BaseLoadStubCompiler::NonexistentHandlerFrontend(
+ Handle<JSObject> object,
+ Handle<JSObject> last,
+ Handle<String> name,
+ Label* success,
+ Handle<GlobalObject> global) {
+ Label miss;
+
+ Register reg = HandlerFrontendHeader(
+ object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+
+ // If the last object in the prototype chain is a global object,
+ // check that the global property cell is empty.
+ if (!global.is_null()) {
+ GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
+ }
+
+ if (!last->HasFastProperties()) {
+ __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset));
+ __ Branch(&miss, ne, scratch2(),
+ Operand(isolate()->factory()->null_value()));
+ }
+
+ HandlerFrontendFooter(success, &miss);
+}
+
+
+void BaseLoadStubCompiler::GenerateLoadField(Register reg,
+ Handle<JSObject> holder,
+ PropertyIndex index) {
GenerateFastPropertyLoad(masm(), v0, reg, holder, index);
__ Ret();
}
-void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
- Handle<JSObject> holder,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Handle<JSFunction> value,
- Handle<String> name,
- Label* miss) {
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss, scratch1);
-
- // Check that the maps haven't changed.
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
-
+void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) {
// Return the constant value.
__ LoadHeapObject(v0, value);
__ Ret();
}
-void StubCompiler::GenerateDictionaryLoadCallback(
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Handle<ExecutableAccessorInfo> callback,
- Handle<String> name,
- Label* miss) {
- ASSERT(!receiver.is(scratch1));
- ASSERT(!receiver.is(scratch2));
- ASSERT(!receiver.is(scratch3));
-
- // Load the properties dictionary.
- Register dictionary = scratch1;
- __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
- // Probe the dictionary.
- Label probe_done;
- StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
- miss,
- &probe_done,
- dictionary,
- name_reg,
- scratch2,
- scratch3);
- __ bind(&probe_done);
-
- // If probing finds an entry in the dictionary, scratch3 contains the
- // pointer into the dictionary. Check that the value is the callback.
- Register pointer = scratch3;
- const int kElementsStartOffset = StringDictionary::kHeaderSize +
- StringDictionary::kElementsStartIndex * kPointerSize;
- const int kValueOffset = kElementsStartOffset + kPointerSize;
- __ lw(scratch2, FieldMemOperand(pointer, kValueOffset));
- __ Branch(miss, ne, scratch2, Operand(callback));
-}
-
-
-void StubCompiler::GenerateLoadCallback(
- Handle<JSObject> object,
- Handle<JSObject> holder,
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Register scratch4,
- Handle<ExecutableAccessorInfo> callback,
- Handle<String> name,
- Label* miss) {
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss, scratch1);
-
- // Check that the maps haven't changed.
- Register reg = CheckPrototypes(object, receiver, holder, scratch1,
- scratch2, scratch3, name, miss);
-
- if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
- GenerateDictionaryLoadCallback(
- reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss);
- }
-
+void BaseLoadStubCompiler::GenerateLoadCallback(
+ Register reg,
+ Handle<ExecutableAccessorInfo> callback) {
// Build AccessorInfo::args_ list on the stack and push property name below
// the exit frame to make GC aware of them and store pointers to them.
- __ push(receiver);
- __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
+ __ push(receiver());
+ __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
if (heap()->InNewSpace(callback->data())) {
- __ li(scratch3, callback);
- __ lw(scratch3,
- FieldMemOperand(scratch3, ExecutableAccessorInfo::kDataOffset));
+ __ li(scratch3(), callback);
+ __ lw(scratch3(), FieldMemOperand(scratch3(),
+ ExecutableAccessorInfo::kDataOffset));
} else {
- __ li(scratch3, Handle<Object>(callback->data(), masm()->isolate()));
+ __ li(scratch3(), Handle<Object>(callback->data(),
+ callback->GetIsolate()));
}
__ Subu(sp, sp, 4 * kPointerSize);
__ sw(reg, MemOperand(sp, 3 * kPointerSize));
- __ sw(scratch3, MemOperand(sp, 2 * kPointerSize));
- __ li(scratch3, Operand(ExternalReference::isolate_address()));
- __ sw(scratch3, MemOperand(sp, 1 * kPointerSize));
- __ sw(name_reg, MemOperand(sp, 0 * kPointerSize));
+ __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
+ __ li(scratch3(), Operand(ExternalReference::isolate_address()));
+ __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize));
+ __ sw(name(), MemOperand(sp, 0 * kPointerSize));
- __ mov(a2, scratch2); // Saved in case scratch2 == a1.
+ __ mov(a2, scratch2()); // Saved in case scratch2 == a1.
__ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
// NOTE: the O32 abi requires a0 to hold a special pointer when returning a
@@ -1320,22 +1318,15 @@
}
-void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
- Handle<JSObject> interceptor_holder,
- LookupResult* lookup,
- Register receiver,
- Register name_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Handle<String> name,
- Label* miss) {
+void BaseLoadStubCompiler::GenerateLoadInterceptor(
+ Register holder_reg,
+ Handle<JSObject> object,
+ Handle<JSObject> interceptor_holder,
+ LookupResult* lookup,
+ Handle<String> name) {
ASSERT(interceptor_holder->HasNamedInterceptor());
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver, miss);
-
// So far the most popular follow ups for interceptor loads are FIELD
// and CALLBACKS, so inline only them, other cases may be added
// later.
@@ -1356,17 +1347,14 @@
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
- Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
- scratch1, scratch2, scratch3,
- name, miss);
- ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1));
+ ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from
// the holder and it is needed should the interceptor return without any
// result. The CALLBACKS case needs the receiver to be passed into C++ code,
// the FIELD case might cause a miss during the prototype check.
bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
- bool must_preserve_receiver_reg = !receiver.is(holder_reg) &&
+ bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
(lookup->type() == CALLBACKS || must_perfrom_prototype_check);
// Save necessary data before invoking an interceptor.
@@ -1374,86 +1362,40 @@
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
- __ Push(receiver, holder_reg, name_reg);
+ __ Push(receiver(), holder_reg, this->name());
} else {
- __ Push(holder_reg, name_reg);
+ __ Push(holder_reg, this->name());
}
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method).
CompileCallLoadPropertyWithInterceptor(masm(),
- receiver,
+ receiver(),
holder_reg,
- name_reg,
+ this->name(),
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
- __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
- __ Branch(&interceptor_failed, eq, v0, Operand(scratch1));
+ __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
+ __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
- __ pop(name_reg);
+ __ pop(this->name());
__ pop(holder_reg);
if (must_preserve_receiver_reg) {
- __ pop(receiver);
+ __ pop(receiver());
}
// Leave the internal frame.
}
- // Check that the maps from interceptor's holder to lookup's holder
- // haven't changed. And load lookup's holder into |holder| register.
- if (must_perfrom_prototype_check) {
- holder_reg = CheckPrototypes(interceptor_holder,
- holder_reg,
- Handle<JSObject>(lookup->holder()),
- scratch1,
- scratch2,
- scratch3,
- name,
- miss);
- }
-
- if (lookup->IsField()) {
- // We found FIELD property in prototype chain of interceptor's holder.
- // Retrieve a field from field's holder.
- GenerateFastPropertyLoad(masm(), v0, holder_reg,
- Handle<JSObject>(lookup->holder()),
- lookup->GetFieldIndex());
- __ Ret();
- } else {
- // We found CALLBACKS property in prototype chain of interceptor's
- // holder.
- ASSERT(lookup->type() == CALLBACKS);
- Handle<ExecutableAccessorInfo> callback(
- ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
- ASSERT(callback->getter() != NULL);
-
- // Tail call to runtime.
- // Important invariant in CALLBACKS case: the code above must be
- // structured to never clobber |receiver| register.
- __ li(scratch2, callback);
-
- __ Push(receiver, holder_reg);
- __ lw(scratch3,
- FieldMemOperand(scratch2, ExecutableAccessorInfo::kDataOffset));
- __ li(scratch1, Operand(ExternalReference::isolate_address()));
- __ Push(scratch3, scratch1, scratch2, name_reg);
-
- ExternalReference ref =
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty),
- masm()->isolate());
- __ TailCallExternalReference(ref, 6, 1);
- }
+ GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
} else { // !compile_followup_inline
// Call the runtime system to load the interceptor.
// Check that the maps haven't changed.
- Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder,
- scratch1, scratch2, scratch3,
- name, miss);
- PushInterceptorArguments(masm(), receiver, holder_reg,
- name_reg, interceptor_holder);
+ PushInterceptorArguments(masm(), receiver(), holder_reg,
+ this->name(), interceptor_holder);
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate());
@@ -2905,40 +2847,15 @@
Handle<JSObject> last,
Handle<String> name,
Handle<GlobalObject> global) {
- // ----------- S t a t e -------------
- // -- a0 : receiver
- // -- ra : return address
- // -----------------------------------
- Label miss;
+ Label success;
- // Check that the receiver is not a smi.
- __ JumpIfSmi(a0, &miss);
+ NonexistentHandlerFrontend(object, last, name, &success, global);
- Register scratch = a1;
-
- // Check the maps of the full prototype chain.
- Register result =
- CheckPrototypes(object, a0, last, a3, scratch, t0, name, &miss);
-
- // If the last object in the prototype chain is a global object,
- // check that the global property cell is empty.
- if (!global.is_null()) {
- GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
- }
-
- if (!last->HasFastProperties()) {
- __ lw(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
- __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
- __ Branch(&miss, ne, scratch, Operand(isolate()->factory()->null_value()));
- }
-
+ __ bind(&success);
// Return undefined if maps of the full prototype chain is still the same.
__ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
__ Ret();
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
// Return the generated code.
return GetCode(Code::NONEXISTENT, factory()->empty_string());
}
@@ -3002,48 +2919,16 @@
#define __ ACCESS_MASM(masm())
-Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
- Handle<JSObject> receiver,
- Handle<JSObject> holder,
- Handle<String> name,
- Handle<JSFunction> getter) {
- // ----------- S t a t e -------------
- // -- a0 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
- Label miss;
-
- // Check that the maps haven't changed.
- __ JumpIfSmi(a0, &miss);
- CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss);
-
- GenerateLoadViaGetter(masm(), getter);
-
- __ bind(&miss);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
- // Return the generated code.
- return GetCode(Code::CALLBACKS, name);
-}
-
-
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
- Handle<GlobalObject> holder,
+ Handle<GlobalObject> global,
Handle<JSGlobalPropertyCell> cell,
Handle<String> name,
bool is_dont_delete) {
- // ----------- S t a t e -------------
- // -- a0 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
- Label miss;
+ Label success, miss;
- // Check that the map of the global has not changed.
- __ JumpIfSmi(a0, &miss);
- CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss);
+ HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
+ name, &miss, PERFORM_INITIAL_CHECKS);
// Get the value from the cell.
__ li(a3, Operand(cell));
@@ -3055,15 +2940,14 @@
__ Branch(&miss, eq, t0, Operand(at));
}
- __ mov(v0, t0);
+ HandlerFrontendFooter(&success, &miss);
+ __ bind(&success);
+
Counters* counters = masm()->isolate()->counters();
__ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
+ __ mov(v0, t0);
__ Ret();
- __ bind(&miss);
- __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3);
- GenerateLoadMiss(masm(), Code::LOAD_IC);
-
// Return the generated code.
return GetCode(Code::NORMAL, name);
}
@@ -3097,9 +2981,9 @@
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
+ CodeHandleList* handlers) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
@@ -3111,13 +2995,12 @@
int receiver_count = receiver_maps->length();
__ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
- __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
+ __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
eq, a2, Operand(receiver_maps->at(current)));
}
__ bind(&miss);
- Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
- __ Jump(miss_ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index fe707c7..e583016 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -80,6 +80,9 @@
}
switch (instance_type) {
+ case SYMBOL_TYPE:
+ Symbol::cast(this)->SymbolVerify();
+ break;
case MAP_TYPE:
Map::cast(this)->MapVerify();
break;
@@ -213,6 +216,13 @@
}
+void Symbol::SymbolVerify() {
+ CHECK(IsSymbol());
+ CHECK(HasHashCode());
+ CHECK_GT(Hash(), 0);
+}
+
+
void HeapNumber::HeapNumberVerify() {
CHECK(IsHeapNumber());
}
@@ -469,7 +479,7 @@
void String::StringVerify() {
CHECK(IsString());
CHECK(length() >= 0 && length() <= Smi::kMaxValue);
- if (IsSymbol()) {
+ if (IsInternalizedString()) {
CHECK(!HEAP->InNewSpace(this));
}
if (IsConsString()) {
diff --git a/src/objects-inl.h b/src/objects-inl.h
index feece39..374bcbd 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -183,6 +183,7 @@
TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE)
+TYPE_CHECKER(Symbol, SYMBOL_TYPE)
bool Object::IsString() {
@@ -191,6 +192,16 @@
}
+bool Object::IsName() {
+ return IsString() || IsSymbol();
+}
+
+
+bool Object::IsUniqueName() {
+ return IsInternalizedString() || IsSymbol();
+}
+
+
bool Object::IsSpecObject() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE;
@@ -204,15 +215,15 @@
}
-bool Object::IsSymbol() {
+bool Object::IsInternalizedString() {
if (!this->IsHeapObject()) return false;
uint32_t type = HeapObject::cast(this)->map()->instance_type();
- // Because the symbol tag is non-zero and no non-string types have the
- // symbol bit set we can test for symbols with a very simple test
- // operation.
- STATIC_ASSERT(kSymbolTag != 0);
- ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE);
- return (type & kIsSymbolMask) != 0;
+ // Because the internalized tag is non-zero and no non-string types have the
+ // internalized bit set we can test for internalized strings with a very
+ // simple test operation.
+ STATIC_ASSERT(kInternalizedTag != 0);
+ ASSERT(kNotStringTag + kIsInternalizedMask > LAST_TYPE);
+ return (type & kIsInternalizedMask) != 0;
}
@@ -293,10 +304,10 @@
}
-bool StringShape::IsSymbol() {
+bool StringShape::IsInternalized() {
ASSERT(valid());
- STATIC_ASSERT(kSymbolTag != 0);
- return (type_ & kIsSymbolMask) != 0;
+ STATIC_ASSERT(kInternalizedTag != 0);
+ return (type_ & kIsInternalizedMask) != 0;
}
@@ -685,13 +696,13 @@
bool Object::IsDictionary() {
return IsHashTable() &&
- this != HeapObject::cast(this)->GetHeap()->symbol_table();
+ this != HeapObject::cast(this)->GetHeap()->string_table();
}
-bool Object::IsSymbolTable() {
+bool Object::IsStringTable() {
return IsHashTable() &&
- this == HeapObject::cast(this)->GetHeap()->raw_unchecked_symbol_table();
+ this == HeapObject::cast(this)->GetHeap()->raw_unchecked_string_table();
}
@@ -2358,7 +2369,7 @@
while (true) {
Object* element = KeyAt(entry);
// Empty entry. Uses raw unchecked accessors because it is called by the
- // symbol table during bootstrapping.
+ // string table during bootstrapping.
if (element == isolate->heap()->raw_unchecked_undefined_value()) break;
if (element != isolate->heap()->raw_unchecked_the_hole_value() &&
Shape::IsMatch(key, element)) return entry;
@@ -2399,7 +2410,7 @@
CAST_ACCESSOR(DeoptimizationOutputData)
CAST_ACCESSOR(DependentCode)
CAST_ACCESSOR(TypeFeedbackCells)
-CAST_ACCESSOR(SymbolTable)
+CAST_ACCESSOR(StringTable)
CAST_ACCESSOR(JSFunctionResultCache)
CAST_ACCESSOR(NormalizedMapCache)
CAST_ACCESSOR(ScopeInfo)
@@ -2416,11 +2427,13 @@
CAST_ACCESSOR(ExternalString)
CAST_ACCESSOR(ExternalAsciiString)
CAST_ACCESSOR(ExternalTwoByteString)
+CAST_ACCESSOR(Symbol)
CAST_ACCESSOR(JSReceiver)
CAST_ACCESSOR(JSObject)
CAST_ACCESSOR(Smi)
CAST_ACCESSOR(HeapObject)
CAST_ACCESSOR(HeapNumber)
+CAST_ACCESSOR(Name)
CAST_ACCESSOR(Oddball)
CAST_ACCESSOR(JSGlobalPropertyCell)
CAST_ACCESSOR(SharedFunctionInfo)
@@ -2473,12 +2486,12 @@
SMI_ACCESSORS(String, length, kLengthOffset)
-uint32_t String::hash_field() {
+uint32_t Name::hash_field() {
return READ_UINT32_FIELD(this, kHashFieldOffset);
}
-void String::set_hash_field(uint32_t value) {
+void Name::set_hash_field(uint32_t value) {
WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
#if V8_HOST_ARCH_64_BIT
WRITE_UINT32_FIELD(this, kHashFieldOffset + kIntSize, 0);
@@ -2488,7 +2501,8 @@
bool String::Equals(String* other) {
if (other == this) return true;
- if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
+ if (StringShape(this).IsInternalized() &&
+ StringShape(other).IsInternalized()) {
return false;
}
return SlowEquals(other);
@@ -3217,9 +3231,10 @@
int HeapObject::SizeFromMap(Map* map) {
int instance_size = map->instance_size();
if (instance_size != kVariableSizeSentinel) return instance_size;
- // We can ignore the "symbol" bit becase it is only set for symbols
- // and implies a string type.
- int instance_type = static_cast<int>(map->instance_type()) & ~kIsSymbolMask;
+ // We can ignore the "internalized" bit becase it is only set for strings
+ // and thus implies a string type.
+ int instance_type =
+ static_cast<int>(map->instance_type()) & ~kIsInternalizedMask;
// Only inline the most frequent cases.
if (instance_type == FIXED_ARRAY_TYPE) {
return FixedArray::BodyDescriptor::SizeOf(map, this);
@@ -3807,12 +3822,6 @@
StubType type,
int argc,
InlineCacheHolderFlag holder) {
- // Extra IC state is only allowed for call IC stubs or for store IC
- // stubs.
- ASSERT(extra_ic_state == kNoExtraICState ||
- kind == CALL_IC ||
- kind == STORE_IC ||
- kind == KEYED_STORE_IC);
// Compute the bit mask.
int bits = KindField::encode(kind)
| ICStateField::encode(ic_state)
@@ -5265,22 +5274,22 @@
}
-bool String::IsHashFieldComputed(uint32_t field) {
+bool Name::IsHashFieldComputed(uint32_t field) {
return (field & kHashNotComputedMask) == 0;
}
-bool String::HasHashCode() {
+bool Name::HasHashCode() {
return IsHashFieldComputed(hash_field());
}
-uint32_t String::Hash() {
+uint32_t Name::Hash() {
// Fast case: has hash code already been computed?
uint32_t field = hash_field();
if (IsHashFieldComputed(field)) return field >> kHashShift;
- // Slow case: compute hash code and set it.
- return ComputeAndSetHash();
+ // Slow case: compute hash code and set it. Has to be a string.
+ return String::cast(this)->ComputeAndSetHash();
}
@@ -5732,6 +5741,12 @@
}
+Handle<Object> TypeFeedbackCells::MonomorphicArraySentinel(Isolate* isolate,
+ ElementsKind elements_kind) {
+ return Handle<Object>(Smi::FromInt(static_cast<int>(elements_kind)), isolate);
+}
+
+
Object* TypeFeedbackCells::RawUninitializedSentinel(Heap* heap) {
return heap->the_hole_value();
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 3fd4dfe..32940c4 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -76,6 +76,9 @@
}
switch (instance_type) {
+ case SYMBOL_TYPE:
+ Symbol::cast(this)->SymbolPrint(out);
+ break;
case MAP_TYPE:
Map::cast(this)->MapPrint(out);
break;
@@ -478,25 +481,32 @@
case MAP_TYPE: return "MAP";
case HEAP_NUMBER_TYPE: return "HEAP_NUMBER";
case SYMBOL_TYPE: return "SYMBOL";
- case ASCII_SYMBOL_TYPE: return "ASCII_SYMBOL";
- case CONS_SYMBOL_TYPE: return "CONS_SYMBOL";
- case CONS_ASCII_SYMBOL_TYPE: return "CONS_ASCII_SYMBOL";
- case EXTERNAL_ASCII_SYMBOL_TYPE:
- case EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE:
- case EXTERNAL_SYMBOL_TYPE: return "EXTERNAL_SYMBOL";
- case SHORT_EXTERNAL_ASCII_SYMBOL_TYPE:
- case SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE:
- case SHORT_EXTERNAL_SYMBOL_TYPE: return "SHORT_EXTERNAL_SYMBOL";
- case ASCII_STRING_TYPE: return "ASCII_STRING";
case STRING_TYPE: return "TWO_BYTE_STRING";
+ case ASCII_STRING_TYPE: return "ASCII_STRING";
case CONS_STRING_TYPE:
- case CONS_ASCII_STRING_TYPE: return "CONS_STRING";
+ case CONS_ASCII_STRING_TYPE:
+ return "CONS_STRING";
+ case EXTERNAL_STRING_TYPE:
case EXTERNAL_ASCII_STRING_TYPE:
case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
- case EXTERNAL_STRING_TYPE: return "EXTERNAL_STRING";
+ return "EXTERNAL_STRING";
+ case SHORT_EXTERNAL_STRING_TYPE:
case SHORT_EXTERNAL_ASCII_STRING_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
- case SHORT_EXTERNAL_STRING_TYPE: return "SHORT_EXTERNAL_STRING";
+ return "SHORT_EXTERNAL_STRING";
+ case INTERNALIZED_STRING_TYPE: return "INTERNALIZED_STRING";
+ case ASCII_INTERNALIZED_STRING_TYPE: return "ASCII_INTERNALIZED_STRING";
+ case CONS_INTERNALIZED_STRING_TYPE: return "CONS_INTERNALIZED_STRING";
+ case CONS_ASCII_INTERNALIZED_STRING_TYPE:
+ return "CONS_ASCII_INTERNALIZED_STRING";
+ case EXTERNAL_INTERNALIZED_STRING_TYPE:
+ case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
+ case EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE:
+ return "EXTERNAL_INTERNALIZED_STRING";
+ case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
+ case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
+ case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE:
+ return "SHORT_EXTERNAL_INTERNALIZED_STRING";
case FIXED_ARRAY_TYPE: return "FIXED_ARRAY";
case BYTE_ARRAY_TYPE: return "BYTE_ARRAY";
case FREE_SPACE_TYPE: return "FREE_SPACE";
@@ -539,6 +549,12 @@
}
+void Symbol::SymbolPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "Symbol");
+ PrintF(out, " - hash: %d\n", Hash());
+}
+
+
void Map::MapPrint(FILE* out) {
HeapObject::PrintHeader(out, "Map");
PrintF(out, " - type: %s\n", TypeToString(instance_type()));
@@ -668,7 +684,7 @@
void String::StringPrint(FILE* out) {
- if (StringShape(this).IsSymbol()) {
+ if (StringShape(this).IsInternalized()) {
PrintF(out, "#");
} else if (StringShape(this).IsCons()) {
PrintF(out, "c\"");
@@ -690,7 +706,7 @@
PrintF(out, "%s", truncated_epilogue);
}
- if (!StringShape(this).IsSymbol()) PrintF(out, "\"");
+ if (!StringShape(this).IsInternalized()) PrintF(out, "\"");
}
@@ -1023,7 +1039,18 @@
void AllocationSiteInfo::AllocationSiteInfoPrint(FILE* out) {
HeapObject::PrintHeader(out, "AllocationSiteInfo");
PrintF(out, " - payload: ");
- if (payload()->IsJSArray()) {
+ if (payload()->IsJSGlobalPropertyCell()) {
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(payload());
+ Object* cell_contents = cell->value();
+ if (cell_contents->IsSmi()) {
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(cell_contents)->value());
+ PrintF(out, "Array allocation with ElementsKind ");
+ PrintElementsKind(out, kind);
+ PrintF(out, "\n");
+ return;
+ }
+ } else if (payload()->IsJSArray()) {
PrintF(out, "Array literal ");
payload()->ShortPrint(out);
PrintF(out, "\n");
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index 7082e59..088f5eb 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -128,6 +128,11 @@
kVisitDataObjectGeneric,
Foreign::kSize);
+ case SYMBOL_TYPE:
+ return GetVisitorIdForSize(kVisitDataObject,
+ kVisitDataObjectGeneric,
+ Symbol::kSize);
+
case FILLER_TYPE:
return kVisitDataObjectGeneric;
diff --git a/src/objects.cc b/src/objects.cc
index 3a825ec..e05ba05 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// 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:
@@ -142,6 +142,8 @@
holder = native_context->string_function()->instance_prototype();
} else if (IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
+ } else if (IsSymbol()) {
+ holder = native_context->symbol_delegate();
} else {
Isolate::Current()->PushStackTraceAndDie(
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
@@ -624,7 +626,7 @@
// holder in the prototype chain.
// Proxy handlers do not use the proxy's prototype, so we can skip this.
if (!result->IsHandler()) {
- Object* last = result->IsProperty()
+ Object* last = result->IsProperty() && !receiver->IsSymbol()
? result->holder()
: Object::cast(heap->null_value());
ASSERT(this != this->GetPrototype(isolate));
@@ -709,6 +711,8 @@
holder = native_context->string_function()->instance_prototype();
} else if (holder->IsBoolean()) {
holder = native_context->boolean_function()->instance_prototype();
+ } else if (holder->IsSymbol()) {
+ holder = native_context->symbol_delegate();
} else if (holder->IsJSProxy()) {
return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
} else {
@@ -776,6 +780,16 @@
}
+Object* Object::GetDelegate(Isolate* isolate) {
+ if (IsSymbol()) {
+ Heap* heap = Symbol::cast(this)->GetHeap();
+ Context* context = heap->isolate()->context()->native_context();
+ return context->symbol_delegate();
+ }
+ return GetPrototype(isolate);
+}
+
+
MaybeObject* Object::GetHash(CreationFlag flag) {
// The object is either a number, a string, an odd-ball,
// a real JS object, or a Harmony proxy.
@@ -783,8 +797,8 @@
uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
return Smi::FromInt(hash & Smi::kMaxValue);
}
- if (IsString()) {
- uint32_t hash = String::cast(this)->Hash();
+ if (IsName()) {
+ uint32_t hash = Name::cast(this)->Hash();
return Smi::FromInt(hash);
}
if (IsOddball()) {
@@ -966,28 +980,33 @@
return false;
}
bool is_ascii = this->IsOneByteRepresentation();
- bool is_symbol = this->IsSymbol();
+ bool is_internalized = this->IsInternalizedString();
// Morph the object to an external string by adjusting the map and
// reinitializing the fields.
if (size >= ExternalString::kSize) {
this->set_map_no_write_barrier(
- is_symbol
- ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
- : heap->external_symbol_map())
- : (is_ascii ? heap->external_string_with_ascii_data_map()
- : heap->external_string_map()));
+ is_internalized
+ ? (is_ascii
+ ? heap->external_internalized_string_with_ascii_data_map()
+ : heap->external_internalized_string_map())
+ : (is_ascii
+ ? heap->external_string_with_ascii_data_map()
+ : heap->external_string_map()));
} else {
this->set_map_no_write_barrier(
- is_symbol
- ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
- : heap->short_external_symbol_map())
- : (is_ascii ? heap->short_external_string_with_ascii_data_map()
- : heap->short_external_string_map()));
+ is_internalized
+ ? (is_ascii
+ ? heap->
+ short_external_internalized_string_with_ascii_data_map()
+ : heap->short_external_internalized_string_map())
+ : (is_ascii
+ ? heap->short_external_string_with_ascii_data_map()
+ : heap->short_external_string_map()));
}
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
self->set_resource(resource);
- if (is_symbol) self->Hash(); // Force regeneration of the hash value.
+ if (is_internalized) self->Hash(); // Force regeneration of the hash value.
// Fill the remainder of the string with dead wood.
int new_size = this->Size(); // Byte size of the external String object.
@@ -1017,22 +1036,22 @@
if (size < ExternalString::kShortSize) {
return false;
}
- bool is_symbol = this->IsSymbol();
+ bool is_internalized = this->IsInternalizedString();
// Morph the object to an external string by adjusting the map and
// reinitializing the fields. Use short version if space is limited.
if (size >= ExternalString::kSize) {
this->set_map_no_write_barrier(
- is_symbol ? heap->external_ascii_symbol_map()
- : heap->external_ascii_string_map());
+ is_internalized ? heap->external_ascii_internalized_string_map()
+ : heap->external_ascii_string_map());
} else {
this->set_map_no_write_barrier(
- is_symbol ? heap->short_external_ascii_symbol_map()
- : heap->short_external_ascii_string_map());
+ is_internalized ? heap->short_external_ascii_internalized_string_map()
+ : heap->short_external_ascii_string_map());
}
ExternalAsciiString* self = ExternalAsciiString::cast(this);
self->set_resource(resource);
- if (is_symbol) self->Hash(); // Force regeneration of the hash value.
+ if (is_internalized) self->Hash(); // Force regeneration of the hash value.
// Fill the remainder of the string with dead wood.
int new_size = this->Size(); // Byte size of the external String object.
@@ -1320,6 +1339,9 @@
accumulator->Add("<Odd Oddball>");
break;
}
+ case SYMBOL_TYPE:
+ accumulator->Add("<Symbol: %d>", Symbol::cast(this)->Hash());
+ break;
case HEAP_NUMBER_TYPE:
accumulator->Add("<Number: ");
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
@@ -1428,6 +1450,7 @@
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
break;
+ case SYMBOL_TYPE:
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
@@ -1502,14 +1525,14 @@
String* JSReceiver::class_name() {
if (IsJSFunction() && IsJSFunctionProxy()) {
- return GetHeap()->function_class_symbol();
+ return GetHeap()->function_class_string();
}
if (map()->constructor()->IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(map()->constructor());
return String::cast(constructor->shared()->instance_class_name());
}
// If the constructor is not present, return "Object".
- return GetHeap()->Object_symbol();
+ return GetHeap()->Object_string();
}
@@ -1525,7 +1548,7 @@
}
// TODO(rossberg): what about proxies?
// If the constructor is not present, return "Object".
- return GetHeap()->Object_symbol();
+ return GetHeap()->Object_string();
}
@@ -1574,11 +1597,11 @@
name, map()->NumberOfOwnDescriptors()));
// Normalize the object if the name is an actual string (not the
- // hidden symbols) and is not a real identifier.
+ // hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = GetHeap()->isolate();
if ((!IsIdentifier(isolate->unicode_cache(), name)
- && name != isolate->heap()->hidden_symbol()) ||
+ && name != isolate->heap()->hidden_string()) ||
(map()->unused_property_fields() == 0 &&
TooManyFastProperties(properties()->length(), store_mode))) {
Object* obj;
@@ -1756,7 +1779,7 @@
Handle<Object> old_value) {
Isolate* isolate = object->GetIsolate();
HandleScope scope(isolate);
- Handle<String> type = isolate->factory()->LookupUtf8Symbol(type_str);
+ Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
if (object->IsJSGlobalObject()) {
object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
}
@@ -2268,13 +2291,13 @@
ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
- // Ensure the keys are symbols before writing them into the instance
- // descriptor. Since it may cause a GC, it has to be done before we
+ // Ensure the keys are internalized strings before writing them into the
+ // instance descriptor. Since it may cause a GC, it has to be done before we
// temporarily put the heap in an invalid state while appending descriptors.
for (int i = 0; i < nof_callbacks; ++i) {
Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i)));
Handle<String> key =
- isolate->factory()->SymbolFromString(
+ isolate->factory()->InternalizedStringFromString(
Handle<String>(String::cast(entry->name())));
entry->set_name(*key);
}
@@ -2662,15 +2685,16 @@
if (has_pending_exception) return Failure::Exception();
// [[GetProperty]] requires to check that all properties are configurable.
- Handle<String> configurable_name = isolate->factory()->LookupOneByteSymbol(
- STATIC_ASCII_VECTOR("configurable_"));
+ Handle<String> configurable_name =
+ isolate->factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("configurable_"));
Handle<Object> configurable(
v8::internal::GetProperty(isolate, desc, configurable_name));
ASSERT(!isolate->has_pending_exception());
ASSERT(configurable->IsTrue() || configurable->IsFalse());
if (configurable->IsFalse()) {
Handle<String> trap =
- isolate->factory()->LookupOneByteSymbol(
+ isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("getPropertyDescriptor"));
Handle<Object> args[] = { handler, trap, name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2681,7 +2705,7 @@
// Check for DataDescriptor.
Handle<String> hasWritable_name =
- isolate->factory()->LookupOneByteSymbol(
+ isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("hasWritable_"));
Handle<Object> hasWritable(
v8::internal::GetProperty(isolate, desc, hasWritable_name));
@@ -2689,7 +2713,7 @@
ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
if (hasWritable->IsTrue()) {
Handle<String> writable_name =
- isolate->factory()->LookupOneByteSymbol(
+ isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("writable_"));
Handle<Object> writable(
v8::internal::GetProperty(isolate, desc, writable_name));
@@ -2705,7 +2729,7 @@
}
// We have an AccessorDescriptor.
- Handle<String> set_name = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> set_name = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("set_"));
Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_name));
ASSERT(!isolate->has_pending_exception());
@@ -2738,7 +2762,7 @@
Object* bool_result = result->ToBoolean();
if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
Handle<Object> handler(receiver->handler(), isolate);
- Handle<String> trap_name = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("delete"));
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2785,21 +2809,21 @@
if (has_pending_exception) return NONE;
// Convert result to PropertyAttributes.
- Handle<String> enum_n = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("enumerable"));
Handle<Object> enumerable(v8::internal::GetProperty(isolate, desc, enum_n));
if (isolate->has_pending_exception()) return NONE;
- Handle<String> conf_n = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("configurable"));
Handle<Object> configurable(v8::internal::GetProperty(isolate, desc, conf_n));
if (isolate->has_pending_exception()) return NONE;
- Handle<String> writ_n = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("writable"));
Handle<Object> writable(v8::internal::GetProperty(isolate, desc, writ_n));
if (isolate->has_pending_exception()) return NONE;
if (configurable->IsFalse()) {
- Handle<String> trap = isolate->factory()->LookupOneByteSymbol(
+ Handle<String> trap = isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("getPropertyDescriptor"));
Handle<Object> args[] = { handler, trap, name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2860,7 +2884,7 @@
Isolate* isolate = GetIsolate();
Handle<Object> handler(this->handler(), isolate);
- Handle<String> trap_name = isolate->factory()->LookupUtf8Symbol(name);
+ Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
Handle<Object> trap(v8::internal::GetProperty(isolate, handler, trap_name));
if (isolate->has_pending_exception()) return trap;
@@ -2901,13 +2925,13 @@
AssertNoContextChange ncc;
// Optimization for 2-byte strings often used as keys in a decompression
- // dictionary. We make these short keys into symbols to avoid constantly
+ // dictionary. We internalize these short keys to avoid constantly
// reallocating them.
- if (!name_raw->IsSymbol() && name_raw->length() <= 2) {
- Object* symbol_version;
- { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name_raw);
- if (maybe_symbol_version->ToObject(&symbol_version)) {
- name_raw = String::cast(symbol_version);
+ if (!name_raw->IsInternalizedString() && name_raw->length() <= 2) {
+ Object* internalized_version;
+ { MaybeObject* maybe_string_version = heap->InternalizeString(name_raw);
+ if (maybe_string_version->ToObject(&internalized_version)) {
+ name_raw = String::cast(internalized_version);
}
}
}
@@ -3780,7 +3804,7 @@
MaybeObject* JSObject::SetIdentityHash(Smi* hash, CreationFlag flag) {
- MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
+ MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_string(),
hash);
if (maybe->IsFailure()) return maybe;
return this;
@@ -3796,14 +3820,14 @@
MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
- Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
+ Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string());
if (stored_value->IsSmi()) return stored_value;
// Do not generate permanent identity hash code if not requested.
if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
Smi* hash = GenerateIdentityHash();
- MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
+ MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_string(),
hash);
if (result->IsFailure()) return result;
if (result->ToObjectUnchecked()->IsUndefined()) {
@@ -3825,7 +3849,7 @@
Object* JSObject::GetHiddenProperty(String* key) {
- ASSERT(key->IsSymbol());
+ ASSERT(key->IsInternalizedString());
if (IsJSGlobalProxy()) {
// For a proxy, use the prototype as target object.
Object* proxy_parent = GetPrototype();
@@ -3841,7 +3865,7 @@
if (inline_value->IsSmi()) {
// Handle inline-stored identity hash.
- if (key == GetHeap()->identity_hash_symbol()) {
+ if (key == GetHeap()->identity_hash_string()) {
return inline_value;
} else {
return GetHeap()->undefined_value();
@@ -3867,7 +3891,7 @@
MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
- ASSERT(key->IsSymbol());
+ ASSERT(key->IsInternalizedString());
if (IsJSGlobalProxy()) {
// For a proxy, use the prototype as target object.
Object* proxy_parent = GetPrototype();
@@ -3883,7 +3907,7 @@
// If there is no backing store yet, store the identity hash inline.
if (value->IsSmi() &&
- key == GetHeap()->identity_hash_symbol() &&
+ key == GetHeap()->identity_hash_string() &&
(inline_value->IsUndefined() || inline_value->IsSmi())) {
return SetHiddenPropertiesHashTable(value);
}
@@ -3908,7 +3932,7 @@
void JSObject::DeleteHiddenProperty(String* key) {
- ASSERT(key->IsSymbol());
+ ASSERT(key->IsInternalizedString());
if (IsJSGlobalProxy()) {
// For a proxy, use the prototype as target object.
Object* proxy_parent = GetPrototype();
@@ -3924,7 +3948,7 @@
Object* inline_value = hidden_lookup->ToObjectUnchecked();
// We never delete (inline-stored) identity hashes.
- ASSERT(key != GetHeap()->identity_hash_symbol());
+ ASSERT(key != GetHeap()->identity_hash_string());
if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
@@ -3936,7 +3960,7 @@
bool JSObject::HasHiddenProperties() {
return GetPropertyAttributePostInterceptor(this,
- GetHeap()->hidden_symbol(),
+ GetHeap()->hidden_string(),
false) != ABSENT;
}
@@ -3947,13 +3971,13 @@
Object* inline_value;
if (HasFastProperties()) {
// If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden symbol. Since the
- // hidden symbols hash code is zero (and no other string has hash
+ // in the descriptor array matches the hidden string. Since the
+ // hidden strings hash code is zero (and no other string has hash
// code zero) it will always occupy the first entry if present.
DescriptorArray* descriptors = this->map()->instance_descriptors();
if (descriptors->number_of_descriptors() > 0) {
int sorted_index = descriptors->GetSortedKeyIndex(0);
- if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() &&
+ if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
sorted_index < map()->NumberOfOwnDescriptors()) {
ASSERT(descriptors->GetType(sorted_index) == FIELD);
inline_value =
@@ -3966,12 +3990,12 @@
}
} else {
PropertyAttributes attributes;
- // You can't install a getter on a property indexed by the hidden symbol,
+ // You can't install a getter on a property indexed by the hidden string,
// so we can be sure that GetLocalPropertyPostInterceptor returns a real
// object.
inline_value =
GetLocalPropertyPostInterceptor(this,
- GetHeap()->hidden_symbol(),
+ GetHeap()->hidden_string(),
&attributes)->ToObjectUnchecked();
}
@@ -3991,7 +4015,7 @@
// We were storing the identity hash inline and now allocated an actual
// dictionary. Put the identity hash into the new dictionary.
MaybeObject* insert_result =
- hashtable->Put(GetHeap()->identity_hash_symbol(), inline_value);
+ hashtable->Put(GetHeap()->identity_hash_string(), inline_value);
ObjectHashTable* new_table;
if (!insert_result->To(&new_table)) return insert_result;
// We expect no resizing for the first insert.
@@ -3999,7 +4023,7 @@
}
MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
+ SetPropertyPostInterceptor(GetHeap()->hidden_string(),
hashtable,
DONT_ENUM,
kNonStrictMode,
@@ -4016,13 +4040,13 @@
ASSERT(HasHiddenProperties() != value->IsSmi());
if (HasFastProperties()) {
// If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden symbol. Since the
- // hidden symbols hash code is zero (and no other string has hash
+ // in the descriptor array matches the hidden string. Since the
+ // hidden strings hash code is zero (and no other string has hash
// code zero) it will always occupy the first entry if present.
DescriptorArray* descriptors = this->map()->instance_descriptors();
if (descriptors->number_of_descriptors() > 0) {
int sorted_index = descriptors->GetSortedKeyIndex(0);
- if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() &&
+ if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
sorted_index < map()->NumberOfOwnDescriptors()) {
ASSERT(descriptors->GetType(sorted_index) == FIELD);
this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index),
@@ -4032,7 +4056,7 @@
}
}
MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
+ SetPropertyPostInterceptor(GetHeap()->hidden_string(),
value,
DONT_ENUM,
kNonStrictMode,
@@ -5492,8 +5516,8 @@
TransitionFlag flag) {
DescriptorArray* descriptors = instance_descriptors();
- // Ensure the key is a symbol.
- MaybeObject* maybe_failure = descriptor->KeyToSymbol();
+ // Ensure the key is an internalized string.
+ MaybeObject* maybe_failure = descriptor->KeyToInternalizedString();
if (maybe_failure->IsFailure()) return maybe_failure;
int old_size = NumberOfOwnDescriptors();
@@ -5536,8 +5560,8 @@
TransitionFlag flag) {
DescriptorArray* old_descriptors = instance_descriptors();
- // Ensure the key is a symbol.
- MaybeObject* maybe_result = descriptor->KeyToSymbol();
+ // Ensure the key is an internalized string.
+ MaybeObject* maybe_result = descriptor->KeyToInternalizedString();
if (maybe_result->IsFailure()) return maybe_result;
// We replace the key if it is already present.
@@ -5573,8 +5597,8 @@
Descriptor* descriptor,
int insertion_index,
TransitionFlag flag) {
- // Ensure the key is a symbol.
- MaybeObject* maybe_failure = descriptor->KeyToSymbol();
+ // Ensure the key is an internalized string.
+ MaybeObject* maybe_failure = descriptor->KeyToInternalizedString();
if (maybe_failure->IsFailure()) return maybe_failure;
String* key = descriptor->GetKey();
@@ -7266,7 +7290,7 @@
bool String::MarkAsUndetectable() {
- if (StringShape(this).IsSymbol()) return false;
+ if (StringShape(this).IsInternalized()) return false;
Map* map = this->map();
Heap* heap = GetHeap();
@@ -7506,6 +7530,21 @@
}
+bool AllocationSiteInfo::GetElementsKindPayload(ElementsKind* kind) {
+ ASSERT(kind != NULL);
+ if (payload()->IsJSGlobalPropertyCell()) {
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(payload());
+ Object* cell_contents = cell->value();
+ if (cell_contents->IsSmi()) {
+ *kind = static_cast<ElementsKind>(
+ Smi::cast(cell_contents)->value());
+ return true;
+ }
+ }
+ return false;
+}
+
+
// Heuristic: We only need to create allocation site info if the boilerplate
// elements kind is the initial elements kind.
AllocationSiteMode AllocationSiteInfo::GetMode(
@@ -8090,12 +8129,13 @@
MaybeObject* Oddball::Initialize(const char* to_string,
Object* to_number,
byte kind) {
- String* symbol;
- { MaybeObject* maybe_symbol =
- Isolate::Current()->heap()->LookupUtf8Symbol(CStrVector(to_string));
- if (!maybe_symbol->To(&symbol)) return maybe_symbol;
+ String* internalized_to_string;
+ { MaybeObject* maybe_string =
+ Isolate::Current()->heap()->InternalizeUtf8String(
+ CStrVector(to_string));
+ if (!maybe_string->To(&internalized_to_string)) return maybe_string;
}
- set_to_string(symbol);
+ set_to_string(internalized_to_string);
set_to_number(to_number);
set_kind(kind);
return this;
@@ -8712,6 +8752,46 @@
}
+void Code::FindAllMaps(MapHandleList* maps) {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Object* object = info->target_object();
+ if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
+ }
+}
+
+
+Code* Code::FindFirstCode() {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ return Code::GetCodeFromTargetAddress(info->target_address());
+ }
+ return NULL;
+}
+
+
+void Code::FindAllCode(CodeHandleList* code_list, int length) {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+ int i = 0;
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ if (i++ == length) return;
+ RelocInfo* info = it.rinfo();
+ Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+ ASSERT(code->is_load_stub());
+ code_list->Add(Handle<Code>(code));
+ }
+ UNREACHABLE();
+}
+
+
void Code::ClearInlineCaches() {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
@@ -9328,19 +9408,10 @@
}
-MaybeObject* JSArray::Initialize(int capacity) {
- Heap* heap = GetHeap();
+MaybeObject* JSArray::Initialize(int capacity, int length) {
ASSERT(capacity >= 0);
- set_length(Smi::FromInt(0));
- FixedArray* new_elements;
- if (capacity == 0) {
- new_elements = heap->empty_fixed_array();
- } else {
- MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
- if (!maybe_obj->To(&new_elements)) return maybe_obj;
- }
- set_elements(new_elements);
- return this;
+ return GetHeap()->AllocateJSArrayStorage(this, length, capacity,
+ INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
}
@@ -9424,7 +9495,7 @@
self, "deleted", indices[i], old_values[i]);
}
JSObject::EnqueueChangeRecord(
- self, "updated", isolate->factory()->length_symbol(),
+ self, "updated", isolate->factory()->length_string(),
old_length_handle);
}
return *hresult;
@@ -10029,8 +10100,8 @@
? FAST_HOLEY_DOUBLE_ELEMENTS
: FAST_DOUBLE_ELEMENTS;
- MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
- if (trans->IsFailure()) return trans;
+ MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
MaybeObject* maybe =
SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
@@ -10046,8 +10117,8 @@
? FAST_HOLEY_ELEMENTS
: FAST_ELEMENTS;
- MaybeObject* trans = PossiblyTransitionArrayBoilerplate(kind);
- if (trans->IsFailure()) return trans;
+ MaybeObject* maybe_failure = UpdateAllocationSiteInfo(kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
kind);
@@ -10460,7 +10531,7 @@
if (self->IsJSArray() &&
!old_length->SameValue(Handle<JSArray>::cast(self)->length())) {
EnqueueChangeRecord(
- self, "updated", isolate->factory()->length_symbol(), old_length);
+ self, "updated", isolate->factory()->length_string(), old_length);
}
} else if (old_value->IsTheHole()) {
EnqueueChangeRecord(self, "reconfigured", name, old_value);
@@ -10594,38 +10665,53 @@
}
-MaybeObject* JSObject::PossiblyTransitionArrayBoilerplate(
- ElementsKind to_kind) {
- MaybeObject* ret = NULL;
+MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
if (!FLAG_track_allocation_sites || !IsJSArray()) {
- return ret;
+ return this;
}
AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
if (info == NULL) {
- return ret;
+ return this;
}
- ASSERT(info->payload()->IsJSArray());
- JSArray* payload = JSArray::cast(info->payload());
- ElementsKind kind = payload->GetElementsKind();
- if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
- // If the array is huge, it's not likely to be defined in a local
- // function, so we shouldn't make new instances of it very often.
- uint32_t length = 0;
- CHECK(payload->length()->ToArrayIndex(&length));
- if (length <= 8 * 1024) {
- ret = payload->TransitionElementsKind(to_kind);
- if (FLAG_trace_track_allocation_sites) {
- PrintF(
- "AllocationSiteInfo: JSArray %p boilerplate updated %s->%s\n",
- reinterpret_cast<void*>(this),
- ElementsKindToString(kind),
- ElementsKindToString(to_kind));
+ if (info->payload()->IsJSArray()) {
+ JSArray* payload = JSArray::cast(info->payload());
+ ElementsKind kind = payload->GetElementsKind();
+ if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
+ // If the array is huge, it's not likely to be defined in a local
+ // function, so we shouldn't make new instances of it very often.
+ uint32_t length = 0;
+ CHECK(payload->length()->ToArrayIndex(&length));
+ if (length <= AllocationSiteInfo::kMaximumArrayBytesToPretransition) {
+ if (FLAG_trace_track_allocation_sites) {
+ PrintF(
+ "AllocationSiteInfo: JSArray %p boilerplate updated %s->%s\n",
+ reinterpret_cast<void*>(this),
+ ElementsKindToString(kind),
+ ElementsKindToString(to_kind));
+ }
+ return payload->TransitionElementsKind(to_kind);
+ }
+ }
+ } else if (info->payload()->IsJSGlobalPropertyCell()) {
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(info->payload());
+ Object* cell_contents = cell->value();
+ if (cell_contents->IsSmi()) {
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(cell_contents)->value());
+ if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
+ if (FLAG_trace_track_allocation_sites) {
+ PrintF("AllocationSiteInfo: JSArray %p info updated %s->%s\n",
+ reinterpret_cast<void*>(this),
+ ElementsKindToString(kind),
+ ElementsKindToString(to_kind));
+ }
+ cell->set_value(Smi::FromInt(to_kind));
}
}
}
- return ret;
+ return this;
}
@@ -10639,8 +10725,8 @@
if (from_kind == to_kind) return this;
- MaybeObject* trans = PossiblyTransitionArrayBoilerplate(to_kind);
- if (trans->IsFailure()) return trans;
+ MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
Isolate* isolate = GetIsolate();
if (elements() == isolate->heap()->empty_fixed_array() ||
@@ -11642,10 +11728,10 @@
Smi* flags_;
};
-// Utf8SymbolKey carries a vector of chars as key.
-class Utf8SymbolKey : public HashTableKey {
+// Utf8StringKey carries a vector of chars as key.
+class Utf8StringKey : public HashTableKey {
public:
- explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
+ explicit Utf8StringKey(Vector<const char> string, uint32_t seed)
: string_(string), hash_field_(0), seed_(seed) { }
bool IsMatch(Object* string) {
@@ -11666,7 +11752,7 @@
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return Isolate::Current()->heap()->AllocateSymbolFromUtf8(
+ return Isolate::Current()->heap()->AllocateInternalizedStringFromUtf8(
string_, chars_, hash_field_);
}
@@ -11678,9 +11764,9 @@
template <typename Char>
-class SequentialSymbolKey : public HashTableKey {
+class SequentialStringKey : public HashTableKey {
public:
- explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
+ explicit SequentialStringKey(Vector<const Char> string, uint32_t seed)
: string_(string), hash_field_(0), seed_(seed) { }
uint32_t Hash() {
@@ -11705,10 +11791,10 @@
-class OneByteSymbolKey : public SequentialSymbolKey<uint8_t> {
+class OneByteStringKey : public SequentialStringKey<uint8_t> {
public:
- OneByteSymbolKey(Vector<const uint8_t> str, uint32_t seed)
- : SequentialSymbolKey<uint8_t>(str, seed) { }
+ OneByteStringKey(Vector<const uint8_t> str, uint32_t seed)
+ : SequentialStringKey<uint8_t>(str, seed) { }
bool IsMatch(Object* string) {
return String::cast(string)->IsOneByteEqualTo(string_);
@@ -11716,16 +11802,16 @@
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return HEAP->AllocateOneByteSymbol(string_, hash_field_);
+ return HEAP->AllocateOneByteInternalizedString(string_, hash_field_);
}
};
-class SubStringOneByteSymbolKey : public HashTableKey {
+class SubStringOneByteStringKey : public HashTableKey {
public:
- explicit SubStringOneByteSymbolKey(Handle<SeqOneByteString> string,
- int from,
- int length)
+ explicit SubStringOneByteStringKey(Handle<SeqOneByteString> string,
+ int from,
+ int length)
: string_(string), from_(from), length_(length) { }
uint32_t Hash() {
@@ -11752,7 +11838,7 @@
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
- return HEAP->AllocateOneByteSymbol(chars, hash_field_);
+ return HEAP->AllocateOneByteInternalizedString(chars, hash_field_);
}
private:
@@ -11763,10 +11849,10 @@
};
-class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
+class TwoByteStringKey : public SequentialStringKey<uc16> {
public:
- explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
- : SequentialSymbolKey<uc16>(str, seed) { }
+ explicit TwoByteStringKey(Vector<const uc16> str, uint32_t seed)
+ : SequentialStringKey<uc16>(str, seed) { }
bool IsMatch(Object* string) {
return String::cast(string)->IsTwoByteEqualTo(string_);
@@ -11774,15 +11860,15 @@
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
+ return HEAP->AllocateTwoByteInternalizedString(string_, hash_field_);
}
};
-// SymbolKey carries a string/symbol object as key.
-class SymbolKey : public HashTableKey {
+// InternalizedStringKey carries a string/internalized-string object as key.
+class InternalizedStringKey : public HashTableKey {
public:
- explicit SymbolKey(String* string)
+ explicit InternalizedStringKey(String* string)
: string_(string) { }
bool IsMatch(Object* string) {
@@ -11796,21 +11882,20 @@
}
MaybeObject* AsObject() {
- // Attempt to flatten the string, so that symbols will most often
- // be flat strings.
+ // Attempt to flatten the string, so that internalized strings will most
+ // often be flat strings.
string_ = string_->TryFlattenGetString();
Heap* heap = string_->GetHeap();
- // Transform string to symbol if possible.
- Map* map = heap->SymbolMapForString(string_);
+ // Internalize the string if possible.
+ Map* map = heap->InternalizedStringMapForString(string_);
if (map != NULL) {
string_->set_map_no_write_barrier(map);
- ASSERT(string_->IsSymbol());
+ ASSERT(string_->IsInternalizedString());
return string_;
}
- // Otherwise allocate a new symbol.
- return heap->AllocateInternalSymbol(string_,
- string_->length(),
- string_->hash_field());
+ // Otherwise allocate a new internalized string.
+ return heap->AllocateInternalizedStringImpl(
+ string_, string_->length(), string_->hash_field());
}
static uint32_t StringHash(Object* obj) {
@@ -11861,18 +11946,18 @@
// Find entry for key otherwise return kNotFound.
int StringDictionary::FindEntry(String* key) {
- if (!key->IsSymbol()) {
+ if (!key->IsInternalizedString()) {
return HashTable<StringDictionaryShape, String*>::FindEntry(key);
}
- // Optimized for symbol key. Knowledge of the key type allows:
- // 1. Move the check if the key is a symbol out of the loop.
- // 2. Avoid comparing hash codes in symbol to symbol comparison.
- // 3. Detect a case when a dictionary key is not a symbol but the key is.
- // In case of positive result the dictionary key may be replaced by
- // the symbol with minimal performance penalty. It gives a chance to
- // perform further lookups in code stubs (and significant performance boost
- // a certain style of code).
+ // Optimized for internalized string key. Knowledge of the key type allows:
+ // 1. Move the check if the key is internalized out of the loop.
+ // 2. Avoid comparing hash codes in internalized-to-internalized comparison.
+ // 3. Detect a case when a dictionary key is not internalized but the key is.
+ // In case of positive result the dictionary key may be replaced by the
+ // internalized string with minimal performance penalty. It gives a chance
+ // to perform further lookups in code stubs (and significant performance
+ // boost a certain style of code).
// EnsureCapacity will guarantee the hash table is never full.
uint32_t capacity = Capacity();
@@ -11884,11 +11969,11 @@
Object* element = get(index);
if (element->IsUndefined()) break; // Empty entry.
if (key == element) return entry;
- if (!element->IsSymbol() &&
+ if (!element->IsInternalizedString() &&
!element->IsTheHole() &&
String::cast(element)->Equals(key)) {
- // Replace a non-symbol key by the equivalent symbol for faster further
- // lookups.
+ // Replace a key that is not an internalized string by the equivalent
+ // internalized string for faster further lookups.
set(index, key);
return entry;
}
@@ -12009,7 +12094,7 @@
// Force instantiation of template instances class.
// Please note this list is compiler dependent.
-template class HashTable<SymbolTableShape, HashTableKey*>;
+template class HashTable<StringTableShape, HashTableKey*>;
template class HashTable<CompilationCacheShape, HashTableKey*>;
@@ -12566,13 +12651,13 @@
}
-MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
- SymbolKey key(string);
+MaybeObject* StringTable::LookupString(String* string, Object** s) {
+ InternalizedStringKey key(string);
return LookupKey(&key, s);
}
-// This class is used for looking up two character strings in the symbol table.
+// This class is used for looking up two character strings in the string table.
// If we don't have a hit we don't want to waste much time so we unroll the
// string hash calculation loop here for speed. Doesn't work if the two
// characters form a decimal integer, since such strings have a different hash
@@ -12623,7 +12708,7 @@
}
Object* AsObject() {
- // The TwoCharHashTableKey is only used for looking in the symbol
+ // The TwoCharHashTableKey is only used for looking in the string
// table, not for adding to it.
UNREACHABLE();
return NULL;
@@ -12636,97 +12721,95 @@
};
-bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
- SymbolKey key(string);
+bool StringTable::LookupStringIfExists(String* string, String** result) {
+ InternalizedStringKey key(string);
int entry = FindEntry(&key);
if (entry == kNotFound) {
return false;
} else {
- String* result = String::cast(KeyAt(entry));
- ASSERT(StringShape(result).IsSymbol());
- *symbol = result;
+ *result = String::cast(KeyAt(entry));
+ ASSERT(StringShape(*result).IsInternalized());
return true;
}
}
-bool SymbolTable::LookupTwoCharsSymbolIfExists(uint16_t c1,
+bool StringTable::LookupTwoCharsStringIfExists(uint16_t c1,
uint16_t c2,
- String** symbol) {
+ String** result) {
TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
int entry = FindEntry(&key);
if (entry == kNotFound) {
return false;
} else {
- String* result = String::cast(KeyAt(entry));
- ASSERT(StringShape(result).IsSymbol());
- *symbol = result;
+ *result = String::cast(KeyAt(entry));
+ ASSERT(StringShape(*result).IsInternalized());
return true;
}
}
-MaybeObject* SymbolTable::LookupUtf8Symbol(Vector<const char> str,
+MaybeObject* StringTable::LookupUtf8String(Vector<const char> str,
Object** s) {
- Utf8SymbolKey key(str, GetHeap()->HashSeed());
+ Utf8StringKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
-MaybeObject* SymbolTable::LookupOneByteSymbol(Vector<const uint8_t> str,
+MaybeObject* StringTable::LookupOneByteString(Vector<const uint8_t> str,
Object** s) {
- OneByteSymbolKey key(str, GetHeap()->HashSeed());
+ OneByteStringKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
-MaybeObject* SymbolTable::LookupSubStringOneByteSymbol(
+MaybeObject* StringTable::LookupSubStringOneByteString(
Handle<SeqOneByteString> str,
int from,
int length,
Object** s) {
- SubStringOneByteSymbolKey key(str, from, length);
+ SubStringOneByteStringKey key(str, from, length);
return LookupKey(&key, s);
}
-MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
+MaybeObject* StringTable::LookupTwoByteString(Vector<const uc16> str,
Object** s) {
- TwoByteSymbolKey key(str, GetHeap()->HashSeed());
+ TwoByteStringKey key(str, GetHeap()->HashSeed());
return LookupKey(&key, s);
}
-MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
+MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
int entry = FindEntry(key);
- // Symbol already in table.
+ // String already in table.
if (entry != kNotFound) {
*s = KeyAt(entry);
return this;
}
- // Adding new symbol. Grow table if needed.
+ // Adding new string. Grow table if needed.
Object* obj;
{ MaybeObject* maybe_obj = EnsureCapacity(1, key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- // Create symbol object.
- Object* symbol;
- { MaybeObject* maybe_symbol = key->AsObject();
- if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
+ // Create string object.
+ Object* string;
+ { MaybeObject* maybe_string = key->AsObject();
+ if (!maybe_string->ToObject(&string)) return maybe_string;
}
- // If the symbol table grew as part of EnsureCapacity, obj is not
- // the current symbol table and therefore we cannot use
- // SymbolTable::cast here.
- SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
+ // If the string table grew as part of EnsureCapacity, obj is not
+ // the current string table and therefore we cannot use
+ // StringTable::cast here.
+ StringTable* table = reinterpret_cast<StringTable*>(obj);
- // Add the new symbol and return it along with the symbol table.
+ // Add the new string and return it along with the string table.
entry = table->FindInsertionEntry(key->Hash());
- table->set(EntryToIndex(entry), symbol);
+ table->set(EntryToIndex(entry), string);
table->ElementAdded();
- *s = symbol;
+ *s = string;
return table;
}
@@ -12866,42 +12949,42 @@
}
-// SymbolsKey used for HashTable where key is array of symbols.
-class SymbolsKey : public HashTableKey {
+// StringsKey used for HashTable where key is array of internalzied strings.
+class StringsKey : public HashTableKey {
public:
- explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
+ explicit StringsKey(FixedArray* strings) : strings_(strings) { }
- bool IsMatch(Object* symbols) {
- FixedArray* o = FixedArray::cast(symbols);
- int len = symbols_->length();
+ bool IsMatch(Object* strings) {
+ FixedArray* o = FixedArray::cast(strings);
+ int len = strings_->length();
if (o->length() != len) return false;
for (int i = 0; i < len; i++) {
- if (o->get(i) != symbols_->get(i)) return false;
+ if (o->get(i) != strings_->get(i)) return false;
}
return true;
}
- uint32_t Hash() { return HashForObject(symbols_); }
+ uint32_t Hash() { return HashForObject(strings_); }
uint32_t HashForObject(Object* obj) {
- FixedArray* symbols = FixedArray::cast(obj);
- int len = symbols->length();
+ FixedArray* strings = FixedArray::cast(obj);
+ int len = strings->length();
uint32_t hash = 0;
for (int i = 0; i < len; i++) {
- hash ^= String::cast(symbols->get(i))->Hash();
+ hash ^= String::cast(strings->get(i))->Hash();
}
return hash;
}
- Object* AsObject() { return symbols_; }
+ Object* AsObject() { return strings_; }
private:
- FixedArray* symbols_;
+ FixedArray* strings_;
};
Object* MapCache::Lookup(FixedArray* array) {
- SymbolsKey key(array);
+ StringsKey key(array);
int entry = FindEntry(&key);
if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
@@ -12909,7 +12992,7 @@
MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
- SymbolsKey key(array);
+ StringsKey key(array);
Object* obj;
{ MaybeObject* maybe_obj = EnsureCapacity(1, &key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -13428,9 +13511,10 @@
Object* k = KeyAt(i);
if (IsKey(k)) {
Object* value = ValueAt(i);
- // Ensure the key is a symbol before writing into the instance descriptor.
+ // Ensure the key is an internalized string before writing into the
+ // instance descriptor.
String* key;
- MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
+ MaybeObject* maybe_key = heap->InternalizeString(String::cast(k));
if (!maybe_key->To(&key)) return maybe_key;
PropertyDetails details = DetailsAt(i);
diff --git a/src/objects.h b/src/objects.h
index 7d4a29a..bf8c1e8 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -77,7 +77,7 @@
// - DescriptorArray
// - HashTable
// - Dictionary
-// - SymbolTable
+// - StringTable
// - CompilationCacheTable
// - CodeCacheHashTable
// - MapCache
@@ -95,15 +95,25 @@
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
-// - String
-// - SeqString
-// - SeqOneByteString
-// - SeqTwoByteString
-// - SlicedString
-// - ConsString
-// - ExternalString
-// - ExternalAsciiString
-// - ExternalTwoByteString
+// - Name
+// - String
+// - SeqString
+// - SeqOneByteString
+// - SeqTwoByteString
+// - SlicedString
+// - ConsString
+// - ExternalString
+// - ExternalAsciiString
+// - ExternalTwoByteString
+// - InternalizedString
+// - SeqInternalizedString
+// - SeqOneByteInternalizedString
+// - SeqTwoByteInternalizedString
+// - ConsInternalizedString
+// - ExternalInternalizedString
+// - ExternalAsciiInternalizedString
+// - ExternalTwoByteInternalizedString
+// - Symbol
// - HeapNumber
// - Code
// - Map
@@ -234,8 +244,8 @@
// encoding is mentioned explicitly in the name. Likewise, the default
// representation is considered sequential. It is not mentioned in the
// name. The other representations (e.g. CONS, EXTERNAL) are explicitly
-// mentioned. Finally, the string is either a SYMBOL_TYPE (if it is a
-// symbol) or a STRING_TYPE (if it is not a symbol).
+// mentioned. Finally, the string is either a STRING_TYPE (if it is a normal
+// string) or a INTERNALIZED_STRING_TYPE (if it is a internalized string).
//
// NOTE: The following things are some that depend on the string types having
// instance_types that are less than those of all other types:
@@ -246,29 +256,30 @@
// JSObject for GC purposes. The first four entries here have typeof
// 'object', whereas JS_FUNCTION_TYPE has typeof 'function'.
#define INSTANCE_TYPE_LIST_ALL(V) \
- V(SYMBOL_TYPE) \
- V(ASCII_SYMBOL_TYPE) \
- V(CONS_SYMBOL_TYPE) \
- V(CONS_ASCII_SYMBOL_TYPE) \
- V(EXTERNAL_SYMBOL_TYPE) \
- V(EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE) \
- V(EXTERNAL_ASCII_SYMBOL_TYPE) \
- V(SHORT_EXTERNAL_SYMBOL_TYPE) \
- V(SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE) \
- V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE) \
V(STRING_TYPE) \
V(ASCII_STRING_TYPE) \
V(CONS_STRING_TYPE) \
V(CONS_ASCII_STRING_TYPE) \
V(SLICED_STRING_TYPE) \
V(EXTERNAL_STRING_TYPE) \
- V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
V(EXTERNAL_ASCII_STRING_TYPE) \
+ V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
V(SHORT_EXTERNAL_STRING_TYPE) \
- V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
V(SHORT_EXTERNAL_ASCII_STRING_TYPE) \
- V(PRIVATE_EXTERNAL_ASCII_STRING_TYPE) \
+ V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE) \
\
+ V(INTERNALIZED_STRING_TYPE) \
+ V(ASCII_INTERNALIZED_STRING_TYPE) \
+ V(CONS_INTERNALIZED_STRING_TYPE) \
+ V(CONS_ASCII_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \
+ V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE) \
+ V(SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE) \
+ \
+ V(SYMBOL_TYPE) \
V(MAP_TYPE) \
V(CODE_TYPE) \
V(ODDBALL_TYPE) \
@@ -347,46 +358,6 @@
// Since string types are not consecutive, this macro is used to
// iterate over them.
#define STRING_TYPE_LIST(V) \
- V(SYMBOL_TYPE, \
- kVariableSizeSentinel, \
- symbol, \
- Symbol) \
- V(ASCII_SYMBOL_TYPE, \
- kVariableSizeSentinel, \
- ascii_symbol, \
- AsciiSymbol) \
- V(CONS_SYMBOL_TYPE, \
- ConsString::kSize, \
- cons_symbol, \
- ConsSymbol) \
- V(CONS_ASCII_SYMBOL_TYPE, \
- ConsString::kSize, \
- cons_ascii_symbol, \
- ConsAsciiSymbol) \
- V(EXTERNAL_SYMBOL_TYPE, \
- ExternalTwoByteString::kSize, \
- external_symbol, \
- ExternalSymbol) \
- V(EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE, \
- ExternalTwoByteString::kSize, \
- external_symbol_with_ascii_data, \
- ExternalSymbolWithAsciiData) \
- V(EXTERNAL_ASCII_SYMBOL_TYPE, \
- ExternalAsciiString::kSize, \
- external_ascii_symbol, \
- ExternalAsciiSymbol) \
- V(SHORT_EXTERNAL_SYMBOL_TYPE, \
- ExternalTwoByteString::kShortSize, \
- short_external_symbol, \
- ShortExternalSymbol) \
- V(SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE, \
- ExternalTwoByteString::kShortSize, \
- short_external_symbol_with_ascii_data, \
- ShortExternalSymbolWithAsciiData) \
- V(SHORT_EXTERNAL_ASCII_SYMBOL_TYPE, \
- ExternalAsciiString::kShortSize, \
- short_external_ascii_symbol, \
- ShortExternalAsciiSymbol) \
V(STRING_TYPE, \
kVariableSizeSentinel, \
string, \
@@ -415,26 +386,67 @@
ExternalTwoByteString::kSize, \
external_string, \
ExternalString) \
- V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
- ExternalTwoByteString::kSize, \
- external_string_with_ascii_data, \
- ExternalStringWithAsciiData) \
V(EXTERNAL_ASCII_STRING_TYPE, \
ExternalAsciiString::kSize, \
external_ascii_string, \
ExternalAsciiString) \
+ V(EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
+ ExternalTwoByteString::kSize, \
+ external_string_with_ascii_data, \
+ ExternalStringWithAsciiData) \
V(SHORT_EXTERNAL_STRING_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_string, \
ShortExternalString) \
+ V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \
+ ExternalAsciiString::kShortSize, \
+ short_external_ascii_string, \
+ ShortExternalAsciiString) \
V(SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE, \
ExternalTwoByteString::kShortSize, \
short_external_string_with_ascii_data, \
ShortExternalStringWithAsciiData) \
- V(SHORT_EXTERNAL_ASCII_STRING_TYPE, \
+ \
+ V(INTERNALIZED_STRING_TYPE, \
+ kVariableSizeSentinel, \
+ internalized_string, \
+ InternalizedString) \
+ V(ASCII_INTERNALIZED_STRING_TYPE, \
+ kVariableSizeSentinel, \
+ ascii_internalized_string, \
+ AsciiInternalizedString) \
+ V(CONS_INTERNALIZED_STRING_TYPE, \
+ ConsString::kSize, \
+ cons_internalized_string, \
+ ConsInternalizedString) \
+ V(CONS_ASCII_INTERNALIZED_STRING_TYPE, \
+ ConsString::kSize, \
+ cons_ascii_internalized_string, \
+ ConsAsciiInternalizedString) \
+ V(EXTERNAL_INTERNALIZED_STRING_TYPE, \
+ ExternalTwoByteString::kSize, \
+ external_internalized_string, \
+ ExternalInternalizedString) \
+ V(EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE, \
+ ExternalAsciiString::kSize, \
+ external_ascii_internalized_string, \
+ ExternalAsciiInternalizedString) \
+ V(EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \
+ ExternalTwoByteString::kSize, \
+ external_internalized_string_with_ascii_data, \
+ ExternalInternalizedStringWithAsciiData) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE, \
+ ExternalTwoByteString::kShortSize, \
+ short_external_internalized_string, \
+ ShortExternalInternalizedString) \
+ V(SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE, \
ExternalAsciiString::kShortSize, \
- short_external_ascii_string, \
- ShortExternalAsciiString)
+ short_external_ascii_internalized_string, \
+ ShortExternalAsciiInternalizedString) \
+ V(SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE, \
+ ExternalTwoByteString::kShortSize, \
+ short_external_internalized_string_with_ascii_data, \
+ ShortExternalInternalizedStringWithAsciiData) \
// A struct is a simple object a set of object-valued fields. Including an
// object type in this causes the compiler to generate most of the boilerplate
@@ -485,12 +497,12 @@
const uint32_t kStringTag = 0x0;
const uint32_t kNotStringTag = 0x80;
-// Bit 6 indicates that the object is a symbol (if set) or not (if cleared).
+// Bit 6 indicates that the object is an internalized string (if set) or not.
// There are not enough types that the non-string types (with bit 7 set) can
// have bit 6 set too.
-const uint32_t kIsSymbolMask = 0x40;
-const uint32_t kNotSymbolTag = 0x0;
-const uint32_t kSymbolTag = 0x40;
+const uint32_t kIsInternalizedMask = 0x40;
+const uint32_t kNotInternalizedTag = 0x0;
+const uint32_t kInternalizedTag = 0x40;
// If bit 7 is clear then bit 2 indicates whether the string consists of
// two-byte characters or one-byte characters.
@@ -533,57 +545,57 @@
// A ConsString with an empty string as the right side is a candidate
-// for being shortcut by the garbage collector unless it is a
-// symbol. It's not common to have non-flat symbols, so we do not
-// shortcut them thereby avoiding turning symbols into strings. See
-// heap.cc and mark-compact.cc.
+// for being shortcut by the garbage collector unless it is internalized.
+// It's not common to have non-flat internalized strings, so we do not
+// shortcut them thereby avoiding turning internalized strings into strings.
+// See heap.cc and mark-compact.cc.
const uint32_t kShortcutTypeMask =
kIsNotStringMask |
- kIsSymbolMask |
+ kIsInternalizedMask |
kStringRepresentationMask;
const uint32_t kShortcutTypeTag = kConsStringTag;
enum InstanceType {
// String types.
- SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag,
- ASCII_SYMBOL_TYPE = kOneByteStringTag | kSymbolTag | kSeqStringTag,
- CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag,
- CONS_ASCII_SYMBOL_TYPE = kOneByteStringTag | kSymbolTag | kConsStringTag,
- SHORT_EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag |
- kExternalStringTag | kShortExternalStringTag,
- SHORT_EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE =
- kTwoByteStringTag | kSymbolTag | kExternalStringTag |
- kAsciiDataHintTag | kShortExternalStringTag,
- SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kOneByteStringTag | kExternalStringTag |
- kSymbolTag | kShortExternalStringTag,
- EXTERNAL_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kExternalStringTag,
- EXTERNAL_SYMBOL_WITH_ASCII_DATA_TYPE =
- kTwoByteStringTag | kSymbolTag | kExternalStringTag | kAsciiDataHintTag,
- EXTERNAL_ASCII_SYMBOL_TYPE =
- kOneByteStringTag | kSymbolTag | kExternalStringTag,
STRING_TYPE = kTwoByteStringTag | kSeqStringTag,
ASCII_STRING_TYPE = kOneByteStringTag | kSeqStringTag,
CONS_STRING_TYPE = kTwoByteStringTag | kConsStringTag,
CONS_ASCII_STRING_TYPE = kOneByteStringTag | kConsStringTag,
SLICED_STRING_TYPE = kTwoByteStringTag | kSlicedStringTag,
SLICED_ASCII_STRING_TYPE = kOneByteStringTag | kSlicedStringTag,
- SHORT_EXTERNAL_STRING_TYPE =
- kTwoByteStringTag | kExternalStringTag | kShortExternalStringTag,
- SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
- kTwoByteStringTag | kExternalStringTag |
- kAsciiDataHintTag | kShortExternalStringTag,
- SHORT_EXTERNAL_ASCII_STRING_TYPE =
- kOneByteStringTag | kExternalStringTag | kShortExternalStringTag,
EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag,
- EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
- kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag,
- // LAST_STRING_TYPE
EXTERNAL_ASCII_STRING_TYPE = kOneByteStringTag | kExternalStringTag,
- PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
+ EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
+ EXTERNAL_STRING_TYPE | kAsciiDataHintTag,
+ SHORT_EXTERNAL_STRING_TYPE = EXTERNAL_STRING_TYPE | kShortExternalStringTag,
+ SHORT_EXTERNAL_ASCII_STRING_TYPE =
+ EXTERNAL_ASCII_STRING_TYPE | kShortExternalStringTag,
+ SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
+ EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kShortExternalStringTag,
+
+ INTERNALIZED_STRING_TYPE = STRING_TYPE | kInternalizedTag,
+ ASCII_INTERNALIZED_STRING_TYPE = ASCII_STRING_TYPE | kInternalizedTag,
+ CONS_INTERNALIZED_STRING_TYPE = CONS_STRING_TYPE | kInternalizedTag,
+ CONS_ASCII_INTERNALIZED_STRING_TYPE =
+ CONS_ASCII_STRING_TYPE | kInternalizedTag,
+ EXTERNAL_INTERNALIZED_STRING_TYPE = EXTERNAL_STRING_TYPE | kInternalizedTag,
+ EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE =
+ EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag,
+ EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE =
+ EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag,
+ SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE =
+ SHORT_EXTERNAL_STRING_TYPE | kInternalizedTag,
+ SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE =
+ SHORT_EXTERNAL_ASCII_STRING_TYPE | kInternalizedTag,
+ SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ASCII_DATA_TYPE =
+ SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE | kInternalizedTag,
+
+ // Non-string names
+ SYMBOL_TYPE = kNotStringTag, // LAST_NAME_TYPE, FIRST_NONSTRING_TYPE
// Objects allocated in their own spaces (never in new space).
- MAP_TYPE = kNotStringTag, // FIRST_NONSTRING_TYPE
+ MAP_TYPE,
CODE_TYPE,
ODDBALL_TYPE,
JS_GLOBAL_PROPERTY_CELL_TYPE,
@@ -665,7 +677,11 @@
FIRST_TYPE = 0x0,
LAST_TYPE = JS_FUNCTION_TYPE,
INVALID_TYPE = FIRST_TYPE - 1,
- FIRST_NONSTRING_TYPE = MAP_TYPE,
+ FIRST_NAME_TYPE = FIRST_TYPE,
+ LAST_NAME_TYPE = SYMBOL_TYPE,
+ FIRST_UNIQUE_NAME_TYPE = INTERNALIZED_STRING_TYPE,
+ LAST_UNIQUE_NAME_TYPE = SYMBOL_TYPE,
+ FIRST_NONSTRING_TYPE = SYMBOL_TYPE,
// Boundaries for testing for an external array.
FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_BYTE_ARRAY_TYPE,
LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_PIXEL_ARRAY_TYPE,
@@ -711,7 +727,7 @@
V(DICTIONARY_PROPERTIES_SUB_TYPE) \
V(MAP_CODE_CACHE_SUB_TYPE) \
V(SCOPE_INFO_SUB_TYPE) \
- V(SYMBOL_TABLE_SUB_TYPE) \
+ V(STRING_TABLE_SUB_TYPE) \
V(DESCRIPTOR_ARRAY_SUB_TYPE) \
V(TRANSITION_ARRAY_SUB_TYPE)
@@ -841,8 +857,9 @@
#define HEAP_OBJECT_TYPE_LIST(V) \
V(HeapNumber) \
+ V(Name) \
+ V(UniqueName) \
V(String) \
- V(Symbol) \
V(SeqString) \
V(ExternalString) \
V(ConsString) \
@@ -850,7 +867,9 @@
V(ExternalTwoByteString) \
V(ExternalAsciiString) \
V(SeqTwoByteString) \
- V(SeqOneByteString) \
+ V(SeqOneByteString) \
+ V(InternalizedString) \
+ V(Symbol) \
\
V(ExternalArray) \
V(ExternalByteArray) \
@@ -899,7 +918,7 @@
V(JSRegExp) \
V(HashTable) \
V(Dictionary) \
- V(SymbolTable) \
+ V(StringTable) \
V(JSFunctionResultCache) \
V(NormalizedMapCache) \
V(CompilationCacheTable) \
@@ -1021,6 +1040,9 @@
// Return the object's prototype (might be Heap::null_value()).
Object* GetPrototype(Isolate* isolate);
+ // Return the prototype, or the method holder for a value-like object.
+ Object* GetDelegate(Isolate* isolate);
+
// Returns the permanent hash code associated with this object depending on
// the actual object type. Might return a failure in case no hash was
// created yet or GC was caused by creation.
@@ -1798,7 +1820,7 @@
//
// Hidden properties are not local properties of the object itself.
// Instead they are stored in an auxiliary structure kept as a local
- // property with a special name Heap::hidden_symbol(). But if the
+ // property with a special name Heap::hidden_string(). But if the
// receiver is a JSGlobalProxy then the auxiliary object is a property
// of its prototype, and if it's a detached proxy, then you can't have
// hidden properties.
@@ -1817,7 +1839,7 @@
// Deletes a hidden property. Deleting a non-existing property is
// considered successful.
void DeleteHiddenProperty(String* key);
- // Returns true if the object has a property with the hidden symbol as name.
+ // Returns true if the object has a property with the hidden string as name.
bool HasHiddenProperties();
static int GetIdentityHash(Handle<JSObject> obj);
@@ -2029,7 +2051,7 @@
ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
- MUST_USE_RESULT MaybeObject* PossiblyTransitionArrayBoilerplate(
+ MUST_USE_RESULT MaybeObject* UpdateAllocationSiteInfo(
ElementsKind to_kind);
// Replaces an existing transition with a transition to a map with a FIELD.
@@ -3016,7 +3038,7 @@
};
-class SymbolTableShape : public BaseShape<HashTableKey*> {
+class StringTableShape : public BaseShape<HashTableKey*> {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
return key->IsMatch(value);
@@ -3037,44 +3059,47 @@
class SeqOneByteString;
-// SymbolTable.
+// StringTable.
//
// No special elements in the prefix and the element size is 1
-// because only the symbol itself (the key) needs to be stored.
-class SymbolTable: public HashTable<SymbolTableShape, HashTableKey*> {
+// because only the string itself (the key) needs to be stored.
+class StringTable: public HashTable<StringTableShape, HashTableKey*> {
public:
- // Find symbol in the symbol table. If it is not there yet, it is
- // added. The return value is the symbol table which might have
- // been enlarged. If the return value is not a failure, the symbol
- // pointer *s is set to the symbol found.
- MUST_USE_RESULT MaybeObject* LookupUtf8Symbol(Vector<const char> str,
- Object** s);
- MUST_USE_RESULT MaybeObject* LookupOneByteSymbol(Vector<const uint8_t> str,
- Object** s);
- MUST_USE_RESULT MaybeObject* LookupSubStringOneByteSymbol(
+ // Find string in the string table. If it is not there yet, it is
+ // added. The return value is the string table which might have
+ // been enlarged. If the return value is not a failure, the string
+ // pointer *s is set to the string found.
+ MUST_USE_RESULT MaybeObject* LookupUtf8String(
+ Vector<const char> str,
+ Object** s);
+ MUST_USE_RESULT MaybeObject* LookupOneByteString(
+ Vector<const uint8_t> str,
+ Object** s);
+ MUST_USE_RESULT MaybeObject* LookupSubStringOneByteString(
Handle<SeqOneByteString> str,
int from,
int length,
Object** s);
- MUST_USE_RESULT MaybeObject* LookupTwoByteSymbol(Vector<const uc16> str,
- Object** s);
+ MUST_USE_RESULT MaybeObject* LookupTwoByteString(
+ Vector<const uc16> str,
+ Object** s);
MUST_USE_RESULT MaybeObject* LookupString(String* key, Object** s);
- // Looks up a symbol that is equal to the given string and returns
- // true if it is found, assigning the symbol to the given output
+ // Looks up a string that is equal to the given string and returns
+ // true if it is found, assigning the string to the given output
// parameter.
- bool LookupSymbolIfExists(String* str, String** symbol);
- bool LookupTwoCharsSymbolIfExists(uint16_t c1, uint16_t c2, String** symbol);
+ bool LookupStringIfExists(String* str, String** result);
+ bool LookupTwoCharsStringIfExists(uint16_t c1, uint16_t c2, String** result);
// Casting.
- static inline SymbolTable* cast(Object* obj);
+ static inline StringTable* cast(Object* obj);
private:
MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s);
template <bool seq_ascii> friend class JsonParser;
- DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringTable);
};
@@ -3102,7 +3127,7 @@
// MapCache.
//
-// Maps keys that are a fixed array of symbols to a map.
+// Maps keys that are a fixed array of internalized strings to a map.
// Used for canonicalize maps for object literals.
class MapCache: public HashTable<MapCacheShape, HashTableKey*> {
public:
@@ -3535,13 +3560,13 @@
// Lookup support for serialized scope info. Returns the
// the stack slot index for a given slot name if the slot is
- // present; otherwise returns a value < 0. The name must be a symbol
- // (canonicalized).
+ // present; otherwise returns a value < 0. The name must be an internalized
+ // string.
int StackSlotIndex(String* name);
// Lookup support for serialized scope info. Returns the
// context slot index for a given slot name if the slot is present; otherwise
- // returns a value < 0. The name must be a symbol (canonicalized).
+ // returns a value < 0. The name must be an internalized string.
// If the slot is present and mode != NULL, sets *mode to the corresponding
// mode for that variable.
int ContextSlotIndex(String* name,
@@ -3550,13 +3575,13 @@
// Lookup support for serialized scope info. Returns the
// parameter index for a given parameter name if the parameter is present;
- // otherwise returns a value < 0. The name must be a symbol (canonicalized).
+ // otherwise returns a value < 0. The name must be an internalized string.
int ParameterIndex(String* name);
// Lookup support for serialized scope info. Returns the function context
// slot index if the function name is present and context-allocated (named
// function expressions, only), otherwise returns a value < 0. The name
- // must be a symbol (canonicalized).
+ // must be an internalized string.
int FunctionContextSlotIndex(String* name, VariableMode* mode);
@@ -4178,6 +4203,11 @@
// The object that indicates a megamorphic state.
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
+ // The object that indicates a monomorphic state of Array with
+ // ElementsKind
+ static inline Handle<Object> MonomorphicArraySentinel(Isolate* isolate,
+ ElementsKind elements_kind);
+
// A raw version of the uninitialized sentinel that's safe to read during
// garbage collection (e.g., for patching the cache).
static inline Object* RawUninitializedSentinel(Heap* heap);
@@ -4252,6 +4282,11 @@
NONEXISTENT
};
+ enum IcFragment {
+ IC_FRAGMENT,
+ HANDLER_FRAGMENT
+ };
+
enum {
NUMBER_OF_KINDS = LAST_IC_KIND + 1
};
@@ -4434,6 +4469,11 @@
// Find the first map in an IC stub.
Map* FindFirstMap();
+ void FindAllMaps(MapHandleList* maps);
+
+ // Find the first code in an IC stub.
+ Code* FindFirstCode();
+ void FindAllCode(CodeHandleList* code_list, int length);
class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
class ExtraICStateKeyedAccessGrowMode:
@@ -7058,7 +7098,9 @@
static const int kPayloadOffset = HeapObject::kHeaderSize;
static const int kSize = kPayloadOffset + kPointerSize;
+ static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
+ bool GetElementsKindPayload(ElementsKind* kind);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSiteInfo);
};
@@ -7174,7 +7216,7 @@
inline bool IsExternalTwoByte();
inline bool IsSequentialAscii();
inline bool IsSequentialTwoByte();
- inline bool IsSymbol();
+ inline bool IsInternalized();
inline StringRepresentationTag representation_tag();
inline uint32_t encoding_tag();
inline uint32_t full_representation_tag();
@@ -7198,6 +7240,102 @@
};
+// The Name abstract class captures anything that can be used as a property
+// name, i.e., strings and symbols. All names store a hash value.
+class Name: public HeapObject {
+ public:
+ // Get and set the hash field of the name.
+ inline uint32_t hash_field();
+ inline void set_hash_field(uint32_t value);
+
+ // Tells whether the hash code has been computed.
+ inline bool HasHashCode();
+
+ // Returns a hash value used for the property table
+ inline uint32_t Hash();
+
+ // Casting.
+ static inline Name* cast(Object* obj);
+
+ // Layout description.
+ static const int kHashFieldOffset = HeapObject::kHeaderSize;
+ static const int kSize = kHashFieldOffset + kPointerSize;
+
+ // Mask constant for checking if a name has a computed hash code
+ // and if it is a string that is an array index. The least significant bit
+ // indicates whether a hash code has been computed. If the hash code has
+ // been computed the 2nd bit tells whether the string can be used as an
+ // array index.
+ static const int kHashNotComputedMask = 1;
+ static const int kIsNotArrayIndexMask = 1 << 1;
+ static const int kNofHashBitFields = 2;
+
+ // Shift constant retrieving hash code from hash field.
+ static const int kHashShift = kNofHashBitFields;
+
+ // Only these bits are relevant in the hash, since the top two are shifted
+ // out.
+ static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift;
+
+ // Array index strings this short can keep their index in the hash field.
+ static const int kMaxCachedArrayIndexLength = 7;
+
+ // For strings which are array indexes the hash value has the string length
+ // mixed into the hash, mainly to avoid a hash value of zero which would be
+ // the case for the string '0'. 24 bits are used for the array index value.
+ static const int kArrayIndexValueBits = 24;
+ static const int kArrayIndexLengthBits =
+ kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields;
+
+ STATIC_CHECK((kArrayIndexLengthBits > 0));
+
+ static const int kArrayIndexHashLengthShift =
+ kArrayIndexValueBits + kNofHashBitFields;
+
+ static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
+
+ static const int kArrayIndexValueMask =
+ ((1 << kArrayIndexValueBits) - 1) << kHashShift;
+
+ // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we
+ // could use a mask to test if the length of string is less than or equal to
+ // kMaxCachedArrayIndexLength.
+ STATIC_CHECK(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1));
+
+ static const int kContainsCachedArrayIndexMask =
+ (~kMaxCachedArrayIndexLength << kArrayIndexHashLengthShift) |
+ kIsNotArrayIndexMask;
+
+ // Value of empty hash field indicating that the hash is not computed.
+ static const int kEmptyHashField =
+ kIsNotArrayIndexMask | kHashNotComputedMask;
+
+ protected:
+ static inline bool IsHashFieldComputed(uint32_t field);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Name);
+};
+
+
+// ES6 symbols.
+class Symbol: public Name {
+ public:
+ // Casting.
+ static inline Symbol* cast(Object* obj);
+
+ // Dispatched behavior.
+ DECLARE_PRINTER(Symbol)
+ DECLARE_VERIFIER(Symbol)
+
+ // Layout description.
+ static const int kSize = Name::kSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
+};
+
+
// The String abstract class captures JavaScript string values:
//
// Ecma-262:
@@ -7206,7 +7344,7 @@
// ordered sequence of zero or more 16-bit unsigned integer values.
//
// All string values have a length field.
-class String: public HeapObject {
+class String: public Name {
public:
enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING };
@@ -7259,10 +7397,6 @@
inline int length();
inline void set_length(int value);
- // Get and set the hash field of the string.
- inline uint32_t hash_field();
- inline void set_hash_field(uint32_t value);
-
// Returns whether this string has only ASCII chars, i.e. all of them can
// be ASCII encoded. This might be the case even if the string is
// two-byte. Such strings may appear when the embedder prefers
@@ -7363,12 +7497,6 @@
SmartArrayPointer<uc16> ToWideCString(
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL);
- // Tells whether the hash code has been computed.
- inline bool HasHashCode();
-
- // Returns a hash value used for the property table
- inline uint32_t Hash();
-
bool ComputeArrayIndex(uint32_t* index);
// Externalization.
@@ -7401,70 +7529,19 @@
inline bool IsFlat();
// Layout description.
- static const int kLengthOffset = HeapObject::kHeaderSize;
- static const int kHashFieldOffset = kLengthOffset + kPointerSize;
- static const int kSize = kHashFieldOffset + kPointerSize;
+ static const int kLengthOffset = Name::kSize;
+ static const int kSize = kLengthOffset + kPointerSize;
// Maximum number of characters to consider when trying to convert a string
// value into an array index.
static const int kMaxArrayIndexSize = 10;
+ STATIC_CHECK(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
// Max char codes.
static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar;
static const int kMaxUtf16CodeUnit = 0xffff;
- // Mask constant for checking if a string has a computed hash code
- // and if it is an array index. The least significant bit indicates
- // whether a hash code has been computed. If the hash code has been
- // computed the 2nd bit tells whether the string can be used as an
- // array index.
- static const int kHashNotComputedMask = 1;
- static const int kIsNotArrayIndexMask = 1 << 1;
- static const int kNofHashBitFields = 2;
-
- // Shift constant retrieving hash code from hash field.
- static const int kHashShift = kNofHashBitFields;
-
- // Only these bits are relevant in the hash, since the top two are shifted
- // out.
- static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift;
-
- // Array index strings this short can keep their index in the hash
- // field.
- static const int kMaxCachedArrayIndexLength = 7;
-
- // For strings which are array indexes the hash value has the string length
- // mixed into the hash, mainly to avoid a hash value of zero which would be
- // the case for the string '0'. 24 bits are used for the array index value.
- static const int kArrayIndexValueBits = 24;
- static const int kArrayIndexLengthBits =
- kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields;
-
- STATIC_CHECK((kArrayIndexLengthBits > 0));
- STATIC_CHECK(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
-
- static const int kArrayIndexHashLengthShift =
- kArrayIndexValueBits + kNofHashBitFields;
-
- static const int kArrayIndexHashMask = (1 << kArrayIndexHashLengthShift) - 1;
-
- static const int kArrayIndexValueMask =
- ((1 << kArrayIndexValueBits) - 1) << kHashShift;
-
- // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we
- // could use a mask to test if the length of string is less than or equal to
- // kMaxCachedArrayIndexLength.
- STATIC_CHECK(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1));
-
- static const int kContainsCachedArrayIndexMask =
- (~kMaxCachedArrayIndexLength << kArrayIndexHashLengthShift) |
- kIsNotArrayIndexMask;
-
- // Value of empty hash field indicating that the hash is not computed.
- static const int kEmptyHashField =
- kIsNotArrayIndexMask | kHashNotComputedMask;
-
// Value of hash field containing computed hash equal to zero.
static const int kEmptyStringHash = kIsNotArrayIndexMask;
@@ -7546,13 +7623,13 @@
unsigned length);
private:
+ friend class Name;
+
// Try to flatten the top level ConsString that is hiding behind this
// string. This is a no-op unless the string is a ConsString. Flatten
// mutates the ConsString and might return a failure.
MUST_USE_RESULT MaybeObject* SlowTryFlatten(PretenureFlag pretenure);
- static inline bool IsHashFieldComputed(uint32_t field);
-
// Slow case of String::Equals. This implementation works on any strings
// but it is most efficient on strings that are almost flat.
bool SlowEquals(String* other);
@@ -8345,7 +8422,7 @@
// Initialize the array with the given capacity. The function may
// fail due to out-of-memory situations, but only if the requested
// capacity is non-zero.
- MUST_USE_RESULT MaybeObject* Initialize(int capacity);
+ MUST_USE_RESULT MaybeObject* Initialize(int capacity, int length = 0);
// Initializes the array to a certain length.
inline bool AllowsSetElementsLength();
@@ -8892,10 +8969,10 @@
#undef DECLARE_VERIFIER
#define VISITOR_SYNCHRONIZATION_TAGS_LIST(V) \
- V(kSymbolTable, "symbol_table", "(Symbols)") \
+ V(kStringTable, "string_table", "(Internalized strings)") \
V(kExternalStringsTable, "external_strings_table", "(External strings)") \
V(kStrongRootList, "strong_root_list", "(Strong roots)") \
- V(kSymbol, "symbol", "(Symbol)") \
+ V(kInternalizedString, "internalized_string", "(Internal string)") \
V(kBootstrapper, "bootstrapper", "(Bootstrapper)") \
V(kTop, "top", "(Isolate)") \
V(kRelocatable, "relocatable", "(Relocatable)") \
diff --git a/src/parser.cc b/src/parser.cc
index 29b1fe7..62b633e 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -257,10 +257,10 @@
if (static_cast<unsigned>(symbol_id)
>= static_cast<unsigned>(symbol_cache_.length())) {
if (scanner().is_literal_ascii()) {
- return isolate()->factory()->LookupOneByteSymbol(
+ return isolate()->factory()->InternalizeOneByteString(
Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
} else {
- return isolate()->factory()->LookupTwoByteSymbol(
+ return isolate()->factory()->InternalizeTwoByteString(
scanner().literal_utf16_string());
}
}
@@ -278,10 +278,10 @@
Handle<String> result = symbol_cache_.at(symbol_id);
if (result.is_null()) {
if (scanner().is_literal_ascii()) {
- result = isolate()->factory()->LookupOneByteSymbol(
+ result = isolate()->factory()->InternalizeOneByteString(
Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
} else {
- result = isolate()->factory()->LookupTwoByteSymbol(
+ result = isolate()->factory()->InternalizeTwoByteString(
scanner().literal_utf16_string());
}
symbol_cache_.at(symbol_id) = result;
@@ -617,7 +617,7 @@
ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize();
- Handle<String> no_name = isolate()->factory()->empty_symbol();
+ Handle<String> no_name = isolate()->factory()->empty_string();
FunctionLiteral* result = NULL;
{ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
@@ -920,7 +920,7 @@
if (literal != NULL &&
literal->handle()->IsString() &&
!String::cast(*(literal->handle()))->Equals(
- isolate_->heap()->Proto_symbol()) &&
+ isolate_->heap()->proto_string()) &&
!String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
Handle<String> key = Handle<String>::cast(literal->handle());
@@ -1057,9 +1057,9 @@
// Check "use strict" directive (ES5 14.1).
if (top_scope_->is_classic_mode() &&
- directive->Equals(isolate()->heap()->use_strict()) &&
+ directive->Equals(isolate()->heap()->use_strict_string()) &&
token_loc.end_pos - token_loc.beg_pos ==
- isolate()->heap()->use_strict()->length() + 2) {
+ isolate()->heap()->use_strict_string()->length() + 2) {
// TODO(mstarzinger): Global strict eval calls, need their own scope
// as specified in ES5 10.4.2(3). The correct fix would be to always
// add this scope in DoParseProgram(), but that requires adaptations
@@ -1144,7 +1144,7 @@
if (estmt != NULL &&
estmt->expression()->AsVariableProxy() != NULL &&
estmt->expression()->AsVariableProxy()->name()->Equals(
- isolate()->heap()->module_symbol()) &&
+ isolate()->heap()->module_string()) &&
!scanner().literal_contains_escapes()) {
return ParseModuleDeclaration(NULL, ok);
}
@@ -1716,7 +1716,7 @@
isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
TENURED);
Expression* expression =
- NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
+ NewThrowTypeError(isolate()->factory()->redeclaration_string(),
type_string, name);
declaration_scope->SetIllegalRedeclaration(expression);
}
@@ -1978,8 +1978,8 @@
bool Parser::IsEvalOrArguments(Handle<String> string) {
- return string.is_identical_to(isolate()->factory()->eval_symbol()) ||
- string.is_identical_to(isolate()->factory()->arguments_symbol());
+ return string.is_identical_to(isolate()->factory()->eval_string()) ||
+ string.is_identical_to(isolate()->factory()->arguments_string());
}
@@ -2233,7 +2233,7 @@
// Note that the function does different things depending on
// the number of arguments (1 or 2).
initialize = factory()->NewCallRuntime(
- isolate()->factory()->InitializeConstGlobal_symbol(),
+ isolate()->factory()->InitializeConstGlobal_string(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
arguments);
} else {
@@ -2256,7 +2256,7 @@
// Note that the function does different things depending on
// the number of arguments (2 or 3).
initialize = factory()->NewCallRuntime(
- isolate()->factory()->InitializeVarGlobal_symbol(),
+ isolate()->factory()->InitializeVarGlobal_string(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
arguments);
}
@@ -2368,7 +2368,7 @@
expr != NULL &&
expr->AsVariableProxy() != NULL &&
expr->AsVariableProxy()->name()->Equals(
- isolate()->heap()->native_symbol()) &&
+ isolate()->heap()->native_string()) &&
!scanner().literal_contains_escapes()) {
return ParseNativeDeclaration(ok);
}
@@ -2380,7 +2380,7 @@
scanner().HasAnyLineTerminatorBeforeNext() ||
expr->AsVariableProxy() == NULL ||
!expr->AsVariableProxy()->name()->Equals(
- isolate()->heap()->module_symbol()) ||
+ isolate()->heap()->module_string()) ||
scanner().literal_contains_escapes()) {
ExpectSemicolon(CHECK_OK);
}
@@ -2505,7 +2505,7 @@
Scope* declaration_scope = top_scope_->DeclarationScope();
if (declaration_scope->is_global_scope() ||
declaration_scope->is_eval_scope()) {
- Handle<String> type = isolate()->factory()->illegal_return_symbol();
+ Handle<String> type = isolate()->factory()->illegal_return_string();
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
return factory()->NewExpressionStatement(throw_error);
}
@@ -2853,8 +2853,8 @@
// implementing stack allocated block scoped variables.
Factory* heap_factory = isolate()->factory();
Handle<String> tempstr =
- heap_factory->NewConsString(heap_factory->dot_for_symbol(), name);
- Handle<String> tempname = heap_factory->LookupSymbol(tempstr);
+ heap_factory->NewConsString(heap_factory->dot_for_string(), name);
+ Handle<String> tempname = heap_factory->InternalizeString(tempstr);
Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
ForInStatement* loop = factory()->NewForInStatement(labels);
@@ -2898,7 +2898,7 @@
// the error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> type =
- isolate()->factory()->invalid_lhs_in_for_in_symbol();
+ isolate()->factory()->invalid_lhs_in_for_in_string();
expression = NewThrowReferenceError(type);
}
ForInStatement* loop = factory()->NewForInStatement(labels);
@@ -3012,7 +3012,7 @@
// TODO(ES5): Should change parsing for spec conformance.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> type =
- isolate()->factory()->invalid_lhs_in_assignment_symbol();
+ isolate()->factory()->invalid_lhs_in_assignment_string();
expression = NewThrowReferenceError(type);
}
@@ -3253,7 +3253,7 @@
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> type =
- isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
+ isolate()->factory()->invalid_lhs_in_prefix_op_string();
expression = NewThrowReferenceError(type);
}
@@ -3288,7 +3288,7 @@
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> type =
- isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
+ isolate()->factory()->invalid_lhs_in_postfix_op_string();
expression = NewThrowReferenceError(type);
}
@@ -3363,7 +3363,7 @@
// they are actually direct calls to eval is determined at run time.
VariableProxy* callee = result->AsVariableProxy();
if (callee != NULL &&
- callee->IsVariable(isolate()->factory()->eval_symbol())) {
+ callee->IsVariable(isolate()->factory()->eval_string())) {
top_scope_->DeclarationScope()->RecordEvalCall();
}
result = factory()->NewCall(result, args, pos);
@@ -3470,7 +3470,7 @@
fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
} else {
fni_->PushLiteralName(
- isolate()->factory()->anonymous_function_symbol());
+ isolate()->factory()->anonymous_function_string());
}
}
Expect(Token::RBRACK, CHECK_OK);
@@ -3992,7 +3992,7 @@
next == Token::STRING || is_keyword) {
Handle<String> name;
if (is_keyword) {
- name = isolate_->factory()->LookupUtf8Symbol(Token::String(next));
+ name = isolate_->factory()->InternalizeUtf8String(Token::String(next));
} else {
name = GetSymbol(CHECK_OK);
}
@@ -4313,7 +4313,7 @@
// We want a non-null handle as the function name.
if (should_infer_name) {
- function_name = isolate()->factory()->empty_symbol();
+ function_name = isolate()->factory()->empty_string();
}
int num_parameters = 0;
@@ -4619,7 +4619,7 @@
top_scope_->DeclarationScope()->ForceEagerCompilation();
}
- const Runtime::Function* function = Runtime::FunctionForSymbol(name);
+ const Runtime::Function* function = Runtime::FunctionForName(name);
// Check for built-in IS_VAR macro.
if (function != NULL &&
@@ -4906,7 +4906,7 @@
Expression* Parser::NewThrowReferenceError(Handle<String> type) {
- return NewThrowError(isolate()->factory()->MakeReferenceError_symbol(),
+ return NewThrowError(isolate()->factory()->MakeReferenceError_string(),
type, HandleVector<Object>(NULL, 0));
}
@@ -4916,7 +4916,7 @@
int argc = first.is_null() ? 0 : 1;
Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
return NewThrowError(
- isolate()->factory()->MakeSyntaxError_symbol(), type, arguments);
+ isolate()->factory()->MakeSyntaxError_string(), type, arguments);
}
@@ -4928,7 +4928,7 @@
Vector< Handle<Object> > arguments =
HandleVector<Object>(elements, ARRAY_SIZE(elements));
return NewThrowError(
- isolate()->factory()->MakeTypeError_symbol(), type, arguments);
+ isolate()->factory()->MakeTypeError_string(), type, arguments);
}
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 98c343e..d0425b4 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -113,7 +113,7 @@
literal_chars_(0),
symbol_store_(0),
symbol_keys_(0),
- symbol_table_(vector_compare),
+ string_table_(vector_compare),
symbol_id_(0) {
}
@@ -123,7 +123,7 @@
bool is_ascii,
Vector<const byte> literal_bytes) {
Key key = { is_ascii, literal_bytes };
- HashMap::Entry* entry = symbol_table_.Lookup(&key, hash, true);
+ HashMap::Entry* entry = string_table_.Lookup(&key, hash, true);
int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
if (id == 0) {
// Copy literal contents for later comparison.
diff --git a/src/preparse-data.h b/src/preparse-data.h
index f347430..3a1e99d 100644
--- a/src/preparse-data.h
+++ b/src/preparse-data.h
@@ -221,7 +221,7 @@
Collector<byte> literal_chars_;
Collector<byte> symbol_store_;
Collector<Key> symbol_keys_;
- HashMap symbol_table_;
+ HashMap string_table_;
int symbol_id_;
};
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index c0fdf48..df6183a 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -362,7 +362,7 @@
void PrettyPrinter::VisitProperty(Property* node) {
Expression* key = node->key();
Literal* literal = key->AsLiteral();
- if (literal != NULL && literal->handle()->IsSymbol()) {
+ if (literal != NULL && literal->handle()->IsInternalizedString()) {
Print("(");
Visit(node->obj());
Print(").");
@@ -1068,7 +1068,7 @@
IndentedScope indent(this, "PROPERTY", node);
Visit(node->obj());
Literal* literal = node->key()->AsLiteral();
- if (literal != NULL && literal->handle()->IsSymbol()) {
+ if (literal != NULL && literal->handle()->IsInternalizedString()) {
PrintLiteralIndented("NAME", literal->handle(), false);
} else {
PrintIndentedVisit("KEY", node->key());
diff --git a/src/property.h b/src/property.h
index 0500e57..941b51d 100644
--- a/src/property.h
+++ b/src/property.h
@@ -48,9 +48,9 @@
return Smi::cast(value)->value();
}
- MUST_USE_RESULT MaybeObject* KeyToSymbol() {
- if (!StringShape(key_).IsSymbol()) {
- MaybeObject* maybe_result = HEAP->LookupSymbol(key_);
+ MUST_USE_RESULT MaybeObject* KeyToInternalizedString() {
+ if (!StringShape(key_).IsInternalized()) {
+ MaybeObject* maybe_result = HEAP->InternalizeString(key_);
if (!maybe_result->To(&key_)) return maybe_result;
}
return key_;
@@ -155,6 +155,18 @@
return value();
}
+ bool is_inobject(Handle<JSObject> holder) {
+ if (is_header_index()) return true;
+ return field_index() < holder->map()->inobject_properties();
+ }
+
+ int translate(Handle<JSObject> holder) {
+ if (is_header_index()) return header_index();
+ int index = field_index() - holder->map()->inobject_properties();
+ if (index >= 0) return index;
+ return index + holder->map()->instance_size() / kPointerSize;
+ }
+
private:
static const int kHeaderIndexBit = 1 << 31;
static const int kIndexMask = ~kHeaderIndexBit;
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 02907de..44fe050 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -253,7 +253,7 @@
ZoneList<Statement*>* body = function->body();
if (!body->is_empty()) {
Variable* result = scope->NewTemporary(
- info->isolate()->factory()->result_symbol());
+ info->isolate()->factory()->result_string());
Processor processor(result, info->zone());
processor.Process(body);
if (processor.HasStackOverflow()) return false;
diff --git a/src/runtime.cc b/src/runtime.cc
index 5724428..2215ead 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -80,9 +80,6 @@
RUNTIME_ASSERT(args[index]->Is##Type()); \
Handle<Type> name = args.at<Type>(index);
-#define CONVERT_ARG_STUB_CALLER_ARGS(name) \
- Arguments* name = reinterpret_cast<Arguments*>(args[0]);
-
// Cast the given object to a boolean and store it in a variable with
// the given name. If the object is not a boolean call IllegalOperation
// and return.
@@ -290,40 +287,41 @@
Isolate* isolate = context->GetIsolate();
int properties_length = constant_properties->length();
int number_of_properties = properties_length / 2;
- // Check that there are only symbols and array indices among keys.
- int number_of_symbol_keys = 0;
+ // Check that there are only internal strings and array indices among keys.
+ int number_of_string_keys = 0;
for (int p = 0; p != properties_length; p += 2) {
Object* key = constant_properties->get(p);
uint32_t element_index = 0;
- if (key->IsSymbol()) {
- number_of_symbol_keys++;
+ if (key->IsInternalizedString()) {
+ number_of_string_keys++;
} else if (key->ToArrayIndex(&element_index)) {
// An index key does not require space in the property backing store.
number_of_properties--;
} else {
- // Bail out as a non-symbol non-index key makes caching impossible.
+ // Bail out as a non-internalized-string non-index key makes caching
+ // impossible.
// ASSERT to make sure that the if condition after the loop is false.
- ASSERT(number_of_symbol_keys != number_of_properties);
+ ASSERT(number_of_string_keys != number_of_properties);
break;
}
}
- // If we only have symbols and array indices among keys then we can
- // use the map cache in the native context.
+ // If we only have internalized strings and array indices among keys then we
+ // can use the map cache in the native context.
const int kMaxKeys = 10;
- if ((number_of_symbol_keys == number_of_properties) &&
- (number_of_symbol_keys < kMaxKeys)) {
+ if ((number_of_string_keys == number_of_properties) &&
+ (number_of_string_keys < kMaxKeys)) {
// Create the fixed array with the key.
Handle<FixedArray> keys =
- isolate->factory()->NewFixedArray(number_of_symbol_keys);
- if (number_of_symbol_keys > 0) {
+ isolate->factory()->NewFixedArray(number_of_string_keys);
+ if (number_of_string_keys > 0) {
int index = 0;
for (int p = 0; p < properties_length; p += 2) {
Object* key = constant_properties->get(p);
- if (key->IsSymbol()) {
+ if (key->IsInternalizedString()) {
keys->set(index++, key);
}
}
- ASSERT(index == number_of_symbol_keys);
+ ASSERT(index == number_of_string_keys);
}
*is_result_from_cache = true;
return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
@@ -396,7 +394,7 @@
}
Handle<Object> result;
uint32_t element_index = 0;
- if (key->IsSymbol()) {
+ if (key->IsInternalizedString()) {
if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
// Array index as string (uint32).
result = JSObject::SetOwnElement(
@@ -676,7 +674,18 @@
JSObject* boilerplate_object = JSObject::cast(*boilerplate);
AllocationSiteMode mode = AllocationSiteInfo::GetMode(
boilerplate_object->GetElementsKind());
- return isolate->heap()->CopyJSObject(boilerplate_object, mode);
+ if (mode == TRACK_ALLOCATION_SITE) {
+ return isolate->heap()->CopyJSObjectWithAllocationSite(boilerplate_object);
+ }
+
+ return isolate->heap()->CopyJSObject(boilerplate_object);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 0);
+ return isolate->heap()->AllocateSymbol();
}
@@ -954,7 +963,7 @@
do {
if (obj->IsAccessCheckNeeded() &&
!isolate->MayNamedAccess(JSObject::cast(obj),
- isolate->heap()->Proto_symbol(),
+ isolate->heap()->proto_string(),
v8::ACCESS_GET)) {
isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
return isolate->heap()->undefined_value();
@@ -1779,7 +1788,7 @@
CONVERT_ARG_CHECKED(String, source, 1);
// If source is the empty string we set it to "(?:)" instead as
// suggested by ECMA-262, 5th, section 15.10.4.1.
- if (source->length() == 0) source = isolate->heap()->query_colon_symbol();
+ if (source->length() == 0) source = isolate->heap()->query_colon_string();
Object* global = args[2];
if (!global->IsTrue()) global = isolate->heap()->false_value();
@@ -1816,27 +1825,27 @@
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
Heap* heap = isolate->heap();
MaybeObject* result;
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_string(),
source,
final);
// TODO(jkummerow): Turn these back into ASSERTs when we can be certain
// that it never fires in Release mode in the wild.
CHECK(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_string(),
global,
final);
CHECK(!result->IsFailure());
result =
- regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
+ regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_string(),
ignoreCase,
final);
CHECK(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
+ result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_string(),
multiline,
final);
CHECK(!result->IsFailure());
result =
- regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
+ regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_string(),
Smi::FromInt(0),
writable);
CHECK(!result->IsFailure());
@@ -1860,7 +1869,7 @@
Handle<JSObject> holder,
const char* name,
Builtins::Name builtin_name) {
- Handle<String> key = isolate->factory()->LookupUtf8Symbol(name);
+ Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
Handle<Code> code(isolate->builtins()->builtin(builtin_name));
Handle<JSFunction> optimized =
isolate->factory()->NewFunction(key,
@@ -2084,7 +2093,7 @@
RUNTIME_ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
- String* name = isolate->heap()->prototype_symbol();
+ String* name = isolate->heap()->prototype_string();
if (function->HasFastProperties()) {
// Construct a new field descriptor with updated attributes.
@@ -3768,13 +3777,13 @@
// Slow case.
CONVERT_DOUBLE_ARG_CHECKED(value, 0);
if (isnan(value)) {
- return *isolate->factory()->nan_symbol();
+ return *isolate->factory()->nan_string();
}
if (isinf(value)) {
if (value < 0) {
- return *isolate->factory()->minus_infinity_symbol();
+ return *isolate->factory()->minus_infinity_string();
}
- return *isolate->factory()->infinity_symbol();
+ return *isolate->factory()->infinity_string();
}
char* str = DoubleToRadixCString(value, radix);
MaybeObject* result =
@@ -4756,7 +4765,7 @@
int dest_pos = 0;
for (int i = 0; i < total_property_count; i++) {
Object* name = old_names->get(i);
- if (name == isolate->heap()->hidden_symbol()) {
+ if (name == isolate->heap()->hidden_string()) {
continue;
}
names->set(dest_pos++, name);
@@ -4917,8 +4926,8 @@
}
// Handle special arguments properties.
- if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
- if (key->Equals(isolate->heap()->callee_symbol())) {
+ if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
+ if (key->Equals(isolate->heap()->callee_string())) {
Object* function = frame->function();
if (function->IsJSFunction() &&
!JSFunction::cast(function)->shared()->is_classic_mode()) {
@@ -4956,38 +4965,38 @@
NoHandleAllocation ha(isolate);
Object* obj = args[0];
- if (obj->IsNumber()) return isolate->heap()->number_symbol();
+ if (obj->IsNumber()) return isolate->heap()->number_string();
HeapObject* heap_obj = HeapObject::cast(obj);
// typeof an undetectable object is 'undefined'
if (heap_obj->map()->is_undetectable()) {
- return isolate->heap()->undefined_symbol();
+ return isolate->heap()->undefined_string();
}
InstanceType instance_type = heap_obj->map()->instance_type();
if (instance_type < FIRST_NONSTRING_TYPE) {
- return isolate->heap()->string_symbol();
+ return isolate->heap()->string_string();
}
switch (instance_type) {
case ODDBALL_TYPE:
if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
- return isolate->heap()->boolean_symbol();
+ return isolate->heap()->boolean_string();
}
if (heap_obj->IsNull()) {
return FLAG_harmony_typeof
- ? isolate->heap()->null_symbol()
- : isolate->heap()->object_symbol();
+ ? isolate->heap()->null_string()
+ : isolate->heap()->object_string();
}
ASSERT(heap_obj->IsUndefined());
- return isolate->heap()->undefined_symbol();
+ return isolate->heap()->undefined_string();
case JS_FUNCTION_TYPE:
case JS_FUNCTION_PROXY_TYPE:
- return isolate->heap()->function_symbol();
+ return isolate->heap()->function_string();
default:
// For any kind of object not handled above, the spec rule for
// host objects gives that it is okay to return "object"
- return isolate->heap()->object_symbol();
+ return isolate->heap()->object_string();
}
}
@@ -6319,7 +6328,7 @@
int special_length = special->length();
if (!array->HasFastObjectElements()) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
@@ -6353,21 +6362,21 @@
// Get the position and check that it is a positive smi.
i++;
if (i >= array_length) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
Object* next_smi = fixed_array->get(i);
if (!next_smi->IsSmi()) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
pos = Smi::cast(next_smi)->value();
if (pos < 0) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
}
ASSERT(pos >= 0);
ASSERT(len >= 0);
if (pos > special_length || len > special_length - pos) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
increment = len;
} else if (elt->IsString()) {
@@ -6379,7 +6388,7 @@
}
} else {
ASSERT(!elt->IsTheHole());
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
if (increment > String::kMaxLength - position) {
isolate->context()->mark_out_of_memory();
@@ -6429,7 +6438,7 @@
CONVERT_ARG_CHECKED(String, separator, 2);
if (!array->HasFastObjectElements()) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length) {
@@ -6455,7 +6464,7 @@
Object* element_obj = fixed_array->get(i);
if (!element_obj->IsString()) {
// TODO(1161): handle this case.
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
String* element = String::cast(element_obj);
int increment = element->length();
@@ -7451,11 +7460,11 @@
bound_function->set_function_bindings(*new_bindings);
// Update length.
- Handle<String> length_symbol = isolate->factory()->length_symbol();
+ Handle<String> length_string = isolate->factory()->length_string();
Handle<Object> new_length(args.at<Object>(3));
PropertyAttributes attr =
static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
- ForceSetProperty(bound_function, length_symbol, new_length, attr);
+ ForceSetProperty(bound_function, length_string, new_length, attr);
return *bound_function;
}
@@ -7708,7 +7717,7 @@
HandleScope handle_scope(isolate);
ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation);
if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
- return isolate->Throw(*isolate->factory()->LookupOneByteSymbol(
+ return isolate->Throw(*isolate->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("Recompile queue is full.")));
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
@@ -10163,7 +10172,7 @@
if (isolate->debug()->break_id() == 0 ||
break_id != isolate->debug()->break_id()) {
return isolate->Throw(
- isolate->heap()->illegal_execution_state_symbol());
+ isolate->heap()->illegal_execution_state_string());
}
return isolate->heap()->true_value();
@@ -11686,7 +11695,7 @@
if (!maybe_check->ToObject(&check)) return maybe_check;
}
if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
// Get the step action and check validity.
@@ -11696,13 +11705,13 @@
step_action != StepOut &&
step_action != StepInMin &&
step_action != StepMin) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
// Get the number of steps.
int step_count = NumberToInt32(args[2]);
if (step_count < 1) {
- return isolate->Throw(isolate->heap()->illegal_argument_symbol());
+ return isolate->Throw(isolate->heap()->illegal_argument_string());
}
// Clear all current stepping setup.
@@ -11801,7 +11810,7 @@
// does not support eval) then create an 'arguments' object.
int index;
if (scope_info->StackLocalCount() > 0) {
- index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
+ index = scope_info->StackSlotIndex(isolate->heap()->arguments_string());
if (index != -1) {
return Handle<Object>(frame->GetExpression(index), isolate);
}
@@ -11811,7 +11820,7 @@
VariableMode mode;
InitializationFlag init_flag;
index = scope_info->ContextSlotIndex(
- isolate->heap()->arguments_symbol(), &mode, &init_flag);
+ isolate->heap()->arguments_string(), &mode, &init_flag);
if (index != -1) {
return Handle<Object>(function_context->get(index), isolate);
}
@@ -12669,7 +12678,7 @@
const char* error_message =
LiveEdit::RestartFrame(it.frame(), isolate->runtime_zone());
if (error_message) {
- return *(isolate->factory()->LookupUtf8Symbol(error_message));
+ return *(isolate->factory()->InternalizeUtf8String(error_message));
}
return heap->true_value();
}
@@ -12859,7 +12868,7 @@
ASSERT_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
HandleScope scope(isolate);
- Handle<String> key = isolate->factory()->hidden_stack_trace_symbol();
+ Handle<String> key = isolate->factory()->hidden_stack_trace_string();
JSObject::SetHiddenProperty(fun, key, key);
return *fun;
}
@@ -12871,7 +12880,7 @@
HandleScope scope(isolate);
ASSERT_EQ(args.length(), 1);
CONVERT_ARG_CHECKED(JSObject, error_object, 0);
- String* key = isolate->heap()->hidden_stack_trace_symbol();
+ String* key = isolate->heap()->hidden_stack_trace_string();
Object* result = error_object->GetHiddenProperty(key);
RUNTIME_ASSERT(result->IsJSArray() ||
result->IsString() ||
@@ -12886,7 +12895,7 @@
ASSERT_EQ(args.length(), 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
CONVERT_ARG_HANDLE_CHECKED(HeapObject, value, 1);
- Handle<String> key = isolate->factory()->hidden_stack_trace_symbol();
+ Handle<String> key = isolate->factory()->hidden_stack_trace_string();
if (value->IsUndefined()) {
error_object->DeleteHiddenProperty(*key);
} else {
@@ -13246,14 +13255,14 @@
ASSERT(dictionary != NULL);
ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
for (int i = 0; i < kNumFunctions; ++i) {
- Object* name_symbol;
- { MaybeObject* maybe_name_symbol =
- heap->LookupUtf8Symbol(kIntrinsicFunctions[i].name);
- if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
+ Object* name_string;
+ { MaybeObject* maybe_name_string =
+ heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
+ if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
}
StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
{ MaybeObject* maybe_dictionary = string_dictionary->Add(
- String::cast(name_symbol),
+ String::cast(name_string),
Smi::FromInt(i),
PropertyDetails(NONE, NORMAL));
if (!maybe_dictionary->ToObject(&dictionary)) {
@@ -13267,7 +13276,7 @@
}
-const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
+const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
Heap* heap = name->GetHeap();
int entry = heap->intrinsic_function_names()->FindEntry(*name);
if (entry != kNotFound) {
diff --git a/src/runtime.h b/src/runtime.h
index 3e51d14..a0f4fe7 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -296,6 +296,9 @@
/* Harmony modules */ \
F(IsJSModule, 1, 1) \
\
+ /* Harmony symbols */ \
+ F(CreateSymbol, 0, 1) \
+ \
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
F(CreateJSFunctionProxy, 4, 1) \
@@ -509,6 +512,7 @@
#define INLINE_FUNCTION_LIST(F) \
F(IsSmi, 1, 1) \
F(IsNonNegativeSmi, 1, 1) \
+ F(IsSymbol, 1, 1) \
F(IsArray, 1, 1) \
F(IsRegExp, 1, 1) \
F(IsConstructCall, 0, 1) \
@@ -542,7 +546,7 @@
// ----------------------------------------------------------------------------
-// INLINE_AND_RUNTIME_FUNCTION_LIST defines all inlined functions accessed
+// INLINE_RUNTIME_FUNCTION_LIST defines all inlined functions accessed
// with a native call of the form %_name from within JS code that also have
// a corresponding runtime function, that is called for slow cases.
// Entries have the form F(name, number of arguments, number of return values).
@@ -642,15 +646,16 @@
static const int kNotFound = -1;
- // Add symbols for all the intrinsic function names to a StringDictionary.
+ // Add internalized strings for all the intrinsic function names to a
+ // StringDictionary.
// Returns failure if an allocation fails. In this case, it must be
// retried with a new, empty StringDictionary, not with the same one.
// Alternatively, heap initialization can be completely restarted.
MUST_USE_RESULT static MaybeObject* InitializeIntrinsicFunctionNames(
Heap* heap, Object* dictionary);
- // Get the intrinsic function with the given name, which must be a symbol.
- static const Function* FunctionForSymbol(Handle<String> name);
+ // Get the intrinsic function with the given name, which must be internalized.
+ static const Function* FunctionForName(Handle<String> name);
// Get the intrinsic function with the given FunctionId.
static const Function* FunctionForId(FunctionId id);
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 0de3a8d..15ee29f 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -280,7 +280,7 @@
int ScopeInfo::StackSlotIndex(String* name) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
if (length() > 0) {
int start = StackLocalEntriesIndex();
int end = StackLocalEntriesIndex() + StackLocalCount();
@@ -297,7 +297,7 @@
int ScopeInfo::ContextSlotIndex(String* name,
VariableMode* mode,
InitializationFlag* init_flag) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
ASSERT(mode != NULL);
ASSERT(init_flag != NULL);
if (length() > 0) {
@@ -329,7 +329,7 @@
int ScopeInfo::ParameterIndex(String* name) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
if (length() > 0) {
// We must read parameters from the end since for
// multiply declared parameters the value of the
@@ -349,7 +349,7 @@
int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
ASSERT(mode != NULL);
if (length() > 0) {
if (FunctionVariableField::decode(Flags()) == CONTEXT &&
@@ -442,13 +442,13 @@
VariableMode mode,
InitializationFlag init_flag,
int slot_index) {
- String* symbol;
+ String* internalized_name;
ASSERT(slot_index > kNotFound);
- if (HEAP->LookupSymbolIfExists(name, &symbol)) {
- int index = Hash(data, symbol);
+ if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
+ int index = Hash(data, internalized_name);
Key& key = keys_[index];
key.data = data;
- key.name = symbol;
+ key.name = internalized_name;
// Please note value only takes a uint as index.
values_[index] = Value(mode, init_flag, slot_index - kNotFound).raw();
#ifdef DEBUG
@@ -470,8 +470,8 @@
VariableMode mode,
InitializationFlag init_flag,
int slot_index) {
- String* symbol;
- if (HEAP->LookupSymbolIfExists(name, &symbol)) {
+ String* internalized_name;
+ if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
int index = Hash(data, name);
Key& key = keys_[index];
ASSERT(key.data == data);
diff --git a/src/scopes.cc b/src/scopes.cc
index 2be22c8..4ac9d0e 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -52,8 +52,8 @@
static bool Match(void* key1, void* key2) {
String* name1 = *reinterpret_cast<String**>(key1);
String* name2 = *reinterpret_cast<String**>(key2);
- ASSERT(name1->IsSymbol());
- ASSERT(name2->IsSymbol());
+ ASSERT(name1->IsInternalizedString());
+ ASSERT(name2->IsInternalizedString());
return name1 == name2;
}
@@ -182,7 +182,7 @@
Handle<ScopeInfo> scope_info) {
outer_scope_ = outer_scope;
type_ = type;
- scope_name_ = isolate_->factory()->empty_symbol();
+ scope_name_ = isolate_->factory()->empty_string();
dynamics_ = NULL;
receiver_ = NULL;
function_ = NULL;
@@ -335,7 +335,7 @@
if (is_declaration_scope()) {
Variable* var =
variables_.Declare(this,
- isolate_->factory()->this_symbol(),
+ isolate_->factory()->this_string(),
VAR,
false,
Variable::THIS,
@@ -352,7 +352,7 @@
// Note that it might never be accessed, in which case it won't be
// allocated during variable allocation.
variables_.Declare(this,
- isolate_->factory()->arguments_symbol(),
+ isolate_->factory()->arguments_string(),
VAR,
true,
Variable::ARGUMENTS,
@@ -1198,7 +1198,7 @@
bool Scope::HasArgumentsParameter() {
for (int i = 0; i < params_.length(); i++) {
if (params_[i]->name().is_identical_to(
- isolate_->factory()->arguments_symbol())) {
+ isolate_->factory()->arguments_string())) {
return true;
}
}
@@ -1218,7 +1218,7 @@
void Scope::AllocateParameterLocals() {
ASSERT(is_function_scope());
- Variable* arguments = LocalLookup(isolate_->factory()->arguments_symbol());
+ Variable* arguments = LocalLookup(isolate_->factory()->arguments_string());
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
bool uses_nonstrict_arguments = false;
@@ -1274,7 +1274,7 @@
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
- ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
+ ASSERT(!var->IsVariable(isolate_->factory()->result_string()) ||
!var->IsStackLocal());
if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
@@ -1359,7 +1359,7 @@
if (already_resolved()) return;
if (is_module_scope()) {
ASSERT(interface_->IsFrozen());
- Handle<String> name = isolate_->factory()->LookupOneByteSymbol(
+ Handle<String> name = isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR(".module"));
ASSERT(module_var_ == NULL);
module_var_ = host_scope->NewInternal(name);
diff --git a/src/serialize.cc b/src/serialize.cc
index ca1c884..e587dfa 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -1356,9 +1356,9 @@
// should go through the root array or through the partial snapshot cache.
// If this is not the case you may have to add something to the root array.
ASSERT(!startup_serializer_->address_mapper()->IsMapped(heap_object));
- // All the symbols that the partial snapshot needs should be either in the
- // root table or in the partial snapshot cache.
- ASSERT(!heap_object->IsSymbol());
+ // All the internalized strings that the partial snapshot needs should be
+ // either in the root table or in the partial snapshot cache.
+ ASSERT(!heap_object->IsInternalizedString());
if (address_mapper_.IsMapped(heap_object)) {
int space = SpaceOfObject(heap_object);
diff --git a/src/serialize.h b/src/serialize.h
index 4bbde5a..e0bcf4e 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -638,7 +638,7 @@
// Serialize the current state of the heap. The order is:
// 1) Strong references.
// 2) Partial snapshot cache.
- // 3) Weak references (e.g. the symbol table).
+ // 3) Weak references (e.g. the string table).
virtual void SerializeStrongReferences();
virtual void SerializeObject(Object* o,
HowToCode how_to_code,
diff --git a/src/spaces.h b/src/spaces.h
index 02982cf..e7e11db 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1745,7 +1745,7 @@
first_unswept_page_ = first;
}
- void IncrementUnsweptFreeBytes(int by) {
+ void IncrementUnsweptFreeBytes(intptr_t by) {
unswept_free_bytes_ += by;
}
@@ -1754,7 +1754,7 @@
unswept_free_bytes_ += (p->area_size() - p->LiveBytes());
}
- void DecrementUnsweptFreeBytes(int by) {
+ void DecrementUnsweptFreeBytes(intptr_t by) {
unswept_free_bytes_ -= by;
}
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 9510254..bcc30f9 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -493,7 +493,7 @@
// Common case: on-stack function present and resolved.
PrintPrototype(fun, receiver);
*code = fun->code();
- } else if (f->IsSymbol()) {
+ } else if (f->IsInternalizedString()) {
// Unresolved and megamorphic calls: Instead of the function
// we have the function name on the stack.
PrintName(f);
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index bdcd30d..2bc7355 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -63,7 +63,7 @@
// Validate that the name does not move on scavenge, and that we
// can use identity checks instead of string equality checks.
ASSERT(!heap()->InNewSpace(name));
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
// The state bits are not important to the hash function because
// the stub cache only contains monomorphic stubs. Make sure that
@@ -100,6 +100,68 @@
}
+Handle<JSObject> StubCache::StubHolder(Handle<JSObject> receiver,
+ Handle<JSObject> holder) {
+ InlineCacheHolderFlag cache_holder =
+ IC::GetCodeCacheForObject(*receiver, *holder);
+ return Handle<JSObject>(IC::GetCodeCacheHolder(
+ isolate_, *receiver, cache_holder));
+}
+
+
+Handle<Code> StubCache::FindStub(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type,
+ Code::IcFragment fragment) {
+ Code::Flags flags = Code::ComputeMonomorphicFlags(kind, fragment, type);
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
+ isolate_);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+ return Handle<Code>::null();
+}
+
+
+Handle<Code> StubCache::FindHandler(Handle<String> name,
+ Handle<JSObject> handler_holder,
+ Code::Kind kind,
+ Code::StubType type) {
+ return FindStub(name, handler_holder, kind, type, Code::HANDLER_FRAGMENT);
+}
+
+
+Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ Handle<Code> ic = FindStub(name, receiver, Code::LOAD_IC,
+ handler->type(), Code::IC_FRAGMENT);
+ if (!ic.is_null()) return ic;
+
+ LoadStubCompiler ic_compiler(isolate());
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ Handle<Code> ic = FindStub(name, receiver, Code::KEYED_LOAD_IC,
+ handler->type(), Code::IC_FRAGMENT);
+ if (!ic.is_null()) return ic;
+
+ KeyedLoadStubCompiler ic_compiler(isolate());
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
Handle<JSObject> receiver) {
// If no global objects are present in the prototype chain, the load
@@ -125,19 +187,15 @@
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::NONEXISTENT);
- Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<Code> handler = FindHandler(
+ cache_name, receiver, Code::LOAD_IC, Code::NONEXISTENT);
+ if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ handler =
compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
- JSObject::UpdateMapCodeCache(receiver, cache_name, code);
- return code;
+ JSObject::UpdateMapCodeCache(receiver, cache_name, handler);
+ return handler;
}
@@ -145,22 +203,23 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::FIELD);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ if (receiver.is_identical_to(holder)) {
+ LoadFieldStub stub(LoadStubCompiler::receiver(),
+ field.is_inobject(holder),
+ field.translate(holder));
+ return stub.GetCode(isolate());
+ }
+
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::FIELD);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadField(receiver, holder, name, field);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -170,23 +229,16 @@
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback) {
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -194,23 +246,16 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> getter) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadViaGetter(receiver, holder, name, getter);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -218,50 +263,37 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> handler = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
+ if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
- compiler.CompileLoadConstant(receiver, holder, name, value);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+
+ return handler;
}
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadInterceptor(receiver, holder, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
-Handle<Code> StubCache::ComputeLoadNormal() {
+Handle<Code> StubCache::ComputeLoadNormal(Handle<String> name,
+ Handle<JSObject> receiver) {
return isolate_->builtins()->LoadIC_Normal();
}
@@ -271,22 +303,16 @@
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
bool is_dont_delete) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindStub(
+ name, stub_holder, Code::LOAD_IC, Code::NORMAL, Code::IC_FRAGMENT);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> ic =
compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, ic);
+ return ic;
}
@@ -294,22 +320,23 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::FIELD);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ if (receiver.is_identical_to(holder)) {
+ LoadFieldStub stub(KeyedLoadStubCompiler::receiver(),
+ field.is_inobject(holder),
+ field.translate(holder));
+ return stub.GetCode(isolate());
+ }
+
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadField(receiver, holder, name, field);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -317,45 +344,31 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> handler = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION);
+ if (!handler.is_null()) return handler;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code =
- compiler.CompileLoadConstant(receiver, holder, name, value);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadInterceptor(receiver, holder, name);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -364,23 +377,16 @@
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
@@ -400,8 +406,6 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreField(receiver, field_index, transition, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -410,7 +414,7 @@
Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
Handle<String> name =
- isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
+ isolate()->factory()->KeyedLoadElementMonomorphic_string();
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -418,7 +422,6 @@
KeyedLoadStubCompiler compiler(isolate());
Handle<Code> code = compiler.CompileLoadElement(receiver_map);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
Map::UpdateCodeCache(receiver_map, name, code);
return code;
}
@@ -438,8 +441,8 @@
stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
Handle<String> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
- ? isolate()->factory()->KeyedStoreElementMonomorphic_symbol()
- : isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
+ ? isolate()->factory()->KeyedStoreElementMonomorphic_string()
+ : isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_string();
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -447,7 +450,6 @@
KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
Handle<Code> code = compiler.CompileStoreElement(receiver_map);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
Map::UpdateCodeCache(receiver_map, name, code);
return code;
}
@@ -472,8 +474,6 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -495,8 +495,6 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreCallback(name, receiver, holder, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -516,8 +514,6 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreViaSetter(name, receiver, holder, setter);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -534,8 +530,6 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -557,8 +551,6 @@
DO_NOT_ALLOW_JSARRAY_GROWTH);
Handle<Code> code =
compiler.CompileStoreField(receiver, field_index, transition, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -577,13 +569,15 @@
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+ isolate_, *object, cache_holder));
// Compute check type based on receiver/holder.
CheckType check = RECEIVER_MAP_CHECK;
if (object->IsString()) {
check = STRING_CHECK;
+ } else if (object->IsSymbol()) {
+ check = SYMBOL_CHECK;
} else if (object->IsNumber()) {
check = NUMBER_CHECK;
} else if (object->IsBoolean()) {
@@ -600,7 +594,7 @@
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::CONSTANT_FUNCTION, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -612,7 +606,7 @@
PROFILE(isolate_,
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -627,19 +621,20 @@
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+ isolate_, *object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
// because they may be represented as immediates without a
// map. Instead, we check against the map in the holder.
- if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
+ if (object->IsNumber() || object->IsSymbol() ||
+ object->IsBoolean() || object->IsString()) {
object = holder;
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::FIELD, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -651,7 +646,7 @@
PROFILE(isolate_,
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -665,19 +660,20 @@
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+ isolate_, *object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
// because they may be represented as immediates without a
// map. Instead, we check against the map in the holder.
- if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
+ if (object->IsNumber() || object->IsSymbol() ||
+ object->IsBoolean() || object->IsString()) {
object = holder;
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -689,7 +685,7 @@
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -704,11 +700,11 @@
Handle<JSFunction> function) {
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
isolate_, *receiver, cache_holder));
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::NORMAL, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@@ -719,7 +715,7 @@
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -881,13 +877,30 @@
Handle<Object> probe = cache->Lookup(receiver_maps, flags);
if (probe->IsCode()) return Handle<Code>::cast(probe);
+ CodeHandleList handlers(receiver_maps->length());
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadElementPolymorphic(receiver_maps);
+ compiler.CompileElementHandlers(receiver_maps, &handlers);
+ Handle<Code> code = compiler.CompilePolymorphicIC(
+ receiver_maps, &handlers, factory()->empty_string(),
+ Code::NORMAL, ELEMENT);
+
+ isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+
PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
return code;
}
+Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name) {
+ LoadStubCompiler ic_compiler(isolate_);
+ Handle<Code> ic = ic_compiler.CompilePolymorphicIC(
+ receiver_maps, handlers, name, Code::NORMAL, PROPERTY);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeStoreElementPolymorphic(
MapHandleList* receiver_maps,
KeyedAccessGrowMode grow_mode,
@@ -1382,18 +1395,11 @@
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* miss,
- FrontendCheckType check) {
- if (check == PERFORM_INITIAL_CHECKS) {
- GenerateNameCheck(name, this->name(), miss);
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(object_reg, miss);
- }
-
+ Label* miss) {
// Check the prototype chain.
return CheckPrototypes(object, object_reg, holder,
scratch1(), scratch2(), scratch3(),
- name, miss);
+ name, miss, SKIP_RECEIVER);
}
@@ -1401,12 +1407,10 @@
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check) {
+ Label* success) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
HandlerFrontendFooter(success, &miss);
return reg;
@@ -1416,15 +1420,19 @@
Handle<Code> BaseLoadStubCompiler::CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
- PropertyIndex index) {
- Label success;
- Register reg = HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
- __ bind(&success);
- GenerateLoadField(reg, holder, index);
+ PropertyIndex field) {
+ Label miss;
+
+ Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss);
+
+ LoadFieldStub stub(reg, field.is_inobject(holder), field.translate(holder));
+ GenerateTailCall(stub.GetCode(isolate()));
+
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::FIELD, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::FIELD, name);
}
@@ -1434,13 +1442,12 @@
Handle<String> name,
Handle<JSFunction> value) {
Label success;
- HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
GenerateLoadConstant(value);
// Return the generated code.
- return GetCode(Code::CONSTANT_FUNCTION, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CONSTANT_FUNCTION, name);
}
@@ -1452,13 +1459,12 @@
Label success;
Register reg = CallbackHandlerFrontend(
- object, receiver(), holder, name, &success,
- PERFORM_INITIAL_CHECKS, callback);
+ object, receiver(), holder, name, &success, callback);
__ bind(&success);
GenerateLoadCallback(reg, callback);
// Return the generated code.
- return GetCode(Code::CALLBACKS, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
}
@@ -1471,15 +1477,14 @@
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
- Register reg = HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptor(reg, object, holder, &lookup, name);
// Return the generated code.
- return GetCode(Code::INTERCEPTOR, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::INTERCEPTOR, name);
}
@@ -1491,12 +1496,20 @@
Label success;
Handle<JSObject> holder(lookup->holder());
if (lookup->IsField()) {
- // We found FIELD property in prototype chain of interceptor's holder.
- // Retrieve a field from field's holder.
- Register reg = HandlerFrontend(interceptor_holder, interceptor_reg, holder,
- name, &success, SKIP_INITIAL_CHECKS);
- __ bind(&success);
- GenerateLoadField(reg, holder, lookup->GetFieldIndex());
+ PropertyIndex field = lookup->GetFieldIndex();
+ if (interceptor_holder.is_identical_to(holder)) {
+ LoadFieldStub stub(interceptor_reg,
+ field.is_inobject(holder),
+ field.translate(holder));
+ GenerateTailCall(stub.GetCode(isolate()));
+ } else {
+ // We found FIELD property in prototype chain of interceptor's holder.
+ // Retrieve a field from field's holder.
+ Register reg = HandlerFrontend(
+ interceptor_holder, interceptor_reg, holder, name, &success);
+ __ bind(&success);
+ GenerateLoadField(reg, holder, field);
+ }
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
@@ -1506,61 +1519,69 @@
ASSERT(callback->getter() != NULL);
Register reg = CallbackHandlerFrontend(
- interceptor_holder, interceptor_reg, holder,
- name, &success, SKIP_INITIAL_CHECKS, callback);
+ interceptor_holder, interceptor_reg, holder, name, &success, callback);
__ bind(&success);
GenerateLoadCallback(reg, callback);
}
}
+Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
+ Handle<Map> receiver_map,
+ Handle<Code> handler,
+ Handle<String> name) {
+ MapHandleList receiver_maps(1);
+ receiver_maps.Add(receiver_map);
+ CodeHandleList handlers(1);
+ handlers.Add(handler);
+ Code::StubType type = handler->type();
+ return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
+}
+
+
Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
Handle<JSFunction> getter) {
Label success;
- HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
GenerateLoadViaGetter(masm(), getter);
// Return the generated code.
- return GetCode(Code::CALLBACKS, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
}
#undef __
-Handle<Code> LoadStubCompiler::GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, type);
- Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+void LoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+}
+
+
+void KeyedLoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+}
+
+
+Handle<Code> BaseLoadStubCompiler::GetCode(Code::IcFragment fragment,
+ Code::StubType type,
+ Handle<String> name,
+ InlineCacheState state) {
+ Code::Flags flags = Code::ComputeFlags(kind(), state, fragment, type);
+ Handle<Code> code = GetCodeWithFlags(flags, name);
+ PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
+ JitEvent(name, code);
return code;
}
-Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state) {
- Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
- Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- return code;
-}
-
-
-Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
- MapHandleList* receiver_maps) {
- CodeHandleList handler_ics(receiver_maps->length());
+void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
+ CodeHandleList* handlers) {
for (int i = 0; i < receiver_maps->length(); ++i) {
Handle<Map> receiver_map = receiver_maps->at(i);
Handle<Code> cached_stub;
@@ -1582,17 +1603,11 @@
}
}
- handler_ics.Add(cached_stub);
+ handlers->Add(cached_stub);
}
- Handle<Code> code = CompileLoadPolymorphic(receiver_maps, &handler_ics);
- isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
- return code;
}
-
Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
Handle<String> name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
@@ -1621,7 +1636,7 @@
Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
MapHandleList* receiver_maps) {
// Collect MONOMORPHIC stubs for all |receiver_maps|.
- CodeHandleList handler_ics(receiver_maps->length());
+ CodeHandleList handlers(receiver_maps->length());
MapHandleList transitioned_maps(receiver_maps->length());
for (int i = 0; i < receiver_maps->length(); ++i) {
Handle<Map> receiver_map(receiver_maps->at(i));
@@ -1650,11 +1665,11 @@
grow_mode_).GetCode(isolate());
}
ASSERT(!cached_stub.is_null());
- handler_ics.Add(cached_stub);
+ handlers.Add(cached_stub);
transitioned_maps.Add(transitioned_map);
}
Handle<Code> code =
- CompileStorePolymorphic(receiver_maps, &handler_ics, &transitioned_maps);
+ CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
PROFILE(isolate(),
CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 7753406..5e3fbfc 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -74,6 +74,26 @@
void Initialize();
+ Handle<JSObject> StubHolder(Handle<JSObject> receiver,
+ Handle<JSObject> holder);
+
+ Handle<Code> FindStub(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type,
+ Code::IcFragment fragment);
+
+ Handle<Code> FindHandler(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type);
+
+ Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
@@ -104,7 +124,8 @@
Handle<JSObject> object,
Handle<JSObject> holder);
- Handle<Code> ComputeLoadNormal();
+ Handle<Code> ComputeLoadNormal(Handle<String> name,
+ Handle<JSObject> object);
Handle<Code> ComputeLoadGlobal(Handle<String> name,
Handle<JSObject> object,
@@ -245,6 +266,10 @@
KeyedAccessGrowMode grow_mode,
StrictModeFlag strict_mode);
+ Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name);
+
// Finds the Code object stored in the Heap::non_monomorphic_cache().
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
@@ -414,6 +439,10 @@
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
+enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
+enum IcCheckType { ELEMENT, PROPERTY };
+
+
// The stub compilers compile stubs for the stub cache.
class StubCompiler BASE_EMBEDDED {
public:
@@ -455,6 +484,11 @@
Register src,
Handle<JSObject> holder,
PropertyIndex index);
+ static void DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
@@ -512,9 +546,10 @@
Register scratch1,
Register scratch2,
Handle<String> name,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check = CHECK_ALL_MAPS) {
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
- scratch2, name, kInvalidProtoDepth, miss);
+ scratch2, name, kInvalidProtoDepth, miss, check);
}
Register CheckPrototypes(Handle<JSObject> object,
@@ -525,7 +560,8 @@
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss);
+ Label* miss,
+ PrototypeCheckType check = CHECK_ALL_MAPS);
protected:
@@ -543,6 +579,8 @@
Heap* heap() { return isolate()->heap(); }
Factory* factory() { return isolate()->factory(); }
+ void GenerateTailCall(Handle<Code> code);
+
private:
Isolate* isolate_;
MacroAssembler masm_;
@@ -578,27 +616,33 @@
Handle<JSObject> holder,
Handle<String> name);
+ Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
+ Handle<Code> handler,
+ Handle<String> name);
+ Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check);
+
protected:
Register HandlerFrontendHeader(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check);
+ Label* success);
void HandlerFrontendFooter(Label* success, Label* miss);
Register HandlerFrontend(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check);
+ Label* success);
Register CallbackHandlerFrontend(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback);
void NonexistentHandlerFrontend(Handle<JSObject> object,
Handle<JSObject> last,
@@ -622,6 +666,10 @@
Handle<String> name,
LookupResult* lookup);
+ Handle<Code> GetCode(Code::IcFragment fragment,
+ Code::StubType type,
+ Handle<String> name,
+ InlineCacheState state = MONOMORPHIC);
Register receiver() { return registers_[0]; }
Register name() { return registers_[1]; }
@@ -632,12 +680,11 @@
private:
virtual Code::Kind kind() = 0;
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
+ virtual void JitEvent(Handle<String> name, Handle<Code> code) = 0;
virtual void GenerateNameCheck(Handle<String> name,
Register name_reg,
Label* miss) { }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC) = 0;
Register* registers_;
};
@@ -666,12 +713,16 @@
Handle<String> name,
bool is_dont_delete);
+ static Register receiver() { return registers()[0]; }
+
private:
- Register* registers();
+ static Register* registers();
virtual Code::Kind kind() { return Code::LOAD_IC; }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC);
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+ return code->ic_state() == MONOMORPHIC
+ ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
+ }
+ virtual void JitEvent(Handle<String> name, Handle<Code> code);
};
@@ -682,19 +733,23 @@
Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
- Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
- CodeHandleList* handler_ics);
+ void CompileElementHandlers(MapHandleList* receiver_maps,
+ CodeHandleList* handlers);
Handle<Code> CompileLoadElementPolymorphic(MapHandleList* receiver_maps);
static void GenerateLoadDictionaryElement(MacroAssembler* masm);
+ static Register receiver() { return registers()[0]; }
+
private:
- Register* registers();
+ static Register* registers();
virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC);
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+ return code->ic_state() == MONOMORPHIC
+ ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
+ }
+ virtual void JitEvent(Handle<String> name, Handle<Code> code);
virtual void GenerateNameCheck(Handle<String> name,
Register name_reg,
Label* miss);
diff --git a/src/symbol.js b/src/symbol.js
new file mode 100644
index 0000000..b7f9dc9
--- /dev/null
+++ b/src/symbol.js
@@ -0,0 +1,39 @@
+// 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.
+
+"use strict";
+
+var $Symbol = function() { return %CreateSymbol() }
+global.Symbol = $Symbol
+
+// Symbols only have a toString method and no prototype.
+var SymbolDelegate = {
+ __proto__: null,
+ toString: $Object.prototype.toString
+}
+
+$Object.freeze(SymbolDelegate)
diff --git a/src/type-info.cc b/src/type-info.cc
index b2d5917..62ca324 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -163,8 +163,13 @@
bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) {
- Handle<Object> value = GetInfo(expr->CallNewFeedbackId());
- return value->IsJSFunction();
+ Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
+ if (info->IsSmi()) {
+ ASSERT(static_cast<ElementsKind>(Smi::cast(*info)->value()) <=
+ LAST_FAST_ELEMENTS_KIND);
+ return Isolate::Current()->global_context()->array_function();
+ }
+ return info->IsJSFunction();
}
@@ -265,6 +270,8 @@
case RECEIVER_MAP_CHECK:
UNREACHABLE();
break;
+ case SYMBOL_CHECK:
+ return Handle<JSObject>(native_context_->symbol_delegate());
case STRING_CHECK:
function = native_context_->string_function();
break;
@@ -286,10 +293,33 @@
Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) {
- return Handle<JSFunction>::cast(GetInfo(expr->CallNewFeedbackId()));
+ Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
+ if (info->IsSmi()) {
+ ASSERT(static_cast<ElementsKind>(Smi::cast(*info)->value()) <=
+ LAST_FAST_ELEMENTS_KIND);
+ return Handle<JSFunction>(Isolate::Current()->global_context()->
+ array_function());
+ } else {
+ return Handle<JSFunction>::cast(info);
+ }
}
+ElementsKind TypeFeedbackOracle::GetCallNewElementsKind(CallNew* expr) {
+ Handle<Object> info = GetInfo(expr->CallNewFeedbackId());
+ if (info->IsSmi()) {
+ return static_cast<ElementsKind>(Smi::cast(*info)->value());
+ } else {
+ // TODO(mvstanton): avoided calling GetInitialFastElementsKind() for perf
+ // reasons. Is there a better fix?
+ if (FLAG_packed_arrays) {
+ return FAST_SMI_ELEMENTS;
+ } else {
+ return FAST_HOLEY_SMI_ELEMENTS;
+ }
+ }
+}
+
Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap(
ObjectLiteral::Property* prop) {
ASSERT(ObjectLiteralStoreIsMonomorphic(prop));
@@ -308,6 +338,7 @@
if (!object->IsCode()) return false;
Handle<Code> code = Handle<Code>::cast(object);
if (!code->is_load_stub()) return false;
+ if (code->ic_state() != MONOMORPHIC) return false;
return stub->Describes(*code);
}
@@ -321,8 +352,8 @@
return TypeInfo::Smi();
case CompareIC::NUMBER:
return TypeInfo::Number();
- case CompareIC::SYMBOL:
- return TypeInfo::Symbol();
+ case CompareIC::INTERNALIZED_STRING:
+ return TypeInfo::InternalizedString();
case CompareIC::STRING:
return TypeInfo::String();
case CompareIC::OBJECT:
@@ -484,6 +515,29 @@
}
+static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
+ Zone* zone) {
+ for (int i = 0; i < list->length(); ++i) {
+ if (list->at(i).is_identical_to(map)) return;
+ }
+ list->Add(map, zone);
+}
+
+
+void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code,
+ SmallMapList* types) {
+ MapHandleList maps;
+ code->FindAllMaps(&maps);
+ types->Reserve(maps.length(), zone());
+ for (int i = 0; i < maps.length(); i++) {
+ Handle<Map> map(maps.at(i));
+ if (!CanRetainOtherContext(*map, *native_context_)) {
+ AddMapIfMissing(map, types, zone());
+ }
+ }
+}
+
+
void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
Handle<String> name,
Code::Flags flags,
@@ -497,6 +551,8 @@
ASSERT(Handle<Code>::cast(object)->ic_state() == GENERIC);
} else if (object->IsMap()) {
types->Add(Handle<Map>::cast(object), zone());
+ } else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC) {
+ CollectPolymorphicMaps(Handle<Code>::cast(object), types);
} else if (FLAG_collect_megamorphic_maps_from_stub_cache &&
Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
types->Reserve(4, zone());
@@ -544,15 +600,6 @@
}
-static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
- Zone* zone) {
- for (int i = 0; i < list->length(); ++i) {
- if (list->at(i).is_identical_to(map)) return;
- }
- list->Add(map, zone);
-}
-
-
void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
SmallMapList* types) {
Handle<Object> object = GetInfo(ast_id);
@@ -560,18 +607,7 @@
Handle<Code> code = Handle<Code>::cast(object);
if (code->kind() == Code::KEYED_LOAD_IC ||
code->kind() == Code::KEYED_STORE_IC) {
- AssertNoAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(*code, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsMap()) {
- Map* map = Map::cast(object);
- if (!CanRetainOtherContext(map, *native_context_)) {
- AddMapIfMissing(Handle<Map>(map), types, zone());
- }
- }
- }
+ CollectPolymorphicMaps(code, types);
}
}
diff --git a/src/type-info.h b/src/type-info.h
index 1ad3233..2b50bf4 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -65,12 +65,12 @@
static TypeInfo Integer32() { return TypeInfo(kInteger32); }
// We know it's a Smi.
static TypeInfo Smi() { return TypeInfo(kSmi); }
- // We know it's a Symbol.
- static TypeInfo Symbol() { return TypeInfo(kSymbol); }
// We know it's a heap number.
static TypeInfo Double() { return TypeInfo(kDouble); }
// We know it's a string.
static TypeInfo String() { return TypeInfo(kString); }
+ // We know it's an internalized string.
+ static TypeInfo InternalizedString() { return TypeInfo(kInternalizedString); }
// We know it's a non-primitive (object) type.
static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); }
// We haven't started collecting info yet.
@@ -140,14 +140,14 @@
return ((type_ & kSmi) == kSmi);
}
- inline bool IsSymbol() {
+ inline bool IsInternalizedString() {
ASSERT(type_ != kUninitialized);
- return ((type_ & kSymbol) == kSymbol);
+ return ((type_ & kInternalizedString) == kInternalizedString);
}
- inline bool IsNonSymbol() {
+ inline bool IsNonInternalizedString() {
ASSERT(type_ != kUninitialized);
- return ((type_ & kSymbol) == kString);
+ return ((type_ & kInternalizedString) == kString);
}
inline bool IsInteger32() {
@@ -181,7 +181,7 @@
case kNumber: return "Number";
case kInteger32: return "Integer32";
case kSmi: return "Smi";
- case kSymbol: return "Symbol";
+ case kInternalizedString: return "InternalizedString";
case kDouble: return "Double";
case kString: return "String";
case kNonPrimitive: return "Object";
@@ -193,16 +193,16 @@
private:
enum Type {
- kUnknown = 0, // 0000000
- kPrimitive = 0x10, // 0010000
- kNumber = 0x11, // 0010001
- kInteger32 = 0x13, // 0010011
- kSmi = 0x17, // 0010111
- kDouble = 0x19, // 0011001
- kString = 0x30, // 0110000
- kSymbol = 0x32, // 0110010
- kNonPrimitive = 0x40, // 1000000
- kUninitialized = 0x7f // 1111111
+ kUnknown = 0, // 0000000
+ kPrimitive = 0x10, // 0010000
+ kNumber = 0x11, // 0010001
+ kInteger32 = 0x13, // 0010011
+ kSmi = 0x17, // 0010111
+ kDouble = 0x19, // 0011001
+ kString = 0x30, // 0110000
+ kInternalizedString = 0x32, // 0110010
+ kNonPrimitive = 0x40, // 1000000
+ kUninitialized = 0x7f // 1111111
};
explicit inline TypeInfo(Type t) : type_(t) { }
@@ -272,11 +272,14 @@
static bool CanRetainOtherContext(JSFunction* function,
Context* native_context);
+ void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
+
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
Handle<JSFunction> GetCallTarget(Call* expr);
Handle<JSFunction> GetCallNewTarget(CallNew* expr);
+ ElementsKind GetCallNewElementsKind(CallNew* expr);
Handle<Map> GetObjectLiteralStoreMap(ObjectLiteral::Property* prop);
@@ -323,8 +326,12 @@
// Returns an element from the backing store. Returns undefined if
// there is no information.
+ public:
+ // TODO(mvstanton): how to get this information without making the method
+ // public?
Handle<Object> GetInfo(TypeFeedbackId ast_id);
+ private:
Handle<Context> native_context_;
Isolate* isolate_;
Handle<UnseededNumberDictionary> dictionary_;
diff --git a/src/utils.h b/src/utils.h
index 9080bd6..c391b9c 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -249,6 +249,7 @@
// using a shift count of 32.
static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
static const uint32_t kShift = shift;
+ static const uint32_t kSize = size;
// Value for the field with all bits set.
static const T kMax = static_cast<T>((1U << size) - 1);
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 986e6dd..374ebbc 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -98,7 +98,7 @@
SC(alive_after_last_gc, V8.AliveAfterLastGC) \
SC(objs_since_last_young, V8.ObjsSinceLastYoung) \
SC(objs_since_last_full, V8.ObjsSinceLastFull) \
- SC(symbol_table_capacity, V8.SymbolTableCapacity) \
+ SC(string_table_capacity, V8.StringTableCapacity) \
SC(number_of_symbols, V8.NumberOfSymbols) \
SC(script_wrappers, V8.ScriptWrappers) \
SC(call_initialize_stubs, V8.CallInitializeStubs) \
diff --git a/src/v8globals.h b/src/v8globals.h
index c3b59a1..072c365 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -276,6 +276,7 @@
enum CheckType {
RECEIVER_MAP_CHECK,
STRING_CHECK,
+ SYMBOL_CHECK,
NUMBER_CHECK,
BOOLEAN_CHECK
};
@@ -293,7 +294,7 @@
enum InlineCacheHolderFlag {
OWN_MAP, // For fast properties objects.
- PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
+ DELEGATE_MAP // For slow properties objects (except GlobalObjects).
};
diff --git a/src/v8natives.js b/src/v8natives.js
index 9a8e4e3..356ce88 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -231,10 +231,9 @@
// ECMA-262 - 15.2.4.2
function ObjectToString() {
- if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- return '[object Undefined]';
- }
- if (IS_NULL(this)) return '[object Null]';
+ if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
+ if (IS_NULL(this)) return "[object Null]";
+ if (IS_SYMBOL(this)) return "[object Symbol]";
return "[object " + %_ClassOf(ToObject(this)) + "]";
}
diff --git a/src/variables.cc b/src/variables.cc
index 9161217..488da42 100644
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -76,7 +76,7 @@
initialization_flag_(initialization_flag),
interface_(interface) {
// Names must be canonicalized for fast equality checks.
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
// Var declared variables never need initialization.
ASSERT(!(mode == VAR && initialization_flag == kNeedsInitialization));
}
diff --git a/src/variables.h b/src/variables.h
index bb35ee8..39451d5 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -131,7 +131,7 @@
// True if the variable is named eval and not known to be shadowed.
bool is_possibly_eval(Isolate* isolate) const {
- return IsVariable(isolate->factory()->eval_symbol());
+ return IsVariable(isolate->factory()->eval_string());
}
Variable* local_if_not_shadowed() const {
diff --git a/src/version.cc b/src/version.cc
index 7a973c1..f448e3e 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 17
-#define BUILD_NUMBER 6
+#define BUILD_NUMBER 7
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 52c81e2..144962b 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -389,6 +389,10 @@
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
__ j(above_equal, &exit);
+ // Symbols are "objects".
+ __ CmpInstanceType(rcx, SYMBOL_TYPE);
+ __ j(equal, &exit);
+
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
@@ -523,6 +527,10 @@
// Invoke the code.
if (is_construct) {
+ // No type feedback cell is available
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->factory()->undefined_value());
+ __ Move(rbx, undefined_sentinel);
// Expects rdi to hold function pointer.
CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ CallStub(&stub);
@@ -1503,30 +1511,62 @@
// -- rsp[0] : return address
// -- rsp[8] : last argument
// -----------------------------------
- Label generic_constructor;
-
if (FLAG_debug_code) {
// The array construct code is only set for the builtin and internal
// Array functions which always have a map.
+
// Initial map for the builtin Array function should be a map.
- __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
+ __ movq(rcx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi.
STATIC_ASSERT(kSmiTag == 0);
- Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
+ Condition not_smi = NegateCondition(masm->CheckSmi(rcx));
__ Check(not_smi, "Unexpected initial map for Array function");
- __ CmpObjectType(rbx, MAP_TYPE, rcx);
+ __ CmpObjectType(rcx, MAP_TYPE, rcx);
__ Check(equal, "Unexpected initial map for Array function");
+
+ if (FLAG_optimize_constructed_arrays) {
+ // We should either have undefined in ebx or a valid jsglobalpropertycell
+ Label okay_here;
+ Handle<Object> undefined_sentinel(
+ masm->isolate()->factory()->undefined_value());
+ Handle<Map> global_property_cell_map(
+ masm->isolate()->heap()->global_property_cell_map());
+ __ Cmp(rbx, undefined_sentinel);
+ __ j(equal, &okay_here);
+ __ Cmp(FieldOperand(rbx, 0), global_property_cell_map);
+ __ Assert(equal, "Expected property cell in register rbx");
+ __ bind(&okay_here);
+ }
}
- // Run the native code for the Array function called as constructor.
- ArrayNativeCode(masm, &generic_constructor);
+ if (FLAG_optimize_constructed_arrays) {
+ Label not_zero_case, not_one_case;
+ __ testq(rax, rax);
+ __ j(not_zero, ¬_zero_case);
+ ArrayNoArgumentConstructorStub no_argument_stub;
+ __ TailCallStub(&no_argument_stub);
- // Jump to the generic construct code in case the specialized code cannot
- // handle the construction.
- __ bind(&generic_constructor);
- Handle<Code> generic_construct_stub =
- masm->isolate()->builtins()->JSConstructStubGeneric();
- __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ __ bind(¬_zero_case);
+ __ cmpq(rax, Immediate(1));
+ __ j(greater, ¬_one_case);
+ ArraySingleArgumentConstructorStub single_argument_stub;
+ __ TailCallStub(&single_argument_stub);
+
+ __ bind(¬_one_case);
+ ArrayNArgumentsConstructorStub n_argument_stub;
+ __ TailCallStub(&n_argument_stub);
+ } else {
+ Label generic_constructor;
+ // Run the native code for the Array function called as constructor.
+ ArrayNativeCode(masm, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
+ __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+ }
}
@@ -1639,7 +1679,7 @@
// Load the empty string into rbx, remove the receiver from the
// stack, and jump back to the case where the argument is a string.
__ bind(&no_arguments);
- __ LoadRoot(rbx, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(rbx, Heap::kempty_stringRootIndex);
__ pop(rcx);
__ lea(rsp, Operand(rsp, kPointerSize));
__ push(rcx);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 2079978..6aa8903 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -73,6 +73,44 @@
}
+static void InitializeArrayConstructorDescriptor(Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ // register state
+ // rdi -- constructor function
+ // rbx -- type info cell with elements kind
+ // rax -- number of arguments to the constructor function
+ static Register registers[] = { rdi, rbx };
+ descriptor->register_param_count_ = 2;
+ // stack param count needs (constructor pointer, and single argument)
+ descriptor->stack_parameter_count_ = &rax;
+ descriptor->register_params_ = registers;
+ descriptor->extra_expression_stack_count_ = 1;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(ArrayConstructor_StubFailure);
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeArrayConstructorDescriptor(isolate, descriptor);
+}
+
+
#define __ ACCESS_MASM(masm)
void ToNumberStub::Generate(MacroAssembler* masm) {
@@ -2350,7 +2388,7 @@
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- __ Cmp(rax, masm->isolate()->factory()->length_symbol());
+ __ Cmp(rax, masm->isolate()->factory()->length_string());
receiver = rdx;
} else {
ASSERT(kind() == Code::LOAD_IC);
@@ -2377,7 +2415,7 @@
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- __ Cmp(rax, masm->isolate()->factory()->prototype_symbol());
+ __ Cmp(rax, masm->isolate()->factory()->prototype_string());
receiver = rdx;
} else {
ASSERT(kind() == Code::LOAD_IC);
@@ -2404,7 +2442,7 @@
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
- __ Cmp(rax, masm->isolate()->factory()->length_symbol());
+ __ Cmp(rax, masm->isolate()->factory()->length_string());
receiver = rdx;
} else {
ASSERT(kind() == Code::LOAD_IC);
@@ -2442,7 +2480,7 @@
Register value = rax;
Register scratch = rbx;
if (kind() == Code::KEYED_STORE_IC) {
- __ Cmp(rcx, masm->isolate()->factory()->length_symbol());
+ __ Cmp(rcx, masm->isolate()->factory()->length_string());
}
// Check that the receiver isn't a smi.
@@ -2485,6 +2523,12 @@
}
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, rax, reg_, inobject_, index_);
+ __ ret(0);
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in rdx and the parameter count is in rax.
@@ -3014,7 +3058,7 @@
// (4) Cons string. Check that it's flat.
// Replace subject with first string and reload instance type.
__ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
- Heap::kEmptyStringRootIndex);
+ Heap::kempty_stringRootIndex);
__ j(not_equal, &runtime);
__ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
__ bind(&check_underlying);
@@ -3557,24 +3601,24 @@
__ CompareMap(input, masm->isolate()->factory()->heap_number_map(), NULL);
__ j(not_equal, fail);
}
- // We could be strict about symbol/string here, but as long as
+ // We could be strict about internalized/non-internalized here, but as long as
// hydrogen doesn't care, the stub doesn't have to care either.
__ bind(&ok);
}
-static void BranchIfNonSymbol(MacroAssembler* masm,
- Label* label,
- Register object,
- Register scratch) {
+static void BranchIfNotInternalizedString(MacroAssembler* masm,
+ Label* label,
+ Register object,
+ Register scratch) {
__ JumpIfSmi(object, label);
__ movq(scratch, FieldOperand(object, HeapObject::kMapOffset));
__ movzxbq(scratch,
FieldOperand(scratch, Map::kInstanceTypeOffset));
- // Ensure that no non-strings have the symbol bit set.
- STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask);
- STATIC_ASSERT(kSymbolTag != 0);
- __ testb(scratch, Immediate(kIsSymbolMask));
+ // Ensure that no non-strings have the internalized bit set.
+ STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask);
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ testb(scratch, Immediate(kIsInternalizedMask));
__ j(zero, label);
}
@@ -3742,15 +3786,17 @@
// The number comparison code did not provide a valid result.
__ bind(&non_number_comparison);
- // Fast negative check for symbol-to-symbol equality.
+ // Fast negative check for internalized-to-internalized equality.
Label check_for_strings;
if (cc == equal) {
- BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
- BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);
+ BranchIfNotInternalizedString(
+ masm, &check_for_strings, rax, kScratchRegister);
+ BranchIfNotInternalizedString(
+ masm, &check_for_strings, rdx, kScratchRegister);
- // We've already checked for object identity, so if both operands
- // are symbols they aren't equal. Register eax (not rax) already holds a
- // non-zero value, which indicates not equal, so just return.
+ // We've already checked for object identity, so if both operands are
+ // internalized strings they aren't equal. Register eax (not rax) already
+ // holds a non-zero value, which indicates not equal, so just return.
__ ret(0);
}
@@ -3850,12 +3896,13 @@
}
-static void GenerateRecordCallTarget(MacroAssembler* masm) {
+static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// rbx : cache cell for call target
// rdi : the function to call
+ ASSERT(!FLAG_optimize_constructed_arrays);
Isolate* isolate = masm->isolate();
Label initialize, done;
@@ -3888,6 +3935,79 @@
}
+static void GenerateRecordCallTarget(MacroAssembler* masm) {
+ // Cache the called function in a global property cell. Cache states
+ // are uninitialized, monomorphic (indicated by a JSFunction), and
+ // megamorphic.
+ // rbx : cache cell for call target
+ // rdi : the function to call
+ ASSERT(FLAG_optimize_constructed_arrays);
+ Isolate* isolate = masm->isolate();
+ Label initialize, done, miss, megamorphic, not_array_function;
+
+ // Load the cache state into rcx.
+ __ movq(rcx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
+
+ // A monomorphic cache hit or an already megamorphic state: invoke the
+ // function without changing the state.
+ __ cmpq(rcx, rdi);
+ __ j(equal, &done);
+ __ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate));
+ __ j(equal, &done);
+
+ // Special handling of the Array() function, which caches not only the
+ // monomorphic Array function but the initial ElementsKind with special
+ // sentinels
+ Handle<Object> terminal_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(isolate,
+ LAST_FAST_ELEMENTS_KIND);
+ __ Cmp(rcx, terminal_kind_sentinel);
+ __ j(not_equal, &miss);
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(rcx);
+ __ cmpq(rdi, rcx);
+ __ j(not_equal, &megamorphic);
+ __ jmp(&done);
+
+ __ bind(&miss);
+
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+ // megamorphic.
+ __ Cmp(rcx, TypeFeedbackCells::UninitializedSentinel(isolate));
+ __ j(equal, &initialize);
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no
+ // write-barrier is needed.
+ __ bind(&megamorphic);
+ __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
+ TypeFeedbackCells::MegamorphicSentinel(isolate));
+ __ jmp(&done, Label::kNear);
+
+ // An uninitialized cache is patched with the function or sentinel to
+ // indicate the ElementsKind if function is the Array constructor.
+ __ bind(&initialize);
+ // Make sure the function is the Array() function
+ __ LoadArrayFunction(rcx);
+ __ cmpq(rdi, rcx);
+ __ j(not_equal, ¬_array_function);
+
+ // The target function is the Array constructor, install a sentinel value in
+ // the constructor's type info cell that will track the initial ElementsKind
+ // that should be used for the array when its constructed.
+ Handle<Object> initial_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(isolate,
+ GetInitialFastElementsKind());
+ __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
+ initial_kind_sentinel);
+ __ jmp(&done);
+
+ __ bind(¬_array_function);
+ __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rdi);
+ // No need for a write barrier here - cells are rescanned.
+
+ __ bind(&done);
+}
+
+
void CallFunctionStub::Generate(MacroAssembler* masm) {
// rbx : cache cell for call target
// rdi : the function to call
@@ -3919,7 +4039,11 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Fast-case: Just invoke the function.
@@ -3994,14 +4118,20 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTarget(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Jump to the function-specific construct stub.
- __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
- __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset));
- __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize));
- __ jmp(rbx);
+ Register jmp_reg = FLAG_optimize_constructed_arrays ? rcx : rbx;
+ __ movq(jmp_reg, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ movq(jmp_reg, FieldOperand(jmp_reg,
+ SharedFunctionInfo::kConstructStubOffset));
+ __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize));
+ __ jmp(jmp_reg);
// rdi: called object
// rax: number of arguments
@@ -4817,8 +4947,8 @@
// Look at the length of the result of adding the two strings.
STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
__ SmiAdd(rbx, rbx, rcx);
- // Use the symbol table when adding two one character strings, as it
- // helps later optimizations to return a symbol here.
+ // Use the string table when adding two one character strings, as it
+ // helps later optimizations to return an internalized string here.
__ SmiCompare(rbx, Smi::FromInt(2));
__ j(not_equal, &longer_than_two);
@@ -4830,10 +4960,10 @@
__ movzxbq(rbx, FieldOperand(rax, SeqOneByteString::kHeaderSize));
__ movzxbq(rcx, FieldOperand(rdx, SeqOneByteString::kHeaderSize));
- // Try to lookup two character string in symbol table. If it is not found
+ // Try to lookup two character string in string table. If it is not found
// just allocate a new one.
Label make_two_character_string, make_flat_ascii_string;
- StringHelper::GenerateTwoCharacterSymbolTableProbe(
+ StringHelper::GenerateTwoCharacterStringTableProbe(
masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
__ IncrementCounter(counters->string_add_native(), 1);
__ ret(2 * kPointerSize);
@@ -5132,7 +5262,7 @@
__ bind(&done);
}
-void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
@@ -5144,7 +5274,7 @@
Register scratch = scratch3;
// Make sure that both characters are not digits as such strings has a
- // different hash algorithm. Don't try to look for these in the symbol table.
+ // different hash algorithm. Don't try to look for these in the string table.
Label not_array_index;
__ leal(scratch, Operand(c1, -'0'));
__ cmpl(scratch, Immediate(static_cast<int>('9' - '0')));
@@ -5168,14 +5298,14 @@
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string.
- // Load the symbol table.
- Register symbol_table = c2;
- __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
+ // Load the string table.
+ Register string_table = c2;
+ __ LoadRoot(string_table, Heap::kStringTableRootIndex);
- // Calculate capacity mask from the symbol table capacity.
+ // Calculate capacity mask from the string table capacity.
Register mask = scratch2;
__ SmiToInteger32(mask,
- FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
+ FieldOperand(string_table, StringTable::kCapacityOffset));
__ decl(mask);
Register map = scratch4;
@@ -5183,31 +5313,31 @@
// Registers
// chars: two character string, char 1 in byte 0 and char 2 in byte 1.
// hash: hash of two character string (32-bit int)
- // symbol_table: symbol table
+ // string_table: string table
// mask: capacity mask (32-bit int)
// map: -
// scratch: -
- // Perform a number of probes in the symbol table.
+ // Perform a number of probes in the string table.
static const int kProbes = 4;
- Label found_in_symbol_table;
+ Label found_in_string_table;
Label next_probe[kProbes];
Register candidate = scratch; // Scratch register contains candidate.
for (int i = 0; i < kProbes; i++) {
- // Calculate entry in symbol table.
+ // Calculate entry in string table.
__ movl(scratch, hash);
if (i > 0) {
- __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
+ __ addl(scratch, Immediate(StringTable::GetProbeOffset(i)));
}
__ andl(scratch, mask);
- // Load the entry from the symbol table.
- STATIC_ASSERT(SymbolTable::kEntrySize == 1);
+ // Load the entry from the string table.
+ STATIC_ASSERT(StringTable::kEntrySize == 1);
__ movq(candidate,
- FieldOperand(symbol_table,
+ FieldOperand(string_table,
scratch,
times_pointer_size,
- SymbolTable::kElementsStartOffset));
+ StringTable::kElementsStartOffset));
// If entry is undefined no string with this hash can be found.
Label is_string;
@@ -5220,7 +5350,7 @@
if (FLAG_debug_code) {
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ cmpq(kScratchRegister, candidate);
- __ Assert(equal, "oddball in symbol table is not undefined or the hole");
+ __ Assert(equal, "oddball in string table is not undefined or the hole");
}
__ jmp(&next_probe[i]);
@@ -5244,7 +5374,7 @@
__ movl(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize));
__ andl(temp, Immediate(0x0000ffff));
__ cmpl(chars, temp);
- __ j(equal, &found_in_symbol_table);
+ __ j(equal, &found_in_string_table);
__ bind(&next_probe[i]);
}
@@ -5253,7 +5383,7 @@
// Scratch register contains result when we fall through to here.
Register result = candidate;
- __ bind(&found_in_symbol_table);
+ __ bind(&found_in_string_table);
if (!result.is(rax)) {
__ movq(rax, result);
}
@@ -5384,7 +5514,7 @@
// Cons string. Check whether it is flat, then fetch first part.
// Flat cons strings have an empty second part.
__ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset),
- Heap::kEmptyStringRootIndex);
+ Heap::kempty_stringRootIndex);
__ j(not_equal, &runtime);
__ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset));
// Update instance type.
@@ -5831,8 +5961,8 @@
}
-void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
- ASSERT(state_ == CompareIC::SYMBOL);
+void ICCompareStub::GenerateInternalizedStrings(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::INTERNALIZED_STRING);
ASSERT(GetCondition() == equal);
// Registers containing left and right operands respectively.
@@ -5846,17 +5976,72 @@
Condition cond = masm->CheckEitherSmi(left, right, tmp1);
__ j(cond, &miss, Label::kNear);
- // Check that both operands are symbols.
+ // Check that both operands are internalized strings.
__ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset));
__ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset));
__ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp2);
- __ testb(tmp1, Immediate(kIsSymbolMask));
+ __ testb(tmp1, Immediate(kIsInternalizedMask));
__ j(zero, &miss, Label::kNear);
- // Symbols are compared by identity.
+ // Internalized strings are compared by identity.
+ Label done;
+ __ cmpq(left, right);
+ // Make sure rax is non-zero. At this point input operands are
+ // guaranteed to be non-zero.
+ ASSERT(right.is(rax));
+ __ j(not_equal, &done, Label::kNear);
+ STATIC_ASSERT(EQUAL == 0);
+ STATIC_ASSERT(kSmiTag == 0);
+ __ Move(rax, Smi::FromInt(EQUAL));
+ __ bind(&done);
+ __ ret(0);
+
+ __ bind(&miss);
+ GenerateMiss(masm);
+}
+
+
+void ICCompareStub::GenerateUniqueNames(MacroAssembler* masm) {
+ ASSERT(state_ == CompareIC::UNIQUE_NAME);
+ ASSERT(GetCondition() == equal);
+
+ // Registers containing left and right operands respectively.
+ Register left = rdx;
+ Register right = rax;
+ Register tmp1 = rcx;
+ Register tmp2 = rbx;
+
+ // Check that both operands are heap objects.
+ Label miss;
+ Condition cond = masm->CheckEitherSmi(left, right, tmp1);
+ __ j(cond, &miss, Label::kNear);
+
+ // Check that both operands are unique names. This leaves the instance
+ // types loaded in tmp1 and tmp2.
+ STATIC_ASSERT(kInternalizedTag != 0);
+ __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset));
+ __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset));
+ __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
+ __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
+
+ Label succeed1;
+ __ testb(tmp1, Immediate(kIsInternalizedMask));
+ __ j(not_zero, &succeed1, Label::kNear);
+ __ cmpb(tmp1, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
+ __ j(not_equal, &miss, Label::kNear);
+ __ bind(&succeed1);
+
+ Label succeed2;
+ __ testb(tmp2, Immediate(kIsInternalizedMask));
+ __ j(not_zero, &succeed2, Label::kNear);
+ __ cmpb(tmp2, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
+ __ j(not_equal, &miss, Label::kNear);
+ __ bind(&succeed2);
+
+ // Unique names are compared by identity.
Label done;
__ cmpq(left, right);
// Make sure rax is non-zero. At this point input operands are
@@ -5915,13 +6100,13 @@
// Handle not identical strings.
__ bind(¬_same);
- // Check that both strings are symbols. If they are, we're done
+ // Check that both strings are internalized strings. If they are, we're done
// because we already know they are not identical.
if (equality) {
Label do_compare;
- STATIC_ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kInternalizedTag != 0);
__ and_(tmp1, tmp2);
- __ testb(tmp1, Immediate(kIsSymbolMask));
+ __ testb(tmp1, Immediate(kIsInternalizedMask));
__ j(zero, &do_compare, Label::kNear);
// Make sure rax is non-zero. At this point input operands are
// guaranteed to be non-zero.
@@ -6069,10 +6254,10 @@
__ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex);
__ j(equal, &the_hole, Label::kNear);
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
__ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- Immediate(kIsSymbolMask));
+ Immediate(kIsInternalizedMask));
__ j(zero, miss);
__ bind(&the_hole);
@@ -6201,14 +6386,14 @@
__ j(equal, &in_dictionary);
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
- // If we hit a non symbol key during negative lookup
+ // If we hit a non internalized string key during negative lookup
// we have to bailout as this key might be equal to the
// key we are looking for.
- // Check if the entry name is not a symbol.
+ // Check if the entry name is not an internalized string.
__ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
__ testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- Immediate(kIsSymbolMask));
+ Immediate(kIsInternalizedMask));
__ j(zero, &maybe_in_dictionary);
}
}
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index 83861a2..675e95b 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -172,11 +172,11 @@
bool ascii);
- // Probe the symbol table for a two character string. If the string is
+ // Probe the string table for a two character string. If the string is
// not found by probing a jump to the label not_found is performed. This jump
- // does not guarantee that the string is not in the symbol table. If the
+ // does not guarantee that the string is not in the string table. If the
// string is found the code falls through with the string in register rax.
- static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm,
+ static void GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
Register c1,
Register c2,
Register scratch1,
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 4798b2a..fa8b44a 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -554,7 +554,7 @@
// the string.
__ bind(&cons_string);
__ CompareRoot(FieldOperand(string, ConsString::kSecondOffset),
- Heap::kEmptyStringRootIndex);
+ Heap::kempty_stringRootIndex);
__ j(not_equal, call_runtime);
__ movq(string, FieldOperand(string, ConsString::kFirstOffset));
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 09973cb..8e776f9 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -348,107 +348,6 @@
}
-void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
- int frame_index) {
- JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
- unsigned height = iterator->Next();
- unsigned height_in_bytes = height * kPointerSize;
- if (trace_) {
- PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
- }
-
- unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, function);
- output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
-
- // Arguments adaptor can not be topmost or bottommost.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous
- // frame's top and this frame's size.
- intptr_t top_address;
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- // Compute the incoming parameter translation.
- int parameter_count = height;
- unsigned output_offset = output_frame_size;
- for (int i = 0; i < parameter_count; ++i) {
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // A marker value is used in place of the context.
- output_offset -= kPointerSize;
- intptr_t context = reinterpret_cast<intptr_t>(
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- output_frame->SetFrameSlot(output_offset, context);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; context (adaptor sentinel)\n",
- top_address + output_offset, output_offset, context);
- }
-
- // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(function);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; function\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Number of incoming arguments.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; argc (%d)\n",
- top_address + output_offset, output_offset, value, height - 1);
- }
-
- ASSERT(0 == output_offset);
-
- Builtins* builtins = isolate_->builtins();
- Code* adaptor_trampoline =
- builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
- intptr_t pc_value = reinterpret_cast<intptr_t>(
- adaptor_trampoline->instruction_start() +
- isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
- output_frame->SetPc(pc_value);
-}
-
-
void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
int frame_index) {
//
@@ -756,125 +655,6 @@
}
-void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
- int frame_index,
- bool is_setter_stub_frame) {
- JSFunction* accessor = JSFunction::cast(ComputeLiteral(iterator->Next()));
- // The receiver (and the implicit return value, if any) are expected in
- // registers by the LoadIC/StoreIC, so they don't belong to the output stack
- // frame. This means that we have to use a height of 0.
- unsigned height = 0;
- unsigned height_in_bytes = height * kPointerSize;
- const char* kind = is_setter_stub_frame ? "setter" : "getter";
- if (trace_) {
- PrintF(" translating %s stub => height=%u\n", kind, height_in_bytes);
- }
-
- // We need 1 stack entry for the return address + 4 stack entries from
- // StackFrame::INTERNAL (FP, context, frame type, code object, see
- // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
- // entry for the implicit return value, see
- // StoreStubCompiler::CompileStoreViaSetter.
- unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
- unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
- // Allocate and store the output frame description.
- FrameDescription* output_frame =
- new(output_frame_size) FrameDescription(output_frame_size, accessor);
- output_frame->SetFrameType(StackFrame::INTERNAL);
-
- // A frame for an accessor stub can not be the topmost or bottommost one.
- ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
- ASSERT(output_[frame_index] == NULL);
- output_[frame_index] = output_frame;
-
- // The top address of the frame is computed from the previous frame's top and
- // this frame's size.
- intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- output_frame->SetTop(top_address);
-
- unsigned output_offset = output_frame_size;
-
- // Read caller's PC from the previous frame.
- output_offset -= kPointerSize;
- intptr_t callers_pc = output_[frame_index - 1]->GetPc();
- output_frame->SetFrameSlot(output_offset, callers_pc);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's pc\n",
- top_address + output_offset, output_offset, callers_pc);
- }
-
- // Read caller's FP from the previous frame, and set this frame's FP.
- output_offset -= kPointerSize;
- intptr_t value = output_[frame_index - 1]->GetFp();
- output_frame->SetFrameSlot(output_offset, value);
- intptr_t fp_value = top_address + output_offset;
- output_frame->SetFp(fp_value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; caller's fp\n",
- fp_value, output_offset, value);
- }
-
- // The context can be gotten from the previous frame.
- output_offset -= kPointerSize;
- value = output_[frame_index - 1]->GetContext();
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; context\n",
- top_address + output_offset, output_offset, value);
- }
-
- // A marker value is used in place of the function.
- output_offset -= kPointerSize;
- value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL));
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; function (%s sentinel)\n",
- top_address + output_offset, output_offset, value, kind);
- }
-
- // Get Code object from accessor stub.
- output_offset -= kPointerSize;
- Builtins::Name name = is_setter_stub_frame ?
- Builtins::kStoreIC_Setter_ForDeopt :
- Builtins::kLoadIC_Getter_ForDeopt;
- Code* accessor_stub = isolate_->builtins()->builtin(name);
- value = reinterpret_cast<intptr_t>(accessor_stub);
- output_frame->SetFrameSlot(output_offset, value);
- if (trace_) {
- PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
- " ; code object\n",
- top_address + output_offset, output_offset, value);
- }
-
- // Skip receiver.
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- iterator->Skip(Translation::NumberOfOperandsFor(opcode));
-
- if (is_setter_stub_frame) {
- // The implicit return value was part of the artificial setter stub
- // environment.
- output_offset -= kPointerSize;
- DoTranslateCommand(iterator, frame_index, output_offset);
- }
-
- ASSERT(0 == output_offset);
-
- Smi* offset = is_setter_stub_frame ?
- isolate_->heap()->setter_stub_deopt_pc_offset() :
- isolate_->heap()->getter_stub_deopt_pc_offset();
- intptr_t pc = reinterpret_cast<intptr_t>(
- accessor_stub->instruction_start() + offset->value());
- output_frame->SetPc(pc);
-}
-
-
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
int frame_index) {
BailoutId node_id = BailoutId(iterator->Next());
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 5a0106d..fa1d948 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -1611,7 +1611,7 @@
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
- if (key->handle()->IsSymbol()) {
+ if (key->handle()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
__ Move(rcx, key->handle());
@@ -2612,7 +2612,7 @@
__ CompareRoot(rcx, Heap::kHashTableMapRootIndex);
__ j(equal, if_false);
- // Look for valueOf symbol in the descriptor array, and indicate false if
+ // Look for valueOf string in the descriptor array, and indicate false if
// found. Since we omit an enumeration index check, if it is added via a
// transition that shares its descriptor array, this is a false positive.
Label entry, loop, done;
@@ -2634,11 +2634,11 @@
// Calculate location of the first key name.
__ addq(rbx, Immediate(DescriptorArray::kFirstOffset));
// Loop through all the keys in the descriptor array. If one of these is the
- // symbol valueOf the result is false.
+ // internalized string "valueOf" the result is false.
__ jmp(&entry);
__ bind(&loop);
__ movq(rdx, FieldOperand(rbx, 0));
- __ Cmp(rdx, FACTORY->value_of_symbol());
+ __ Cmp(rdx, FACTORY->value_of_string());
__ j(equal, if_false);
__ addq(rbx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
@@ -2671,6 +2671,28 @@
}
+void FullCodeGenerator::EmitIsSymbol(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 1);
+
+ VisitForAccumulatorValue(args->at(0));
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ context()->PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ __ JumpIfSmi(rax, if_false);
+ __ CmpObjectType(rax, SYMBOL_TYPE, rbx);
+ PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
+ context()->Plug(if_true, if_false);
+}
+
+
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
@@ -2873,12 +2895,12 @@
// Functions have class 'Function'.
__ bind(&function);
- __ Move(rax, isolate()->factory()->function_class_symbol());
+ __ Move(rax, isolate()->factory()->function_class_string());
__ jmp(&done);
// Objects with a non-function constructor have class 'Object'.
__ bind(&non_function_constructor);
- __ Move(rax, isolate()->factory()->Object_symbol());
+ __ Move(rax, isolate()->factory()->Object_string());
__ jmp(&done);
// Non-JS objects have class null.
@@ -3238,7 +3260,7 @@
__ bind(&index_out_of_range);
// When the index is out of range, the spec requires us to return
// the empty string.
- __ LoadRoot(result, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(result, Heap::kempty_stringRootIndex);
__ jmp(&done);
__ bind(&need_conversion);
@@ -3564,7 +3586,7 @@
__ movq(array_length, FieldOperand(array, JSArray::kLengthOffset));
__ SmiCompare(array_length, Smi::FromInt(0));
__ j(not_zero, &non_trivial_array);
- __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(rax, Heap::kempty_stringRootIndex);
__ jmp(&return_result);
// Save the array length on the stack.
@@ -4228,12 +4250,12 @@
}
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
- if (check->Equals(isolate()->heap()->number_symbol())) {
+ if (check->Equals(isolate()->heap()->number_string())) {
__ JumpIfSmi(rax, if_true);
__ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
__ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->string_symbol())) {
+ } else if (check->Equals(isolate()->heap()->string_string())) {
__ JumpIfSmi(rax, if_false);
// Check for undetectable objects => false.
__ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
@@ -4241,16 +4263,16 @@
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(zero, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
+ } else if (check->Equals(isolate()->heap()->boolean_string())) {
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
__ CompareRoot(rax, Heap::kFalseValueRootIndex);
Split(equal, if_true, if_false, fall_through);
} else if (FLAG_harmony_typeof &&
- check->Equals(isolate()->heap()->null_symbol())) {
+ check->Equals(isolate()->heap()->null_string())) {
__ CompareRoot(rax, Heap::kNullValueRootIndex);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
+ } else if (check->Equals(isolate()->heap()->undefined_string())) {
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, if_true);
__ JumpIfSmi(rax, if_false);
@@ -4259,19 +4281,23 @@
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->function_symbol())) {
+ } else if (check->Equals(isolate()->heap()->function_string())) {
__ JumpIfSmi(rax, if_false);
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
__ j(equal, if_true);
__ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
Split(equal, if_true, if_false, fall_through);
- } else if (check->Equals(isolate()->heap()->object_symbol())) {
+ } else if (check->Equals(isolate()->heap()->object_string())) {
__ JumpIfSmi(rax, if_false);
if (!FLAG_harmony_typeof) {
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ j(equal, if_true);
}
+ if (FLAG_harmony_symbols) {
+ __ CmpObjectType(rax, SYMBOL_TYPE, rdx);
+ __ j(equal, if_true);
+ }
__ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
__ j(below, if_false);
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 3911438..15423e4 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -101,8 +101,8 @@
// Helper function used to load a property from a dictionary backing storage.
// This function may return false negatives, so miss_label
// must always call a backup property load that is complete.
-// This function is safe to call if name is not a symbol, and will jump to
-// the miss_label in that case.
+// This function is safe to call if name is not an internalized string,
+// and will jump to the miss_label in that case.
// The generated code assumes that the receiver has slow properties,
// is not a global object and does not have interceptors.
static void GenerateDictionaryLoad(MacroAssembler* masm,
@@ -160,8 +160,8 @@
// storage. This function may fail to store a property even though it
// is in the dictionary, so code at miss_label must always call a
// backup property store that is complete. This function is safe to
-// call if name is not a symbol, and will jump to the miss_label in
-// that case. The generated code assumes that the receiver has slow
+// call if name is not an internalized string, and will jump to the miss_label
+// in that case. The generated code assumes that the receiver has slow
// properties, is not a global object and does not have interceptors.
static void GenerateDictionaryStore(MacroAssembler* masm,
Label* miss_label,
@@ -313,31 +313,31 @@
}
-// Checks whether a key is an array index string or a symbol string.
-// Falls through if the key is a symbol.
+// Checks whether a key is an array index string or an internalized string.
+// Falls through if the key is an internalized string.
static void GenerateKeyStringCheck(MacroAssembler* masm,
Register key,
Register map,
Register hash,
Label* index_string,
- Label* not_symbol) {
+ Label* not_internalized) {
// Register use:
// key - holds the key and is unchanged. Assumed to be non-smi.
// Scratch registers:
// map - used to hold the map of the key.
// hash - used to hold the hash of the key.
__ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
- __ j(above_equal, not_symbol);
+ __ j(above_equal, not_internalized);
// Is the string an array index, with cached numeric value?
__ movl(hash, FieldOperand(key, String::kHashFieldOffset));
__ testl(hash, Immediate(String::kContainsCachedArrayIndexMask));
__ j(zero, index_string); // The value in hash is used at jump target.
- // Is the string a symbol?
- STATIC_ASSERT(kSymbolTag != 0);
+ // Is the string internalized?
+ STATIC_ASSERT(kInternalizedTag != 0);
__ testb(FieldOperand(map, Map::kInstanceTypeOffset),
- Immediate(kIsSymbolMask));
- __ j(zero, not_symbol);
+ Immediate(kIsInternalizedMask));
+ __ j(zero, not_internalized);
}
@@ -421,7 +421,7 @@
int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
__ and_(rcx, Immediate(mask));
- // Load the key (consisting of map and symbol) from the cache and
+ // Load the key (consisting of map and internalized string) from the cache and
// check for match.
Label load_in_object_property;
static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
@@ -1075,7 +1075,7 @@
__ bind(&check_string);
GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call);
- // The key is known to be a symbol.
+ // The key is known to be an internalized string.
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
@@ -1102,7 +1102,7 @@
__ bind(&slow_call);
// This branch is taken if:
// - the receiver requires boxing or access check,
- // - the key is neither smi nor symbol,
+ // - the key is neither smi nor internalized string,
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub
// that will get fetched next time.
@@ -1321,9 +1321,10 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
- rdx);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, rax, rcx, rbx, rdx);
// Cache miss: Jump to runtime.
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 3722f14..de47f6f 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2342,13 +2342,13 @@
__ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
__ movq(temp, FieldOperand(temp,
SharedFunctionInfo::kInstanceClassNameOffset));
- // The class name we are testing against is a symbol because it's a literal.
- // The name in the constructor is a symbol because of the way the context is
- // booted. This routine isn't expected to work for random API-created
+ // The class name we are testing against is internalized since it's a literal.
+ // The name in the constructor is internalized because of the way the context
+ // is booted. This routine isn't expected to work for random API-created
// classes and it doesn't have to because you can't access it with natives
- // syntax. Since both sides are symbols it is sufficient to use an identity
- // comparison.
- ASSERT(class_name->IsSymbol());
+ // syntax. Since both sides are internalized it is sufficient to use an
+ // identity comparison.
+ ASSERT(class_name->IsInternalizedString());
__ Cmp(temp, class_name);
// End with the answer in the z flag.
}
@@ -3534,69 +3534,57 @@
static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
- bool minus_zero_check =
- instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
-
+ Label done, round_to_zero, below_one_half, do_not_compensate, restore;
__ movq(kScratchRegister, one_half, RelocInfo::NONE64);
__ movq(xmm_scratch, kScratchRegister);
+ __ ucomisd(xmm_scratch, input_reg);
+ __ j(above, &below_one_half);
- if (CpuFeatures::IsSupported(SSE4_1) && !minus_zero_check) {
- CpuFeatures::Scope scope(SSE4_1);
- __ addsd(xmm_scratch, input_reg);
- __ roundsd(xmm_scratch, xmm_scratch, Assembler::kRoundDown);
- __ cvttsd2si(output_reg, xmm_scratch);
- // Overflow is signalled with minint.
- __ cmpl(output_reg, Immediate(0x80000000));
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
- } else {
- Label done, round_to_zero, below_one_half, do_not_compensate;
- __ ucomisd(xmm_scratch, input_reg);
- __ j(above, &below_one_half);
+ // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
+ __ addsd(xmm_scratch, input_reg);
+ __ cvttsd2si(output_reg, xmm_scratch);
+ // Overflow is signalled with minint.
+ __ cmpl(output_reg, Immediate(0x80000000));
+ __ RecordComment("D2I conversion overflow");
+ DeoptimizeIf(equal, instr->environment());
+ __ jmp(&done);
- // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
- __ addsd(xmm_scratch, input_reg);
- __ cvttsd2si(output_reg, xmm_scratch);
- // Overflow is signalled with minint.
- __ cmpl(output_reg, Immediate(0x80000000));
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
- __ jmp(&done);
+ __ bind(&below_one_half);
+ __ movq(kScratchRegister, minus_one_half, RelocInfo::NONE64);
+ __ movq(xmm_scratch, kScratchRegister);
+ __ ucomisd(xmm_scratch, input_reg);
+ __ j(below_equal, &round_to_zero);
- __ bind(&below_one_half);
- __ movq(kScratchRegister, minus_one_half, RelocInfo::NONE64);
- __ movq(xmm_scratch, kScratchRegister);
- __ ucomisd(xmm_scratch, input_reg);
- __ j(below_equal, &round_to_zero);
+ // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
+ // compare and compensate.
+ __ movq(kScratchRegister, input_reg); // Back up input_reg.
+ __ subsd(input_reg, xmm_scratch);
+ __ cvttsd2si(output_reg, input_reg);
+ // Catch minint due to overflow, and to prevent overflow when compensating.
+ __ cmpl(output_reg, Immediate(0x80000000));
+ __ RecordComment("D2I conversion overflow");
+ DeoptimizeIf(equal, instr->environment());
- // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
- // compare and compensate.
- __ subsd(input_reg, xmm_scratch);
- __ cvttsd2si(output_reg, input_reg);
- // Catch minint due to overflow, and to prevent overflow when compensating.
- __ cmpl(output_reg, Immediate(0x80000000));
- __ RecordComment("D2I conversion overflow");
- DeoptimizeIf(equal, instr->environment());
+ __ cvtlsi2sd(xmm_scratch, output_reg);
+ __ ucomisd(input_reg, xmm_scratch);
+ __ j(equal, &restore, Label::kNear);
+ __ subl(output_reg, Immediate(1));
+ // No overflow because we already ruled out minint.
+ __ bind(&restore);
+ __ movq(input_reg, kScratchRegister); // Restore input_reg.
+ __ jmp(&done);
- __ cvtlsi2sd(xmm_scratch, output_reg);
- __ ucomisd(input_reg, xmm_scratch);
- __ j(equal, &done, Label::kNear);
- __ subl(output_reg, Immediate(1));
- // No overflow because we already ruled out minint.
- __ jmp(&done);
-
- __ bind(&round_to_zero);
- // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
- // we can ignore the difference between a result of -0 and +0.
- if (minus_zero_check) {
- __ movq(output_reg, input_reg);
- __ testq(output_reg, output_reg);
- __ RecordComment("Minus zero");
- DeoptimizeIf(negative, instr->environment());
- }
- __ Set(output_reg, 0);
- __ bind(&done);
+ __ bind(&round_to_zero);
+ // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
+ // we can ignore the difference between a result of -0 and +0.
+ if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ __ movq(output_reg, input_reg);
+ __ testq(output_reg, output_reg);
+ __ RecordComment("Minus zero");
+ DeoptimizeIf(negative, instr->environment());
}
+ __ Set(output_reg, 0);
+ __ bind(&done);
}
@@ -3925,12 +3913,30 @@
ASSERT(ToRegister(instr->constructor()).is(rdi));
ASSERT(ToRegister(instr->result()).is(rax));
- CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
__ Set(rax, instr->arity());
+ if (FLAG_optimize_constructed_arrays) {
+ // No cell in ebx for construct type feedback in optimized code
+ Handle<Object> undefined_value(isolate()->factory()->undefined_value());
+ __ Move(rbx, undefined_value);
+ }
+ CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
}
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+ ASSERT(ToRegister(instr->constructor()).is(rdi));
+ ASSERT(ToRegister(instr->result()).is(rax));
+ ASSERT(FLAG_optimize_constructed_arrays);
+
+ __ Set(rax, instr->arity());
+ __ Move(rbx, instr->hydrogen()->property_cell());
+ Handle<Code> array_construct_code =
+ isolate()->builtins()->ArrayConstructCode();
+ CallCode(array_construct_code, RelocInfo::CONSTRUCT_CALL, instr);
+}
+
+
void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
CallRuntime(instr->function(), instr->arity(), instr);
}
@@ -5503,14 +5509,14 @@
Register input,
Handle<String> type_name) {
Condition final_branch_condition = no_condition;
- if (type_name->Equals(heap()->number_symbol())) {
+ if (type_name->Equals(heap()->number_string())) {
__ JumpIfSmi(input, true_label);
__ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->string_symbol())) {
+ } else if (type_name->Equals(heap()->string_string())) {
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
__ j(above_equal, false_label);
@@ -5518,17 +5524,17 @@
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = zero;
- } else if (type_name->Equals(heap()->boolean_symbol())) {
+ } else if (type_name->Equals(heap()->boolean_string())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
__ CompareRoot(input, Heap::kFalseValueRootIndex);
final_branch_condition = equal;
- } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
+ } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
__ CompareRoot(input, Heap::kNullValueRootIndex);
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->undefined_symbol())) {
+ } else if (type_name->Equals(heap()->undefined_string())) {
__ CompareRoot(input, Heap::kUndefinedValueRootIndex);
__ j(equal, true_label);
__ JumpIfSmi(input, false_label);
@@ -5538,7 +5544,7 @@
Immediate(1 << Map::kIsUndetectable));
final_branch_condition = not_zero;
- } else if (type_name->Equals(heap()->function_symbol())) {
+ } else if (type_name->Equals(heap()->function_string())) {
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
__ JumpIfSmi(input, false_label);
__ CmpObjectType(input, JS_FUNCTION_TYPE, input);
@@ -5546,13 +5552,19 @@
__ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
final_branch_condition = equal;
- } else if (type_name->Equals(heap()->object_symbol())) {
+ } else if (type_name->Equals(heap()->object_string())) {
__ JumpIfSmi(input, false_label);
if (!FLAG_harmony_typeof) {
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, true_label);
}
- __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
+ if (FLAG_harmony_symbols) {
+ __ CmpObjectType(input, SYMBOL_TYPE, input);
+ __ j(equal, true_label);
+ __ CmpInstanceType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+ } else {
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
+ }
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 7d680ae..93ea6cf 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -357,6 +357,17 @@
}
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+ stream->Add("= ");
+ constructor()->PrintTo(stream);
+ stream->Add(" #%d / ", arity());
+ ASSERT(hydrogen()->property_cell()->value()->IsSmi());
+ ElementsKind kind = static_cast<ElementsKind>(
+ Smi::cast(hydrogen()->property_cell()->value())->value());
+ stream->Add(" (%s) ", ElementsKindToString(kind));
+}
+
+
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
arguments()->PrintTo(stream);
@@ -1084,16 +1095,7 @@
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
return DefineAsRegister(result);
} else {
- LOperand* input;
- if (op == kMathRound &&
- (!CpuFeatures::IsSupported(SSE4_1) ||
- instr->CheckFlag(HValue::kBailoutOnMinusZero))) {
- // Math.round implemented without roundsd. Input may be overwritten.
- ASSERT(instr->value()->representation().IsDouble());
- input = UseTempRegister(instr->value());
- } else {
- input = UseRegisterAtStart(instr->value());
- }
+ LOperand* input = UseRegisterAtStart(instr->value());
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
switch (op) {
case kMathAbs:
@@ -1149,6 +1151,15 @@
}
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+ ASSERT(FLAG_optimize_constructed_arrays);
+ LOperand* constructor = UseFixed(instr->constructor(), rdi);
+ argument_count_ -= instr->argument_count();
+ LCallNewArray* result = new(zone()) LCallNewArray(constructor);
+ return MarkAsCall(DefineFixed(result, rax), instr);
+}
+
+
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* function = UseFixed(instr->function(), rdi);
argument_count_ -= instr->argument_count();
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 0744ed5..2ee7668 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -68,6 +68,7 @@
V(CallKnownGlobal) \
V(CallNamed) \
V(CallNew) \
+ V(CallNewArray) \
V(CallRuntime) \
V(CallStub) \
V(CheckFunction) \
@@ -1748,6 +1749,23 @@
};
+class LCallNewArray: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LCallNewArray(LOperand* constructor) {
+ inputs_[0] = constructor;
+ }
+
+ LOperand* constructor() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+ DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
class LCallRuntime: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 807e90d..5f467e3 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -4269,6 +4269,15 @@
}
+void MacroAssembler::LoadArrayFunction(Register function) {
+ movq(function,
+ Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
+ movq(function, FieldOperand(function, GlobalObject::kGlobalContextOffset));
+ movq(function,
+ Operand(function, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
+
+
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map) {
// Load the initial map. The global functions all have initial maps.
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 35cc3f5..6753724 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1154,6 +1154,7 @@
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
+ void LoadArrayFunction(Register function);
// Load the initial map from the global function. The registers
// function and map can be the same.
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 4e440c5..c471569 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -110,14 +110,14 @@
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
-// Name must be a symbol and receiver must be a heap object.
+// Name must be an internalized string and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<String> name,
Register r0,
Register r1) {
- ASSERT(name->IsSymbol());
+ ASSERT(name->IsInternalizedString());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1);
__ IncrementCounter(counters->negative_lookups_miss(), 1);
@@ -351,23 +351,24 @@
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ movq(dst, FieldOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ movq(dst, FieldOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ movq(dst, FieldOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ movq(dst, FieldOperand(src, offset));
}
@@ -911,6 +912,11 @@
#define __ ACCESS_MASM((masm()))
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
@@ -919,7 +925,9 @@
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -949,8 +957,8 @@
if (!current->HasFastProperties() &&
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
- if (!name->IsSymbol()) {
- name = factory()->LookupSymbol(name);
+ if (!name->IsInternalizedString()) {
+ name = factory()->InternalizeString(name);
}
ASSERT(current->property_dictionary()->FindEntry(*name) ==
StringDictionary::kNotFound);
@@ -968,8 +976,10 @@
// Save the map in scratch1 for later.
__ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
- __ CheckMap(reg, Handle<Map>(current_map),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
@@ -1001,9 +1011,11 @@
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, Handle<Map>(holder->map()),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, Handle<Map>(holder->map()),
+ miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
@@ -1023,9 +1035,11 @@
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ jmp(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
@@ -1035,12 +1049,10 @@
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
@@ -1090,8 +1102,7 @@
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
@@ -1137,8 +1148,8 @@
}
__ PushAddress(ExternalReference::isolate_address()); // isolate
__ push(name()); // name
- // Save a pointer to where we pushed the arguments pointer.
- // This will be passed as the const AccessorInfo& to the C++ callback.
+ // Save a pointer to where we pushed the arguments pointer. This will be
+ // passed as the const ExecutableAccessorInfo& to the C++ callback.
#if defined(__MINGW64__)
Register accessor_info_arg = rdx;
@@ -1877,7 +1888,7 @@
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
- __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
+ __ LoadRoot(rax, Heap::kempty_stringRootIndex);
__ ret((argc + 1) * kPointerSize);
}
__ bind(&miss);
@@ -2180,7 +2191,7 @@
break;
case STRING_CHECK:
- // Check that the object is a two-byte string or a symbol.
+ // Check that the object is a string.
__ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
__ j(above_equal, &miss);
// Check that the maps starting from the prototype haven't changed.
@@ -2191,6 +2202,12 @@
rax, holder, rbx, rdx, rdi, name, &miss);
break;
+ case SYMBOL_CHECK:
+ // Check that the object is a symbol.
+ __ CmpObjectType(rdx, SYMBOL_TYPE, rax);
+ __ j(not_equal, &miss);
+ break;
+
case NUMBER_CHECK: {
Label fast;
// Check that the object is a smi or a heap number.
@@ -2752,7 +2769,7 @@
__ ret(0);
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
@@ -2826,8 +2843,9 @@
// rax is used as receiver(), which we would otherwise clobber before a
// potential miss.
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
__ Move(rbx, cell);
@@ -2851,7 +2869,7 @@
__ ret(0);
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
@@ -2878,35 +2896,39 @@
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(rdx, &miss);
- Register map_reg = rbx;
- __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
+ __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
// Check map and tail call if there's a match
__ Cmp(map_reg, receiver_maps->at(current));
- __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
+ __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
}
__ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index bcd1e98..8ed3f52 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -94,6 +94,7 @@
'test-sockets.cc',
'test-spaces.cc',
'test-strings.cc',
+ 'test-symbols.cc',
'test-strtod.cc',
'test-thread-termination.cc',
'test-threads.cc',
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index a8754fc..eb0d907 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -92,6 +92,7 @@
'test-sockets.cc',
'test-spaces.cc',
'test-strings.cc',
+ 'test-symbols.cc',
'test-strtod.cc',
'test-thread-termination.cc',
'test-threads.cc',
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index c8d7354..8cabd3d 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -121,7 +121,7 @@
v8::HandleScope scope;
env->Enter();
Handle<JSFunction> function =
- FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
+ FACTORY->NewFunction(FACTORY->function_string(), FACTORY->null_value());
// Force the creation of an initial map and set the code to
// something empty.
FACTORY->NewJSObject(function);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 1cde03f..8077adf 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -613,8 +613,9 @@
// Trigger GCs so that the newly allocated string moves to old gen.
HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
- CHECK(isymbol->IsSymbol());
+ i::Handle<i::String> isymbol =
+ FACTORY->InternalizedStringFromString(istring);
+ CHECK(isymbol->IsInternalizedString());
}
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -631,8 +632,9 @@
// Trigger GCs so that the newly allocated string moves to old gen.
HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
- CHECK(isymbol->IsSymbol());
+ i::Handle<i::String> isymbol =
+ FACTORY->InternalizedStringFromString(istring);
+ CHECK(isymbol->IsInternalizedString());
}
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -3774,7 +3776,7 @@
CHECK_EQ(v8_num(1.00), v8_num(1));
CHECK_NE(v8_num(1), v8_num(2));
- // Assume String is not symbol.
+ // Assume String is not internalized.
CHECK(v8_str("a")->StrictEquals(v8_str("a")));
CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
@@ -12880,7 +12882,7 @@
UC16VectorResource* uc16_resource) {
CHECK(i::StringShape(string).IsExternal());
if (string->IsOneByteRepresentation()) {
- // Check old map is not symbol or long.
+ // Check old map is not internalized or long.
CHECK(string->map() == HEAP->external_ascii_string_map());
// Morph external string to be TwoByte string.
string->set_map(HEAP->external_string_map());
@@ -12888,7 +12890,7 @@
i::ExternalTwoByteString::cast(string);
morphed->set_resource(uc16_resource);
} else {
- // Check old map is not symbol or long.
+ // Check old map is not internalized or long.
CHECK(string->map() == HEAP->external_string_map());
// Morph external string to be ASCII string.
string->set_map(HEAP->external_ascii_string_map());
@@ -15342,8 +15344,8 @@
HEAP->CollectAllAvailableGarbage(); // Tenure string.
// Turn into a symbol.
i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
- CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure());
- CHECK(string3_i->IsSymbol());
+ CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure());
+ CHECK(string3_i->IsInternalizedString());
// We need to add usages for string* to avoid warnings in GCC 4.7
CHECK(string0->IsExternal());
@@ -17845,7 +17847,7 @@
v8::HandleScope scope;
LocalContext context;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
- i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
+ i::Handle<i::Object> empty_string = FACTORY->empty_string();
CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index e7b294a..f6632d4 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -94,17 +94,19 @@
static MaybeObject* GetGlobalProperty(const char* name) {
- Handle<String> symbol = FACTORY->LookupUtf8Symbol(name);
- return Isolate::Current()->context()->global_object()->GetProperty(*symbol);
+ Handle<String> internalized_name = FACTORY->InternalizeUtf8String(name);
+ return Isolate::Current()->context()->global_object()->GetProperty(
+ *internalized_name);
}
static void SetGlobalProperty(const char* name, Object* value) {
Isolate* isolate = Isolate::Current();
Handle<Object> object(value, isolate);
- Handle<String> symbol = isolate->factory()->LookupUtf8Symbol(name);
+ Handle<String> internalized_name =
+ isolate->factory()->InternalizeUtf8String(name);
Handle<JSObject> global(isolate->context()->global_object());
- SetProperty(isolate, global, symbol, object, NONE, kNonStrictMode);
+ SetProperty(isolate, global, internalized_name, object, NONE, kNonStrictMode);
}
@@ -295,16 +297,16 @@
Execution::Call(fun0, global, 0, NULL, &has_pending_exception);
CHECK(!has_pending_exception);
- Object* foo_symbol =
- FACTORY->LookupOneByteSymbol(STATIC_ASCII_VECTOR("foo"))->
+ Object* foo_string =
+ FACTORY->InternalizeOneByteString(STATIC_ASCII_VECTOR("foo"))->
ToObjectChecked();
MaybeObject* fun1_object = isolate->context()->global_object()->
- GetProperty(String::cast(foo_symbol));
+ GetProperty(String::cast(foo_string));
Handle<Object> fun1(fun1_object->ToObjectChecked(), isolate);
CHECK(fun1->IsJSFunction());
Handle<Object> argv[] =
- { FACTORY->LookupOneByteSymbol(STATIC_ASCII_VECTOR("hello")) };
+ { FACTORY->InternalizeOneByteString(STATIC_ASCII_VECTOR("hello")) };
Execution::Call(Handle<JSFunction>::cast(fun1),
global,
ARRAY_SIZE(argv),
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index d837eac..8d37440 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -154,7 +154,7 @@
Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
v8::Utils::OpenHandle(*context_->Global())));
Handle<v8::internal::String> debug_string =
- FACTORY->LookupOneByteSymbol(STATIC_ASCII_VECTOR("debug"));
+ FACTORY->InternalizeOneByteString(STATIC_ASCII_VECTOR("debug"));
SetProperty(isolate, global, debug_string,
Handle<Object>(debug->debug_context()->global_proxy(), isolate),
DONT_ENUM,
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index a009448..c45c7b6 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -184,10 +184,10 @@
CHECK(s->IsString());
CHECK_EQ(10, s->length());
- String* object_symbol = String::cast(heap->Object_symbol());
+ String* object_string = String::cast(heap->Object_string());
CHECK(
Isolate::Current()->context()->global_object()->HasLocalProperty(
- object_symbol));
+ object_string));
// Check ToString for oddballs
CheckOddball(isolate, heap->true_value(), "true");
@@ -233,10 +233,10 @@
// Check GC.
heap->CollectGarbage(NEW_SPACE);
- Handle<String> name = factory->LookupUtf8Symbol("theFunction");
- Handle<String> prop_name = factory->LookupUtf8Symbol("theSlot");
- Handle<String> prop_namex = factory->LookupUtf8Symbol("theSlotx");
- Handle<String> obj_name = factory->LookupUtf8Symbol("theObject");
+ Handle<String> name = factory->InternalizeUtf8String("theFunction");
+ Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
+ Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
+ Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
{
HandleScope inner_scope(isolate);
@@ -564,15 +564,15 @@
};
-static void CheckSymbols(const char** strings) {
+static void CheckInternalizedStrings(const char** strings) {
for (const char* string = *strings; *strings != 0; string = *strings++) {
Object* a;
- MaybeObject* maybe_a = HEAP->LookupUtf8Symbol(string);
- // LookupUtf8Symbol may return a failure if a GC is needed.
+ MaybeObject* maybe_a = HEAP->InternalizeUtf8String(string);
+ // InternalizeUtf8String may return a failure if a GC is needed.
if (!maybe_a->ToObject(&a)) continue;
- CHECK(a->IsSymbol());
+ CHECK(a->IsInternalizedString());
Object* b;
- MaybeObject* maybe_b = HEAP->LookupUtf8Symbol(string);
+ MaybeObject* maybe_b = HEAP->InternalizeUtf8String(string);
if (!maybe_b->ToObject(&b)) continue;
CHECK_EQ(b, a);
CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
@@ -580,11 +580,11 @@
}
-TEST(SymbolTable) {
+TEST(StringTable) {
InitializeVM();
- CheckSymbols(not_so_random_string_table);
- CheckSymbols(not_so_random_string_table);
+ CheckInternalizedStrings(not_so_random_string_table);
+ CheckInternalizedStrings(not_so_random_string_table);
}
@@ -592,14 +592,14 @@
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
+ Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
Handle<JSFunction> function =
FACTORY->NewFunction(name, FACTORY->undefined_value());
Handle<Map> initial_map =
FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
+ Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
Handle<JSObject> obj = FACTORY->NewJSObject(function);
obj->SetProperty(
*prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
@@ -615,14 +615,14 @@
InitializeVM();
v8::HandleScope sc;
- String* object_symbol = String::cast(HEAP->Object_symbol());
+ String* object_string = String::cast(HEAP->Object_string());
Object* raw_object = Isolate::Current()->context()->global_object()->
- GetProperty(object_symbol)->ToObjectChecked();
+ GetProperty(object_string)->ToObjectChecked();
JSFunction* object_function = JSFunction::cast(raw_object);
Handle<JSFunction> constructor(object_function);
Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
- Handle<String> first = FACTORY->LookupUtf8Symbol("first");
- Handle<String> second = FACTORY->LookupUtf8Symbol("second");
+ Handle<String> first = FACTORY->InternalizeUtf8String("first");
+ Handle<String> second = FACTORY->InternalizeUtf8String("second");
// check for empty
CHECK(!obj->HasLocalProperty(*first));
@@ -666,19 +666,19 @@
CHECK(!obj->HasLocalProperty(*first));
CHECK(!obj->HasLocalProperty(*second));
- // check string and symbol match
+ // check string and internalized string match
const char* string1 = "fisk";
Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
obj->SetProperty(
*s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
- Handle<String> s1_symbol = FACTORY->LookupUtf8Symbol(string1);
- CHECK(obj->HasLocalProperty(*s1_symbol));
+ Handle<String> s1_string = FACTORY->InternalizeUtf8String(string1);
+ CHECK(obj->HasLocalProperty(*s1_string));
- // check symbol and string match
+ // check internalized string and string match
const char* string2 = "fugl";
- Handle<String> s2_symbol = FACTORY->LookupUtf8Symbol(string2);
+ Handle<String> s2_string = FACTORY->InternalizeUtf8String(string2);
obj->SetProperty(
- *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
+ *s2_string, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
CHECK(obj->HasLocalProperty(*s2));
}
@@ -688,14 +688,14 @@
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
+ Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
Handle<JSFunction> function =
FACTORY->NewFunction(name, FACTORY->undefined_value());
Handle<Map> initial_map =
FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
function->set_initial_map(*initial_map);
- Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
+ Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
Handle<JSObject> obj = FACTORY->NewJSObject(function);
// Set a propery
@@ -712,7 +712,7 @@
InitializeVM();
v8::HandleScope sc;
- Handle<String> name = FACTORY->LookupUtf8Symbol("Array");
+ Handle<String> name = FACTORY->InternalizeUtf8String("Array");
Object* raw_object = Isolate::Current()->context()->global_object()->
GetProperty(*name)->ToObjectChecked();
Handle<JSFunction> function = Handle<JSFunction>(
@@ -759,14 +759,14 @@
InitializeVM();
v8::HandleScope sc;
- String* object_symbol = String::cast(HEAP->Object_symbol());
+ String* object_string = String::cast(HEAP->Object_string());
Object* raw_object = Isolate::Current()->context()->global_object()->
- GetProperty(object_symbol)->ToObjectChecked();
+ GetProperty(object_string)->ToObjectChecked();
JSFunction* object_function = JSFunction::cast(raw_object);
Handle<JSFunction> constructor(object_function);
Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
- Handle<String> first = FACTORY->LookupUtf8Symbol("first");
- Handle<String> second = FACTORY->LookupUtf8Symbol("second");
+ Handle<String> first = FACTORY->InternalizeUtf8String("first");
+ Handle<String> second = FACTORY->InternalizeUtf8String("second");
obj->SetProperty(
*first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
@@ -821,10 +821,11 @@
non_ascii[3 * i + 2] = chars[2];
}
Handle<String> non_ascii_sym =
- FACTORY->LookupUtf8Symbol(Vector<const char>(non_ascii, 3 * length));
+ FACTORY->InternalizeUtf8String(
+ Vector<const char>(non_ascii, 3 * length));
CHECK_EQ(length, non_ascii_sym->length());
Handle<String> ascii_sym =
- FACTORY->LookupOneByteSymbol(OneByteVector(ascii, length));
+ FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
CHECK_EQ(length, ascii_sym->length());
Handle<String> non_ascii_str =
FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
@@ -1001,7 +1002,7 @@
" var z = x + y;"
"};"
"foo()";
- Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
+ Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
// This compile will add the code to the compilation cache.
{ v8::HandleScope scope;
@@ -1048,7 +1049,7 @@
" var z = x + y;"
"};"
"foo()";
- Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
+ Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
// This compile will add the code to the compilation cache.
{ v8::HandleScope scope;
@@ -1118,8 +1119,8 @@
" var x = 23;"
"};"
"bar();";
- Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
- Handle<String> bar_name = FACTORY->LookupUtf8Symbol("bar");
+ Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
+ Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
// Perfrom one initial GC to enable code flushing.
HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
@@ -1182,7 +1183,7 @@
" var z = x + y;"
"};"
"foo()";
- Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
+ Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
// This compile will add the code to the compilation cache.
{ v8::HandleScope scope;
@@ -2261,7 +2262,7 @@
// Check values.
CHECK_EQ(hash,
- internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
+ internal_obj->GetHiddenProperty(heap->identity_hash_string()));
CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
// Check size.
@@ -2421,7 +2422,7 @@
v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
- CHECK(ic_before->ic_state() == MEGAMORPHIC);
+ CHECK(ic_before->ic_state() == POLYMORPHIC);
// Fire context dispose notification.
v8::V8::ContextDisposedNotification();
@@ -2536,7 +2537,7 @@
// Fourth is the tricky part. Make sure the code containing the CallIC is
// visited first without clearing the IC. The shared function info is then
// visited later, causing the CallIC to be cleared.
- Handle<String> name = FACTORY->LookupUtf8Symbol("call");
+ Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
Handle<GlobalObject> global(isolate->context()->global_object());
MaybeObject* maybe_call = global->GetProperty(*name);
JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 83e4197..ab819b7 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -184,8 +184,8 @@
JSObject::kHeaderSize)->ToObjectChecked();
// allocate a garbage
- String* func_name =
- String::cast(HEAP->LookupUtf8Symbol("theFunction")->ToObjectChecked());
+ String* func_name = String::cast(
+ HEAP->InternalizeUtf8String("theFunction")->ToObjectChecked());
SharedFunctionInfo* function_share = SharedFunctionInfo::cast(
HEAP->AllocateSharedFunctionInfo(func_name)->ToObjectChecked());
JSFunction* function = JSFunction::cast(
@@ -203,8 +203,8 @@
HEAP->AllocateJSObject(function)->ToObjectChecked());
HEAP->CollectGarbage(OLD_POINTER_SPACE);
- func_name =
- String::cast(HEAP->LookupUtf8Symbol("theFunction")->ToObjectChecked());
+ func_name = String::cast(
+ HEAP->InternalizeUtf8String("theFunction")->ToObjectChecked());
CHECK(Isolate::Current()->context()->global_object()->
HasLocalProperty(func_name));
Object* func_value = Isolate::Current()->context()->global_object()->
@@ -214,11 +214,11 @@
obj = JSObject::cast(HEAP->AllocateJSObject(function)->ToObjectChecked());
String* obj_name =
- String::cast(HEAP->LookupUtf8Symbol("theObject")->ToObjectChecked());
+ String::cast(HEAP->InternalizeUtf8String("theObject")->ToObjectChecked());
Isolate::Current()->context()->global_object()->SetProperty(
obj_name, obj, NONE, kNonStrictMode)->ToObjectChecked();
String* prop_name =
- String::cast(HEAP->LookupUtf8Symbol("theSlot")->ToObjectChecked());
+ String::cast(HEAP->InternalizeUtf8String("theSlot")->ToObjectChecked());
obj->SetProperty(prop_name,
Smi::FromInt(23),
NONE,
@@ -227,7 +227,7 @@
HEAP->CollectGarbage(OLD_POINTER_SPACE);
obj_name =
- String::cast(HEAP->LookupUtf8Symbol("theObject")->ToObjectChecked());
+ String::cast(HEAP->InternalizeUtf8String("theObject")->ToObjectChecked());
CHECK(Isolate::Current()->context()->global_object()->
HasLocalProperty(obj_name));
CHECK(Isolate::Current()->context()->global_object()->
@@ -235,7 +235,7 @@
obj = JSObject::cast(Isolate::Current()->context()->global_object()->
GetProperty(obj_name)->ToObjectChecked());
prop_name =
- String::cast(HEAP->LookupUtf8Symbol("theSlot")->ToObjectChecked());
+ String::cast(HEAP->InternalizeUtf8String("theSlot")->ToObjectChecked());
CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
old mode 100755
new mode 100644
diff --git a/test/cctest/test-random.cc b/test/cctest/test-random.cc
index 55879bf..32b626e 100644
--- a/test/cctest/test-random.cc
+++ b/test/cctest/test-random.cc
@@ -83,10 +83,10 @@
CompileRun("function f() { return Math.random(); }");
- Object* symbol = FACTORY->LookupOneByteSymbol(STATIC_ASCII_VECTOR("f"))->
+ Object* string = FACTORY->InternalizeOneByteString(STATIC_ASCII_VECTOR("f"))->
ToObjectChecked();
MaybeObject* fun_object =
- context->global_object()->GetProperty(String::cast(symbol));
+ context->global_object()->GetProperty(String::cast(string));
Handle<JSFunction> fun(JSFunction::cast(fun_object->ToObjectChecked()));
// Optimize function.
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index eaee454..b07db0f 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -288,8 +288,8 @@
#endif
CHECK(Isolate::Current()->global_object()->IsJSObject());
CHECK(Isolate::Current()->native_context()->IsContext());
- CHECK(HEAP->symbol_table()->IsSymbolTable());
- CHECK(!FACTORY->LookupOneByteSymbol(
+ CHECK(HEAP->string_table()->IsStringTable());
+ CHECK(!FACTORY->InternalizeOneByteString(
STATIC_ASCII_VECTOR("Empty"))->IsFailure());
}
diff --git a/test/cctest/test-symbols.cc b/test/cctest/test-symbols.cc
new file mode 100644
index 0000000..adc100d
--- /dev/null
+++ b/test/cctest/test-symbols.cc
@@ -0,0 +1,63 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+
+// Check that we can traverse very deep stacks of ConsStrings using
+// StringCharacterStram. Check that Get(int) works on very deep stacks
+// of ConsStrings. These operations may not be very fast, but they
+// should be possible without getting errors due to too deep recursion.
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "objects.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+ if (env.IsEmpty()) {
+ v8::HandleScope scope;
+ const char* extensions[] = { "v8/print" };
+ v8::ExtensionConfiguration config(1, extensions);
+ env = v8::Context::New(&config);
+ }
+ v8::HandleScope scope;
+ env->Enter();
+}
+
+
+TEST(Create) {
+ InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+
+ const int kNumSymbols = 30;
+ Handle<Symbol> symbols[kNumSymbols];
+
+ for (int i = 0; i < kNumSymbols; ++i) {
+ symbols[i] = isolate->factory()->NewSymbol();
+ CHECK(symbols[i]->IsName());
+ CHECK(symbols[i]->IsSymbol());
+ CHECK(symbols[i]->HasHashCode());
+ CHECK_GT(symbols[i]->Hash(), 0);
+ symbols[i]->ShortPrint();
+ PrintF("\n");
+#if OBJECT_PRINT
+ symbols[i]->Print();
+#endif
+#if VERIFY_HEAP
+ symbols[i]->Verify();
+#endif
+ }
+
+ HEAP->PerformScavenge();
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+
+ // All symbols should be distinct.
+ for (int i = 0; i < kNumSymbols; ++i) {
+ CHECK(symbols[i]->SameValue(*symbols[i]));
+ for (int j = i + 1; j < kNumSymbols; ++j) {
+ CHECK(!symbols[i]->SameValue(*symbols[j]));
+ }
+ }
+}
diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc
index be86b0d..cd333d3 100644
--- a/test/cctest/test-weakmaps.cc
+++ b/test/cctest/test-weakmaps.cc
@@ -173,7 +173,7 @@
LocalContext context;
v8::HandleScope scope;
Handle<JSFunction> function =
- FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
+ FACTORY->NewFunction(FACTORY->function_string(), FACTORY->null_value());
Handle<JSObject> key = FACTORY->NewJSObject(function);
Handle<JSWeakMap> weakmap = AllocateJSWeakMap();
@@ -209,7 +209,7 @@
LocalContext context;
v8::HandleScope scope;
Handle<JSFunction> function =
- FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
+ FACTORY->NewFunction(FACTORY->function_string(), FACTORY->null_value());
// Start second old-space page so that keys land on evacuation candidate.
Page* first_page = HEAP->old_pointer_space()->anchor()->next_page();
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js
index 3c82387..d57fd32 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -26,7 +26,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
-// Flags: --track-allocation-sites
+// Flags: --track-allocation-sites --nooptimize-constructed-arrays
+
+// TODO(mvstanton): remove --nooptimize-constructed-arrays and enable
+// the constructed array code below when the feature is turned on
+// by default.
// Test element kind of objects.
// Since --smi-only-arrays affects builtins, its default setting at compile
@@ -36,6 +40,7 @@
// enabled, this test takes the appropriate code path to check smi-only arrays.
support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
+optimize_constructed_arrays = false;
if (support_smi_only_arrays) {
print("Tests include smi-only arrays.");
@@ -43,6 +48,12 @@
print("Tests do NOT include smi-only arrays.");
}
+if (optimize_constructed_arrays) {
+ print("Tests include constructed array optimizations.");
+} else {
+ print("Tests do NOT include constructed array optimizations.");
+}
+
var elements_kind = {
fast_smi_only : 'fast smi only elements',
fast : 'fast elements',
@@ -66,6 +77,11 @@
if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
}
+function isHoley(obj) {
+ if (%HasFastHoleyElements(obj)) return true;
+ return false;
+}
+
function assertKind(expected, obj, name_opt) {
if (!support_smi_only_arrays &&
expected == elements_kind.fast_smi_only) {
@@ -74,9 +90,45 @@
assertEquals(expected, getKind(obj), name_opt);
}
+function assertHoley(obj, name_opt) {
+ assertEquals(true, isHoley(obj), name_opt);
+}
+
+function assertNotHoley(obj, name_opt) {
+ assertEquals(false, isHoley(obj), name_opt);
+}
+
if (support_smi_only_arrays) {
+
+ obj = [];
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = [1, 2, 3];
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = new Array();
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = new Array(0);
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = new Array(2);
+ assertHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = new Array(1,2,3);
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast_smi_only, obj);
+
+ obj = new Array(1, "hi", 2, undefined);
+ assertNotHoley(obj);
+ assertKind(elements_kind.fast, obj);
+
function fastliteralcase(literal, value) {
- // var literal = [1, 2, 3];
literal[0] = value;
return literal;
}
@@ -104,7 +156,6 @@
// Verify that we will not pretransition the double->fast path.
obj = fastliteralcase(get_standard_literal(), "elliot");
assertKind(elements_kind.fast, obj);
-
// This fails until we turn off optimistic transitions to the
// most general elements kind seen on keyed stores. It's a goal
// to turn it off, but for now we need it.
@@ -123,4 +174,99 @@
assertKind(elements_kind.fast, obj);
obj = fastliteralcase_smifast(2);
assertKind(elements_kind.fast, obj);
+
+ if (optimize_constructed_arrays) {
+ function newarraycase_smidouble(value) {
+ var a = new Array();
+ a[0] = value;
+ return a;
+ }
+
+ // Case: new Array() as allocation site, smi->double
+ obj = newarraycase_smidouble(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_smidouble(1.5);
+ assertKind(elements_kind.fast_double, obj);
+ obj = newarraycase_smidouble(2);
+ assertKind(elements_kind.fast_double, obj);
+
+ function newarraycase_smiobj(value) {
+ var a = new Array();
+ a[0] = value;
+ return a;
+ }
+
+ // Case: new Array() as allocation site, smi->fast
+ obj = newarraycase_smiobj(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_smiobj("gloria");
+ assertKind(elements_kind.fast, obj);
+ obj = newarraycase_smiobj(2);
+ assertKind(elements_kind.fast, obj);
+
+ function newarraycase_length_smidouble(value) {
+ var a = new Array(3);
+ a[0] = value;
+ return a;
+ }
+
+ // Case: new Array(length) as allocation site
+ obj = newarraycase_length_smidouble(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_length_smidouble(1.5);
+ assertKind(elements_kind.fast_double, obj);
+ obj = newarraycase_length_smidouble(2);
+ assertKind(elements_kind.fast_double, obj);
+
+ // Try to continue the transition to fast object, but
+ // we will not pretransition from double->fast, because
+ // it may hurt performance ("poisoning").
+ obj = newarraycase_length_smidouble("coates");
+ assertKind(elements_kind.fast, obj);
+ obj = newarraycase_length_smidouble(2.5);
+ // However, because of optimistic transitions, we will
+ // transition to the most general kind of elements kind found,
+ // therefore I can't count on this assert yet.
+ // assertKind(elements_kind.fast_double, obj);
+
+ function newarraycase_length_smiobj(value) {
+ var a = new Array(3);
+ a[0] = value;
+ return a;
+ }
+
+ // Case: new Array(<length>) as allocation site, smi->fast
+ obj = newarraycase_length_smiobj(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_length_smiobj("gloria");
+ assertKind(elements_kind.fast, obj);
+ obj = newarraycase_length_smiobj(2);
+ assertKind(elements_kind.fast, obj);
+
+ function newarraycase_list_smidouble(value) {
+ var a = new Array(1, 2, 3);
+ a[0] = value;
+ return a;
+ }
+
+ obj = newarraycase_list_smidouble(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_list_smidouble(1.5);
+ assertKind(elements_kind.fast_double, obj);
+ obj = newarraycase_list_smidouble(2);
+ assertKind(elements_kind.fast_double, obj);
+
+ function newarraycase_list_smiobj(value) {
+ var a = new Array(4, 5, 6);
+ a[0] = value;
+ return a;
+ }
+
+ obj = newarraycase_list_smiobj(1);
+ assertKind(elements_kind.fast_smi_only, obj);
+ obj = newarraycase_list_smiobj("coates");
+ assertKind(elements_kind.fast, obj);
+ obj = newarraycase_list_smiobj(2);
+ assertKind(elements_kind.fast, obj);
+ }
}
diff --git a/test/mjsunit/array-natives-elements.js b/test/mjsunit/array-natives-elements.js
index f74f8be..b3a7141 100644
--- a/test/mjsunit/array-natives-elements.js
+++ b/test/mjsunit/array-natives-elements.js
@@ -27,6 +27,7 @@
// Flags: --allow-natives-syntax --smi-only-arrays
// Flags: --noparallel-recompilation
+// Flags: --notrack-allocation-sites
// Test element kind of objects.
// Since --smi-only-arrays affects builtins, its default setting at compile time
diff --git a/test/mjsunit/elements-transition.js b/test/mjsunit/elements-transition.js
index 0dffd37..e28f3c3 100644
--- a/test/mjsunit/elements-transition.js
+++ b/test/mjsunit/elements-transition.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax --smi-only-arrays
+// Flags: --allow-natives-syntax --smi-only-arrays --notrack-allocation-sites
support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
diff --git a/test/mjsunit/harmony/symbols.js b/test/mjsunit/harmony/symbols.js
new file mode 100644
index 0000000..baec514
--- /dev/null
+++ b/test/mjsunit/harmony/symbols.js
@@ -0,0 +1,127 @@
+// 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.
+
+// Flags: --harmony-symbols --harmony-collections
+// Flags: --expose-gc --allow-natives-syntax
+
+var symbols = []
+
+// Test different forms of constructor calls, all equivalent.
+function TestNew() {
+ function IndirectSymbol() { return new Symbol }
+ function indirect() { return new IndirectSymbol() }
+ for (var i = 0; i < 10; ++i) {
+ symbols.push(new Symbol)
+ symbols.push(new Symbol())
+ symbols.push(Symbol())
+ symbols.push(indirect())
+ }
+ %OptimizeFunctionOnNextCall(indirect)
+ indirect() // Call once before GC throws away type feedback.
+ gc() // Promote existing symbols and then allocate some more.
+ for (var i = 0; i < 10; ++i) {
+ symbols.push(new Symbol)
+ symbols.push(new Symbol())
+ symbols.push(Symbol())
+ symbols.push(indirect())
+ }
+}
+TestNew()
+
+
+function TestType() {
+ for (var i in symbols) {
+ assertTrue(%_IsSymbol(symbols[i]))
+ assertEquals("object", typeof symbols[i])
+ assertTrue(typeof symbols[i] === "object")
+ assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i]))
+ }
+}
+TestType()
+
+
+function TestEquality() {
+ // Every symbol should equal itself.
+ for (var i in symbols) {
+ assertSame(symbols[i], symbols[i])
+ assertEquals(symbols[i], symbols[i])
+ assertTrue(Object.is(symbols[i], symbols[i]))
+ assertTrue(symbols[i] === symbols[i])
+ assertTrue(symbols[i] == symbols[i])
+ }
+
+ // All symbols should be distinct.
+ for (var i = 0; i < symbols.length; ++i) {
+ for (var j = i + 1; j < symbols.length; ++j) {
+ assertFalse(Object.is(symbols[i], symbols[j]))
+ assertFalse(symbols[i] === symbols[j])
+ assertFalse(symbols[i] == symbols[j])
+ }
+ }
+}
+TestEquality()
+
+
+function TestGet() {
+ for (var i in symbols) {
+ assertEquals("[object Symbol]", symbols[i].toString())
+ assertEquals(undefined, symbols[i].valueOf)
+ assertEquals(undefined, symbols[i].a)
+ assertEquals(undefined, symbols[i]["a" + "b"])
+ assertEquals(undefined, symbols[i]["" + "1"])
+ assertEquals(undefined, symbols[i][62])
+ }
+}
+TestGet()
+
+
+function TestSet() {
+ for (var i in symbols) {
+ symbols[i].toString = 0
+ assertEquals("[object Symbol]", symbols[i].toString())
+ symbols[i].a = 0
+ assertEquals(undefined, symbols[i].a)
+ symbols[i]["a" + "b"] = 0
+ assertEquals(undefined, symbols[i]["a" + "b"])
+ symbols[i][62] = 0
+ assertEquals(undefined, symbols[i][62])
+ }
+}
+TestSet()
+
+
+function TestMap() {
+ var map = new Map;
+ for (var i in symbols) {
+ map.set(symbols[i], i)
+ }
+ for (var i in symbols) {
+ assertTrue(map.has(symbols[i]))
+ assertEquals(i, map.get(symbols[i]))
+ }
+}
+TestMap()
diff --git a/test/mjsunit/regress/regress-crbug-178790.js b/test/mjsunit/regress/regress-crbug-178790.js
new file mode 100644
index 0000000..57071ea
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-178790.js
@@ -0,0 +1,52 @@
+// 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.
+
+// Create a regexp in the form of a?a?...a? so that fully
+// traversing the entire graph would be prohibitively expensive.
+// This should not cause time out.
+var r1 = "";
+for (var i = 0; i < 1000; i++) {
+ r1 += "a?";
+}
+"test".match(RegExp(r1));
+
+var r2 = "";
+for (var i = 0; i < 100; i++) {
+ r2 += "(a?|b?|c?|d?|e?|f?|g?)";
+}
+"test".match(RegExp(r2));
+
+// Create a regexp in the form of ((..(a)a..)a.
+// Compiling it causes EatsAtLeast to reach the maximum
+// recursion depth possible with a given budget.
+// This should not cause a stack overflow.
+var r3 = "a";
+for (var i = 0; i < 1000; i++) {
+ r3 = "(" + r3 + ")a";
+}
+"test".match(RegExp(r3));
+
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index c57c52b..6ebf3f6 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -794,6 +794,7 @@
],
'experimental_library_files': [
'../../src/macros.py',
+ '../../src/symbol.js',
'../../src/proxy.js',
'../../src/collection.js',
'../../src/object-observe.js'