case "string":
return "\"" + x.toString() + "\"";
case "symbol":
- return "Symbol()";
+ return "Symbol(" + (x.name ? Stringify(x.name, depth) : "") + ")"
case "object":
if (x === null) return "null";
if (x.constructor && x.constructor.name === "Array") {
ASSERT(type != ODDBALL_TYPE);
ASSERT(type != JS_GLOBAL_PROPERTY_CELL_TYPE);
- if (type < FIRST_NONSTRING_TYPE) {
+ if (type <= LAST_NAME_TYPE) {
+ if (type == SYMBOL_TYPE) return OLD_POINTER_SPACE;
+ ASSERT(type < FIRST_NONSTRING_TYPE);
// There are four string representations: sequential strings, external
// strings, cons strings, and sliced strings.
// Only the latter two contain non-map-word pointers to heap objects.
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SlicedString::kSize>);
+ table_.Register(kVisitSymbol,
+ &ObjectEvacuationStrategy<POINTER_OBJECT>::
+ template VisitSpecialized<Symbol::kSize>);
+
table_.Register(kVisitSharedFunctionInfo,
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SharedFunctionInfo::kSize>);
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;
+ AllocationSpace space = pretenure == TENURED ? OLD_POINTER_SPACE : NEW_SPACE;
Object* result;
- MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_DATA_SPACE);
+ MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_POINTER_SPACE);
if (!maybe->ToObject(&result)) return maybe;
HeapObject::cast(result)->set_map_no_write_barrier(symbol_map());
Symbol::cast(result)->set_hash_field(
Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
+ Symbol::cast(result)->set_name(undefined_value());
ASSERT(result->IsSymbol());
return result;
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,check-security,\"%s\"\n", *str);
} else if (key->IsSymbol()) {
- ApiEvent("api,check-security,symbol(hash %x)\n", Symbol::cast(key)->Hash());
+ Symbol* symbol = Symbol::cast(key);
+ if (symbol->name()->IsUndefined()) {
+ ApiEvent("api,check-security,symbol(hash %x)\n",
+ Symbol::cast(key)->Hash());
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
+ *str,
+ Symbol::cast(key)->Hash());
+ }
} else if (key->IsUndefined()) {
ApiEvent("api,check-security,undefined\n");
} else {
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
} else {
- uint32_t hash = Symbol::cast(name)->Hash();
- ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
+ Symbol* symbol = Symbol::cast(name);
+ uint32_t hash = symbol->Hash();
+ if (symbol->name()->IsUndefined()) {
+ ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
+ tag, *class_name, *str, hash);
+ }
}
}
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append(",1,\"%s%s\"", prefix, *str);
} else {
- msg.Append(",1,symbol(hash %x)", prefix, Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ if (symbol->name()->IsUndefined()) {
+ msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
+ } else {
+ SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
+ DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
+ }
}
msg.Append('\n');
msg.WriteToLogFile();
if (name->IsString()) {
name_buffer_->AppendString(String::cast(name));
} else {
- name_buffer_->AppendBytes("symbol(hash ");
- name_buffer_->AppendHex(Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ name_buffer_->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ name_buffer_->AppendBytes("\"");
+ name_buffer_->AppendString(String::cast(symbol->name()));
+ name_buffer_->AppendBytes("\" ");
+ }
+ name_buffer_->AppendBytes("hash ");
+ name_buffer_->AppendHex(symbol->Hash());
name_buffer_->AppendByte(')');
}
}
msg.AppendDetailed(String::cast(name), false);
msg.Append('"');
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append('\n');
msg.WriteToLogFile();
if (name->IsString()) {
name_buffer_->AppendString(String::cast(name));
} else {
- name_buffer_->AppendBytes("symbol(hash ");
- name_buffer_->AppendHex(Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ name_buffer_->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ name_buffer_->AppendBytes("\"");
+ name_buffer_->AppendString(String::cast(symbol->name()));
+ name_buffer_->AppendBytes("\" ");
+ }
+ name_buffer_->AppendBytes("hash ");
+ name_buffer_->AppendHex(symbol->Hash());
name_buffer_->AppendByte(')');
}
}
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("\"%s\"", *str);
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append(',');
msg.AppendAddress(shared->address());
String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s", *sourcestr);
} else {
- msg.Append("symbol(hash %x)", Name::cast(source)->Hash());
+ Symbol* symbol = Symbol::cast(source);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append(":%d\",", line);
msg.AppendAddress(shared->address());
msg.Append(String::cast(name));
msg.Append('"');
} else {
- msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
+ Symbol* symbol = Symbol::cast(name);
+ msg.Append("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg.Append("\"");
+ msg.AppendDetailed(String::cast(symbol->name()), false);
+ msg.Append("\" ");
+ }
+ msg.Append("hash %x)", symbol->Hash());
}
msg.Append('\n');
msg.WriteToLogFile();
CHECK(IsSymbol());
CHECK(HasHashCode());
CHECK_GT(Hash(), 0);
+ CHECK(name()->IsUndefined() || name()->IsString());
}
}
+ACCESSORS(Symbol, name, Object, kNameOffset)
+
+
bool String::Equals(String* other) {
if (other == this) return true;
if (this->IsInternalizedString() && other->IsInternalizedString()) {
void Symbol::SymbolPrint(FILE* out) {
HeapObject::PrintHeader(out, "Symbol");
PrintF(out, " - hash: %d\n", Hash());
+ PrintF(out, " - name: ");
+ name()->ShortPrint();
+ PrintF(out, "\n");
}
SlicedString::BodyDescriptor,
int>::Visit);
+ table_.Register(kVisitSymbol,
+ &FixedBodyVisitor<StaticVisitor,
+ Symbol::BodyDescriptor,
+ int>::Visit);
+
table_.Register(kVisitFixedArray,
&FlexibleBodyVisitor<StaticVisitor,
FixedArray::BodyDescriptor,
SlicedString::BodyDescriptor,
void>::Visit);
+ table_.Register(kVisitSymbol,
+ &FixedBodyVisitor<StaticVisitor,
+ Symbol::BodyDescriptor,
+ void>::Visit);
+
table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit);
table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit);
Foreign::kSize);
case SYMBOL_TYPE:
- return GetVisitorIdForSize(kVisitDataObject,
- kVisitDataObjectGeneric,
- Symbol::kSize);
+ return kVisitSymbol;
case FILLER_TYPE:
return kVisitDataObjectGeneric;
V(StructGeneric) \
V(ConsString) \
V(SlicedString) \
+ V(Symbol) \
V(Oddball) \
V(Code) \
V(Map) \
accumulator->Add("<Odd Oddball>");
break;
}
- case SYMBOL_TYPE:
- accumulator->Add("<Symbol: %d>", Symbol::cast(this)->Hash());
+ case SYMBOL_TYPE: {
+ Symbol* symbol = Symbol::cast(this);
+ accumulator->Add("<Symbol: %d", symbol->Hash());
+ if (!symbol->name()->IsUndefined()) {
+ accumulator->Add(" ");
+ String::cast(symbol->name())->StringShortPrint(accumulator);
+ }
+ accumulator->Add(">");
break;
+ }
case HEAP_NUMBER_TYPE:
accumulator->Add("<Number: ");
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
break;
case SYMBOL_TYPE:
+ Symbol::BodyDescriptor::IterateBody(this, v);
+ break;
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
// ES6 symbols.
class Symbol: public Name {
public:
+ // [name]: the print name of a symbol, or undefined if none.
+ DECL_ACCESSORS(name, Object)
+
// Casting.
static inline Symbol* cast(Object* obj);
DECLARE_VERIFIER(Symbol)
// Layout description.
- static const int kSize = Name::kSize;
+ static const int kNameOffset = Name::kSize;
+ static const int kSize = kNameOffset + kPointerSize;
+
+ typedef FixedBodyDescriptor<kNameOffset, kNameOffset + kPointerSize, kSize>
+ BodyDescriptor;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol);
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
NoHandleAllocation ha(isolate);
- ASSERT(args.length() == 0);
- return isolate->heap()->AllocateSymbol();
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
+ RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
+ Symbol* symbol;
+ MaybeObject* maybe = isolate->heap()->AllocateSymbol();
+ if (!maybe->To(&symbol)) return maybe;
+ if (name->IsString()) symbol->set_name(*name);
+ return symbol;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
+ NoHandleAllocation ha(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(Symbol, symbol, 0);
+ return symbol->name();
}
F(IsJSModule, 1, 1) \
\
/* Harmony symbols */ \
- F(CreateSymbol, 0, 1) \
+ F(CreateSymbol, 1, 1) \
+ F(SymbolName, 1, 1) \
\
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
var $Symbol = global.Symbol;
function SymbolConstructor(x) {
- var value = IS_SYMBOL(x) ? x : %CreateSymbol();
+ var value =
+ IS_SYMBOL(x) ? x : %CreateSymbol(IS_UNDEFINED(x) ? x : ToString(x));
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
}
}
+function SymbolGetName() {
+ var symbol = IS_SYMBOL_WRAPPER(this) ? %_ValueOf(this) : this;
+ if (!IS_SYMBOL(symbol)) {
+ throw MakeTypeError(
+ 'incompatible_method_receiver', ["Symbol.prototype.name", this]);
+
+ }
+ return %SymbolName(symbol);
+}
+
function SymbolToString() {
throw MakeTypeError('symbol_to_string');
}
%FunctionSetPrototype($Symbol, new $Symbol());
%SetProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
+ InstallGetter($Symbol.prototype, "name", SymbolGetName);
InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
"toString", SymbolToString,
"valueOf", SymbolValueOf
for (var i = 0; i < 2; ++i) {
for (var j = 0; j < 5; ++j) {
symbols.push(Symbol())
+ symbols.push(Symbol(undefined))
+ symbols.push(Symbol("66"))
+ symbols.push(Symbol(66))
symbols.push(Symbol(Symbol()))
symbols.push((new Symbol).valueOf())
symbols.push((new Symbol()).valueOf())
TestPrototype()
+function TestName() {
+ for (var i in symbols) {
+ var name = symbols[i].name
+ assertTrue(name === undefined || name === "66")
+ }
+}
+TestName()
+
+
function TestToString() {
for (var i in symbols) {
assertThrows(function() { String(symbols[i]) }, TypeError)