diff options
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/Iterator.js | 41 | ||||
-rw-r--r-- | js/src/builtin/Module.js | 46 | ||||
-rw-r--r-- | js/src/builtin/ModuleObject.cpp | 124 | ||||
-rw-r--r-- | js/src/builtin/ModuleObject.h | 7 | ||||
-rw-r--r-- | js/src/builtin/Object.cpp | 95 | ||||
-rw-r--r-- | js/src/builtin/Promise.cpp | 8 | ||||
-rw-r--r-- | js/src/builtin/Promise.h | 8 | ||||
-rw-r--r-- | js/src/builtin/Promise.js | 69 | ||||
-rw-r--r-- | js/src/builtin/RegExp.cpp | 34 | ||||
-rw-r--r-- | js/src/builtin/RegExp.h | 2 | ||||
-rw-r--r-- | js/src/builtin/RegExp.js | 140 | ||||
-rw-r--r-- | js/src/builtin/SelfHostingDefines.h | 8 | ||||
-rw-r--r-- | js/src/builtin/String.js | 27 | ||||
-rw-r--r-- | js/src/builtin/TestingFunctions.cpp | 12 | ||||
-rw-r--r-- | js/src/builtin/TypedObject.cpp | 1 |
15 files changed, 369 insertions, 253 deletions
diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js index 735eec7a06..e25b761561 100644 --- a/js/src/builtin/Iterator.js +++ b/js/src/builtin/Iterator.js @@ -84,44 +84,3 @@ function LegacyIteratorShim() { function LegacyGeneratorIteratorShim() { return NewLegacyIterator(ToObject(this), LegacyGeneratorIterator); } - -// 7.4.8 CreateListIterator() -function CreateListIterator(array) { - let iterator = NewListIterator(); - UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, array); - UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0); - - // 7.4.8.1 ListIterator next() - // The spec requires that we use a new next function per iterator object. - let next = function() { - if (!IsObject(this) || !IsListIterator(this)) - return callFunction(CallListIteratorMethodIfWrapped, this, "ListIteratorNext"); - - if (ActiveFunction() !== UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_METHOD)) - ThrowTypeError(JSMSG_INCOMPATIBLE_METHOD, "next", "method", ToString(this)); - - let array = UnsafeGetObjectFromReservedSlot(this, ITERATOR_SLOT_TARGET); - let index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); - - if (index >= ToLength(array.length)) { - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, 1/0); - return { value: undefined, done: true }; - } - - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1); - return { value: array[index], done: false }; - }; - - UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_METHOD, next); - iterator.next = next; - - iterator[std_iterator] = ListIteratorIdentity; - return iterator; -} - -function ListIteratorIdentity() { - if (!IsObject(this) || !IsListIterator(this)) - return callFunction(CallListIteratorMethodIfWrapped, this, "ListIteratorIdentity"); - - return this; -} diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js index 7b70a7fe8b..5c3d5e1479 100644 --- a/js/src/builtin/Module.js +++ b/js/src/builtin/Module.js @@ -65,12 +65,12 @@ function ModuleGetExportedNames(exportStarSet = []) return exportedNames; } -// 15.2.1.16.3 ResolveExport(exportName, resolveSet, exportStarSet) -function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) +// 15.2.1.16.3 ResolveExport(exportName, resolveSet) +function ModuleResolveExport(exportName, resolveSet = []) { if (!IsObject(this) || !IsModule(this)) { return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet, - exportStarSet, "ModuleResolveExport"); + "ModuleResolveExport"); } // Step 1 @@ -100,38 +100,29 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) let e = indirectExportEntries[i]; if (exportName === e.exportName) { let importedModule = CallModuleResolveHook(module, e.moduleRequest, - MODULE_STATE_INSTANTIATED); - let indirectResolution = callFunction(importedModule.resolveExport, importedModule, - e.importName, resolveSet, exportStarSet); - if (indirectResolution !== null) - return indirectResolution; + MODULE_STATE_PARSED); + return callFunction(importedModule.resolveExport, importedModule, e.importName, + resolveSet); } } // Step 6 if (exportName === "default") { // A default export cannot be provided by an export *. - ThrowSyntaxError(JSMSG_BAD_DEFAULT_EXPORT); + return null; } // Step 7 - if (callFunction(ArrayIncludes, exportStarSet, module)) - return null; - - // Step 8 - _DefineDataProperty(exportStarSet, exportStarSet.length, module); - - // Step 9 let starResolution = null; - // Step 10 + // Step 8 let starExportEntries = module.starExportEntries; for (let i = 0; i < starExportEntries.length; i++) { let e = starExportEntries[i]; let importedModule = CallModuleResolveHook(module, e.moduleRequest, - MODULE_STATE_INSTANTIATED); + MODULE_STATE_PARSED); let resolution = callFunction(importedModule.resolveExport, importedModule, - exportName, resolveSet, exportStarSet); + exportName, resolveSet); if (resolution === "ambiguous") return resolution; @@ -148,6 +139,7 @@ function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = []) } } + // Step 9 return starResolution; } @@ -213,8 +205,8 @@ function GetModuleEnvironment(module) function RecordInstantationFailure(module) { - // Set the module's environment slot to 'null' to indicate a failed module - // instantiation. + // Set the module's state to 'failed' to indicate a failed module + // instantiation and reset the environment slot to 'undefined'. assert(IsModule(module), "Non-module passed to RecordInstantationFailure"); SetModuleState(module, MODULE_STATE_FAILED); UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined); @@ -275,11 +267,13 @@ function ModuleDeclarationInstantiation() ThrowSyntaxError(JSMSG_MISSING_IMPORT, imp.importName); if (resolution === "ambiguous") ThrowSyntaxError(JSMSG_AMBIGUOUS_IMPORT, imp.importName); + if (resolution.module.state < MODULE_STATE_INSTANTIATED) + ThrowInternalError(JSMSG_BAD_MODULE_STATE); CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName); } } - // Step 16.iv + // Step 17.a.iii InstantiateModuleFunctionDeclarations(module); } catch (e) { RecordInstantationFailure(module); @@ -318,11 +312,3 @@ function ModuleEvaluation() return EvaluateModule(module); } _SetCanonicalName(ModuleEvaluation, "ModuleEvaluation"); - -function ModuleNamespaceEnumerate() -{ - if (!IsObject(this) || !IsModuleNamespace(this)) - return callFunction(CallModuleMethodIfWrapped, this, "ModuleNamespaceEnumerate"); - - return CreateListIterator(ModuleNamespaceExports(this)); -} diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 798ef46e11..575bab0b0c 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -147,7 +147,7 @@ DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot) DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot) DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot) -DEFINE_ATOM_ACCESSOR_METHOD(ExportEntryObject, exportName) +DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName) DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest) DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName) DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName) @@ -289,14 +289,6 @@ ModuleNamespaceObject::create(JSContext* cx, HandleModuleObject module) if (!object) return nullptr; - RootedId funName(cx, INTERNED_STRING_TO_JSID(cx, cx->names().Symbol_iterator_fun)); - RootedFunction enumerateFun(cx); - enumerateFun = JS::GetSelfHostedFunction(cx, "ModuleNamespaceEnumerate", funName, 0); - if (!enumerateFun) - return nullptr; - - SetProxyExtra(object, ProxyHandler::EnumerateFunctionSlot, ObjectValue(*enumerateFun)); - return &object->as<ModuleNamespaceObject>(); } @@ -338,14 +330,9 @@ ModuleNamespaceObject::addBinding(JSContext* cx, HandleAtom exportedName, const char ModuleNamespaceObject::ProxyHandler::family = 0; ModuleNamespaceObject::ProxyHandler::ProxyHandler() - : BaseProxyHandler(&family, true) + : BaseProxyHandler(&family, false) {} -JS::Value ModuleNamespaceObject::ProxyHandler::getEnumerateFunction(HandleObject proxy) const -{ - return GetProxyExtra(proxy, EnumerateFunctionSlot); -} - bool ModuleNamespaceObject::ProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const @@ -358,6 +345,8 @@ bool ModuleNamespaceObject::ProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const { + if (!proto) + return result.succeed(); return result.failCantSetProto(); } @@ -402,21 +391,12 @@ ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, Han Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); if (JSID_IS_SYMBOL(id)) { Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); - if (symbol == cx->wellKnownSymbols().iterator) { - RootedValue enumerateFun(cx, getEnumerateFunction(proxy)); - desc.object().set(proxy); - desc.setConfigurable(false); - desc.setEnumerable(false); - desc.setValue(enumerateFun); - return true; - } - if (symbol == cx->wellKnownSymbols().toStringTag) { RootedValue value(cx, StringValue(cx->names().Module)); desc.object().set(proxy); desc.setWritable(false); desc.setEnumerable(false); - desc.setConfigurable(true); + desc.setConfigurable(false); desc.setValue(value); return true; } @@ -458,8 +438,8 @@ ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy, Hand Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); if (JSID_IS_SYMBOL(id)) { Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); - return symbol == cx->wellKnownSymbols().iterator || - symbol == cx->wellKnownSymbols().toStringTag; + *bp = symbol == cx->wellKnownSymbols().toStringTag; + return true; } *bp = ns->bindings().has(id); @@ -473,23 +453,21 @@ ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy, Hand Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); if (JSID_IS_SYMBOL(id)) { Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); - if (symbol == cx->wellKnownSymbols().iterator) { - vp.set(getEnumerateFunction(proxy)); - return true; - } - if (symbol == cx->wellKnownSymbols().toStringTag) { vp.setString(cx->names().Module); return true; } - return false; + vp.setUndefined(); + return true; } ModuleEnvironmentObject* env; Shape* shape; - if (!ns->bindings().lookup(id, &env, &shape)) - return false; + if (!ns->bindings().lookup(id, &env, &shape)) { + vp.setUndefined(); + return true; + } RootedValue value(cx, env->getSlot(shape->slot())); if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) { @@ -526,7 +504,7 @@ ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); RootedObject exports(cx, &ns->exports()); uint32_t count; - if (!GetLengthProperty(cx, exports, &count) || !props.reserve(props.length() + count)) + if (!GetLengthProperty(cx, exports, &count) || !props.reserve(props.length() + count + 1)) return false; Rooted<ValueVector> names(cx, ValueVector(cx)); @@ -536,6 +514,8 @@ ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject for (uint32_t i = 0; i < count; i++) props.infallibleAppend(AtomToId(&names[i].toString()->asAtom())); + props.infallibleAppend(SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag)); + return true; } @@ -1014,7 +994,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global) static const JSFunctionSpec protoFunctions[] = { JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0), - JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 3, 0), + JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0), JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0), JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0), JS_FS_END @@ -1164,6 +1144,13 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT; ParseNode* kid = isDefault ? pn->pn_left : pn->pn_kid; + if (isDefault && pn->pn_right) { + // This is an export default containing an expression. + RootedAtom localName(cx_, cx_->names().starDefaultStar); + RootedAtom exportName(cx_, cx_->names().default_); + return appendExportEntry(exportName, localName); + } + switch (kid->getKind()) { case PNK_EXPORT_SPEC_LIST: MOZ_ASSERT(!isDefault); @@ -1177,53 +1164,46 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) break; case PNK_CLASS: { - const ClassNode& cls = kid->as<ClassNode>(); - MOZ_ASSERT(cls.names()); - RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom); - RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); - if (!appendExportEntry(exportName, localName)) - return false; - break; + const ClassNode& cls = kid->as<ClassNode>(); + MOZ_ASSERT(cls.names()); + RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom); + RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); + if (!appendExportEntry(exportName, localName)) + return false; + break; } case PNK_VAR: case PNK_CONST: case PNK_LET: { - MOZ_ASSERT(kid->isArity(PN_LIST)); - for (ParseNode* var = kid->pn_head; var; var = var->pn_next) { - if (var->isKind(PNK_ASSIGN)) - var = var->pn_left; - MOZ_ASSERT(var->isKind(PNK_NAME)); - RootedAtom localName(cx_, var->pn_atom); - RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); - if (!appendExportEntry(exportName, localName)) - return false; - } - break; + MOZ_ASSERT(kid->isArity(PN_LIST)); + for (ParseNode* var = kid->pn_head; var; var = var->pn_next) { + if (var->isKind(PNK_ASSIGN)) + var = var->pn_left; + MOZ_ASSERT(var->isKind(PNK_NAME)); + RootedAtom localName(cx_, var->pn_atom); + RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); + if (!appendExportEntry(exportName, localName)) + return false; + } + break; } case PNK_FUNCTION: { - RootedFunction func(cx_, kid->pn_funbox->function()); - if (!func->isArrow()) { - RootedAtom localName(cx_, func->explicitName()); - RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); - MOZ_ASSERT_IF(isDefault, localName); - if (!appendExportEntry(exportName, localName)) - return false; - break; - } - } - - MOZ_FALLTHROUGH; // Arrow functions are handled below. - - default: - MOZ_ASSERT(isDefault); - RootedAtom localName(cx_, cx_->names().starDefaultStar); - RootedAtom exportName(cx_, cx_->names().default_); + RootedFunction func(cx_, kid->pn_funbox->function()); + MOZ_ASSERT(!func->isArrow()); + RootedAtom localName(cx_, func->explicitName()); + RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); + MOZ_ASSERT_IF(isDefault, localName); if (!appendExportEntry(exportName, localName)) return false; break; + } + + default: + MOZ_CRASH("Unexpected parse node"); } + return true; } diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index e83520ebe6..22db762ac6 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -142,15 +142,8 @@ class ModuleNamespaceObject : public ProxyObject private: struct ProxyHandler : public BaseProxyHandler { - enum - { - EnumerateFunctionSlot = 0 - }; - ProxyHandler(); - JS::Value getEnumerateFunction(HandleObject proxy) const; - bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const override; bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 56c77f3047..bfcc8d20ef 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -568,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) @@ -1290,10 +1199,6 @@ static const JSFunctionSpec object_methods[] = { JS_FN(js_toString_str, obj_toString, 0,0), JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0), JS_SELF_HOSTED_FN(js_valueOf_str, "Object_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_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), diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index ec7845e89d..1d068f8c64 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2006,6 +2006,13 @@ CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue ar return promise; } +MOZ_MUST_USE JSObject* +js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value) +{ + RootedValue C(cx, ObjectValue(*constructor)); + return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode); +} + /** * ES2016, 25.4.4.4, Promise.reject. */ @@ -2739,6 +2746,7 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key) static const JSFunctionSpec promise_methods[] = { JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0), JS_FN("then", Promise_then, 2, 0), + JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0), JS_FS_END }; diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index c76dc358c7..6a6453e465 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -128,6 +128,14 @@ OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled, HandleValue onRejected, MutableHandleObject dependent, bool createDependent); +/** + * PromiseResolve ( C, x ) + * + * The abstract operation PromiseResolve, given a constructor and a value, + * returns a new promise resolved with that value. + */ +MOZ_MUST_USE JSObject* +PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value); MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal); diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js index 704cbab0be..91a1e1f562 100644 --- a/js/src/builtin/Promise.js +++ b/js/src/builtin/Promise.js @@ -14,3 +14,72 @@ function Promise_catch(onRejected) { // Steps 1-2. return callContentFunction(this.then, this, undefined, onRejected); } + +// Promise.prototype.finally(onFinally) +// See https://tc39.es/proposal-promise-finally/ +function Promise_finally(onFinally) { + // Step 1. + var promise = this; + + // Step 2. + if (!IsObject(promise)) + ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Promise", "finally", "value"); + + // Step 3. + var C = SpeciesConstructor(promise, GetBuiltinConstructor("Promise")); + + // Step 4. + assert(IsConstructor(C), "SpeciesConstructor returns a constructor function"); + + // Steps 5-6. + var thenFinally, catchFinally; + if (!IsCallable(onFinally)) { + thenFinally = onFinally; + catchFinally = onFinally; + } else { + // ThenFinally Function. + // The parentheses prevent the inferring of a function name. + (thenFinally) = function(value) { + // Steps 1-2 (implicit). + + // Step 3. + var result = onFinally(); + + // Steps 4-5 (implicit). + + // Step 6. + var promise = PromiseResolve(C, result); + + // Step 7. + // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term. + // https://github.com/tc39/ecma262/issues/933 + + // Step 8. + return callContentFunction(promise.then, promise, function() { return value; }); + }; + + // CatchFinally Function. + // The parentheses prevent the inferring of a function name. + (catchFinally) = function(reason) { + // Steps 1-2 (implicit). + + // Step 3. + var result = onFinally(); + + // Steps 4-5 (implicit). + + // Step 6. + var promise = PromiseResolve(C, result); + + // Step 7. + // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term. + // https://github.com/tc39/ecma262/issues/933 + + // Step 8. + return callContentFunction(promise.then, promise, function() { throw reason; }); + }; + } + + // Step 7. + return callContentFunction(promise.then, promise, thenFinally, catchFinally); +} diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 7cf20d23c5..55e0c85785 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -178,7 +178,7 @@ CheckPatternSyntax(JSContext* cx, HandleAtom pattern, RegExpFlag flags) CompileOptions options(cx); frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); return irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern, - flags & UnicodeFlag); + flags & UnicodeFlag, flags & DotAllFlag); } enum RegExpSharedUse { @@ -664,6 +664,29 @@ js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp) return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_multiline_impl>(cx, args); } +// ES 2018 dotAll +MOZ_ALWAYS_INLINE bool +regexp_dotall_impl(JSContext* cx, const CallArgs& args) +{ + MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv())); + + if (!IsRegExpObject(args.thisv())) { + args.rval().setUndefined(); + return true; + } + + Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>()); + args.rval().setBoolean(reObj->dotall()); + return true; +} + +bool +js::regexp_dotall(JSContext* cx, unsigned argc, JS::Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_dotall_impl>(cx, args); +} + // ES 2017 draft rev32 21.2.5.10. MOZ_ALWAYS_INLINE bool regexp_source_impl(JSContext* cx, const CallArgs& args) @@ -759,6 +782,7 @@ const JSPropertySpec js::regexp_properties[] = { JS_PSG("source", regexp_source, 0), JS_PSG("sticky", regexp_sticky, 0), JS_PSG("unicode", regexp_unicode, 0), + JS_PSG("dotall", regexp_dotall, 0), JS_PS_END }; @@ -771,6 +795,7 @@ const JSFunctionSpec js::regexp_methods[] = { JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0), JS_SELF_HOSTED_FN("test", "RegExpTest" , 1,0), JS_SELF_HOSTED_SYM_FN(match, "RegExpMatch", 1,0), + JS_SELF_HOSTED_SYM_FN(matchAll, "RegExpMatchAll", 1, 0), JS_SELF_HOSTED_SYM_FN(replace, "RegExpReplace", 2,0), JS_SELF_HOSTED_SYM_FN(search, "RegExpSearch", 1,0), JS_SELF_HOSTED_SYM_FN(split, "RegExpSplit", 2,0), @@ -1642,6 +1667,13 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto) if (unicodeGetter != regexp_unicode) return false; + JSNative dotAllGetter; + if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().dotall), &dotAllGetter)) + return false; + + if (dotAllGetter != regexp_dotall) + return false; + // Check if @@match, @@search, and exec are own data properties, // those values should be tested in selfhosted JS. bool has = false; diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 4e0ff69484..f808f5146a 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -153,6 +153,8 @@ extern MOZ_MUST_USE bool regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp); extern MOZ_MUST_USE bool regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp); +extern MOZ_MUST_USE bool +regexp_dotall(JSContext* cx, unsigned argc, JS::Value* vp); } /* namespace js */ diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 0b849292cf..91212066c8 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags +// Updated for ES2018 /s (dotAll) function RegExpFlagsGetter() { // Steps 1-2. var R = this; @@ -31,6 +32,10 @@ function RegExpFlagsGetter() { // Steps 16-18. if (R.sticky) result += "y"; + + // ES2018 + if (R.dotall) + result += "s"; // Step 19. return result; @@ -1026,3 +1031,138 @@ function RegExpSpecies() { return this; } _SetCanonicalName(RegExpSpecies, "get [Symbol.species]"); + +// String.prototype.matchAll proposal. +// +// RegExp.prototype [ @@matchAll ] ( string ) +function RegExpMatchAll(string) { + // Step 1. + var rx = this; + + // Step 2. + if (!IsObject(rx)) + ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx); + + if (rx.flags === undefined || rx.flags === null) + ThrowTypeError(JSMSG_FLAGS_UNDEFINED_OR_NULL); + + // Step 3. + var str = ToString(string); + + // Step 4. + var C = SpeciesConstructor(rx, GetBuiltinConstructor("RegExp")); + + // Step 5. + var flags = ToString(rx.flags); + + // Step 2.b.iii; located here because it needs to check |flags|. + if (!callFunction(std_String_includes, flags, "g")) { + ThrowTypeError(JSMSG_REQUIRES_GLOBAL_REGEXP, "matchAll"); + } + + // Step 6. + var matcher = new C(rx, flags); + + // Steps 7-8. + matcher.lastIndex = ToLength(rx.lastIndex); + + // Steps 9-12. + // Note, always global because non-global throws as per + // https://github.com/tc39/ecma262/pull/1716 + var flags = REGEXP_GLOBAL_FLAG | + (callFunction(std_String_includes, flags, "u") ? REGEXP_UNICODE_FLAG : 0); + + // Step 13. + return CreateRegExpStringIterator(matcher, str, flags); +} + +// String.prototype.matchAll proposal. +// +// CreateRegExpStringIterator ( R, S, global, fullUnicode ) +function CreateRegExpStringIterator(regexp, string, flags) { + // Step 1. + assert(typeof string === "string", "|string| is a string value"); + + // Steps 2-3. + assert(typeof flags === "number", "|flags| is a number value"); + + // Steps 4-9. + var iterator = NewRegExpStringIterator(); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_REGEXP_SLOT, regexp); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_STRING_SLOT, string); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_FLAGS_SLOT, flags | 0); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_DONE_SLOT, false); + + // Step 10. + return iterator; +} + +// String.prototype.matchAll proposal. +// +// %RegExpStringIteratorPrototype%.next ( ) +function RegExpStringIteratorNext() { + // Steps 1-3. + var obj; + if (!IsObject(this) || (obj = GuardToRegExpStringIterator(this)) === null) { + return callFunction(CallRegExpStringIteratorMethodIfWrapped, this, + "RegExpStringIteratorNext"); + } + + var result = { value: undefined, done: false }; + + // Step 4. + var done = UnsafeGetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT); + if (done) { + result.done = true; + return result; + } + + // Step 5. + var regexp = UnsafeGetObjectFromReservedSlot(obj, REGEXP_STRING_ITERATOR_REGEXP_SLOT); + + // Step 6. + var string = UnsafeGetStringFromReservedSlot(obj, REGEXP_STRING_ITERATOR_STRING_SLOT); + + // Steps 7-8. + var flags = UnsafeGetInt32FromReservedSlot(obj, REGEXP_STRING_ITERATOR_FLAGS_SLOT); + var global = !!(flags & REGEXP_GLOBAL_FLAG); + var fullUnicode = !!(flags & REGEXP_UNICODE_FLAG); + + // Step 9. + var match = RegExpExec(regexp, string, false); + + // Step 10. + if (match === null) { + // Step 10.a. + UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true); + + // Step 10.b. + result.done = true; + return result; + } + + // Step 11.a. + if (global) { + // Step 11.a.i. + var matchStr = ToString(match[0]); + + // Step 11.a.ii. + if (matchStr.length === 0) { + // Step 11.a.ii.1. + var thisIndex = ToLength(regexp.lastIndex); + + // Step 11.a.ii.2. + var nextIndex = fullUnicode ? AdvanceStringIndex(string, thisIndex) : thisIndex + 1; + + // Step 11.a.ii.3. + regexp.lastIndex = nextIndex; + } + } else { + // Step 11.b.i. + UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true); + } + + // Steps 11.a.iii and 11.b.ii. + result.value = match; + return result; +} diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index b57c172691..117ac7ffd3 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -71,8 +71,6 @@ // Used for list, i.e. Array and String, iterators. #define ITERATOR_SLOT_NEXT_INDEX 1 #define ITERATOR_SLOT_ITEM_KIND 2 -// Used for ListIterator. -#define ITERATOR_SLOT_NEXT_METHOD 2 #define ITEM_KIND_KEY 0 #define ITEM_KIND_VALUE 1 @@ -92,6 +90,12 @@ #define REGEXP_MULTILINE_FLAG 0x04 #define REGEXP_STICKY_FLAG 0x08 #define REGEXP_UNICODE_FLAG 0x10 +#define REGEXP_DOTALL_FLAG 0x20 + +#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0 +#define REGEXP_STRING_ITERATOR_STRING_SLOT 1 +#define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2 +#define REGEXP_STRING_ITERATOR_DONE_SLOT 3 #define MODULE_OBJECT_ENVIRONMENT_SLOT 2 diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index f830b1aa24..d07ec6127b 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -63,6 +63,33 @@ function String_generic_match(thisValue, regexp) { return callFunction(String_match, thisValue, regexp); } +// String.prototype.matchAll proposal. +// +// String.prototype.matchAll ( regexp ) +function String_matchAll(regexp) { + // Step 1. + RequireObjectCoercible(this); + + // Step 2. + if (regexp !== undefined && regexp !== null) { + // Step 2.a. + var matcher = GetMethod(regexp, std_matchAll); + + // Step 2.b. + if (matcher !== undefined) + return callContentFunction(matcher, regexp, this); + } + + // Step 3. + var string = ToString(this); + + // Step 4. + var rx = RegExpCreate(regexp, "g"); + + // Step 5. + return callContentFunction(GetMethod(rx, std_matchAll), rx, string); +} + /** * A helper function implementing the logic for both String.prototype.padStart * and String.prototype.padEnd as described in ES7 Draft March 29, 2016 diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 992fe2c97c..b521e2bb34 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -239,8 +239,11 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) value = BooleanValue(true); if (!JS_SetProperty(cx, info, "intl-api", value)) return false; - +#ifdef XP_SOLARIS + value = BooleanValue(false); +#else value = BooleanValue(true); +#endif if (!JS_SetProperty(cx, info, "mapped-array-buffer", value)) return false; @@ -3897,10 +3900,10 @@ ConvertRegExpTreeToObject(JSContext* cx, irregexp::RegExpTree* tree) return nullptr; return obj; } - if (tree->IsLookahead()) { - if (!StringProp(cx, obj, "type", "Lookahead")) + if (tree->IsLookaround()) { + if (!StringProp(cx, obj, "type", "Lookaround")) return nullptr; - irregexp::RegExpLookahead* t = tree->AsLookahead(); + irregexp::RegExpLookaround* t = tree->AsLookaround(); if (!BooleanProp(cx, obj, "is_positive", t->is_positive())) return nullptr; if (!TreeProp(cx, obj, "body", t->body())) @@ -3972,6 +3975,7 @@ ParseRegExp(JSContext* cx, unsigned argc, Value* vp) flags & MultilineFlag, match_only, flags & UnicodeFlag, flags & IgnoreCaseFlag, flags & GlobalFlag, flags & StickyFlag, + flags & DotAllFlag, &data)) { return false; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index ff36807745..50bf0b8360 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -2215,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 */ |