ES6 symbols: turn symbols into a proper primitive type
(qua last week's TC39) Specifically: - Install Symbol constructor function on the global object. - Adjust code generation for typeof. - Remove IsSymbol built-in, IS_SYMBOL macro now defined using typeof. - Remove hack that allowed symbols as constructor results, and some other special cases. - Remove symbol_delegate and GetDelegate function. - Extend ToBoolean stub to handle symbols. - Extend ToNumber to return NaN on symbols. - Poison symbol's toString function, and thereby ToString on symbols. R=mstarzinger@chromium.org BUG=v8:2158 Review URL: https://codereview.chromium.org/12957004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14051 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
51a888ff48
commit
83d4a41dec
@ -4274,7 +4274,7 @@ class Internals {
|
|||||||
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
|
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
|
||||||
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
|
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
|
||||||
static const int kContextHeaderSize = 2 * kApiPointerSize;
|
static const int kContextHeaderSize = 2 * kApiPointerSize;
|
||||||
static const int kContextEmbedderDataIndex = 54;
|
static const int kContextEmbedderDataIndex = 55;
|
||||||
static const int kFullStringRepresentationMask = 0x07;
|
static const int kFullStringRepresentationMask = 0x07;
|
||||||
static const int kStringEncodingMask = 0x4;
|
static const int kStringEncodingMask = 0x4;
|
||||||
static const int kExternalTwoByteRepresentationTag = 0x02;
|
static const int kExternalTwoByteRepresentationTag = 0x02;
|
||||||
|
@ -3189,7 +3189,7 @@ Local<String> v8::Object::ObjectProtoToString() {
|
|||||||
i::Handle<i::Object> name(self->class_name(), isolate);
|
i::Handle<i::Object> name(self->class_name(), isolate);
|
||||||
|
|
||||||
// Native implementation of Object.prototype.toString (v8natives.js):
|
// Native implementation of Object.prototype.toString (v8natives.js):
|
||||||
// var c = %ClassOf(this);
|
// var c = %_ClassOf(this);
|
||||||
// if (c === 'Arguments') c = 'Object';
|
// if (c === 'Arguments') c = 'Object';
|
||||||
// return "[object " + c + "]";
|
// return "[object " + c + "]";
|
||||||
|
|
||||||
|
@ -1105,10 +1105,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
__ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE);
|
__ CompareObjectType(r0, r1, r3, FIRST_SPEC_OBJECT_TYPE);
|
||||||
__ b(ge, &exit);
|
__ 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
|
// Throw away the result of the constructor invocation and use the
|
||||||
// on-stack receiver as the result.
|
// on-stack receiver as the result.
|
||||||
__ bind(&use_receiver);
|
__ bind(&use_receiver);
|
||||||
|
@ -2764,28 +2764,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
@ -4292,6 +4270,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
|
__ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
|
||||||
__ tst(r1, Operand(1 << Map::kIsUndetectable));
|
__ tst(r1, Operand(1 << Map::kIsUndetectable));
|
||||||
Split(eq, if_true, if_false, fall_through);
|
Split(eq, if_true, if_false, fall_through);
|
||||||
|
} else if (check->Equals(isolate()->heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(r0, if_false);
|
||||||
|
__ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
|
||||||
|
Split(eq, if_true, if_false, fall_through);
|
||||||
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
||||||
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
|
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
|
||||||
__ b(eq, if_true);
|
__ b(eq, if_true);
|
||||||
@ -4324,10 +4306,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ CompareRoot(r0, Heap::kNullValueRootIndex);
|
__ CompareRoot(r0, Heap::kNullValueRootIndex);
|
||||||
__ b(eq, if_true);
|
__ b(eq, if_true);
|
||||||
}
|
}
|
||||||
if (FLAG_harmony_symbols) {
|
|
||||||
__ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
|
|
||||||
__ b(eq, if_true);
|
|
||||||
}
|
|
||||||
// Check for JS objects => true.
|
// Check for JS objects => true.
|
||||||
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
__ b(lt, if_false);
|
__ b(lt, if_false);
|
||||||
|
@ -2301,6 +2301,12 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
|||||||
__ bind(¬_string);
|
__ bind(¬_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expected.Contains(ToBooleanStub::SYMBOL)) {
|
||||||
|
// Symbol value -> true.
|
||||||
|
__ CompareInstanceType(map, ip, SYMBOL_TYPE);
|
||||||
|
__ b(eq, true_label);
|
||||||
|
}
|
||||||
|
|
||||||
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
||||||
CpuFeatureScope scope(masm(), VFP2);
|
CpuFeatureScope scope(masm(), VFP2);
|
||||||
// heap number -> false iff +0, -0, or NaN.
|
// heap number -> false iff +0, -0, or NaN.
|
||||||
@ -6074,6 +6080,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
__ tst(ip, Operand(1 << Map::kIsUndetectable));
|
__ tst(ip, Operand(1 << Map::kIsUndetectable));
|
||||||
final_branch_condition = eq;
|
final_branch_condition = eq;
|
||||||
|
|
||||||
|
} else if (type_name->Equals(heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(input, false_label);
|
||||||
|
__ CompareObjectType(input, input, scratch, SYMBOL_TYPE);
|
||||||
|
final_branch_condition = eq;
|
||||||
|
|
||||||
} else if (type_name->Equals(heap()->boolean_string())) {
|
} else if (type_name->Equals(heap()->boolean_string())) {
|
||||||
__ CompareRoot(input, Heap::kTrueValueRootIndex);
|
__ CompareRoot(input, Heap::kTrueValueRootIndex);
|
||||||
__ b(eq, true_label);
|
__ b(eq, true_label);
|
||||||
@ -6108,15 +6119,8 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
||||||
__ b(eq, true_label);
|
__ b(eq, true_label);
|
||||||
}
|
}
|
||||||
if (FLAG_harmony_symbols) {
|
__ CompareObjectType(input, input, scratch,
|
||||||
__ CompareObjectType(input, input, scratch, SYMBOL_TYPE);
|
FIRST_NONCALLABLE_SPEC_OBJECT_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);
|
__ b(lt, false_label);
|
||||||
__ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
__ b(gt, false_label);
|
__ b(gt, false_label);
|
||||||
|
@ -2391,6 +2391,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
|||||||
// Check that the object is a symbol.
|
// Check that the object is a symbol.
|
||||||
__ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
|
__ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
|
||||||
__ b(ne, &miss);
|
__ b(ne, &miss);
|
||||||
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
|
GenerateDirectLoadGlobalFunctionPrototype(
|
||||||
|
masm(), Context::SYMBOL_FUNCTION_INDEX, r0, &miss);
|
||||||
|
CheckPrototypes(
|
||||||
|
Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
|
||||||
|
r0, holder, r3, r1, r4, name, &miss);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NUMBER_CHECK: {
|
case NUMBER_CHECK: {
|
||||||
|
@ -1280,7 +1280,17 @@ void Genesis::InitializeExperimentalGlobal() {
|
|||||||
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
|
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
|
||||||
|
|
||||||
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
|
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
|
||||||
// longer need to live behind a flag, so functions get added to the snapshot.
|
// longer need to live behind flags, so functions get added to the snapshot.
|
||||||
|
|
||||||
|
if (FLAG_harmony_symbols) {
|
||||||
|
// --- S y m b o l ---
|
||||||
|
Handle<JSFunction> symbol_fun =
|
||||||
|
InstallFunction(global, "Symbol", JS_VALUE_TYPE, JSValue::kSize,
|
||||||
|
isolate()->initial_object_prototype(),
|
||||||
|
Builtins::kIllegal, true);
|
||||||
|
native_context()->set_symbol_function(*symbol_fun);
|
||||||
|
}
|
||||||
|
|
||||||
if (FLAG_harmony_collections) {
|
if (FLAG_harmony_collections) {
|
||||||
{ // -- S e t
|
{ // -- S e t
|
||||||
Handle<JSObject> prototype =
|
Handle<JSObject> prototype =
|
||||||
@ -1436,9 +1446,6 @@ void Genesis::InstallNativeFunctions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Genesis::InstallExperimentalNativeFunctions() {
|
void Genesis::InstallExperimentalNativeFunctions() {
|
||||||
if (FLAG_harmony_symbols) {
|
|
||||||
INSTALL_NATIVE(JSObject, "SymbolDelegate", symbol_delegate);
|
|
||||||
}
|
|
||||||
if (FLAG_harmony_proxies) {
|
if (FLAG_harmony_proxies) {
|
||||||
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
|
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
|
||||||
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
|
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
|
||||||
|
@ -510,6 +510,7 @@ void ToBooleanStub::Types::Print(StringStream* stream) const {
|
|||||||
if (Contains(SMI)) stream->Add("Smi");
|
if (Contains(SMI)) stream->Add("Smi");
|
||||||
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
|
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
|
||||||
if (Contains(STRING)) stream->Add("String");
|
if (Contains(STRING)) stream->Add("String");
|
||||||
|
if (Contains(SYMBOL)) stream->Add("Symbol");
|
||||||
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
|
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +550,9 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
|
|||||||
Add(STRING);
|
Add(STRING);
|
||||||
return !object->IsUndetectableObject() &&
|
return !object->IsUndetectableObject() &&
|
||||||
String::cast(*object)->length() != 0;
|
String::cast(*object)->length() != 0;
|
||||||
|
} else if (object->IsSymbol()) {
|
||||||
|
Add(SYMBOL);
|
||||||
|
return true;
|
||||||
} else if (object->IsHeapNumber()) {
|
} else if (object->IsHeapNumber()) {
|
||||||
ASSERT(!object->IsUndetectableObject());
|
ASSERT(!object->IsUndetectableObject());
|
||||||
Add(HEAP_NUMBER);
|
Add(HEAP_NUMBER);
|
||||||
@ -565,6 +569,7 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
|
|||||||
bool ToBooleanStub::Types::NeedsMap() const {
|
bool ToBooleanStub::Types::NeedsMap() const {
|
||||||
return Contains(ToBooleanStub::SPEC_OBJECT)
|
return Contains(ToBooleanStub::SPEC_OBJECT)
|
||||||
|| Contains(ToBooleanStub::STRING)
|
|| Contains(ToBooleanStub::STRING)
|
||||||
|
|| Contains(ToBooleanStub::SYMBOL)
|
||||||
|| Contains(ToBooleanStub::HEAP_NUMBER);
|
|| Contains(ToBooleanStub::HEAP_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1488,6 +1488,7 @@ class ToBooleanStub: public PlatformCodeStub {
|
|||||||
SMI,
|
SMI,
|
||||||
SPEC_OBJECT,
|
SPEC_OBJECT,
|
||||||
STRING,
|
STRING,
|
||||||
|
SYMBOL,
|
||||||
HEAP_NUMBER,
|
HEAP_NUMBER,
|
||||||
NUMBER_OF_TYPES
|
NUMBER_OF_TYPES
|
||||||
};
|
};
|
||||||
|
@ -103,6 +103,7 @@ enum BindingFlags {
|
|||||||
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
|
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
|
||||||
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
|
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
|
||||||
V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
|
V(STRING_FUNCTION_PROTOTYPE_MAP_INDEX, Map, string_function_prototype_map) \
|
||||||
|
V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \
|
||||||
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
|
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
|
||||||
V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
|
V(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
|
||||||
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
|
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
|
||||||
@ -156,7 +157,6 @@ enum BindingFlags {
|
|||||||
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
|
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
|
||||||
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
|
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
|
||||||
error_message_for_code_gen_from_strings) \
|
error_message_for_code_gen_from_strings) \
|
||||||
V(SYMBOL_DELEGATE_INDEX, JSObject, symbol_delegate) \
|
|
||||||
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
|
V(TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX, JSFunction, \
|
||||||
to_complete_property_descriptor) \
|
to_complete_property_descriptor) \
|
||||||
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
|
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
|
||||||
@ -251,6 +251,7 @@ class Context: public FixedArray {
|
|||||||
NUMBER_FUNCTION_INDEX,
|
NUMBER_FUNCTION_INDEX,
|
||||||
STRING_FUNCTION_INDEX,
|
STRING_FUNCTION_INDEX,
|
||||||
STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
|
STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
|
||||||
|
SYMBOL_FUNCTION_INDEX,
|
||||||
OBJECT_FUNCTION_INDEX,
|
OBJECT_FUNCTION_INDEX,
|
||||||
INTERNAL_ARRAY_FUNCTION_INDEX,
|
INTERNAL_ARRAY_FUNCTION_INDEX,
|
||||||
ARRAY_FUNCTION_INDEX,
|
ARRAY_FUNCTION_INDEX,
|
||||||
@ -287,7 +288,6 @@ class Context: public FixedArray {
|
|||||||
EMBEDDER_DATA_INDEX,
|
EMBEDDER_DATA_INDEX,
|
||||||
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
|
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
|
||||||
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
|
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
|
||||||
SYMBOL_DELEGATE_INDEX,
|
|
||||||
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
|
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
|
||||||
DERIVED_HAS_TRAP_INDEX,
|
DERIVED_HAS_TRAP_INDEX,
|
||||||
DERIVED_GET_TRAP_INDEX,
|
DERIVED_GET_TRAP_INDEX,
|
||||||
|
@ -2214,7 +2214,8 @@ function Stringify(x, depth) {
|
|||||||
return x.toString();
|
return x.toString();
|
||||||
case "string":
|
case "string":
|
||||||
return "\"" + x.toString() + "\"";
|
return "\"" + x.toString() + "\"";
|
||||||
// TODO(rossberg): add symbol case
|
case "symbol":
|
||||||
|
return "Symbol()";
|
||||||
case "object":
|
case "object":
|
||||||
if (x === null) return "null";
|
if (x === null) return "null";
|
||||||
if (x.constructor && x.constructor.name === "Array") {
|
if (x.constructor && x.constructor.name === "Array") {
|
||||||
|
@ -213,6 +213,8 @@ namespace internal {
|
|||||||
V(prototype_string, "prototype") \
|
V(prototype_string, "prototype") \
|
||||||
V(string_string, "string") \
|
V(string_string, "string") \
|
||||||
V(String_string, "String") \
|
V(String_string, "String") \
|
||||||
|
V(symbol_string, "symbol") \
|
||||||
|
V(Symbol_string, "Symbol") \
|
||||||
V(Date_string, "Date") \
|
V(Date_string, "Date") \
|
||||||
V(this_string, "this") \
|
V(this_string, "this") \
|
||||||
V(to_string_string, "toString") \
|
V(to_string_string, "toString") \
|
||||||
|
@ -1277,7 +1277,8 @@ Representation HBranch::observed_input_representation(int index) {
|
|||||||
ToBooleanStub::UNDEFINED |
|
ToBooleanStub::UNDEFINED |
|
||||||
ToBooleanStub::NULL_TYPE |
|
ToBooleanStub::NULL_TYPE |
|
||||||
ToBooleanStub::SPEC_OBJECT |
|
ToBooleanStub::SPEC_OBJECT |
|
||||||
ToBooleanStub::STRING);
|
ToBooleanStub::STRING |
|
||||||
|
ToBooleanStub::SYMBOL);
|
||||||
if (expected_input_types_.ContainsAnyOf(tagged_types)) {
|
if (expected_input_types_.ContainsAnyOf(tagged_types)) {
|
||||||
return Representation::Tagged();
|
return Representation::Tagged();
|
||||||
} else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
} else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
||||||
|
@ -5083,19 +5083,7 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
|
|||||||
typecheck->SetSuccessorAt(1, not_spec_object);
|
typecheck->SetSuccessorAt(1, not_spec_object);
|
||||||
current_block()->Finish(typecheck);
|
current_block()->Finish(typecheck);
|
||||||
if_spec_object->AddLeaveInlined(return_value, state);
|
if_spec_object->AddLeaveInlined(return_value, state);
|
||||||
if (!FLAG_harmony_symbols) {
|
not_spec_object->AddLeaveInlined(receiver, state);
|
||||||
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) {
|
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
|
||||||
// Return from an inlined setter call. The returned value is never used, the
|
// Return from an inlined setter call. The returned value is never used, the
|
||||||
@ -10080,16 +10068,6 @@ void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
|
||||||
ASSERT(call->arguments()->length() == 1);
|
ASSERT(call->arguments()->length() == 1);
|
||||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||||
|
@ -409,10 +409,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
||||||
__ j(above_equal, &exit);
|
__ 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
|
// Throw away the result of the constructor invocation and use the
|
||||||
// on-stack receiver as the result.
|
// on-stack receiver as the result.
|
||||||
__ bind(&use_receiver);
|
__ bind(&use_receiver);
|
||||||
|
@ -632,6 +632,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
|||||||
__ bind(¬_string);
|
__ bind(¬_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (types_.Contains(SYMBOL)) {
|
||||||
|
// Symbol value -> true.
|
||||||
|
Label not_symbol;
|
||||||
|
__ CmpInstanceType(map, SYMBOL_TYPE);
|
||||||
|
__ j(not_equal, ¬_symbol, Label::kNear);
|
||||||
|
__ bind(¬_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
if (types_.Contains(HEAP_NUMBER)) {
|
if (types_.Contains(HEAP_NUMBER)) {
|
||||||
// heap number -> false iff +0, -0, or NaN.
|
// heap number -> false iff +0, -0, or NaN.
|
||||||
Label not_heap_number, false_result;
|
Label not_heap_number, false_result;
|
||||||
|
@ -2567,7 +2567,6 @@ void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
|||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||||
// TODO(rossberg): incorporate symbols.
|
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
|
|
||||||
@ -2703,28 +2702,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
@ -4275,6 +4252,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
|
||||||
1 << Map::kIsUndetectable);
|
1 << Map::kIsUndetectable);
|
||||||
Split(zero, if_true, if_false, fall_through);
|
Split(zero, if_true, if_false, fall_through);
|
||||||
|
} else if (check->Equals(isolate()->heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(eax, if_false);
|
||||||
|
__ CmpObjectType(eax, SYMBOL_TYPE, edx);
|
||||||
|
Split(equal, if_true, if_false, fall_through);
|
||||||
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
||||||
__ cmp(eax, isolate()->factory()->true_value());
|
__ cmp(eax, isolate()->factory()->true_value());
|
||||||
__ j(equal, if_true);
|
__ j(equal, if_true);
|
||||||
@ -4306,10 +4287,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ cmp(eax, isolate()->factory()->null_value());
|
__ cmp(eax, isolate()->factory()->null_value());
|
||||||
__ j(equal, if_true);
|
__ 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);
|
__ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
|
||||||
__ j(below, if_false);
|
__ j(below, if_false);
|
||||||
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
|
@ -2116,6 +2116,12 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
|||||||
__ bind(¬_string);
|
__ bind(¬_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expected.Contains(ToBooleanStub::SYMBOL)) {
|
||||||
|
// Symbol value -> true.
|
||||||
|
__ CmpInstanceType(map, SYMBOL_TYPE);
|
||||||
|
__ j(equal, true_label);
|
||||||
|
}
|
||||||
|
|
||||||
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
|
||||||
// heap number -> false iff +0, -0, or NaN.
|
// heap number -> false iff +0, -0, or NaN.
|
||||||
Label not_heap_number;
|
Label not_heap_number;
|
||||||
@ -5979,6 +5985,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
1 << Map::kIsUndetectable);
|
1 << Map::kIsUndetectable);
|
||||||
final_branch_condition = zero;
|
final_branch_condition = zero;
|
||||||
|
|
||||||
|
} else if (type_name->Equals(heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(input, false_label);
|
||||||
|
__ CmpObjectType(input, SYMBOL_TYPE, input);
|
||||||
|
final_branch_condition = equal;
|
||||||
|
|
||||||
} else if (type_name->Equals(heap()->boolean_string())) {
|
} else if (type_name->Equals(heap()->boolean_string())) {
|
||||||
__ cmp(input, factory()->true_value());
|
__ cmp(input, factory()->true_value());
|
||||||
__ j(equal, true_label);
|
__ j(equal, true_label);
|
||||||
@ -6013,13 +6024,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
__ cmp(input, factory()->null_value());
|
__ cmp(input, factory()->null_value());
|
||||||
__ j(equal, true_label);
|
__ j(equal, true_label);
|
||||||
}
|
}
|
||||||
if (FLAG_harmony_symbols) {
|
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
|
||||||
__ 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);
|
__ j(below, false_label);
|
||||||
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
__ j(above, false_label);
|
__ j(above, false_label);
|
||||||
|
@ -2350,6 +2350,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
|||||||
// Check that the object is a symbol.
|
// Check that the object is a symbol.
|
||||||
__ CmpObjectType(edx, SYMBOL_TYPE, eax);
|
__ CmpObjectType(edx, SYMBOL_TYPE, eax);
|
||||||
__ j(not_equal, &miss);
|
__ j(not_equal, &miss);
|
||||||
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
|
GenerateDirectLoadGlobalFunctionPrototype(
|
||||||
|
masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
|
||||||
|
CheckPrototypes(
|
||||||
|
Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
|
||||||
|
eax, holder, ebx, edx, edi, name, &miss);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NUMBER_CHECK: {
|
case NUMBER_CHECK: {
|
||||||
|
@ -109,7 +109,7 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object,
|
|||||||
// If the object is a value, we use the prototype map for the cache.
|
// If the object is a value, we use the prototype map for the cache.
|
||||||
ASSERT(object->IsString() || object->IsSymbol() ||
|
ASSERT(object->IsString() || object->IsSymbol() ||
|
||||||
object->IsNumber() || object->IsBoolean());
|
object->IsNumber() || object->IsBoolean());
|
||||||
return DELEGATE_MAP;
|
return PROTOTYPE_MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(JSObject* object,
|
|||||||
!object->HasFastProperties() &&
|
!object->HasFastProperties() &&
|
||||||
!object->IsJSGlobalProxy() &&
|
!object->IsJSGlobalProxy() &&
|
||||||
!object->IsJSGlobalObject()) {
|
!object->IsJSGlobalObject()) {
|
||||||
return DELEGATE_MAP;
|
return PROTOTYPE_MAP;
|
||||||
}
|
}
|
||||||
return OWN_MAP;
|
return OWN_MAP;
|
||||||
}
|
}
|
||||||
@ -133,7 +133,8 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(JSObject* object,
|
|||||||
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
|
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
|
||||||
Object* object,
|
Object* object,
|
||||||
InlineCacheHolderFlag holder) {
|
InlineCacheHolderFlag holder) {
|
||||||
Object* map_owner = holder == OWN_MAP ? object : object->GetDelegate(isolate);
|
Object* map_owner =
|
||||||
|
holder == OWN_MAP ? object : object->GetPrototype(isolate);
|
||||||
ASSERT(map_owner->IsJSObject());
|
ASSERT(map_owner->IsJSObject());
|
||||||
return JSObject::cast(map_owner);
|
return JSObject::cast(map_owner);
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
|
|||||||
// The stub was generated for JSObject but called for non-JSObject.
|
// The stub was generated for JSObject but called for non-JSObject.
|
||||||
// IC::GetCodeCacheHolder is not applicable.
|
// IC::GetCodeCacheHolder is not applicable.
|
||||||
return false;
|
return false;
|
||||||
} else if (cache_holder == DELEGATE_MAP &&
|
} else if (cache_holder == PROTOTYPE_MAP &&
|
||||||
receiver->GetPrototype(isolate)->IsNull()) {
|
receiver->GetPrototype(isolate)->IsNull()) {
|
||||||
// IC::GetCodeCacheHolder is not applicable.
|
// IC::GetCodeCacheHolder is not applicable.
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,7 +99,7 @@ macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
|
|||||||
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
|
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
|
||||||
macro IS_STRING(arg) = (typeof(arg) === 'string');
|
macro IS_STRING(arg) = (typeof(arg) === 'string');
|
||||||
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
|
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
|
||||||
macro IS_SYMBOL(arg) = (%_IsSymbol(arg));
|
macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol');
|
||||||
macro IS_OBJECT(arg) = (%_IsObject(arg));
|
macro IS_OBJECT(arg) = (%_IsObject(arg));
|
||||||
macro IS_ARRAY(arg) = (%_IsArray(arg));
|
macro IS_ARRAY(arg) = (%_IsArray(arg));
|
||||||
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
|
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
|
||||||
@ -110,6 +110,7 @@ macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap');
|
|||||||
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
|
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
|
||||||
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
|
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
|
||||||
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
|
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
|
||||||
|
macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol');
|
||||||
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
|
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
|
||||||
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
|
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
|
||||||
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
|
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
|
||||||
|
@ -150,6 +150,7 @@ var kMessages = {
|
|||||||
cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
|
cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
|
||||||
redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
|
redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
|
||||||
harmony_const_assign: ["Assignment to constant variable."],
|
harmony_const_assign: ["Assignment to constant variable."],
|
||||||
|
symbol_to_string: ["Conversion from symbol to string"],
|
||||||
invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"],
|
invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"],
|
||||||
module_type_error: ["Module '", "%0", "' used improperly"],
|
module_type_error: ["Module '", "%0", "' used improperly"],
|
||||||
module_export_undefined: ["Export '", "%0", "' is not defined in module"],
|
module_export_undefined: ["Export '", "%0", "' is not defined in module"],
|
||||||
|
@ -126,10 +126,10 @@ void Object::Lookup(Name* name, LookupResult* result) {
|
|||||||
holder = native_context->number_function()->instance_prototype();
|
holder = native_context->number_function()->instance_prototype();
|
||||||
} else if (IsString()) {
|
} else if (IsString()) {
|
||||||
holder = native_context->string_function()->instance_prototype();
|
holder = native_context->string_function()->instance_prototype();
|
||||||
|
} else if (IsSymbol()) {
|
||||||
|
holder = native_context->symbol_function()->instance_prototype();
|
||||||
} else if (IsBoolean()) {
|
} else if (IsBoolean()) {
|
||||||
holder = native_context->boolean_function()->instance_prototype();
|
holder = native_context->boolean_function()->instance_prototype();
|
||||||
} else if (IsSymbol()) {
|
|
||||||
holder = native_context->symbol_delegate();
|
|
||||||
} else {
|
} else {
|
||||||
Isolate::Current()->PushStackTraceAndDie(
|
Isolate::Current()->PushStackTraceAndDie(
|
||||||
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
|
0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
|
||||||
@ -756,7 +756,7 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
|||||||
// holder in the prototype chain.
|
// holder in the prototype chain.
|
||||||
// Proxy handlers do not use the proxy's prototype, so we can skip this.
|
// Proxy handlers do not use the proxy's prototype, so we can skip this.
|
||||||
if (!result->IsHandler()) {
|
if (!result->IsHandler()) {
|
||||||
Object* last = result->IsProperty() && !receiver->IsSymbol()
|
Object* last = result->IsProperty()
|
||||||
? result->holder()
|
? result->holder()
|
||||||
: Object::cast(heap->null_value());
|
: Object::cast(heap->null_value());
|
||||||
ASSERT(this != this->GetPrototype(isolate));
|
ASSERT(this != this->GetPrototype(isolate));
|
||||||
@ -837,10 +837,10 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
|
|||||||
holder = native_context->number_function()->instance_prototype();
|
holder = native_context->number_function()->instance_prototype();
|
||||||
} else if (holder->IsString()) {
|
} else if (holder->IsString()) {
|
||||||
holder = native_context->string_function()->instance_prototype();
|
holder = native_context->string_function()->instance_prototype();
|
||||||
|
} else if (holder->IsSymbol()) {
|
||||||
|
holder = native_context->symbol_function()->instance_prototype();
|
||||||
} else if (holder->IsBoolean()) {
|
} else if (holder->IsBoolean()) {
|
||||||
holder = native_context->boolean_function()->instance_prototype();
|
holder = native_context->boolean_function()->instance_prototype();
|
||||||
} else if (holder->IsSymbol()) {
|
|
||||||
holder = native_context->symbol_delegate();
|
|
||||||
} else if (holder->IsJSProxy()) {
|
} else if (holder->IsJSProxy()) {
|
||||||
return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
|
return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
|
||||||
} else {
|
} else {
|
||||||
@ -900,6 +900,9 @@ Object* Object::GetPrototype(Isolate* isolate) {
|
|||||||
if (heap_object->IsString()) {
|
if (heap_object->IsString()) {
|
||||||
return context->string_function()->instance_prototype();
|
return context->string_function()->instance_prototype();
|
||||||
}
|
}
|
||||||
|
if (heap_object->IsSymbol()) {
|
||||||
|
return context->symbol_function()->instance_prototype();
|
||||||
|
}
|
||||||
if (heap_object->IsBoolean()) {
|
if (heap_object->IsBoolean()) {
|
||||||
return context->boolean_function()->instance_prototype();
|
return context->boolean_function()->instance_prototype();
|
||||||
} else {
|
} else {
|
||||||
@ -908,16 +911,6 @@ Object* Object::GetPrototype(Isolate* isolate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
MaybeObject* Object::GetHash(CreationFlag flag) {
|
||||||
// The object is either a number, a name, an odd-ball,
|
// The object is either a number, a name, an odd-ball,
|
||||||
// a real JS object, or a Harmony proxy.
|
// a real JS object, or a Harmony proxy.
|
||||||
|
@ -1102,9 +1102,6 @@ class Object : public MaybeObject {
|
|||||||
// Return the object's prototype (might be Heap::null_value()).
|
// Return the object's prototype (might be Heap::null_value()).
|
||||||
Object* GetPrototype(Isolate* isolate);
|
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
|
// Returns the permanent hash code associated with this object depending on
|
||||||
// the actual object type. Might return a failure in case no hash was
|
// the actual object type. Might return a failure in case no hash was
|
||||||
// created yet or GC was caused by creation.
|
// created yet or GC was caused by creation.
|
||||||
|
@ -5035,6 +5035,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
|
|||||||
}
|
}
|
||||||
ASSERT(heap_obj->IsUndefined());
|
ASSERT(heap_obj->IsUndefined());
|
||||||
return isolate->heap()->undefined_string();
|
return isolate->heap()->undefined_string();
|
||||||
|
case SYMBOL_TYPE:
|
||||||
|
return isolate->heap()->symbol_string();
|
||||||
case JS_FUNCTION_TYPE:
|
case JS_FUNCTION_TYPE:
|
||||||
case JS_FUNCTION_PROXY_TYPE:
|
case JS_FUNCTION_PROXY_TYPE:
|
||||||
return isolate->heap()->function_string();
|
return isolate->heap()->function_string();
|
||||||
|
@ -512,7 +512,6 @@ namespace internal {
|
|||||||
#define INLINE_FUNCTION_LIST(F) \
|
#define INLINE_FUNCTION_LIST(F) \
|
||||||
F(IsSmi, 1, 1) \
|
F(IsSmi, 1, 1) \
|
||||||
F(IsNonNegativeSmi, 1, 1) \
|
F(IsNonNegativeSmi, 1, 1) \
|
||||||
F(IsSymbol, 1, 1) \
|
|
||||||
F(IsArray, 1, 1) \
|
F(IsArray, 1, 1) \
|
||||||
F(IsRegExp, 1, 1) \
|
F(IsRegExp, 1, 1) \
|
||||||
F(IsConstructCall, 0, 1) \
|
F(IsConstructCall, 0, 1) \
|
||||||
|
@ -532,6 +532,7 @@ function ToNumber(x) {
|
|||||||
}
|
}
|
||||||
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
||||||
if (IS_UNDEFINED(x)) return $NaN;
|
if (IS_UNDEFINED(x)) return $NaN;
|
||||||
|
if (IS_SYMBOL(x)) return $NaN;
|
||||||
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,6 +543,7 @@ function NonNumberToNumber(x) {
|
|||||||
}
|
}
|
||||||
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
||||||
if (IS_UNDEFINED(x)) return $NaN;
|
if (IS_UNDEFINED(x)) return $NaN;
|
||||||
|
if (IS_SYMBOL(x)) return $NaN;
|
||||||
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,6 +574,7 @@ function ToName(x) {
|
|||||||
// ECMA-262, section 9.9, page 36.
|
// ECMA-262, section 9.9, page 36.
|
||||||
function ToObject(x) {
|
function ToObject(x) {
|
||||||
if (IS_STRING(x)) return new $String(x);
|
if (IS_STRING(x)) return new $String(x);
|
||||||
|
if (IS_SYMBOL(x)) return new $Symbol(x);
|
||||||
if (IS_NUMBER(x)) return new $Number(x);
|
if (IS_NUMBER(x)) return new $Number(x);
|
||||||
if (IS_BOOLEAN(x)) return new $Boolean(x);
|
if (IS_BOOLEAN(x)) return new $Boolean(x);
|
||||||
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
|
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
|
||||||
|
@ -27,13 +27,44 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var $Symbol = function() { return %CreateSymbol() }
|
var $Symbol = global.Symbol;
|
||||||
global.Symbol = $Symbol
|
|
||||||
|
|
||||||
// Symbols only have a toString method and no prototype.
|
function SymbolConstructor(x) {
|
||||||
var SymbolDelegate = {
|
var value = IS_SYMBOL(x) ? x : %CreateSymbol();
|
||||||
__proto__: null,
|
if (%_IsConstructCall()) {
|
||||||
toString: $Object.prototype.toString
|
%_SetValueOf(this, value);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$Object.freeze(SymbolDelegate)
|
function SymbolToString() {
|
||||||
|
throw MakeTypeError('symbol_to_string');
|
||||||
|
}
|
||||||
|
|
||||||
|
function SymbolValueOf() {
|
||||||
|
// NOTE: Both Symbol objects and values can enter here as
|
||||||
|
// 'this'. This is not as dictated by ECMA-262.
|
||||||
|
if (!IS_SYMBOL(this) && !IS_SYMBOL_WRAPPER(this)) {
|
||||||
|
throw MakeTypeError(
|
||||||
|
'incompatible_method_receiver', ["Symbol.prototype.valueOf", this]);
|
||||||
|
}
|
||||||
|
return %_ValueOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
function SetUpSymbol() {
|
||||||
|
%CheckIsBootstrapping();
|
||||||
|
|
||||||
|
%SetCode($Symbol, SymbolConstructor);
|
||||||
|
%FunctionSetPrototype($Symbol, new $Symbol());
|
||||||
|
%SetProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
|
||||||
|
|
||||||
|
InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
|
||||||
|
"toString", SymbolToString,
|
||||||
|
"valueOf", SymbolValueOf
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetUpSymbol();
|
||||||
|
@ -283,11 +283,12 @@ Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
|
|||||||
case RECEIVER_MAP_CHECK:
|
case RECEIVER_MAP_CHECK:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
case SYMBOL_CHECK:
|
|
||||||
return Handle<JSObject>(native_context_->symbol_delegate());
|
|
||||||
case STRING_CHECK:
|
case STRING_CHECK:
|
||||||
function = native_context_->string_function();
|
function = native_context_->string_function();
|
||||||
break;
|
break;
|
||||||
|
case SYMBOL_CHECK:
|
||||||
|
function = native_context_->symbol_function();
|
||||||
|
break;
|
||||||
case NUMBER_CHECK:
|
case NUMBER_CHECK:
|
||||||
function = native_context_->number_function();
|
function = native_context_->number_function();
|
||||||
break;
|
break;
|
||||||
|
@ -296,7 +296,7 @@ enum CallFunctionFlags {
|
|||||||
|
|
||||||
enum InlineCacheHolderFlag {
|
enum InlineCacheHolderFlag {
|
||||||
OWN_MAP, // For fast properties objects.
|
OWN_MAP, // For fast properties objects.
|
||||||
DELEGATE_MAP // For slow properties objects (except GlobalObjects).
|
PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,7 +233,6 @@ $Object.prototype.constructor = $Object;
|
|||||||
function ObjectToString() {
|
function ObjectToString() {
|
||||||
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
|
if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
|
||||||
if (IS_NULL(this)) return "[object Null]";
|
if (IS_NULL(this)) return "[object Null]";
|
||||||
if (IS_SYMBOL(this)) return "[object Symbol]";
|
|
||||||
return "[object " + %_ClassOf(ToObject(this)) + "]";
|
return "[object " + %_ClassOf(ToObject(this)) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,7 +864,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) {
|
|||||||
// DefineObjectProperty() to modify its value.
|
// DefineObjectProperty() to modify its value.
|
||||||
|
|
||||||
// Step 3 - Special handling for length property.
|
// Step 3 - Special handling for length property.
|
||||||
if (p == "length") {
|
if (p === "length") {
|
||||||
var length = obj.length;
|
var length = obj.length;
|
||||||
if (!desc.hasValue()) {
|
if (!desc.hasValue()) {
|
||||||
return DefineObjectProperty(obj, "length", desc, should_throw);
|
return DefineObjectProperty(obj, "length", desc, should_throw);
|
||||||
|
@ -416,10 +416,6 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
|
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
|
||||||
__ j(above_equal, &exit);
|
__ 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
|
// Throw away the result of the constructor invocation and use the
|
||||||
// on-stack receiver as the result.
|
// on-stack receiver as the result.
|
||||||
__ bind(&use_receiver);
|
__ bind(&use_receiver);
|
||||||
|
@ -2678,28 +2678,6 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
@ -4271,6 +4249,10 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
|
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
|
||||||
Immediate(1 << Map::kIsUndetectable));
|
Immediate(1 << Map::kIsUndetectable));
|
||||||
Split(zero, if_true, if_false, fall_through);
|
Split(zero, if_true, if_false, fall_through);
|
||||||
|
} else if (check->Equals(isolate()->heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(rax, if_false);
|
||||||
|
__ CmpObjectType(rax, SYMBOL_TYPE, rdx);
|
||||||
|
Split(equal, if_true, if_false, fall_through);
|
||||||
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
} else if (check->Equals(isolate()->heap()->boolean_string())) {
|
||||||
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
||||||
__ j(equal, if_true);
|
__ j(equal, if_true);
|
||||||
@ -4302,10 +4284,6 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
|
|||||||
__ CompareRoot(rax, Heap::kNullValueRootIndex);
|
__ CompareRoot(rax, Heap::kNullValueRootIndex);
|
||||||
__ j(equal, if_true);
|
__ 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);
|
__ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx);
|
||||||
__ j(below, if_false);
|
__ j(below, if_false);
|
||||||
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
|
@ -5538,6 +5538,11 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
Immediate(1 << Map::kIsUndetectable));
|
Immediate(1 << Map::kIsUndetectable));
|
||||||
final_branch_condition = zero;
|
final_branch_condition = zero;
|
||||||
|
|
||||||
|
} else if (type_name->Equals(heap()->symbol_string())) {
|
||||||
|
__ JumpIfSmi(input, false_label);
|
||||||
|
__ CmpObjectType(input, SYMBOL_TYPE, input);
|
||||||
|
final_branch_condition = equal;
|
||||||
|
|
||||||
} else if (type_name->Equals(heap()->boolean_string())) {
|
} else if (type_name->Equals(heap()->boolean_string())) {
|
||||||
__ CompareRoot(input, Heap::kTrueValueRootIndex);
|
__ CompareRoot(input, Heap::kTrueValueRootIndex);
|
||||||
__ j(equal, true_label);
|
__ j(equal, true_label);
|
||||||
@ -5572,13 +5577,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
|||||||
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
||||||
__ j(equal, true_label);
|
__ j(equal, true_label);
|
||||||
}
|
}
|
||||||
if (FLAG_harmony_symbols) {
|
__ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
|
||||||
__ 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);
|
__ j(below, false_label);
|
||||||
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||||
__ j(above, false_label);
|
__ j(above, false_label);
|
||||||
|
@ -2174,6 +2174,12 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
|||||||
// Check that the object is a symbol.
|
// Check that the object is a symbol.
|
||||||
__ CmpObjectType(rdx, SYMBOL_TYPE, rax);
|
__ CmpObjectType(rdx, SYMBOL_TYPE, rax);
|
||||||
__ j(not_equal, &miss);
|
__ j(not_equal, &miss);
|
||||||
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
|
GenerateDirectLoadGlobalFunctionPrototype(
|
||||||
|
masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss);
|
||||||
|
CheckPrototypes(
|
||||||
|
Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
|
||||||
|
rax, holder, rbx, rdx, rdi, name, &miss);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NUMBER_CHECK: {
|
case NUMBER_CHECK: {
|
||||||
|
@ -34,20 +34,19 @@ var symbols = []
|
|||||||
function TestNew() {
|
function TestNew() {
|
||||||
function IndirectSymbol() { return new Symbol }
|
function IndirectSymbol() { return new Symbol }
|
||||||
function indirect() { return new IndirectSymbol() }
|
function indirect() { return new IndirectSymbol() }
|
||||||
for (var i = 0; i < 10; ++i) {
|
for (var i = 0; i < 2; ++i) {
|
||||||
symbols.push(new Symbol)
|
for (var j = 0; j < 5; ++j) {
|
||||||
symbols.push(new Symbol())
|
symbols.push(Symbol())
|
||||||
symbols.push(Symbol())
|
symbols.push(Symbol(Symbol()))
|
||||||
symbols.push(indirect())
|
symbols.push((new Symbol).valueOf())
|
||||||
}
|
symbols.push((new Symbol()).valueOf())
|
||||||
%OptimizeFunctionOnNextCall(indirect)
|
symbols.push((new Symbol(Symbol())).valueOf())
|
||||||
indirect() // Call once before GC throws away type feedback.
|
symbols.push(Object(Symbol()).valueOf())
|
||||||
gc() // Promote existing symbols and then allocate some more.
|
symbols.push((indirect()).valueOf())
|
||||||
for (var i = 0; i < 10; ++i) {
|
}
|
||||||
symbols.push(new Symbol)
|
%OptimizeFunctionOnNextCall(indirect)
|
||||||
symbols.push(new Symbol())
|
indirect() // Call once before GC throws away type feedback.
|
||||||
symbols.push(Symbol())
|
gc() // Promote existing symbols and then allocate some more.
|
||||||
symbols.push(indirect())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TestNew()
|
TestNew()
|
||||||
@ -55,15 +54,70 @@ TestNew()
|
|||||||
|
|
||||||
function TestType() {
|
function TestType() {
|
||||||
for (var i in symbols) {
|
for (var i in symbols) {
|
||||||
assertTrue(%_IsSymbol(symbols[i]))
|
assertEquals("symbol", typeof symbols[i])
|
||||||
assertEquals("object", typeof symbols[i])
|
assertTrue(typeof symbols[i] === "symbol")
|
||||||
assertTrue(typeof symbols[i] === "object")
|
assertEquals(null, %_ClassOf(symbols[i]))
|
||||||
assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i]))
|
assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i])))
|
||||||
|
assertEquals("Symbol", %_ClassOf(Object(symbols[i])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TestType()
|
TestType()
|
||||||
|
|
||||||
|
|
||||||
|
function TestPrototype() {
|
||||||
|
assertSame(Object.prototype, Symbol.prototype.__proto__)
|
||||||
|
assertSame(Symbol.prototype, Symbol().__proto__)
|
||||||
|
assertSame(Symbol.prototype, Symbol(Symbol()).__proto__)
|
||||||
|
assertSame(Symbol.prototype, (new Symbol).__proto__)
|
||||||
|
assertSame(Symbol.prototype, (new Symbol()).__proto__)
|
||||||
|
assertSame(Symbol.prototype, (new Symbol(Symbol())).__proto__)
|
||||||
|
assertSame(Symbol.prototype, Object(Symbol()).__proto__)
|
||||||
|
for (var i in symbols) {
|
||||||
|
assertSame(Symbol.prototype, symbols[i].__proto__)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestPrototype()
|
||||||
|
|
||||||
|
|
||||||
|
function TestToString() {
|
||||||
|
for (var i in symbols) {
|
||||||
|
assertThrows(function() { String(symbols[i]) }, TypeError)
|
||||||
|
assertThrows(function() { symbols[i] + "" }, TypeError)
|
||||||
|
assertThrows(function() { symbols[i].toString() }, TypeError)
|
||||||
|
assertThrows(function() { (new Symbol(symbols[i])).toString() }, TypeError)
|
||||||
|
assertThrows(function() { Object(symbols[i]).toString() }, TypeError)
|
||||||
|
assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestToString()
|
||||||
|
|
||||||
|
|
||||||
|
function TestToBoolean() {
|
||||||
|
for (var i in symbols) {
|
||||||
|
assertTrue(Boolean(symbols[i]).valueOf())
|
||||||
|
assertFalse(!symbols[i])
|
||||||
|
assertTrue(!!symbols[i])
|
||||||
|
assertTrue(symbols[i] && true)
|
||||||
|
assertFalse(!symbols[i] && false)
|
||||||
|
assertTrue(!symbols[i] || true)
|
||||||
|
assertEquals(1, symbols[i] ? 1 : 2)
|
||||||
|
assertEquals(2, !symbols[i] ? 1 : 2)
|
||||||
|
if (!symbols[i]) assertUnreachable();
|
||||||
|
if (symbols[i]) {} else assertUnreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestToBoolean()
|
||||||
|
|
||||||
|
|
||||||
|
function TestToNumber() {
|
||||||
|
for (var i in symbols) {
|
||||||
|
assertSame(NaN, Number(symbols[i]).valueOf())
|
||||||
|
assertSame(NaN, symbols[i] + 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestToNumber()
|
||||||
|
|
||||||
|
|
||||||
function TestEquality() {
|
function TestEquality() {
|
||||||
// Every symbol should equal itself.
|
// Every symbol should equal itself.
|
||||||
for (var i in symbols) {
|
for (var i in symbols) {
|
||||||
@ -88,8 +142,8 @@ TestEquality()
|
|||||||
|
|
||||||
function TestGet() {
|
function TestGet() {
|
||||||
for (var i in symbols) {
|
for (var i in symbols) {
|
||||||
assertEquals("[object Symbol]", symbols[i].toString())
|
assertThrows(function() { symbols[i].toString() }, TypeError)
|
||||||
assertEquals(undefined, symbols[i].valueOf)
|
assertEquals(symbols[i], symbols[i].valueOf())
|
||||||
assertEquals(undefined, symbols[i].a)
|
assertEquals(undefined, symbols[i].a)
|
||||||
assertEquals(undefined, symbols[i]["a" + "b"])
|
assertEquals(undefined, symbols[i]["a" + "b"])
|
||||||
assertEquals(undefined, symbols[i]["" + "1"])
|
assertEquals(undefined, symbols[i]["" + "1"])
|
||||||
@ -102,7 +156,9 @@ TestGet()
|
|||||||
function TestSet() {
|
function TestSet() {
|
||||||
for (var i in symbols) {
|
for (var i in symbols) {
|
||||||
symbols[i].toString = 0
|
symbols[i].toString = 0
|
||||||
assertEquals("[object Symbol]", symbols[i].toString())
|
assertThrows(function() { symbols[i].toString() }, TypeError)
|
||||||
|
symbols[i].valueOf = 0
|
||||||
|
assertEquals(symbols[i], symbols[i].valueOf())
|
||||||
symbols[i].a = 0
|
symbols[i].a = 0
|
||||||
assertEquals(undefined, symbols[i].a)
|
assertEquals(undefined, symbols[i].a)
|
||||||
symbols[i]["a" + "b"] = 0
|
symbols[i]["a" + "b"] = 0
|
||||||
@ -179,7 +235,7 @@ function TestKeyHas() {
|
|||||||
|
|
||||||
function TestKeyEnum(obj) {
|
function TestKeyEnum(obj) {
|
||||||
for (var name in obj) {
|
for (var name in obj) {
|
||||||
assertFalse(%_IsSymbol(name))
|
assertTrue(typeof name !== "symbol")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,9 +251,7 @@ function TestKeyNames(obj) {
|
|||||||
for (var i = 0; i < symbols.length; ++i) expected.add(symbols[i])
|
for (var i = 0; i < symbols.length; ++i) expected.add(symbols[i])
|
||||||
for (var i = 0; i < names.length; ++i) {
|
for (var i = 0; i < names.length; ++i) {
|
||||||
var name = names[i]
|
var name = names[i]
|
||||||
var asString = String(name)
|
if (typeof name === 'symbol') {
|
||||||
if (asString !== name) {
|
|
||||||
assertEquals("[object Symbol]", asString)
|
|
||||||
assertTrue(expected.has(name))
|
assertTrue(expected.has(name))
|
||||||
expected.delete(name)
|
expected.delete(name)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user