static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 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 kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
i::Handle<i::Object> name(self->class_name(), isolate);
// Native implementation of Object.prototype.toString (v8natives.js):
- // var c = %ClassOf(this);
+ // var c = %_ClassOf(this);
// if (c === 'Arguments') c = 'Object';
// return "[object " + c + "]";
__ 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);
}
-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);
__ 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()->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())) {
__ CompareRoot(r0, Heap::kTrueValueRootIndex);
__ b(eq, if_true);
__ 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);
__ 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)) {
CpuFeatureScope scope(masm(), VFP2);
// heap number -> false iff +0, -0, or NaN.
__ tst(ip, Operand(1 << Map::kIsUndetectable));
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())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ b(eq, true_label);
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ b(eq, true_label);
}
- 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);
- }
+ __ 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);
// Check that the object is a symbol.
__ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
__ 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;
case NUMBER_CHECK: {
Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
// 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) {
{ // -- S e t
Handle<JSObject> prototype =
}
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);
if (Contains(SMI)) stream->Add("Smi");
if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
if (Contains(STRING)) stream->Add("String");
+ if (Contains(SYMBOL)) stream->Add("Symbol");
if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
}
Add(STRING);
return !object->IsUndetectableObject() &&
String::cast(*object)->length() != 0;
+ } else if (object->IsSymbol()) {
+ Add(SYMBOL);
+ return true;
} else if (object->IsHeapNumber()) {
ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER);
bool ToBooleanStub::Types::NeedsMap() const {
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING)
+ || Contains(ToBooleanStub::SYMBOL)
|| Contains(ToBooleanStub::HEAP_NUMBER);
}
SMI,
SPEC_OBJECT,
STRING,
+ SYMBOL,
HEAP_NUMBER,
NUMBER_OF_TYPES
};
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
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(INTERNAL_ARRAY_FUNCTION_INDEX, JSFunction, internal_array_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
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) \
NUMBER_FUNCTION_INDEX,
STRING_FUNCTION_INDEX,
STRING_FUNCTION_PROTOTYPE_MAP_INDEX,
+ SYMBOL_FUNCTION_INDEX,
OBJECT_FUNCTION_INDEX,
INTERNAL_ARRAY_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
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,
return x.toString();
case "string":
return "\"" + x.toString() + "\"";
- // TODO(rossberg): add symbol case
+ case "symbol":
+ return "Symbol()";
case "object":
if (x === null) return "null";
if (x.constructor && x.constructor.name === "Array") {
V(prototype_string, "prototype") \
V(string_string, "string") \
V(String_string, "String") \
+ V(symbol_string, "symbol") \
+ V(Symbol_string, "Symbol") \
V(Date_string, "Date") \
V(this_string, "this") \
V(to_string_string, "toString") \
ToBooleanStub::UNDEFINED |
ToBooleanStub::NULL_TYPE |
ToBooleanStub::SPEC_OBJECT |
- ToBooleanStub::STRING);
+ ToBooleanStub::STRING |
+ ToBooleanStub::SYMBOL);
if (expected_input_types_.ContainsAnyOf(tagged_types)) {
return Representation::Tagged();
} else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
typecheck->SetSuccessorAt(1, not_spec_object);
current_block()->Finish(typecheck);
if_spec_object->AddLeaveInlined(return_value, 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);
- }
+ not_spec_object->AddLeaveInlined(receiver, state);
}
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
// Return from an inlined setter call. The returned value is never used, the
}
-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)));
__ 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);
__ 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)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number, false_result;
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
- // TODO(rossberg): incorporate symbols.
ZoneList<Expression*>* args = expr->arguments();
ASSERT(args->length() == 1);
}
-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);
__ test_b(FieldOperand(edx, Map::kBitFieldOffset),
1 << Map::kIsUndetectable);
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())) {
__ cmp(eax, isolate()->factory()->true_value());
__ j(equal, if_true);
__ 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);
__ bind(¬_string);
}
+ if (expected.Contains(ToBooleanStub::SYMBOL)) {
+ // Symbol value -> true.
+ __ CmpInstanceType(map, SYMBOL_TYPE);
+ __ j(equal, true_label);
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
1 << Map::kIsUndetectable);
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())) {
__ cmp(input, factory()->true_value());
__ j(equal, true_label);
__ cmp(input, factory()->null_value());
__ j(equal, true_label);
}
- 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);
- }
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
// Check that the object is a symbol.
__ CmpObjectType(edx, SYMBOL_TYPE, eax);
__ 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;
case NUMBER_CHECK: {
// If the object is a value, we use the prototype map for the cache.
ASSERT(object->IsString() || object->IsSymbol() ||
object->IsNumber() || object->IsBoolean());
- return DELEGATE_MAP;
+ return PROTOTYPE_MAP;
}
!object->HasFastProperties() &&
!object->IsJSGlobalProxy() &&
!object->IsJSGlobalObject()) {
- return DELEGATE_MAP;
+ return PROTOTYPE_MAP;
}
return OWN_MAP;
}
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
Object* object,
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());
return JSObject::cast(map_owner);
}
// The stub was generated for JSObject but called for non-JSObject.
// IC::GetCodeCacheHolder is not applicable.
return false;
- } else if (cache_holder == DELEGATE_MAP &&
+ } else if (cache_holder == PROTOTYPE_MAP &&
receiver->GetPrototype(isolate)->IsNull()) {
// IC::GetCodeCacheHolder is not applicable.
return false;
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_SYMBOL(arg) = (typeof(arg) === 'symbol');
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
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_ERROR(arg) = (%_ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
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"],
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"],
module_type_error: ["Module '", "%0", "' used improperly"],
module_export_undefined: ["Export '", "%0", "' is not defined in module"],
holder = native_context->number_function()->instance_prototype();
} else if (IsString()) {
holder = native_context->string_function()->instance_prototype();
+ } else if (IsSymbol()) {
+ holder = native_context->symbol_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);
// 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() && !receiver->IsSymbol()
+ Object* last = result->IsProperty()
? result->holder()
: Object::cast(heap->null_value());
ASSERT(this != this->GetPrototype(isolate));
holder = native_context->number_function()->instance_prototype();
} else if (holder->IsString()) {
holder = native_context->string_function()->instance_prototype();
+ } else if (holder->IsSymbol()) {
+ holder = native_context->symbol_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 {
if (heap_object->IsString()) {
return context->string_function()->instance_prototype();
}
+ if (heap_object->IsSymbol()) {
+ return context->symbol_function()->instance_prototype();
+ }
if (heap_object->IsBoolean()) {
return context->boolean_function()->instance_prototype();
} else {
}
-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 name, an odd-ball,
// a real JS object, or a Harmony proxy.
// 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.
}
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_string();
+ case SYMBOL_TYPE:
+ return isolate->heap()->symbol_string();
case JS_FUNCTION_TYPE:
case JS_FUNCTION_PROXY_TYPE:
return isolate->heap()->function_string();
#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) \
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return $NaN;
+ if (IS_SYMBOL(x)) return $NaN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return $NaN;
+ if (IS_SYMBOL(x)) return $NaN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
// ECMA-262, section 9.9, page 36.
function ToObject(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_BOOLEAN(x)) return new $Boolean(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
"use strict";
-var $Symbol = function() { return %CreateSymbol() }
-global.Symbol = $Symbol
+var $Symbol = global.Symbol;
-// Symbols only have a toString method and no prototype.
-var SymbolDelegate = {
- __proto__: null,
- toString: $Object.prototype.toString
+function SymbolConstructor(x) {
+ var value = IS_SYMBOL(x) ? x : %CreateSymbol();
+ if (%_IsConstructCall()) {
+ %_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();
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;
+ case SYMBOL_CHECK:
+ function = native_context_->symbol_function();
+ break;
case NUMBER_CHECK:
function = native_context_->number_function();
break;
enum InlineCacheHolderFlag {
OWN_MAP, // For fast properties objects.
- DELEGATE_MAP // For slow properties objects (except GlobalObjects).
+ PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
};
function ObjectToString() {
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)) + "]";
}
// DefineObjectProperty() to modify its value.
// Step 3 - Special handling for length property.
- if (p == "length") {
+ if (p === "length") {
var length = obj.length;
if (!desc.hasValue()) {
return DefineObjectProperty(obj, "length", desc, should_throw);
__ 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);
}
-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);
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
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())) {
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
__ 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);
Immediate(1 << Map::kIsUndetectable));
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())) {
__ CompareRoot(input, Heap::kTrueValueRootIndex);
__ j(equal, true_label);
__ CompareRoot(input, Heap::kNullValueRootIndex);
__ j(equal, true_label);
}
- 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);
- }
+ __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
__ j(below, false_label);
__ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
__ j(above, false_label);
// Check that the object is a symbol.
__ CmpObjectType(rdx, SYMBOL_TYPE, rax);
__ 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;
case NUMBER_CHECK: {
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())
+ for (var i = 0; i < 2; ++i) {
+ for (var j = 0; j < 5; ++j) {
+ symbols.push(Symbol())
+ symbols.push(Symbol(Symbol()))
+ symbols.push((new Symbol).valueOf())
+ symbols.push((new Symbol()).valueOf())
+ symbols.push((new Symbol(Symbol())).valueOf())
+ symbols.push(Object(Symbol()).valueOf())
+ symbols.push((indirect()).valueOf())
+ }
+ %OptimizeFunctionOnNextCall(indirect)
+ indirect() // Call once before GC throws away type feedback.
+ gc() // Promote existing symbols and then allocate some more.
}
}
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]))
+ assertEquals("symbol", typeof symbols[i])
+ assertTrue(typeof symbols[i] === "symbol")
+ assertEquals(null, %_ClassOf(symbols[i]))
+ assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i])))
+ assertEquals("Symbol", %_ClassOf(Object(symbols[i])))
}
}
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() {
// Every symbol should equal itself.
for (var i in symbols) {
function TestGet() {
for (var i in symbols) {
- assertEquals("[object Symbol]", symbols[i].toString())
- assertEquals(undefined, symbols[i].valueOf)
+ assertThrows(function() { symbols[i].toString() }, TypeError)
+ assertEquals(symbols[i], symbols[i].valueOf())
assertEquals(undefined, symbols[i].a)
assertEquals(undefined, symbols[i]["a" + "b"])
assertEquals(undefined, symbols[i]["" + "1"])
function TestSet() {
for (var i in symbols) {
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
assertEquals(undefined, symbols[i].a)
symbols[i]["a" + "b"] = 0
function TestKeyEnum(obj) {
for (var name in obj) {
- assertFalse(%_IsSymbol(name))
+ assertTrue(typeof name !== "symbol")
}
}
for (var i = 0; i < symbols.length; ++i) expected.add(symbols[i])
for (var i = 0; i < names.length; ++i) {
var name = names[i]
- var asString = String(name)
- if (asString !== name) {
- assertEquals("[object Symbol]", asString)
+ if (typeof name === 'symbol') {
assertTrue(expected.has(name))
expected.delete(name)
}