ES6 symbols: implement name property
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Mar 2013 16:51:28 +0000 (16:51 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Mar 2013 16:51:28 +0000 (16:51 +0000)
Adds string-valued name property to symbols, and uses it for pretty-printing.

Requires allocating symbols in pointer space, with a custom iterator to skip the unboxed hash.

R=mstarzinger@chromium.org
BUG=

Review URL: https://codereview.chromium.org/12459026

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14053 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

16 files changed:
src/d8.js
src/heap-inl.h
src/heap.cc
src/log.cc
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects-visiting-inl.h
src/objects-visiting.cc
src/objects-visiting.h
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h
src/symbol.js
test/mjsunit/harmony/symbols.js

index 8b30fcf..df10461 100644 (file)
--- a/src/d8.js
+++ b/src/d8.js
@@ -2215,7 +2215,7 @@ function Stringify(x, depth) {
     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") {
index 9ed65d8..a15b8ef 100644 (file)
@@ -399,7 +399,9 @@ AllocationSpace Heap::TargetSpaceId(InstanceType type) {
   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.
index 949661d..7c9a7fd 100644 (file)
@@ -1779,6 +1779,10 @@ class ScavengingVisitor : public StaticVisitorBase {
                     &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>);
@@ -5427,10 +5431,10 @@ MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
 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());
@@ -5446,6 +5450,7 @@ MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) {
 
   Symbol::cast(result)->set_hash_field(
       Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
+  Symbol::cast(result)->set_name(undefined_value());
 
   ASSERT(result->IsSymbol());
   return result;
index 4ec981c..5108e67 100644 (file)
@@ -644,7 +644,17 @@ void Logger::ApiNamedSecurityCheck(Object* key) {
         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 {
@@ -833,8 +843,16 @@ void Logger::ApiNamedPropertyAccess(const char* tag,
         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);
+    }
   }
 }
 
@@ -902,7 +920,14 @@ void Logger::CallbackEventInternal(const char* prefix, Name* name,
         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();
@@ -978,8 +1003,15 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
     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(')');
     }
   }
@@ -1006,7 +1038,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
     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();
@@ -1036,8 +1075,15 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
     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(')');
     }
   }
@@ -1073,7 +1119,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
         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());
@@ -1138,7 +1191,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
        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());
@@ -1358,7 +1418,14 @@ void Logger::SuspectReadEvent(Name* name, Object* obj) {
     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();
index 82a71a5..92867db 100644 (file)
@@ -220,6 +220,7 @@ void Symbol::SymbolVerify() {
   CHECK(IsSymbol());
   CHECK(HasHashCode());
   CHECK_GT(Hash(), 0);
+  CHECK(name()->IsUndefined() || name()->IsString());
 }
 
 
index 0254261..b2bad48 100644 (file)
@@ -2505,6 +2505,9 @@ bool Name::Equals(Name* other) {
 }
 
 
+ACCESSORS(Symbol, name, Object, kNameOffset)
+
+
 bool String::Equals(String* other) {
   if (other == this) return true;
   if (this->IsInternalizedString() && other->IsInternalizedString()) {
index 4522ee4..86382e1 100644 (file)
@@ -552,6 +552,9 @@ static const char* TypeToString(InstanceType type) {
 void Symbol::SymbolPrint(FILE* out) {
   HeapObject::PrintHeader(out, "Symbol");
   PrintF(out, " - hash: %d\n", Hash());
+  PrintF(out, " - name: ");
+  name()->ShortPrint();
+  PrintF(out, "\n");
 }
 
 
index 2b7fcf3..6a64cbf 100644 (file)
@@ -49,6 +49,11 @@ void StaticNewSpaceVisitor<StaticVisitor>::Initialize() {
                   SlicedString::BodyDescriptor,
                   int>::Visit);
 
+  table_.Register(kVisitSymbol,
+                  &FixedBodyVisitor<StaticVisitor,
+                  Symbol::BodyDescriptor,
+                  int>::Visit);
+
   table_.Register(kVisitFixedArray,
                   &FlexibleBodyVisitor<StaticVisitor,
                   FixedArray::BodyDescriptor,
@@ -110,6 +115,11 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
                   SlicedString::BodyDescriptor,
                   void>::Visit);
 
+  table_.Register(kVisitSymbol,
+                  &FixedBodyVisitor<StaticVisitor,
+                  Symbol::BodyDescriptor,
+                  void>::Visit);
+
   table_.Register(kVisitFixedArray, &FixedArrayVisitor::Visit);
 
   table_.Register(kVisitFixedDoubleArray, &DataObjectVisitor::Visit);
index 088f5eb..4fe0624 100644 (file)
@@ -129,9 +129,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
                                  Foreign::kSize);
 
     case SYMBOL_TYPE:
-      return GetVisitorIdForSize(kVisitDataObject,
-                                 kVisitDataObjectGeneric,
-                                 Symbol::kSize);
+      return kVisitSymbol;
 
     case FILLER_TYPE:
       return kVisitDataObjectGeneric;
index 9b2422c..d4a2ed2 100644 (file)
@@ -84,6 +84,7 @@ class StaticVisitorBase : public AllStatic {
   V(StructGeneric)            \
   V(ConsString)               \
   V(SlicedString)             \
+  V(Symbol)                   \
   V(Oddball)                  \
   V(Code)                     \
   V(Map)                      \
index 5fb9738..c73c61d 100644 (file)
@@ -1460,9 +1460,16 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
         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);
@@ -1572,6 +1579,8 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
       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:
index c8654e6..8a1bcd2 100644 (file)
@@ -7398,6 +7398,9 @@ class Name: public HeapObject {
 // 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);
 
@@ -7406,7 +7409,11 @@ class Symbol: public Name {
   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);
index a551d44..e1a666f 100644 (file)
@@ -684,8 +684,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
 
 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();
 }
 
 
index 94edf1a..f53625e 100644 (file)
@@ -297,7 +297,8 @@ namespace internal {
   F(IsJSModule, 1, 1) \
   \
   /* Harmony symbols */ \
-  F(CreateSymbol, 0, 1) \
+  F(CreateSymbol, 1, 1) \
+  F(SymbolName, 1, 1) \
   \
   /* Harmony proxies */ \
   F(CreateJSProxy, 2, 1) \
index b67e00b..f478bac 100644 (file)
@@ -30,7 +30,8 @@
 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 {
@@ -38,6 +39,16 @@ function SymbolConstructor(x) {
   }
 }
 
+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');
 }
@@ -61,6 +72,7 @@ function SetUpSymbol() {
   %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
index fe7fd0a..3083d06 100644 (file)
@@ -37,6 +37,9 @@ function TestNew() {
   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())
@@ -79,6 +82,15 @@ function TestPrototype() {
 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)