Skip to content

Commit f55c747

Browse files
committed
[MERGE #5828 @boingoing] Implement Symbol.prototype.description
Merge pull request #5828 from boingoing:symbol#description The proposal is stage 3 and shipping in Chrome, Firefox, and Safari stable. Include a flag (-ESSymbolDescription) enabled by default. See spec: https://tc39.github.io/proposal-Symbol-description/ Fixes #5825
2 parents b26f770 + 5ac55e7 commit f55c747

File tree

9 files changed

+96
-3
lines changed

9 files changed

+96
-3
lines changed

lib/Common/ConfigFlagsList.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ PHASE(All)
655655
#define DEFAULT_CONFIG_ES6RegExSticky (true)
656656
#define DEFAULT_CONFIG_ES2018RegExDotAll (true)
657657
#define DEFAULT_CONFIG_ESBigInt (false)
658+
#define DEFAULT_CONFIG_ESSymbolDescription (true)
658659
#ifdef COMPILE_DISABLE_ES6RegExPrototypeProperties
659660
// If ES6RegExPrototypeProperties needs to be disabled by compile flag, DEFAULT_CONFIG_ES6RegExPrototypeProperties should be false
660661
#define DEFAULT_CONFIG_ES6RegExPrototypeProperties (false)
@@ -1189,6 +1190,9 @@ FLAGR(Boolean, WinRTAdaptiveApps , "Enable the adaptive apps feature, all
11891190
// ES BigInt flag
11901191
FLAGR(Boolean, ESBigInt, "Enable ESBigInt flag", DEFAULT_CONFIG_ESBigInt)
11911192

1193+
// ES Symbol.prototype.description flag
1194+
FLAGR(Boolean, ESSymbolDescription, "Enable Symbol.prototype.description", DEFAULT_CONFIG_ESSymbolDescription)
1195+
11921196
// This flag to be removed once JITing generator functions is stable
11931197
FLAGNR(Boolean, JitES6Generators , "Enable JITing of ES6 generators", false)
11941198

lib/Runtime/Base/ThreadConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ FLAG_RELEASE(IsESSharedArrayBufferEnabled, ESSharedArrayBuffer)
4949
FLAG_RELEASE(IsESDynamicImportEnabled, ESDynamicImport)
5050
FLAG_RELEASE(IsESBigIntEnabled, ESBigInt)
5151
FLAG_RELEASE(IsESExportNsAsEnabled, ESExportNsAs)
52+
FLAG_RELEASE(IsESSymbolDescriptionEnabled, ESSymbolDescription)
5253
#ifdef ENABLE_PROJECTION
5354
FLAG(AreWinRTDelegatesInterfaces, WinRTDelegateInterfaces)
5455
FLAG_RELEASE(IsWinRTAdaptiveAppsEnabled, WinRTAdaptiveApps)

lib/Runtime/Library/JavascriptBuiltInFunctionList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ BUILTIN(JavascriptSymbol, ToString, EntryToString, FunctionInfo::ErrorOnNew | Fu
277277
BUILTIN(JavascriptSymbol, For, EntryFor, FunctionInfo::ErrorOnNew)
278278
BUILTIN(JavascriptSymbol, KeyFor, EntryKeyFor, FunctionInfo::ErrorOnNew)
279279
BUILTIN(JavascriptSymbol, SymbolToPrimitive, EntrySymbolToPrimitive, FunctionInfo::ErrorOnNew)
280+
BUILTIN(JavascriptSymbol, Description, EntryDescription, FunctionInfo::ErrorOnNew | FunctionInfo::HasNoSideEffect | FunctionInfo::CanBeHoisted)
280281
BUILTIN(JavascriptProxy, Revocable, EntryRevocable, FunctionInfo::ErrorOnNew)
281282
BUILTIN(JavascriptProxy, Revoke, EntryRevoke, FunctionInfo::ErrorOnNew)
282283
BUILTIN(JavascriptProxy, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2399,7 +2399,7 @@ namespace Js
23992399

24002400
bool JavascriptLibrary::InitializeSymbolPrototype(DynamicObject* symbolPrototype, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
24012401
{
2402-
typeHandler->Convert(symbolPrototype, mode, 5);
2402+
typeHandler->Convert(symbolPrototype, mode, 6);
24032403
// Note: Any new function addition/deletion/modification should also be updated in JavascriptLibrary::ProfilerRegisterSymbol
24042404
// so that the update is in sync with profiler
24052405
JavascriptLibrary* library = symbolPrototype->GetLibrary();
@@ -2423,6 +2423,12 @@ namespace Js
24232423
&JavascriptSymbol::EntryInfo::SymbolToPrimitive, 1));
24242424
symbolPrototype->SetWritable(PropertyIds::_symbolToPrimitive, false);
24252425
}
2426+
2427+
if (scriptContext->GetConfig()->IsESSymbolDescriptionEnabled())
2428+
{
2429+
library->AddAccessorsToLibraryObject(symbolPrototype, PropertyIds::description, &JavascriptSymbol::EntryInfo::Description, nullptr);
2430+
}
2431+
24262432
symbolPrototype->SetHasNoEnumerableProperties(true);
24272433

24282434
return true;
@@ -7441,6 +7447,7 @@ namespace Js
74417447
REG_OBJECTS_LIB_FUNC(toString, JavascriptSymbol::EntryToString);
74427448
REG_OBJECTS_LIB_FUNC2(for_, _u("for"), JavascriptSymbol::EntryFor);
74437449
REG_OBJECTS_LIB_FUNC(keyFor, JavascriptSymbol::EntryKeyFor);
7450+
REG_OBJECTS_LIB_FUNC(description, JavascriptSymbol::EntryDescription);
74447451

74457452
return hr;
74467453
}

lib/Runtime/Library/JavascriptSymbol.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,35 @@ namespace Js
202202
}
203203
}
204204

205+
// Symbol.prototype.description
206+
Var JavascriptSymbol::EntryDescription(RecyclableObject* function, CallInfo callInfo, ...)
207+
{
208+
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
209+
210+
ARGUMENTS(args, callInfo);
211+
AssertMsg(args.Info.Count, "Should always have implicit 'this'.");
212+
ScriptContext* scriptContext = function->GetScriptContext();
213+
214+
Assert(!(callInfo.Flags & CallFlags_New));
215+
216+
const PropertyRecord* val;
217+
Var aValue = args[0];
218+
if (VarIs<JavascriptSymbol>(aValue))
219+
{
220+
val = VarTo<JavascriptSymbol>(aValue)->GetValue();
221+
}
222+
else if (VarIs<JavascriptSymbolObject>(aValue))
223+
{
224+
val = VarTo<JavascriptSymbolObject>(aValue)->GetValue();
225+
}
226+
else
227+
{
228+
return TryInvokeRemotelyOrThrow(EntryDescription, scriptContext, args, JSERR_This_NeedSymbol, _u("Symbol.prototype.description"));
229+
}
230+
231+
return scriptContext->GetPropertyString(val->GetPropertyId());
232+
}
233+
205234
RecyclableObject * JavascriptSymbol::CloneToScriptContext(ScriptContext* requestContext)
206235
{
207236
// PropertyRecords are per-ThreadContext so we can just create a new primitive wrapper

lib/Runtime/Library/JavascriptSymbol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace Js
3636
static FunctionInfo ToString;
3737
static FunctionInfo For;
3838
static FunctionInfo KeyFor;
39+
static FunctionInfo Description;
3940

4041
static FunctionInfo SymbolToPrimitive;
4142
};
@@ -46,6 +47,7 @@ namespace Js
4647
static Var EntryFor(RecyclableObject* function, CallInfo callInfo, ...);
4748
static Var EntryKeyFor(RecyclableObject* function, CallInfo callInfo, ...);
4849
static Var EntrySymbolToPrimitive(RecyclableObject* function, CallInfo callInfo, ...);
50+
static Var EntryDescription(RecyclableObject* function, CallInfo callInfo, ...);
4951

5052
virtual BOOL Equals(Var other, BOOL* value, ScriptContext * requestContext) override;
5153
virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;

test/DebuggerCommon/symbols.js.dbg.baseline

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
"Symbol.toStringTag": "string Symbol",
109109
"valueOf": "function <large string>",
110110
"toString": "function <large string>",
111-
"Symbol.toPrimitive": "function <large string>"
111+
"Symbol.toPrimitive": "function <large string>",
112+
"description": "Error <large string>"
112113
},
113114
"name": "string Symbol",
114115
"hasInstance": "symbol <large string>",
@@ -180,7 +181,8 @@
180181
},
181182
"length": "number 1",
182183
"name": "string <large string>"
183-
}
184+
},
185+
"description": "string symobject"
184186
}
185187
},
186188
"short symbol name": "symbol Symbol(s)",

test/es7/rlexe.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,10 @@
9595
<tags>exclude_jshost</tags>
9696
</default>
9797
</test>
98+
<test>
99+
<default>
100+
<files>symboldescription.js</files>
101+
<compile-flags>-ESSymbolDescription -args summary -endargs</compile-flags>
102+
</default>
103+
</test>
98104
</regress-exe>

test/es7/symboldescription.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
7+
8+
var tests = [
9+
{
10+
name: "Symbol.prototype.description API shape",
11+
body: function () {
12+
assert.isTrue(Symbol.prototype.hasOwnProperty('description'), "Symbol.prototype has a 'description' property");
13+
14+
var descriptor = Object.getOwnPropertyDescriptor(Symbol.prototype, 'description');
15+
assert.areEqual(undefined, descriptor.writable, "writable(description) isn't set");
16+
assert.isFalse(descriptor.enumerable, "enumerable(description) must be false");
17+
assert.isTrue(descriptor.configurable, "configurable(description) must be true");
18+
19+
assert.areEqual('function', typeof descriptor.get, "Symbol.prototype.description is an accessor with a getter");
20+
assert.areEqual(0, descriptor.get.length, "Symbol.prototype.description getter has length 0");
21+
assert.areEqual("get description", descriptor.get.name, "Symbol.prototype.description getter has name 'get description'");
22+
assert.areEqual(undefined, descriptor.set, "Symbol.prototype.description has no setter");
23+
}
24+
},
25+
{
26+
name: "Symbol.prototype.description functionality",
27+
body: function () {
28+
assert.areEqual('foo', Symbol('foo').description);
29+
assert.areEqual('', Symbol('').description);
30+
assert.areEqual('null', Symbol(null).description);
31+
32+
// Symbol().description === undefined;
33+
// Should be true but we have a limitation in ChakraCore right now.
34+
// See ##5833
35+
assert.areEqual('', Symbol().description);
36+
assert.areEqual('', Symbol(undefined).description);
37+
}
38+
},
39+
];
40+
41+
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

0 commit comments

Comments
 (0)