diff -r b0d842380959 js/src/Makefile.in --- a/js/src/Makefile.in Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/Makefile.in Thu Apr 11 15:23:45 2013 +0200 @@ -137,16 +137,17 @@ CPPSRCS = \ StoreBuffer.cpp \ Iteration.cpp \ Zone.cpp \ Verifier.cpp \ StringBuffer.cpp \ Unicode.cpp \ Xdr.cpp \ Module.cpp \ + Symbol.cpp \ $(NULL) ifdef MOZ_INSTRUMENTS CPPSRCS += \ Instruments.cpp \ $(NULL) endif diff -r b0d842380959 js/src/builtin/Symbol.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/builtin/Symbol.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -0,0 +1,62 @@ +#include "jsobjinlines.h" +#include "Symbol.h" + +using namespace js; + +Class js::SymbolPrimitiveClass = { + "SymbolPrimitive", + JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(1), + JS_PropertyStub, /* addProperty */ + JS_PropertyStub, /* delProperty */ + JS_PropertyStub, /* getProperty */ + JS_StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub +}; + +Class js::SymbolClass = { + "Symbol", + JSCLASS_HAS_CACHED_PROTO(JSProto_Symbol) | JSCLASS_HAS_RESERVED_SLOTS(1), + JS_PropertyStub, /* addProperty */ + JS_PropertyStub, /* delProperty */ + JS_PropertyStub, /* getProperty */ + JS_StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub +}; + +JSBool +js_Symbol(JSContext *cx, unsigned argc, Value *vp) +{ + JSObject *obj = NewBuiltinClassInstance(cx, &SymbolPrimitiveClass); + Rooted symbol(cx, &obj->asSymbolPrimitive()); + if (!symbol) + return false; + RootedString string(cx, argc > 0 ? ToString(cx, vp[2]) + : JS_NewStringCopyZ(cx, "[symbol]")); + if (!string) + return false; + symbol->setString(string); + vp->setObject(*symbol); + return true; +} + +JSObject * +js_InitSymbolClass(JSContext *cx, HandleObject obj) +{ + JS_ASSERT(obj->isNative()); + Rooted global(cx, &obj->asGlobal()); + RootedObject proto(cx, global->createBlankPrototype(cx, &SymbolClass)); + if (!proto) + return NULL; + RootedFunction ctor(cx, global->createConstructor(cx, js_Symbol, cx->names().Symbol, 1)); + if (!ctor) + return NULL; + if (!LinkConstructorAndPrototype(cx, ctor, proto)) + return NULL; + if (!DefineConstructorAndPrototype(cx, global, JSProto_Symbol, ctor, proto)) + return NULL; + return proto; +} diff -r b0d842380959 js/src/builtin/Symbol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/builtin/Symbol.h Thu Apr 11 15:23:45 2013 +0200 @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef Symbol_h___ +#define Symbol_h___ + +#include "jsobj.h" +#include "jsstr.h" + +namespace js { + +class SymbolPrimitive : public JSObject { + public: + JSString *string() { + return getReservedSlot(STRING_SLOT).toString(); + }; + + void setString(JSString *string) { + setReservedSlot(STRING_SLOT, StringValue(string)); + }; + + private: + static const uint32_t STRING_SLOT = 0; +}; + +} // namespace js + +extern JSObject * +js_InitSymbolClass(JSContext *cx, js::HandleObject obj); + +inline js::SymbolPrimitive & +JSObject::asSymbolPrimitive() +{ + JS_ASSERT(isSymbolPrimitive()); + return *static_cast(this); +} + +#endif /* Symbol_h___ */ diff -r b0d842380959 js/src/jsapi.cpp --- a/js/src/jsapi.cpp Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsapi.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -54,16 +54,17 @@ #include "jswrapper.h" #include "jstypedarray.h" #include "builtin/Eval.h" #include "builtin/Intl.h" #include "builtin/MapObject.h" #include "builtin/RegExp.h" #include "builtin/ParallelArray.h" +#include "builtin/Symbol.h" #include "ds/LifoAlloc.h" #include "frontend/BytecodeCompiler.h" #include "gc/Marking.h" #include "gc/Memory.h" #include "ion/AsmJS.h" #include "js/CharacterEncoding.h" #include "js/MemoryMetrics.h" #include "vm/Debugger.h" @@ -1836,16 +1837,17 @@ static JSStdName standard_class_atoms[] {js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_}, #ifdef ENABLE_PARALLEL_JS {js_InitParallelArrayClass, EAGER_CLASS_ATOM(ParallelArray), &js::ParallelArrayObject::class_}, #endif {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)}, #if ENABLE_INTL_API {js_InitIntlClass, EAGER_ATOM_AND_CLASP(Intl)}, #endif + {js_InitSymbolClass, EAGER_ATOM_AND_CLASP(Symbol)}, {NULL, 0, NULL} }; /* * Table of top-level function and constant names and their init functions. * If you add a "standard" global function or property, remember to update * this table. */ diff -r b0d842380959 js/src/jsatom.cpp --- a/js/src/jsatom.cpp Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsatom.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -47,16 +47,17 @@ js_AtomToPrintableString(JSContext *cx, { return js_ValueToPrintable(cx, StringValue(atom), bytes); } const char * js::TypeStrings[] = { js_undefined_str, js_object_str, js_function_str, + js_symbol_str, js_string_str, js_number_str, js_boolean_str, js_null_str, }; #define DEFINE_PROTO_STRING(name,code,init) const char js_##name##_str[] = #name; JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING) @@ -439,20 +440,27 @@ template bool js::IndexToIdSlow(JSContext *cx, uint32_t index, FakeMutableHandle idp); template bool js::InternNonIntElementId(JSContext *cx, JSObject *obj, const Value &idval, typename MaybeRooted::MutableHandleType idp, typename MaybeRooted::MutableHandleType vp) { + if (idval.isObject()) { + JSObject &obj = idval.toObject(); + if (obj.isSymbolPrimitive()) { + idp.set(OBJECT_TO_JSID(&obj)); + vp.setObject(obj); + return true; + } + } JSAtom *atom = ToAtom(cx, idval); - if (!atom) + if (!atom) return false; - idp.set(AtomToId(atom)); vp.setString(atom); return true; } template bool js::InternNonIntElementId(JSContext *cx, JSObject *obj, const Value &idval, MutableHandleId idp, MutableHandleValue vp); diff -r b0d842380959 js/src/jsinterp.cpp --- a/js/src/jsinterp.cpp Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsinterp.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -591,25 +591,30 @@ js::Execute(JSContext *cx, HandleScript return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL, NullFramePtr() /* evalInFrame */, rval); } bool js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp) { + if (v.isObject() && v.toObject().isSymbolPrimitive()) { + *bp = false; + return true; + } + Class *clasp = obj->getClass(); RootedValue local(cx, v); if (clasp->hasInstance) return clasp->hasInstance(cx, obj, &local, bp); RootedValue val(cx, ObjectValue(*obj)); js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, JSDVG_SEARCH_STACK, val, NullPtr()); - return JS_FALSE; + return false; } bool js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result) { if (SameType(lval, rval)) { if (lval.isString()) { JSString *l = lval.toString(); diff -r b0d842380959 js/src/jsinterpinlines.h --- a/js/src/jsinterpinlines.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsinterpinlines.h Thu Apr 11 15:23:45 2013 +0200 @@ -782,27 +782,26 @@ GetObjectElementOperation(JSContext *cx, if (script->hasAnalysis()) { script->analysis()->getCode(pc).getStringElement = true; if (!objArg->isArray() && !objArg->isNative() && !objArg->isTypedArray()) script->analysis()->getCode(pc).nonNativeGetElement = true; } } - if (ValueMightBeSpecial(rref)) { - RootedObject obj(cx, objArg); - Rooted special(cx); - res.set(rref); - if (ValueIsSpecial(obj, res, &special, cx)) { - if (!JSObject::getSpecial(cx, obj, obj, special, res)) + if (rref.isObject()) { + JSObject &robj = rref.toObject(); + if (robj.isSymbolPrimitive()) { + RootedObject obj(cx, objArg); + RootedId id(cx, OBJECT_TO_JSID(&robj)); + if (!JSObject::getGeneric(cx, obj, obj, id, res)) return false; objArg = obj; break; } - objArg = obj; } JSAtom *name = ToAtom(cx, rref); if (name) { if (name->isIndex(&index)) { if (JSObject::getElementNoGC(cx, objArg, objArg, index, res.address())) break; } else { diff -r b0d842380959 js/src/jsobj.cpp --- a/js/src/jsobj.cpp Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsobj.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -41,16 +41,17 @@ #include "jsdbgapi.h" #include "json.h" #include "jswatchpoint.h" #include "jswrapper.h" #include "builtin/MapObject.h" #include "builtin/Module.h" #include "builtin/ParallelArray.h" +#include "builtin/Symbol.h" #include "frontend/BytecodeCompiler.h" #include "frontend/Parser.h" #include "gc/Marking.h" #include "js/MemoryMetrics.h" #include "vm/Shape.h" #include "vm/StringBuffer.h" #include "vm/Xdr.h" @@ -4419,16 +4420,22 @@ js::DefaultValue(JSContext *cx, HandleOb if (clasp == &NumberClass) { id = NameToId(cx->names().valueOf); if (ClassMethodIsNative(cx, obj, &NumberClass, id, js_num_valueOf)) { vp.setNumber(obj->asNumber().unbox()); return true; } } + /* Optimize new Symbol(...).valueOf(). */ + if (clasp == &SymbolPrimitiveClass) { + vp.setString(obj->asSymbolPrimitive().string()); + return true; + } + id = NameToId(cx->names().valueOf); if (!MaybeCallMethod(cx, obj, id, vp)) return false; if (vp.isPrimitive()) return true; id = NameToId(cx->names().toString); if (!MaybeCallMethod(cx, obj, id, vp)) @@ -4553,16 +4560,18 @@ js::CheckAccess(JSContext *cx, JSObject JSType baseops::TypeOf(JSContext *cx, HandleObject obj) { if (EmulatesUndefined(obj)) return JSTYPE_VOID; if (obj->isCallable()) return JSTYPE_FUNCTION; + if (obj->isSymbolPrimitive()) + return JSTYPE_SYMBOL; return JSTYPE_OBJECT; } bool js::IsDelegate(JSContext *cx, HandleObject obj, const js::Value &v, bool *result) { if (v.isPrimitive()) { *result = false; diff -r b0d842380959 js/src/jsobj.h --- a/js/src/jsobj.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsobj.h Thu Apr 11 15:23:45 2013 +0200 @@ -226,16 +226,18 @@ extern Class MathClass; extern Class ModuleClass; extern Class NumberClass; extern Class NormalArgumentsObjectClass; extern Class ObjectClass; extern Class ProxyClass; extern Class RegExpClass; extern Class RegExpStaticsClass; extern Class SetIteratorClass; +extern Class SymbolPrimitiveClass; +extern Class SymbolClass; extern Class StopIterationClass; extern Class StringClass; extern Class StrictArgumentsObjectClass; extern Class WeakMapClass; extern Class WithClass; class ArgumentsObject; class ArrayBufferObject; @@ -253,16 +255,17 @@ class Module; class NestedScopeObject; class NewObjectCache; class NormalArgumentsObject; class NumberObject; class PropertyIteratorObject; class ScopeObject; class SetObject; class SetIteratorObject; +class SymbolPrimitive; class StaticBlockObject; class StrictArgumentsObject; class StringObject; class RegExpObject; class WithObject; } /* namespace js */ @@ -960,16 +963,18 @@ class JSObject : public js::ObjectImpl inline bool isPropertyIterator() const; using js::ObjectImpl::isProxy; inline bool isRegExp() const; inline bool isRegExpStatics() const; inline bool isScope() const; inline bool isScript() const; inline bool isSetIterator() const; inline bool isStopIteration() const; + inline bool isSymbol() const; + inline bool isSymbolPrimitive() const; inline bool isTypedArray() const; inline bool isWeakMap() const; /* Subtypes of ScopeObject. */ inline bool isBlock() const; inline bool isCall() const; inline bool isDeclEnv() const; inline bool isNestedScope() const; @@ -1010,16 +1015,17 @@ class JSObject : public js::ObjectImpl inline js::NormalArgumentsObject &asNormalArguments(); inline js::NumberObject &asNumber(); inline js::PropertyIteratorObject &asPropertyIterator(); inline const js::PropertyIteratorObject &asPropertyIterator() const; inline js::RegExpObject &asRegExp(); inline js::ScopeObject &asScope(); inline js::SetObject &asSet(); inline js::SetIteratorObject &asSetIterator(); + inline js::SymbolPrimitive &asSymbolPrimitive(); inline js::StrictArgumentsObject &asStrictArguments(); inline js::StaticBlockObject &asStaticBlock(); inline js::StringObject &asString(); inline js::WithObject &asWith(); static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; } #ifdef DEBUG diff -r b0d842380959 js/src/jsobjinlines.h --- a/js/src/jsobjinlines.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsobjinlines.h Thu Apr 11 15:23:45 2013 +0200 @@ -885,16 +885,18 @@ inline bool JSObject::isObject() const { inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); } inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); } inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); } inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); } inline bool JSObject::isSetIterator() const { return hasClass(&js::SetIteratorClass); } inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); } inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); } inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); } +inline bool JSObject::isSymbol() const { return hasClass(&js::SymbolClass); } +inline bool JSObject::isSymbolPrimitive() const { return hasClass(&js::SymbolPrimitiveClass); } inline bool JSObject::isString() const { return hasClass(&js::StringClass); } inline bool JSObject::isTypedArray() const { return IsTypedArrayClass(getClass()); } inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); } inline bool JSObject::isWith() const { return hasClass(&js::WithClass); } inline js::NumberObject & JSObject::asNumber() { diff -r b0d842380959 js/src/jsprototypes.h --- a/js/src/jsprototypes.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jsprototypes.h Thu Apr 11 15:23:45 2013 +0200 @@ -52,10 +52,11 @@ macro(Uint8ClampedArray, 30, js_InitTypedArrayClasses) \ macro(Proxy, 31, js_InitProxyClass) \ macro(WeakMap, 32, js_InitWeakMapClass) \ macro(Map, 33, js_InitMapClass) \ macro(Set, 34, js_InitSetClass) \ macro(DataView, 35, js_InitTypedArrayClasses) \ macro(ParallelArray, 36, js_InitParallelArrayClass) \ macro(Intl, 37, js_InitIntlClass) \ + macro(Symbol, 38, js_InitSymbolClass) \ #endif /* jsprototypes_h___ */ diff -r b0d842380959 js/src/jspubtd.h --- a/js/src/jspubtd.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/jspubtd.h Thu Apr 11 15:23:45 2013 +0200 @@ -84,16 +84,17 @@ typedef enum JSVersion { JSVERSION_LATEST = JSVERSION_ECMA_5 } JSVersion; /* Result of typeof operator enumeration. */ typedef enum JSType { JSTYPE_VOID, /* undefined */ JSTYPE_OBJECT, /* object */ JSTYPE_FUNCTION, /* function */ + JSTYPE_SYMBOL, /* symbol */ JSTYPE_STRING, /* string */ JSTYPE_NUMBER, /* number */ JSTYPE_BOOLEAN, /* boolean */ JSTYPE_NULL, /* null */ JSTYPE_LIMIT } JSType; /* Dense index into cached prototypes and class atoms for standard objects. */ diff -r b0d842380959 js/src/vm/CommonPropertyNames.h --- a/js/src/vm/CommonPropertyNames.h Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/vm/CommonPropertyNames.h Thu Apr 11 15:23:45 2013 +0200 @@ -149,14 +149,15 @@ macro(var, var, "var") \ macro(void0, void0, "(void 0)") \ macro(watch, watch, "watch") \ macro(writable, writable, "writable") \ /* Type names must be contiguous and ordered; see js::TypeName. */ \ macro(undefined, undefined, "undefined") \ macro(object, object, "object") \ macro(function, function, "function") \ + macro(symbol, symbol, "symbol") \ macro(string, string, "string") \ macro(number, number, "number") \ macro(boolean, boolean, "boolean") \ macro(null, null, "null") #endif /* CommonPropertyNames_h__ */ diff -r b0d842380959 js/src/vm/GlobalObject.cpp --- a/js/src/vm/GlobalObject.cpp Mon Apr 08 00:28:46 2013 +0900 +++ b/js/src/vm/GlobalObject.cpp Thu Apr 11 15:23:45 2013 +0200 @@ -15,16 +15,17 @@ #include "json.h" #include "jsweakmap.h" #include "builtin/Eval.h" #include "builtin/Intl.h" #include "builtin/MapObject.h" #include "builtin/Object.h" #include "builtin/RegExp.h" +#include "builtin/Symbol.h" #include "frontend/BytecodeEmitter.h" #include "jsobjinlines.h" #include "vm/GlobalObject-inl.h" #include "vm/RegExpObject-inl.h" #include "vm/RegExpStatics-inl.h" @@ -476,16 +477,17 @@ GlobalObject::initStandardClasses(JSCont js_InitProxyClass(cx, global) && js_InitMapClass(cx, global) && GlobalObject::initMapIteratorProto(cx, global) && js_InitSetClass(cx, global) && GlobalObject::initSetIteratorProto(cx, global) && #if ENABLE_INTL_API js_InitIntlClass(cx, global) && #endif + js_InitSymbolClass(cx, global) && true; } /* static */ bool GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle global) { HeapSlot &v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED); if (v.isUndefined()) {