diff options
Diffstat (limited to 'js/src/builtin')
27 files changed, 634 insertions, 396 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 30e6fb35f..05fc41bc1 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -1073,6 +1073,114 @@ function ArrayConcat(arg1) { return A; } +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlatMap(mapperFunction/*, thisArg*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + if (!IsCallable(mapperFunction)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); + + // Step 4. + var T = arguments.length > 1 ? arguments[1] : undefined; + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function ArrayFlat(/* depth */) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + var depthNum = 1; + + // Step 4. + if (arguments.length > 0 && arguments[0] !== undefined) + depthNum = ToInteger(arguments[0]); + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, depthNum); + + // Step 7. + return A; +} + +// https://tc39.github.io/proposal-flatMap/ +// January 4, 2019 +function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) { + // Step 1. + var targetIndex = start; + + // Steps 2-3. + for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { + // Steps 3.a-c. + if (sourceIndex in source) { + // Step 3.c.i. + var element = source[sourceIndex]; + + if (mapperFunction) { + // Step 3.c.ii.1. + assert(arguments.length === 7, "thisArg is present"); + + // Step 3.c.ii.2. + element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source); + } + + // Step 3.c.iii. + var shouldFlatten = false; + + // Step 3.c.iv. + if (depth > 0) { + // Step 3.c.iv.1. + shouldFlatten = IsArray(element); + } + + // Step 3.c.v. + if (shouldFlatten) { + // Step 3.c.v.1. + var elementLen = ToLength(element.length); + + // Step 3.c.v.2. + // Recursive call to walk the depth. + targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1); + } else { + // Step 3.c.vi.1. + if (targetIndex >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 3.c.vi.2. + _DefineDataProperty(target, targetIndex, element); + + // Step 3.c.vi.3. + targetIndex++; + } + } + } + + // Step 4. + return targetIndex; +} + function ArrayStaticConcat(arr, arg1) { if (arguments.length < 1) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.concat'); diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 08777fd51..ceee83349 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -789,7 +789,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) // and it provides the necessary memory fence. AutoLockFutexAPI lock; - SharedMem<int32_t*>(addr) = view->viewDataShared().cast<int32_t*>() + offset; + SharedMem<int32_t*> addr = view->viewDataShared().cast<int32_t*>() + offset; if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) { r.setString(cx->names().futexNotEqual); return true; @@ -834,7 +834,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) } bool -js::atomics_wake(JSContext* cx, unsigned argc, Value* vp) +js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); HandleValue objv = args.get(0); @@ -874,7 +874,7 @@ js::atomics_wake(JSContext* cx, unsigned argc, Value* vp) iter = iter->lower_pri; if (c->offset != offset || !c->rt->fx.isWaiting()) continue; - c->rt->fx.wake(FutexRuntime::WakeExplicit); + c->rt->fx.notify(FutexRuntime::NotifyExplicit); ++woken; --count; } while (count > 0 && iter != waiters); @@ -950,7 +950,7 @@ js::FutexRuntime::isWaiting() // When a worker is awoken for an interrupt it goes into state // WaitingNotifiedForInterrupt for a short time before it actually // wakes up and goes into WaitingInterrupted. In those states the - // worker is still waiting, and if an explicit wake arrives the + // worker is still waiting, and if an explicit notify arrives the // worker transitions to Woken. See further comments in // FutexRuntime::wait(). return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt; @@ -1029,14 +1029,14 @@ js::FutexRuntime::wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked, // should be woken when the interrupt handler returns. // To that end, we flag the thread as interrupted around // the interrupt and check state_ when the interrupt - // handler returns. A wake() call that reaches the + // handler returns. A notify() call that reaches the // runtime during the interrupt sets state_ to Woken. // // - It is in principle possible for wait() to be // reentered on the same thread/runtime and waiting on the // same location and to yet again be interrupted and enter // the interrupt handler. In this case, it is important - // that when another agent wakes waiters, all waiters using + // that when another agent notifies waiters, all waiters using // the same runtime on the same location are woken in LIFO // order; FIFO may be the required order, but FIFO would // fail to wake up the innermost call. Interrupts are @@ -1073,25 +1073,25 @@ finished: } void -js::FutexRuntime::wake(WakeReason reason) +js::FutexRuntime::notify(NotifyReason reason) { MOZ_ASSERT(isWaiting()); - if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) { + if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == NotifyExplicit) { state_ = Woken; return; } switch (reason) { - case WakeExplicit: + case NotifyExplicit: state_ = Woken; break; - case WakeForJSInterrupt: + case NotifyForJSInterrupt: if (state_ == WaitingNotifiedForInterrupt) return; state_ = WaitingNotifiedForInterrupt; break; default: - MOZ_CRASH("bad WakeReason in FutexRuntime::wake()"); + MOZ_CRASH("bad NotifyReason in FutexRuntime::notify()"); } cond_->notify_all(); } @@ -1108,7 +1108,8 @@ const JSFunctionSpec AtomicsMethods[] = { JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor), JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree), JS_FN("wait", atomics_wait, 4,0), - JS_FN("wake", atomics_wake, 3,0), + JS_FN("notify", atomics_notify, 3,0), + JS_FN("wake", atomics_notify, 3,0), //Legacy name JS_FS_END }; @@ -1116,7 +1117,7 @@ JSObject* AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global) { // Create Atomics Object. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto, diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h index adb6fb986..6511dc8bf 100644 --- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -36,7 +36,7 @@ MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool atomics_wake(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); /* asm.js callouts */ namespace wasm { class Instance; } @@ -63,10 +63,10 @@ public: MOZ_MUST_USE bool initInstance(); void destroyInstance(); - // Parameters to wake(). - enum WakeReason { - WakeExplicit, // Being asked to wake up by another thread - WakeForJSInterrupt // Interrupt requested + // Parameters to notify(). + enum NotifyReason { + NotifyExplicit, // Being asked to wake up by another thread + NotifyForJSInterrupt // Interrupt requested }; // Result code from wait(). @@ -83,29 +83,27 @@ public: // times allowed; specify mozilla::Nothing() for an indefinite // wait. // - // wait() will not wake up spuriously. It will return true and - // set *result to a return code appropriate for - // Atomics.wait() on success, and return false on error. + // wait() will not wake up spuriously. MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked, mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result); - // Wake the thread represented by this Runtime. + // Notify the thread represented by this Runtime. // // The futex lock must be held around this call. (The sleeping - // thread will not wake up until the caller of Atomics.wake() + // thread will not wake up until the caller of Atomics.notify() // releases the lock.) // // If the thread is not waiting then this method does nothing. // // If the thread is waiting in a call to wait() and the - // reason is WakeExplicit then the wait() call will return + // reason is NotifyExplicit then the wait() call will return // with Woken. // // If the thread is waiting in a call to wait() and the - // reason is WakeForJSInterrupt then the wait() will return + // reason is NotifyForJSInterrupt then the wait() will return // with WaitingNotifiedForInterrupt; in the latter case the caller // of wait() must handle the interrupt. - void wake(WakeReason reason); + void notify(NotifyReason reason); bool isWaiting(); @@ -128,7 +126,7 @@ public: // interrupt handler WaitingInterrupted, // We are waiting, but have been interrupted // and are running the interrupt handler - Woken // Woken by a script call to Atomics.wake + Woken // Woken by a script call to Atomics.notify }; // Condition variable that this runtime will wait on. diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 71f7b58d4..0cd0c62dd 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -270,7 +270,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 10.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -298,7 +298,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateCollatorPrototype(cx); + proto = GlobalObject::getOrCreateCollatorPrototype(cx, cx->global()); if (!proto) return false; } @@ -358,11 +358,12 @@ collator_finalize(FreeOp* fop, JSObject* obj) static JSObject* CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { - RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, &Collator, cx->names().Collator, + 0)); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &CollatorClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &CollatorClass)); if (!proto) return nullptr; proto->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr)); @@ -772,7 +773,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 11.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -800,7 +801,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateNumberFormatPrototype(cx); + proto = GlobalObject::getOrCreateNumberFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -862,11 +863,12 @@ static JSObject* CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); + ctor = GlobalObject::createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &NumberFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr)); @@ -1250,7 +1252,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 12.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -1278,7 +1280,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx); + proto = GlobalObject::getOrCreateDateTimeFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -1340,11 +1342,12 @@ static JSObject* CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); + ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &DateTimeFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr)); @@ -2731,10 +2734,10 @@ static const JSFunctionSpec intl_static_methods[] = { * Initializes the Intl Object and its standard built-in properties. * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1 */ -bool +/* static */ bool GlobalObject::initIntlObject(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index fa808c0b9..1612f0f6b 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018e +// tzdata version = 2019c #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index c496cfb77..34e2e566d 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -164,7 +164,7 @@ MapIteratorObject::kind() const return MapObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global) { Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); @@ -924,7 +924,7 @@ SetIteratorObject::kind() const return SetObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global) { Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 333cb3e11..575bab0b0 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -103,7 +103,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; @@ -169,7 +169,7 @@ GlobalObject::initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; @@ -768,7 +768,7 @@ AssertModuleScopesMatch(ModuleObject* module) } void -ModuleObject::fixEnvironmentsAfterCompartmentMerge(JSContext* cx) +ModuleObject::fixEnvironmentsAfterCompartmentMerge() { AssertModuleScopesMatch(this); initialEnvironment().fixEnclosingEnvironmentAfterCompartmentMerge(script()->global()); @@ -927,7 +927,7 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports) { MOZ_ASSERT(!self->namespace_()); - MOZ_ASSERT(exports->is<ArrayObject>() || exports->is<UnboxedArrayObject>()); + MOZ_ASSERT(exports->is<ArrayObject>()); RootedModuleNamespaceObject ns(cx, ModuleNamespaceObject::create(cx, self)); if (!ns) @@ -1000,7 +1000,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global) JS_FS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 51a428271..22db762ac 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -237,7 +237,7 @@ class ModuleObject : public NativeObject #ifdef DEBUG static bool IsFrozen(JSContext* cx, HandleModuleObject self); #endif - void fixEnvironmentsAfterCompartmentMerge(JSContext* cx); + void fixEnvironmentsAfterCompartmentMerge(); JSScript* script() const; Scope* enclosingScope() const; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cd4ac122c..bfcc8d20e 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -9,11 +9,13 @@ #include "mozilla/ArrayUtils.h" #include "jscntxt.h" +#include "jsstr.h" #include "builtin/Eval.h" #include "frontend/BytecodeCompiler.h" #include "jit/InlinableNatives.h" #include "js/UniquePtr.h" +#include "vm/AsyncFunction.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" @@ -124,6 +126,27 @@ obj_toSource(JSContext* cx, unsigned argc, Value* vp) return true; } +template <typename CharT> +static bool +Consume(const CharT*& s, const CharT* e, const char *chars) +{ + size_t len = strlen(chars); + if (s + len >= e) + return false; + if (!EqualChars(s, chars, len)) + return false; + s += len; + return true; +} + +template <typename CharT> +static void +ConsumeSpaces(const CharT*& s, const CharT* e) +{ + while (*s == ' ' && s < e) + s++; +} + /* * Given a function source string, return the offset and length of the part * between '(function $name' and ')'. @@ -133,37 +156,53 @@ static bool ArgsAndBodySubstring(mozilla::Range<const CharT> chars, size_t* outOffset, size_t* outLen) { const CharT* const start = chars.begin().get(); - const CharT* const end = chars.end().get(); const CharT* s = start; + const CharT* e = chars.end().get(); - uint8_t parenChomp = 0; - if (s[0] == '(') { - s++; - parenChomp = 1; - } - - /* Try to jump "function" keyword. */ - s = js_strchr_limit(s, ' ', end); - if (!s) + if (s == e) return false; - /* - * Jump over the function's name: it can't be encoded as part - * of an ECMA getter or setter. - */ - s = js_strchr_limit(s, '(', end); - if (!s) - return false; + // Remove enclosing parentheses. + if (*s == '(' && *(e - 1) == ')') { + s++; + e--; + } - if (*s == ' ') + (void) Consume(s, e, "async"); + ConsumeSpaces(s, e); + (void) (Consume(s, e, "function") || Consume(s, e, "get") || Consume(s, e, "set")); + ConsumeSpaces(s, e); + (void) Consume(s, e, "*"); + ConsumeSpaces(s, e); + + // Jump over the function's name. + if (Consume(s, e, "[")) { + s = js_strchr_limit(s, ']', e); + if (!s) + return false; s++; + ConsumeSpaces(s, e); + if (*s != '(') + return false; + } else { + s = js_strchr_limit(s, '(', e); + if (!s) + return false; + } *outOffset = s - start; - *outLen = end - s - parenChomp; + *outLen = e - s; MOZ_ASSERT(*outOffset + *outLen <= chars.length()); return true; } +enum class PropertyKind { + Getter, + Setter, + Method, + Normal +}; + JSString* js::ObjectToSource(JSContext* cx, HandleObject obj) { @@ -182,59 +221,28 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) if (!buf.append('{')) return nullptr; - RootedValue v0(cx), v1(cx); - MutableHandleValue val[2] = {&v0, &v1}; - - RootedString str0(cx), str1(cx); - MutableHandleString gsop[2] = {&str0, &str1}; - AutoIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &idv)) return nullptr; bool comma = false; - for (size_t i = 0; i < idv.length(); ++i) { - RootedId id(cx, idv[i]); - Rooted<PropertyDescriptor> desc(cx); - if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) - return nullptr; - - int valcnt = 0; - if (desc.object()) { - if (desc.isAccessorDescriptor()) { - if (desc.hasGetterObject() && desc.getterObject()) { - val[valcnt].setObject(*desc.getterObject()); - gsop[valcnt].set(cx->names().get); - valcnt++; - } - if (desc.hasSetterObject() && desc.setterObject()) { - val[valcnt].setObject(*desc.setterObject()); - gsop[valcnt].set(cx->names().set); - valcnt++; - } - } else { - valcnt = 1; - val[0].set(desc.value()); - gsop[0].set(nullptr); - } - } - + auto AddProperty = [cx, &comma, &buf](HandleId id, HandleValue val, PropertyKind kind) -> bool { /* Convert id to a string. */ RootedString idstr(cx); if (JSID_IS_SYMBOL(id)) { RootedValue v(cx, SymbolValue(JSID_TO_SYMBOL(id))); idstr = ValueToSource(cx, v); if (!idstr) - return nullptr; + return false; } else { RootedValue idv(cx, IdToValue(id)); idstr = ToString<CanGC>(cx, idv); if (!idstr) - return nullptr; + return false; /* - * If id is a string that's not an identifier, or if it's a negative - * integer, then it must be quoted. + * If id is a string that's not an identifier, or if it's a + * negative integer, then it must be quoted. */ if (JSID_IS_ATOM(id) ? !IsIdentifier(JSID_TO_ATOM(id)) @@ -242,28 +250,65 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) { idstr = QuoteString(cx, idstr, char16_t('\'')); if (!idstr) - return nullptr; + return false; } } - for (int j = 0; j < valcnt; j++) { - /* Convert val[j] to its canonical source form. */ - JSString* valsource = ValueToSource(cx, val[j]); - if (!valsource) - return nullptr; + RootedString valsource(cx, ValueToSource(cx, val)); + if (!valsource) + return false; - RootedLinearString valstr(cx, valsource->ensureLinear(cx)); - if (!valstr) - return nullptr; + RootedLinearString valstr(cx, valsource->ensureLinear(cx)); + if (!valstr) + return false; - size_t voffset = 0; - size_t vlength = valstr->length(); + if (comma && !buf.append(", ")) + return false; + comma = true; + + size_t voffset, vlength; + + // Methods and accessors can return exact syntax of source, that fits + // into property without adding property name or "get"/"set" prefix. + // Use the exact syntax when the following conditions are met: + // + // * It's a function object + // (exclude proxies) + // * Function's kind and property's kind are same + // (this can be false for dynamically defined properties) + // * Function has explicit name + // (this can be false for computed property and dynamically defined + // properties) + // * Function's name and property's name are same + // (this can be false for dynamically defined properties) + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { + RootedFunction fun(cx); + if (val.toObject().is<JSFunction>()) { + fun = &val.toObject().as<JSFunction>(); + // Method's case should be checked on caller. + if (((fun->isGetter() && kind == PropertyKind::Getter) || + (fun->isSetter() && kind == PropertyKind::Setter) || + kind == PropertyKind::Method) && + fun->explicitName()) + { + bool result; + if (!EqualStrings(cx, fun->explicitName(), idstr, &result)) + return false; - /* - * Remove '(function ' from the beginning of valstr and ')' from the - * end so that we can put "get" in front of the function definition. - */ - if (gsop[j] && IsFunctionObject(val[j])) { + if (result) { + if (!buf.append(valstr)) + return false; + return true; + } + } + } + + { + // When falling back try to generate a better string + // representation by skipping the prelude, and also removing + // the enclosing parentheses. bool success; JS::AutoCheckCannotGC nogc; if (valstr->hasLatin1Chars()) @@ -271,29 +316,90 @@ js::ObjectToSource(JSContext* cx, HandleObject obj) else success = ArgsAndBodySubstring(valstr->twoByteRange(nogc), &voffset, &vlength); if (!success) - gsop[j].set(nullptr); + kind = PropertyKind::Normal; } - if (comma && !buf.append(", ")) - return nullptr; - comma = true; + if (kind == PropertyKind::Getter) { + if (!buf.append("get ")) + return false; + } else if (kind == PropertyKind::Setter) { + if (!buf.append("set ")) + return false; + } else if (kind == PropertyKind::Method && fun) { + if (IsWrappedAsyncFunction(fun)) { + if (!buf.append("async ")) + return false; + } - if (gsop[j]) { - if (!buf.append(gsop[j]) || !buf.append(' ')) - return nullptr; + if (fun->isStarGenerator()) { + if (!buf.append('*')) + return false; + } } - if (JSID_IS_SYMBOL(id) && !buf.append('[')) - return nullptr; - if (!buf.append(idstr)) - return nullptr; - if (JSID_IS_SYMBOL(id) && !buf.append(']')) - return nullptr; - if (!buf.append(gsop[j] ? ' ' : ':')) - return nullptr; + } + bool needsBracket = JSID_IS_SYMBOL(id); + if (needsBracket && !buf.append('[')) + return false; + if (!buf.append(idstr)) + return false; + if (needsBracket && !buf.append(']')) + return false; + + if (kind == PropertyKind::Getter || kind == PropertyKind::Setter || + kind == PropertyKind::Method) + { if (!buf.appendSubstring(valstr, voffset, vlength)) - return nullptr; + return false; + } else { + if (!buf.append(':')) + return false; + if (!buf.append(valstr)) + return false; + } + return true; + }; + + RootedId id(cx); + Rooted<PropertyDescriptor> desc(cx); + RootedValue val(cx); + RootedFunction fun(cx); + for (size_t i = 0; i < idv.length(); ++i) { + id = idv[i]; + if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) + return nullptr; + + if (!desc.object()) + continue; + + if (desc.isAccessorDescriptor()) { + if (desc.hasGetterObject() && desc.getterObject()) { + val.setObject(*desc.getterObject()); + if (!AddProperty(id, val, PropertyKind::Getter)) + return nullptr; + } + if (desc.hasSetterObject() && desc.setterObject()) { + val.setObject(*desc.setterObject()); + if (!AddProperty(id, val, PropertyKind::Setter)) + return nullptr; + } + continue; + } + + val.set(desc.value()); + if (IsFunctionObject(val, fun.address())) { + if (IsWrappedAsyncFunction(fun)) + fun = GetUnwrappedAsyncFunction(fun); + + if (fun->isMethod()) { + if (!AddProperty(id, val, PropertyKind::Method)) + return nullptr; + continue; + } } + + if (!AddProperty(id, val, PropertyKind::Normal)) + return nullptr; } if (!buf.append('}')) @@ -419,18 +525,6 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp) return true; } - -bool -js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - args.rval().setObject(*obj); - return true; -} - static bool obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) { @@ -474,97 +568,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) return true; } -#if JS_HAS_OBJ_WATCHPOINT - -bool -js::WatchHandler(JSContext* cx, JSObject* obj_, jsid id_, const JS::Value& old, - JS::Value* nvp, void* closure) -{ - RootedObject obj(cx, obj_); - RootedId id(cx, id_); - - /* Avoid recursion on (obj, id) already being watched on cx. */ - AutoResolving resolving(cx, obj, id, AutoResolving::WATCH); - if (resolving.alreadyStarted()) - return true; - - FixedInvokeArgs<3> args(cx); - - args[0].set(IdToValue(id)); - args[1].set(old); - args[2].set(*nvp); - - RootedValue callable(cx, ObjectValue(*static_cast<JSObject*>(closure))); - RootedValue thisv(cx, ObjectValue(*obj)); - RootedValue rv(cx); - if (!Call(cx, callable, thisv, args, &rv)) - return false; - - *nvp = rv; - return true; -} - -static bool -obj_watch(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - - if (!GlobalObject::warnOnceAboutWatch(cx, obj)) - return false; - - if (args.length() <= 1) { - ReportMissingArg(cx, args.calleev(), 1); - return false; - } - - RootedObject callable(cx, ValueToCallable(cx, args[1], args.length() - 2)); - if (!callable) - return false; - - RootedId propid(cx); - if (!ValueToId<CanGC>(cx, args[0], &propid)) - return false; - - if (!WatchProperty(cx, obj, propid, callable)) - return false; - - args.rval().setUndefined(); - return true; -} - -static bool -obj_unwatch(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - - if (!GlobalObject::warnOnceAboutWatch(cx, obj)) - return false; - - RootedId id(cx); - if (args.length() != 0) { - if (!ValueToId<CanGC>(cx, args[0], &id)) - return false; - } else { - id = JSID_VOID; - } - - if (!UnwatchProperty(cx, obj, id)) - return false; - - args.rval().setUndefined(); - return true; -} - -#endif /* JS_HAS_OBJ_WATCHPOINT */ - /* ECMA 15.2.4.5. */ bool js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp) @@ -1195,11 +1198,7 @@ static const JSFunctionSpec object_methods[] = { #endif JS_FN(js_toString_str, obj_toString, 0,0), JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0), - JS_FN(js_valueOf_str, obj_valueOf, 0,0), -#if JS_HAS_OBJ_WATCHPOINT - JS_FN(js_watch_str, obj_watch, 2,0), - JS_FN(js_unwatch_str, obj_unwatch, 1,0), -#endif + JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0), JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,0), JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0), JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0), @@ -1314,8 +1313,8 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro * only set the [[Prototype]] if it hasn't already been set. */ Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); - if (global->shouldSplicePrototype(cx)) { - if (!global->splicePrototype(cx, global->getClass(), tagged)) + if (global->shouldSplicePrototype()) { + if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged)) return false; } return true; diff --git a/js/src/builtin/Object.h b/js/src/builtin/Object.h index 09512be36..8231888b1 100644 --- a/js/src/builtin/Object.h +++ b/js/src/builtin/Object.h @@ -25,9 +25,6 @@ obj_construct(JSContext* cx, unsigned argc, JS::Value* vp); MOZ_MUST_USE bool obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool -obj_valueOf(JSContext* cx, unsigned argc, JS::Value* vp); - PlainObject* ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject, HandleObjectGroup group = nullptr); diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index a7440aec7..9ed1be0e1 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -87,6 +87,12 @@ function Object_toLocaleString() { return callContentFunction(O.toString, O); } +// ES 2017 draft bb96899bb0d9ef9be08164a26efae2ee5f25e875 19.1.3.7 +function Object_valueOf() { + // Step 1. + return ToObject(this); +} + // ES7 draft (2016 March 8) B.2.2.3 function ObjectDefineSetter(name, setter) { // Step 1. diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index c781a336d..ec7845e89 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -603,7 +603,7 @@ ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueO // Now that everything else is done, do the things the debugger needs. // Step 7 of RejectPromise implemented in onSettled. - promise->onSettled(cx); + PromiseObject::onSettled(cx, promise); // Step 7 of FulfillPromise. // Step 8 of RejectPromise. @@ -1947,26 +1947,23 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, } // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5. -static MOZ_MUST_USE bool -CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode) +static MOZ_MUST_USE JSObject* +CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal, + ResolutionMode mode) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedValue x(cx, args.get(0)); - // Steps 1-2. - if (!args.thisv().isObject()) { + if (!thisVal.isObject()) { const char* msg = mode == ResolveMode ? "Receiver of Promise.resolve call" : "Receiver of Promise.reject call"; JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg); - return false; + return nullptr; } - RootedValue cVal(cx, args.thisv()); - RootedObject C(cx, &cVal.toObject()); + RootedObject C(cx, &thisVal.toObject()); // Step 3 of Resolve. - if (mode == ResolveMode && x.isObject()) { - RootedObject xObj(cx, &x.toObject()); + if (mode == ResolveMode && argVal.isObject()) { + RootedObject xObj(cx, &argVal.toObject()); bool isPromise = false; if (xObj->is<PromiseObject>()) { isPromise = true; @@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio if (isPromise) { RootedValue ctorVal(cx); if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal)) - return false; - if (ctorVal == cVal) { - args.rval().set(x); - return true; - } + return nullptr; + if (ctorVal == thisVal) + return xObj; } } @@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio RootedObject resolveFun(cx); RootedObject rejectFun(cx); if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true)) - return false; + return nullptr; // Step 5 of Resolve, 4 of Reject. - if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise)) - return false; + if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode, + promise)) + { + return nullptr; + } // Step 6 of Resolve, 4 of Reject. - args.rval().setObject(*promise); - return true; + return promise; } /** @@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio bool js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2024,19 +2028,11 @@ js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Roughly step 3. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Roughly step 4. - if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected)) - return nullptr; - - // Step 5. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode); } /** @@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) bool js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2054,30 +2057,11 @@ js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Step 3. - if (value.isObject()) { - JSObject* obj = &value.toObject(); - if (IsWrapper(obj)) - obj = CheckedUnwrap(obj); - // Instead of getting the `constructor` property, do an unforgeable - // check. - if (obj && obj->is<PromiseObject>()) - return obj; - } - - // Step 4. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Steps 5. - if (!ResolvePromiseInternal(cx, promise, value)) - return nullptr; - - // Step 6. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode); } // ES2016, 25.4.4.6, implemented in Promise.js. @@ -2647,14 +2631,14 @@ PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> v return true; } -bool -PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) +/* static */ bool +PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValue resolutionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedObject resolveFun(cx, GetResolveFunctionFromPromise(this)); + RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise)); RootedValue funVal(cx, ObjectValue(*resolveFun)); // For xray'd Promises, the resolve fun may have been created in another @@ -2670,14 +2654,14 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -bool -PromiseObject::reject(JSContext* cx, HandleValue rejectionValue) +/* static */ bool +PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedValue funVal(cx, this->getFixedSlot(PromiseSlot_RejectFunction)); + RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction)); MOZ_ASSERT(IsCallable(funVal)); FixedInvokeArgs<1> args(cx); @@ -2687,10 +2671,9 @@ PromiseObject::reject(JSContext* cx, HandleValue rejectionValue) return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -void -PromiseObject::onSettled(JSContext* cx) +/* static */ void +PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise) { - Rooted<PromiseObject*> promise(cx, this); RootedObject stack(cx); if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) { if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) { @@ -2750,7 +2733,7 @@ PromiseTask::executeAndFinish(JSContext* cx) static JSObject* CreatePromisePrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_); } static const JSFunctionSpec promise_methods[] = { diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index bb4778631..c76dc358c 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -66,10 +66,12 @@ class PromiseObject : public NativeObject return getFixedSlot(PromiseSlot_ReactionsOrResult); } - MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue); - MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue); + static MOZ_MUST_USE bool resolve(JSContext* cx, Handle<PromiseObject*> promise, + HandleValue resolutionValue); + static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise, + HandleValue rejectionValue); - void onSettled(JSContext* cx); + static void onSettled(JSContext* cx, Handle<PromiseObject*> promise); double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); } double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); } diff --git a/js/src/builtin/Reflect.cpp b/js/src/builtin/Reflect.cpp index 2f509a226..4e7fae78c 100644 --- a/js/src/builtin/Reflect.cpp +++ b/js/src/builtin/Reflect.cpp @@ -268,7 +268,8 @@ static const JSFunctionSpec methods[] = { JSObject* js::InitReflect(JSContext* cx, HandleObject obj) { - RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index beff58e13..8e8bb2417 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3044,7 +3044,12 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); RootedValue expr(cx); - expr.setString(next->pn_atom); + if (next->isKind(PNK_RAW_UNDEFINED)) { + expr.setUndefined(); + } else { + MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); + expr.setString(next->pn_atom); + } cooked.infallibleAppend(expr); } @@ -3136,6 +3141,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: return literal(pn, dst); case PNK_YIELD_STAR: @@ -3216,6 +3222,8 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst) return expression(pn->pn_kid, &val) && builder.prototypeMutation(val, &pn->pn_pos, dst); } + if (pn->isKind(PNK_SPREAD)) + return expression(pn, dst); PropKind kind; switch (pn->getOp()) { @@ -3276,6 +3284,10 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) val.setNull(); break; + case PNK_RAW_UNDEFINED: + val.setUndefined(); + break; + case PNK_TRUE: val.setBoolean(true); break; @@ -3332,6 +3344,16 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) return false; for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + if (propdef->isKind(PNK_SPREAD)) { + RootedValue target(cx); + RootedValue spread(cx); + if (!pattern(propdef->pn_kid, &target)) + return false; + if(!builder.spreadExpression(target, &propdef->pn_pos, &spread)) + return false; + elts.infallibleAppend(spread); + continue; + } LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP)); RootedValue key(cx); @@ -3407,12 +3429,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) : GeneratorStyle::None; bool isAsync = pn->pn_funbox->isAsync(); - bool isExpression = -#if JS_HAS_EXPR_CLOSURES - func->isExprBody(); -#else - false; -#endif + bool isExpression = pn->pn_funbox->isExprBody(); RootedValue id(cx); RootedAtom funcAtom(cx, func->explicitName()); diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index b20f41c53..7cf20d23c 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -140,12 +140,12 @@ ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLin /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */ bool -js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval) { RegExpGuard shared(cx); - if (!reobj.getShared(cx, &shared)) + if (!RegExpObject::getShared(cx, reobj, &shared)) return false; ScopedMatchPairs matches(&cx->tempLifoAlloc()); @@ -801,7 +801,7 @@ const JSFunctionSpec js::regexp_methods[] = { name(JSContext* cx, unsigned argc, Value* vp) \ { \ CallArgs args = CallArgsFromVp(argc, vp); \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -827,7 +827,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, STATIC_PAREN_GETTER_CODE(9)) static bool \ name(JSContext* cx, unsigned argc, Value* vp) \ { \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -838,7 +838,7 @@ static bool static_input_setter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - RegExpStatics* res = cx->global()->getRegExpStatics(cx); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return false; @@ -918,12 +918,12 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, Rooted<RegExpObject*> reobj(cx, ®exp->as<RegExpObject>()); RegExpGuard re(cx); - if (!reobj->getShared(cx, &re)) + if (!RegExpObject::getShared(cx, reobj, &re)) return RegExpRunStatus_Error; RegExpStatics* res; if (staticsUpdate == UpdateRegExpStatics) { - res = cx->global()->getRegExpStatics(cx); + res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return RegExpRunStatus_Error; } else { @@ -1725,7 +1725,7 @@ js::intrinsic_GetElemBaseForLambda(JSContext* cx, unsigned argc, Value* vp) if (!fun->isInterpreted() || fun->isClassConstructor()) return true; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return false; @@ -1800,7 +1800,7 @@ js::intrinsic_GetStringDataProperty(JSContext* cx, unsigned argc, Value* vp) return false; RootedValue v(cx); - if (HasDataProperty(cx, nobj, AtomToId(atom), v.address()) && v.isString()) + if (GetPropertyPure(cx, nobj, AtomToId(atom), v.address()) && v.isString()) args.rval().set(v); else args.rval().setUndefined(); diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 715656f40..4e0ff6948 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -31,7 +31,7 @@ enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics }; * |chars| and |length|. */ MOZ_MUST_USE bool -ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 2383922db..5fe691152 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -475,7 +475,7 @@ const Class SimdObject::class_ = { &SimdObjectClassOps }; -bool +/* static */ bool GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global) { // SIMD relies on the TypedObject module being initialized. @@ -483,11 +483,11 @@ GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global) // to be able to call GetTypedObjectModule(). It is NOT necessary // to install the TypedObjectModule global, but at the moment // those two things are not separable. - if (!global->getOrCreateTypedObjectModule(cx)) + if (!GlobalObject::getOrCreateTypedObjectModule(cx, global)) return false; RootedObject globalSimdObject(cx); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -510,7 +510,7 @@ static bool CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr, SimdType simdType, const JSFunctionSpec* methods) { - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -531,7 +531,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s return false; // Create prototype property, which inherits from Object.prototype. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; Rooted<TypedProto*> proto(cx); @@ -551,7 +551,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s } // Bind type descriptor to the global SIMD object - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); MOZ_ASSERT(globalSimdObject); RootedValue typeValue(cx, ObjectValue(*typeDescr)); @@ -568,7 +568,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s return !!typeDescr; } -bool +/* static */ bool GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType) { #define CREATE_(Type) \ @@ -584,13 +584,13 @@ GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType #undef CREATE_ } -SimdTypeDescr* +/* static */ SimdTypeDescr* GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType) { MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type"); - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); if (!globalSimdObject) return nullptr; @@ -628,8 +628,8 @@ SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* JSObject* js::InitSimdClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - return global->getOrCreateSimdGlobalObject(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + return GlobalObject::getOrCreateSimdGlobalObject(cx, global); } template<typename V> diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index e5b2ad552..f830b1aa2 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -828,16 +828,16 @@ function String_static_trim(string) { return callFunction(std_String_trim, string); } -function String_static_trimLeft(string) { +function String_static_trimStart(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimLeft'); - return callFunction(std_String_trimLeft, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimStart'); + return callFunction(std_String_trimStart, string); } -function String_static_trimRight(string) { +function String_static_trimEnd(string) { if (arguments.length < 1) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimRight'); - return callFunction(std_String_trimRight, string); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.trimEnd'); + return callFunction(std_String_trimEnd, string); } function String_static_toLocaleLowerCase(string) { diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index cf48402d6..8fa860ef3 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -33,6 +33,7 @@ SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol) } const JSPropertySpec SymbolObject::properties[] = { + JS_PSG("description", descriptionGetter, 0), JS_PS_END }; @@ -52,17 +53,17 @@ const JSFunctionSpec SymbolObject::staticMethods[] = { JSObject* SymbolObject::initClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); // This uses &JSObject::class_ because: "The Symbol prototype object is an // ordinary object. It is not a Symbol instance and does not have a // [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3) - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, construct, - ClassName(JSProto_Symbol, cx), 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_Symbol, cx), 0)); if (!ctor) return nullptr; @@ -227,6 +228,34 @@ SymbolObject::toPrimitive(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args); } +// ES2019 Stage 4 Draft / November 28, 2018 +// Symbol description accessor +// See: https://tc39.github.io/proposal-Symbol-description/ +bool +SymbolObject::descriptionGetter_impl(JSContext* cx, const CallArgs& args) +{ + // Get symbol object pointer. + HandleValue thisv = args.thisv(); + MOZ_ASSERT(IsSymbol(thisv)); + Rooted<Symbol*> sym(cx, thisv.isSymbol() + ? thisv.toSymbol() + : thisv.toObject().as<SymbolObject>().unbox()); + + // Return the symbol's description if present, otherwise return undefined. + if (JSString* str = sym->description()) + args.rval().setString(str); + else + args.rval().setUndefined(); + return true; +} + +bool +SymbolObject::descriptionGetter(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod<IsSymbol, descriptionGetter_impl>(cx, args); +} + JSObject* js::InitSymbolClass(JSContext* cx, HandleObject obj) { diff --git a/js/src/builtin/SymbolObject.h b/js/src/builtin/SymbolObject.h index 0f204b494..e10b42d53 100644 --- a/js/src/builtin/SymbolObject.h +++ b/js/src/builtin/SymbolObject.h @@ -52,6 +52,10 @@ class SymbolObject : public NativeObject static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp); + // Properties defined on Symbol.prototype. + static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc, Value *vp); + static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; static const JSFunctionSpec staticMethods[]; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 373b6c9ed..4363c7aed 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -239,12 +239,11 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) value = BooleanValue(true); if (!JS_SetProperty(cx, info, "intl-api", value)) return false; - -#if defined(SOLARIS) +#ifdef XP_SOLARIS value = BooleanValue(false); #else value = BooleanValue(true); -#endif +#endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) return false; @@ -3222,13 +3221,13 @@ ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp) return false; } - JSFunction* fun = &args[0].toObject().as<JSFunction>(); + RootedFunction fun(cx, &args[0].toObject().as<JSFunction>()); if (fun->isNative()) { JS_ReportErrorASCII(cx, "Argument must be a scripted function"); return false; } - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; @@ -3323,7 +3322,8 @@ GetConstructorName(JSContext* cx, unsigned argc, Value* vp) } RootedAtom name(cx); - if (!args[0].toObject().constructorDisplayAtom(cx, &name)) + RootedObject obj(cx, &args[0].toObject()); + if (!JSObject::constructorDisplayAtom(cx, obj, &name)) return false; if (name) { @@ -4027,7 +4027,7 @@ DisRegExp(JSContext* cx, unsigned argc, Value* vp) return false; } - if (!reobj->dumpBytecode(cx, match_only, input)) + if (!RegExpObject::dumpBytecode(cx, reobj, match_only, input)) return false; args.rval().setUndefined(); @@ -4046,6 +4046,32 @@ IsConstructor(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +GetErrorNotes(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.requireAtLeast(cx, "getErrorNotes", 1)) + return false; + + if (!args[0].isObject() || !args[0].toObject().is<ErrorObject>()) { + args.rval().setNull(); + return true; + } + + JSErrorReport* report = args[0].toObject().as<ErrorObject>().getErrorReport(); + if (!report) { + args.rval().setNull(); + return true; + } + + RootedObject notesArray(cx, CreateErrorNotesArray(cx, report)); + if (!notesArray) + return false; + + args.rval().setObject(*notesArray); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'zone' [, 'shrinking'])", @@ -4580,6 +4606,10 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = { " Dumps RegExp bytecode."), #endif + JS_FN_HELP("getErrorNotes", GetErrorNotes, 1, 0, +"getErrorNotes(error)", +" Returns an array of error notes."), + JS_FS_HELP_END }; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ae74f01bf..50bf0b836 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -652,7 +652,7 @@ ArrayMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, obj)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(obj)) { + if (!cx->zone()->addTypeDescrObject(cx, obj)) { ReportOutOfMemory(cx); return nullptr; } @@ -993,8 +993,8 @@ StructMetaTypeDescr::create(JSContext* cx, if (!CreateTraceList(cx, descr)) return nullptr; - if (!cx->zone()->typeDescrObjects.put(descr) || - !cx->zone()->typeDescrObjects.put(fieldTypeVec)) + if (!cx->zone()->addTypeDescrObject(cx, descr) || + !cx->zone()->addTypeDescrObject(cx, fieldTypeVec)) { ReportOutOfMemory(cx); return nullptr; @@ -1124,11 +1124,11 @@ DefineSimpleTypeDescr(JSContext* cx, typename T::Type type, HandlePropertyName className) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -1165,10 +1165,8 @@ DefineSimpleTypeDescr(JSContext* cx, if (!CreateTraceList(cx, descr)) return false; - if (!cx->zone()->typeDescrObjects.put(descr)) { - ReportOutOfMemory(cx); + if (!cx->zone()->addTypeDescrObject(cx, descr)) return false; - } return true; } @@ -1187,7 +1185,7 @@ DefineMetaTypeDescr(JSContext* cx, if (!className) return nullptr; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return nullptr; @@ -1199,7 +1197,7 @@ DefineMetaTypeDescr(JSContext* cx, // Create ctor.prototype.prototype, which inherits from Object.__proto__ - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject protoProto(cx); @@ -1218,7 +1216,7 @@ DefineMetaTypeDescr(JSContext* cx, const int constructorLength = 2; RootedFunction ctor(cx); - ctor = global->createConstructor(cx, T::construct, className, constructorLength); + ctor = GlobalObject::createConstructor(cx, T::construct, className, constructorLength); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, @@ -1242,10 +1240,10 @@ DefineMetaTypeDescr(JSContext* cx, * initializer for the `TypedObject` class populate the * `TypedObject` global (which is referred to as "module" herein). */ -bool +/* static */ bool GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -1319,9 +1317,8 @@ GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global) JSObject* js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj) { - MOZ_ASSERT(obj->is<GlobalObject>()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - return global->getOrCreateTypedObjectModule(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + return GlobalObject::getOrCreateTypedObjectModule(cx, global); } /****************************************************************************** @@ -2218,7 +2215,6 @@ const ObjectOps TypedObject::objectOps_ = { TypedObject::obj_setProperty, TypedObject::obj_getOwnPropertyDescriptor, TypedObject::obj_deleteProperty, - nullptr, nullptr, /* watch/unwatch */ nullptr, /* getElements */ TypedObject::obj_enumerate, nullptr, /* thisValue */ diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index c73bc5e7f..d5f233d05 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -229,6 +229,69 @@ function GetInternalError(msg) { // To be used when a function is required but calling it shouldn't do anything. function NullFunction() {} +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataProperties(target, source, excluded) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2. + assert(IsObject(excluded), "excluded is an object"); + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (!callFunction(std_Object_hasOwnProperty, excluded, key) && callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataPropertiesUnfiltered(target, source) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2 (Not applicable). + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + /*************************************** Testing functions ***************************************/ function outer() { return function inner() { diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index 555b9e03a..dcfa19776 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -350,14 +350,14 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers) { MOZ_ASSERT(obj->isNative()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct, - cx->names().WeakMap, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakMap_construct, + cx->names().WeakMap, 0)); if (!ctor) return nullptr; diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index 7ea3f2fef..fbe5e418c 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -41,14 +41,15 @@ const JSFunctionSpec WeakSetObject::methods[] = { }; JSObject* -WeakSetObject::initClass(JSContext* cx, JSObject* obj) +WeakSetObject::initClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!proto) return nullptr; - Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(JSProto_WeakSet, cx), 0)); + Rooted<JSFunction*> ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_WeakSet, cx), 0)); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, properties, methods) || diff --git a/js/src/builtin/WeakSetObject.h b/js/src/builtin/WeakSetObject.h index 0a6ff33f3..50e54c182 100644 --- a/js/src/builtin/WeakSetObject.h +++ b/js/src/builtin/WeakSetObject.h @@ -16,7 +16,7 @@ class WeakSetObject : public NativeObject public: static const unsigned RESERVED_SLOTS = 1; - static JSObject* initClass(JSContext* cx, JSObject* obj); + static JSObject* initClass(JSContext* cx, HandleObject obj); static const Class class_; private: |