Implement ES6 Symbol
https://bugs.webkit.org/show_bug.cgi?id=140435
Reviewed by Geoffrey Garen.
Source/JavaScriptCore:
This patch implements ES6 Symbol. In this patch, we don't support
Symbol.keyFor, Symbol.for, Object.getOwnPropertySymbols. They will be
supported in the subsequent patches.
Since ES6 Symbol is introduced as new primitive value, we implement
Symbol as a derived class from JSCell. And now JSValue accepts Symbol*
as a new primitive value.
Symbol has a *unique* flagged StringImpl* as an `uid`. Which pointer
value represents the Symbol's identity. So don't compare Symbol's
JSCell pointer value for comparison.
This enables re-producing Symbol primitive value from StringImpl* uid
by executing`Symbol::create(vm, uid)`. This is needed to produce
Symbol primitive values from stored StringImpl* in `Object.getOwnPropertySymbols`.
And Symbol.[[Description]] is folded into the string value of Symbol's uid.
By doing so, we can represent ES6 Symbol without extending current PropertyTable key; StringImpl*.
* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.order:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createBuiltinExecutable):
* builtins/BuiltinNames.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::operationPutByValInternal):
* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::subtype):
* interpreter/Interpreter.cpp:
* jit/JITOperations.cpp:
(JSC::getByVal):
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::getByVal):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* runtime/CommonIdentifiers.h:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::opIn):
* runtime/ExceptionHelpers.cpp:
(JSC::createUndefinedVariableError):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::synthesizePrototype):
(JSC::JSValue::dumpInContextAssumingStructure):
(JSC::JSValue::toStringSlowCase):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::isSymbol):
(JSC::JSValue::isPrimitive):
(JSC::JSValue::toPropertyKey):
It represents ToPropertyKey abstract operation in the ES6 spec.
It cleans up the old implementation's `isName` checks.
And to prevent performance regressions in
js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html
js/regress/fold-get-by-id-to-multi-get-by-offset.html
we annnotate this function as ALWAYS_INLINE.
(JSC::JSValue::getPropertySlot):
(JSC::JSValue::get):
(JSC::JSValue::equalSlowCaseInline):
(JSC::JSValue::strictEqualSlowCaseInline):
* runtime/JSCell.cpp:
(JSC::JSCell::put):
(JSC::JSCell::putByIndex):
(JSC::JSCell::toPrimitive):
(JSC::JSCell::getPrimitiveNumber):
(JSC::JSCell::toNumber):
(JSC::JSCell::toObject):
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::isSymbol):
(JSC::JSCell::toBoolean):
(JSC::JSCell::pureToBoolean):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::symbolPrototype):
(JSC::JSGlobalObject::symbolObjectStructure):
* runtime/JSONObject.cpp:
(JSC::Stringifier::Stringifier):
* runtime/JSSymbolTableObject.cpp:
(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):
* runtime/JSType.h:
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::isName): Deleted.
* runtime/MapData.cpp:
(JSC::MapData::find):
(JSC::MapData::add):
(JSC::MapData::remove):
(JSC::MapData::replaceAndPackBackingStore):
* runtime/MapData.h:
(JSC::MapData::clear):
* runtime/NameInstance.h: Removed.
* runtime/NamePrototype.cpp: Removed.
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorGetOwnPropertyDescriptor):
(JSC::objectConstructorDefineProperty):
* runtime/ObjectPrototype.cpp:
(JSC::objectProtoFuncHasOwnProperty):
(JSC::objectProtoFuncDefineGetter):
(JSC::objectProtoFuncDefineSetter):
(JSC::objectProtoFuncLookupGetter):
(JSC::objectProtoFuncLookupSetter):
(JSC::objectProtoFuncPropertyIsEnumerable):
* runtime/Operations.cpp:
(JSC::jsTypeStringForValue):
(JSC::jsIsObjectType):
* runtime/PrivateName.h:
(JSC::PrivateName::PrivateName):
(JSC::PrivateName::operator==):
(JSC::PrivateName::operator!=):
* runtime/PropertyMapHashTable.h:
(JSC::PropertyTable::find):
(JSC::PropertyTable::get):
* runtime/PropertyName.h:
(JSC::PropertyName::PropertyName):
(JSC::PropertyName::publicName):
* runtime/SmallStrings.h:
* runtime/StringConstructor.cpp:
(JSC::callStringConstructor):
In ES6, String constructor accepts Symbol to execute `String(symbol)`.
* runtime/Structure.cpp:
(JSC::Structure::getPropertyNamesFromStructure):
* runtime/StructureInlines.h:
(JSC::Structure::prototypeForLookup):
* runtime/Symbol.cpp: Added.
(JSC::Symbol::Symbol):
(JSC::SymbolObject::create):
(JSC::Symbol::toPrimitive):
(JSC::Symbol::toBoolean):
(JSC::Symbol::getPrimitiveNumber):
(JSC::Symbol::toObject):
(JSC::Symbol::toNumber):
(JSC::Symbol::destroy):
(JSC::Symbol::descriptiveString):
* runtime/Symbol.h: Added.
(JSC::Symbol::createStructure):
(JSC::Symbol::create):
(JSC::Symbol::privateName):
(JSC::Symbol::finishCreation):
(JSC::asSymbol):
* runtime/SymbolConstructor.cpp: Renamed from Source/JavaScriptCore/runtime/NameConstructor.cpp.
(JSC::SymbolConstructor::SymbolConstructor):
(JSC::SymbolConstructor::finishCreation):
(JSC::callSymbol):
(JSC::SymbolConstructor::getConstructData):
(JSC::SymbolConstructor::getCallData):
* runtime/SymbolConstructor.h: Renamed from Source/JavaScriptCore/runtime/NameConstructor.h.
(JSC::SymbolConstructor::create):
(JSC::SymbolConstructor::createStructure):
* runtime/SymbolObject.cpp: Renamed from Source/JavaScriptCore/runtime/NameInstance.cpp.
(JSC::SymbolObject::SymbolObject):
(JSC::SymbolObject::finishCreation):
(JSC::SymbolObject::defaultValue):
Now JSC doesn't support @@toPrimitive. So instead of it, we implement
Symbol.prototype[@@toPrimitive] as ES5 Symbol.[[DefaultValue]].
* runtime/SymbolObject.h: Added.
(JSC::SymbolObject::create):
(JSC::SymbolObject::internalValue):
(JSC::SymbolObject::createStructure):
* runtime/SymbolPrototype.cpp: Added.
(JSC::SymbolPrototype::SymbolPrototype):
(JSC::SymbolPrototype::finishCreation):
(JSC::SymbolPrototype::getOwnPropertySlot):
(JSC::symbolProtoFuncToString):
(JSC::symbolProtoFuncValueOf):
* runtime/SymbolPrototype.h: Renamed from Source/JavaScriptCore/runtime/NamePrototype.h.
(JSC::SymbolPrototype::create):
(JSC::SymbolPrototype::createStructure):
SymbolPrototype object is ordinary JS object. Not wrapper object of Symbol.
It is tested in js/symbol-prototype-is-ordinary-object.html.
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
Source/WTF:
Introduce new unique string mechanizm into StringImpl.
It is used for implementing Symbol which holds a [[Description]] value.
* wtf/text/AtomicString.h:
(WTF::AtomicString::add):
(WTF::AtomicString::addWithStringTableProvider):
Previously, we checked `isAtomic()` or `!length()`. This guard can filter out EmptyUnique.
But now, we introduced new unique StringImpl. Since it has an actual string value, we need to check `isUnique()`.
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::~StringImpl):
(WTF::StringImpl::createUnique):
In createUnique, we leverage Substring mechanizm to produce a new unique
string from an existing string.
* wtf/text/StringImpl.h:
(WTF::StringImpl::StringImpl):
(WTF::StringImpl::createUniqueEmpty):
(WTF::StringImpl::flagIsUnique):
(WTF::StringImpl::isUnique):
(WTF::StringImpl::setIsAtomic):
(WTF::StringImpl::createEmptyUnique): Deleted.
(WTF::StringImpl::isEmptyUnique): Deleted.
Instead of EmptyUnique, we introduced new flag to StringImpl, `isUnique`.
While EmptyUnique cannot hold any string values except for empty string,
the unique StringImpl can hold any String values.
We fold the Symbol's descriptiveString value here.
* wtf/text/StringStatics.cpp:
(WTF::StringImpl::hashAndFlagsForUnique):
(WTF::StringImpl::hashAndFlagsForEmptyUnique): Deleted.
LayoutTests:
* js/script-tests/symbol-abstract-equality-comparison.js: Added.
(Pair):
(relationalOperators.forEach):
* js/script-tests/symbol-abstract-relational-comparison.js: Added.
(relationalOperators.forEach):
* js/script-tests/symbol-in-map.js: Added.
(set shouldBe):
* js/script-tests/symbol-object.js: Added.
* js/script-tests/symbol-prototype-is-ordinary-object.js: Added.
* js/script-tests/symbol-strict-equality-comparison.js: Added.
(Pair):
(relationalOperators.forEach):
* js/script-tests/symbol-tostring.js: Added.
* js/script-tests/symbols.js: Renamed from LayoutTests/js/script-tests/names.js.
(forIn):
* js/symbol-abstract-equality-comparison-expected.txt: Added.
* js/symbol-abstract-equality-comparison.html: Copied from LayoutTests/js/names.html.
* js/symbol-abstract-relational-comparison-expected.txt: Added.
* js/symbol-abstract-relational-comparison.html: Copied from LayoutTests/js/names.html.
* js/symbol-in-map-expected.txt: Added.
* js/symbol-in-map.html: Copied from LayoutTests/js/names.html.
* js/symbol-object-expected.txt: Added.
* js/symbol-object.html: Copied from LayoutTests/js/names.html.
* js/symbol-prototype-is-ordinary-object-expected.txt: Added.
* js/symbol-prototype-is-ordinary-object.html: Copied from LayoutTests/js/names.html.
* js/symbol-strict-equality-comparison-expected.txt: Added.
* js/symbol-strict-equality-comparison.html: Copied from LayoutTests/js/names.html.
* js/symbol-tostring-expected.txt: Added.
* js/symbol-tostring.html: Copied from LayoutTests/js/names.html.
* js/symbols-expected.txt: Renamed from LayoutTests/js/names-expected.txt.
* js/symbols.html: Renamed from LayoutTests/js/names.html.
Canonical link: https://commits.webkit.org/159106@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@179429 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-01-31 01:23:56 +00:00
|
|
|
This tests Abstract Equality Comparison results with Symbols.
|
|
|
|
|
|
|
|
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
|
|
|
|
|
|
|
|
|
|
|
|
PASS 42 == symbol is false
|
|
|
|
PASS symbol == 42 is false
|
|
|
|
PASS NaN == symbol is false
|
|
|
|
PASS symbol == NaN is false
|
|
|
|
PASS Infinity == symbol is false
|
|
|
|
PASS symbol == Infinity is false
|
|
|
|
PASS true == symbol is false
|
|
|
|
PASS symbol == true is false
|
|
|
|
PASS false == symbol is false
|
|
|
|
PASS symbol == false is false
|
|
|
|
PASS null == symbol is false
|
|
|
|
PASS symbol == null is false
|
|
|
|
PASS undefined == symbol is false
|
|
|
|
PASS symbol == undefined is false
|
|
|
|
PASS 'Cappuccino' == symbol is false
|
|
|
|
PASS symbol == 'Cappuccino' is false
|
|
|
|
PASS symbol == symbol is true
|
|
|
|
PASS symbol == symbol is true
|
|
|
|
PASS Symbol.iterator == symbol is false
|
|
|
|
PASS symbol == Symbol.iterator is false
|
|
|
|
PASS object == symbol is false
|
|
|
|
PASS symbol == object is false
|
|
|
|
PASS array == symbol is false
|
|
|
|
PASS symbol == array is false
|
|
|
|
PASS date == symbol is false
|
|
|
|
PASS symbol == date is false
|
|
|
|
PASS symbolObject == symbol is true
|
|
|
|
PASS symbol == symbolObject is true
|
|
|
|
PASS Symbol('Cocoa') == symbol is false
|
|
|
|
PASS symbol == Symbol('Cocoa') is false
|
|
|
|
PASS 42 != symbol is true
|
|
|
|
PASS symbol != 42 is true
|
|
|
|
PASS NaN != symbol is true
|
|
|
|
PASS symbol != NaN is true
|
|
|
|
PASS Infinity != symbol is true
|
|
|
|
PASS symbol != Infinity is true
|
|
|
|
PASS true != symbol is true
|
|
|
|
PASS symbol != true is true
|
|
|
|
PASS false != symbol is true
|
|
|
|
PASS symbol != false is true
|
|
|
|
PASS null != symbol is true
|
|
|
|
PASS symbol != null is true
|
|
|
|
PASS undefined != symbol is true
|
|
|
|
PASS symbol != undefined is true
|
|
|
|
PASS 'Cappuccino' != symbol is true
|
|
|
|
PASS symbol != 'Cappuccino' is true
|
|
|
|
PASS symbol != symbol is false
|
|
|
|
PASS symbol != symbol is false
|
|
|
|
PASS Symbol.iterator != symbol is true
|
|
|
|
PASS symbol != Symbol.iterator is true
|
|
|
|
PASS object != symbol is true
|
|
|
|
PASS symbol != object is true
|
|
|
|
PASS array != symbol is true
|
|
|
|
PASS symbol != array is true
|
|
|
|
PASS date != symbol is true
|
|
|
|
PASS symbol != date is true
|
|
|
|
PASS symbolObject != symbol is false
|
|
|
|
PASS symbol != symbolObject is false
|
|
|
|
PASS Symbol('Cocoa') != symbol is true
|
|
|
|
PASS symbol != Symbol('Cocoa') is true
|
|
|
|
PASS successfullyParsed is true
|
|
|
|
|
|
|
|
TEST COMPLETE
|
|
|
|
|