ES6 symbols: implement name property
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
This commit is contained in:
parent
71c1f69b06
commit
2657e432e4
@ -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") {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
91
src/log.cc
91
src/log.cc
@ -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();
|
||||
|
@ -220,6 +220,7 @@ void Symbol::SymbolVerify() {
|
||||
CHECK(IsSymbol());
|
||||
CHECK(HasHashCode());
|
||||
CHECK_GT(Hash(), 0);
|
||||
CHECK(name()->IsUndefined() || name()->IsString());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -84,6 +84,7 @@ class StaticVisitorBase : public AllStatic {
|
||||
V(StructGeneric) \
|
||||
V(ConsString) \
|
||||
V(SlicedString) \
|
||||
V(Symbol) \
|
||||
V(Oddball) \
|
||||
V(Code) \
|
||||
V(Map) \
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user