From a27e8bf989c96f58017b6295e8776ab22010c0ad Mon Sep 17 00:00:00 2001 From: Martok Date: Wed, 26 Apr 2023 22:03:06 +0200 Subject: [PATCH 01/13] Issue #2213 - Follow-up: Fix derieved Generator prototypes after previous change --- js/src/vm/GeneratorObject.cpp | 2 ++ js/src/vm/Stack-inl.h | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 082e382663..f0718c0f86 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -179,6 +179,8 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation, { Rooted genObj(cx, &obj->as()); MOZ_ASSERT(genObj->isSuspended()); + // See comment in InterpreterStack::resumeGeneratorCallFrame + MOZ_ASSERT_IF(genObj->isConstructing(), genObj->is()); RootedFunction callee(cx, &genObj->callee()); RootedValue newTarget(cx, genObj->newTarget()); diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 9114a6a79e..5f66159c2c 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -351,7 +351,10 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs, constructing = MaybeConstruct(newTarget.isObject()); MOZ_ASSERT_IF(constructing, callee->isConstructor()); } else { - MOZ_ASSERT(!callee->isConstructor()); + // We should really be doing MOZ_ASSERT(!callee->isConstructor()) here. + // However, the GeneratorObject only stores the callee as-is, which in the case of a lambda generator + // (i.e. a |new GeneratorFunction(...)| or derieved generator class) is still flagged as a constructor. + // Instead, we check for the correct state in GeneratorObject::resume. } // Include callee, |this|, and maybe |new.target| From e31a058ce9c3a055ab5eacd148939e029c27efd0 Mon Sep 17 00:00:00 2001 From: Martok Date: Mon, 24 Apr 2023 00:28:56 +0200 Subject: [PATCH 02/13] Issue #2173 - Follow-up: Use common ancestor of PNK_(OPT)DOT in ASTSerializer::expression --- js/src/builtin/ReflectParse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 91bef98884..4aa7f1640b 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3162,7 +3162,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_OPTDOT: case PNK_DOT: { - PropertyAccess* prop = &pn->as(); + PropertyAccessBase* prop = &pn->as(); MOZ_ASSERT(prop->pn_pos.encloses(prop->expression().pn_pos)); RootedValue expr(cx); From aece6260fb6cd70fda5ffd781993f113c6917cf0 Mon Sep 17 00:00:00 2001 From: Martok Date: Tue, 25 Apr 2023 10:08:03 +0200 Subject: [PATCH 03/13] Issue #1894 - Follow-up: Fix return value ordering in IonMonkey nullish coalescing --- js/src/jit/IonBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 7721ed99d5..a6dcdf001a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4443,7 +4443,7 @@ IonBuilder::jsop_logical(JSOp op) MIsNullOrUndefined* isNullOrUndefined = MIsNullOrUndefined::New(alloc(), lhs); current->add(isNullOrUndefined); - test = newTest(isNullOrUndefined, evalLhs, evalRhs); + test = newTest(isNullOrUndefined, evalRhs, evalLhs); break; } From 0a74a5758559b611ceb374e87b15e746b9d1708f Mon Sep 17 00:00:00 2001 From: Martok Date: Tue, 25 Apr 2023 11:10:46 +0200 Subject: [PATCH 04/13] Issue #1285 - Follow-up: Correctly handle follow-up compilations of RegExp with named capturing groups --- js/src/vm/RegExpObject.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index f46f4b4510..1d88754084 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -994,11 +994,33 @@ RegExpShared::initializeNamedCaptures(JSContext* cx, HandleRegExpShared re, irregexp::CharacterVectorVector* names, irregexp::IntegerVector* indices) { - MOZ_ASSERT(!re->groupsTemplate_); MOZ_ASSERT(names); MOZ_ASSERT(indices); MOZ_ASSERT(names->length() == indices->length()); + if (re->getGroupsTemplate()) { + // If initializeNamedCaptures was previously called for a different CompilationMode/Latin1Chars combination, + // the template object is already created and correct. +#ifdef DEBUG + // In debug builds, verify that. + MOZ_ASSERT(re->getGroupsTemplate()->propertyCount() == names->length()); + RootedId id(cx); + RootedNativeObject groupsTemplate(cx, re->getGroupsTemplate()); + Rooted desc(cx); + for (uint32_t i = 0; i < names->length(); i++) { + irregexp::CharacterVector* cv = (*names)[i]; + JSAtom* atom = AtomizeChars(cx, cv->begin(), cv->length()); + MOZ_ASSERT(atom); + id = NameToId(atom->asPropertyName()); + MOZ_ASSERT(NativeGetOwnPropertyDescriptor(cx, groupsTemplate, id, &desc)); + int32_t idx; + MOZ_ASSERT(ToInt32(cx, desc.value(), &idx)); + MOZ_ASSERT(idx == (*indices)[i]); + } +#endif + return true; + } + // The irregexp parser returns named capture information in the form // of two arrays. We create a template object with a property for each // capture name, and store the capture index as Integer in the corresponding value. @@ -1025,7 +1047,7 @@ RegExpShared::initializeNamedCaptures(JSContext* cx, HandleRegExpShared re, // Need to explicitly create an Atom (not a String) or it won't get added to the atom table JSAtom* atom = AtomizeChars(cx, cv->begin(), cv->length()); if (!atom) { - return false; + return false; } id = NameToId(atom->asPropertyName()); RootedValue idx(cx, Int32Value((*indices)[i])); From b592711bb2c324fffebc1349209477cde8bbfffd Mon Sep 17 00:00:00 2001 From: Job Bautista Date: Sat, 22 Apr 2023 10:39:55 +0800 Subject: [PATCH 05/13] Issue #2221 - Enable link-time optimization for Spidermonkey by default if building it shared. Currently only Windows can take advantage of this. The reason why the arrays of deunified sources are named like that in Spidermonkey's moz.build is to avoid UnsortedErrors in python. There's probably a better way to handle that, but I just want something that works for now. And yes, the deunified sources will be reunified if LTO is disabled. --- build/moz.configure/old.configure | 1 + config/external/ffi/moz.build | 6 +++ js/src/moz.build | 65 +++++++++++++++++++++---------- js/src/old-configure.in | 20 ++++++++++ modules/fdlibm/src/moz.build | 6 +++ old-configure.in | 20 ++++++++++ 6 files changed, 97 insertions(+), 21 deletions(-) diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure index fa08574833..40656f42dc 100644 --- a/build/moz.configure/old.configure +++ b/build/moz.configure/old.configure @@ -194,6 +194,7 @@ def old_configure_options(*options): '--enable-ion', '--enable-ios-target', '--enable-jitspew', + '--enable-js-lto', '--enable-libjpeg-turbo', '--enable-libproxy', '--enable-llvm-hacks', diff --git a/config/external/ffi/moz.build b/config/external/ffi/moz.build index 168f28c0bf..8710ebab7a 100644 --- a/config/external/ffi/moz.build +++ b/config/external/ffi/moz.build @@ -128,3 +128,9 @@ else: '/js/src/ctypes/libffi/src/%s/%s' % (CONFIG['FFI_TARGET_DIR'], s) for s in sorted(ffi_srcs) ] + + # Explicitly enable WPO and LTCG in MSVC if we're doing LTO. + if CONFIG['JS_LTO']: + if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']: + CFLAGS += [ '-GL' ] + CXXFLAGS += [ '-GL' ] diff --git a/js/src/moz.build b/js/src/moz.build index 115747daaf..3553dc9bf1 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -7,8 +7,6 @@ include('js-config.mozbuild') include('js-cxxflags.mozbuild') include('js-testing.mozbuild') -FILES_PER_UNIFIED_FILE = 6 - if CONFIG['JS_BUNDLED_EDITLINE']: DIRS += ['editline'] @@ -111,7 +109,7 @@ EXPORTS.js += [ '../public/WeakMapPtr.h', ] -UNIFIED_SOURCES += [ +main_deunified_sources = [ 'builtin/AtomicsObject.cpp', 'builtin/Eval.cpp', 'builtin/intl/Collator.cpp', @@ -388,7 +386,7 @@ SOURCES += [ ] if CONFIG['JS_POSIX_NSPR']: - UNIFIED_SOURCES += [ + posix_nspr_deunified_sources = [ 'vm/PosixNSPR.cpp', ] @@ -405,26 +403,24 @@ if CONFIG['ENABLE_TRACE_LOGGING']: ] if not CONFIG['ENABLE_ION']: - UNIFIED_SOURCES += [ + jit_ioncheck1_deunified_sources = [ 'jit/none/Trampoline-none.cpp' ] elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']: - UNIFIED_SOURCES += [ + jit_ioncheck1_deunified_sources = [ 'jit/x86-shared/Architecture-x86-shared.cpp', 'jit/x86-shared/Assembler-x86-shared.cpp', 'jit/x86-shared/AssemblerBuffer-x86-shared.cpp', 'jit/x86-shared/BaselineCompiler-x86-shared.cpp', 'jit/x86-shared/BaselineIC-x86-shared.cpp', 'jit/x86-shared/CodeGenerator-x86-shared.cpp', + 'jit/x86-shared/Disassembler-x86-shared.cpp', # using namespace js::jit::X86Encoding; 'jit/x86-shared/Lowering-x86-shared.cpp', 'jit/x86-shared/MacroAssembler-x86-shared.cpp', 'jit/x86-shared/MoveEmitter-x86-shared.cpp', ] - UNIFIED_SOURCES += [ - 'jit/x86-shared/Disassembler-x86-shared.cpp', # using namespace js::jit::X86Encoding; - ] if CONFIG['JS_CODEGEN_X64']: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/x64/Assembler-x64.cpp', 'jit/x64/Bailouts-x64.cpp', 'jit/x64/BaselineCompiler-x64.cpp', @@ -436,7 +432,7 @@ elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']: 'jit/x64/Trampoline-x64.cpp', ] else: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/x86/Assembler-x86.cpp', 'jit/x86/Bailouts-x86.cpp', 'jit/x86/BaselineCompiler-x86.cpp', @@ -448,7 +444,7 @@ elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']: 'jit/x86/Trampoline-x86.cpp', ] elif CONFIG['JS_CODEGEN_ARM']: - UNIFIED_SOURCES += [ + jit_ioncheck1_deunified_sources = [ 'jit/arm/Architecture-arm.cpp', 'jit/arm/Assembler-arm.cpp', 'jit/arm/Bailouts-arm.cpp', @@ -464,16 +460,16 @@ elif CONFIG['JS_CODEGEN_ARM']: 'jit/arm/Trampoline-arm.cpp', ] if CONFIG['JS_SIMULATOR_ARM']: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/arm/Simulator-arm.cpp' ] elif CONFIG['OS_ARCH'] == 'Darwin': - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/arm/llvm-compiler-rt/arm/aeabi_idivmod.S', 'jit/arm/llvm-compiler-rt/arm/aeabi_uidivmod.S', ] elif CONFIG['JS_CODEGEN_ARM64']: - UNIFIED_SOURCES += [ + jit_ioncheck1_deunified_sources = [ 'jit/arm64/Architecture-arm64.cpp', 'jit/arm64/Assembler-arm64.cpp', 'jit/arm64/Bailouts-arm64.cpp', @@ -496,14 +492,14 @@ elif CONFIG['JS_CODEGEN_ARM64']: 'jit/arm64/vixl/Utils-vixl.cpp' ] if CONFIG['JS_SIMULATOR_ARM64']: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/arm64/vixl/Debugger-vixl.cpp', 'jit/arm64/vixl/Logic-vixl.cpp', 'jit/arm64/vixl/MozSimulator-vixl.cpp', 'jit/arm64/vixl/Simulator-vixl.cpp' ] elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: - UNIFIED_SOURCES += [ + jit_ioncheck1_deunified_sources = [ 'jit/mips-shared/Architecture-mips-shared.cpp', 'jit/mips-shared/Assembler-mips-shared.cpp', 'jit/mips-shared/Bailouts-mips-shared.cpp', @@ -515,7 +511,7 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: 'jit/mips-shared/MoveEmitter-mips-shared.cpp', ] if CONFIG['JS_CODEGEN_MIPS32']: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/mips32/Architecture-mips32.cpp', 'jit/mips32/Assembler-mips32.cpp', 'jit/mips32/Bailouts-mips32.cpp', @@ -529,11 +525,11 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: 'jit/mips32/Trampoline-mips32.cpp', ] if CONFIG['JS_SIMULATOR_MIPS32']: - UNIFIED_SOURCES += [ + jit_ioncheck3_deunified_sources = [ 'jit/mips32/Simulator-mips32.cpp' ] elif CONFIG['JS_CODEGEN_MIPS64']: - UNIFIED_SOURCES += [ + jit_ioncheck2_deunified_sources = [ 'jit/mips64/Architecture-mips64.cpp', 'jit/mips64/Assembler-mips64.cpp', 'jit/mips64/Bailouts-mips64.cpp', @@ -547,7 +543,7 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: 'jit/mips64/Trampoline-mips64.cpp', ] if CONFIG['JS_SIMULATOR_MIPS64']: - UNIFIED_SOURCES += [ + jit_ioncheck3_deunified_sources = [ 'jit/mips64/Simulator-mips64.cpp' ] @@ -627,6 +623,33 @@ else: 'icuuc', ] +# Explicitly enable WPO and LTCG in MSVC, and deunify sources if +# we're doing LTO +if CONFIG['JS_LTO']: + if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']: + CFLAGS += [ '-GL' ] + CXXFLAGS += [ '-GL' ] + if CONFIG['JS_SHARED_LIBRARY']: + LDFLAGS += [ '/LTCG' ] + SOURCES += main_deunified_sources + if CONFIG['JS_POSIX_NSPR']: + SOURCES += posix_nspr_deunified_sources + SOURCES += jit_ioncheck1_deunified_sources + if CONFIG['ENABLE_ION']: + SOURCES += jit_ioncheck2_deunified_sources + if CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: + SOURCES += jit_ioncheck3_deunified_sources +else: + FILES_PER_UNIFIED_FILE = 6 + UNIFIED_SOURCES += main_deunified_sources + if CONFIG['JS_POSIX_NSPR']: + UNIFIED_SOURCES += posix_nspr_deunified_sources + UNIFIED_SOURCES += jit_ioncheck1_deunified_sources + if CONFIG['ENABLE_ION']: + UNIFIED_SOURCES += jit_ioncheck2_deunified_sources + if CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: + UNIFIED_SOURCES += jit_ioncheck3_deunified_sources + USE_LIBS += [ 'nspr', 'zlib', diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 01a272bd4c..b8fd4bdd5d 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -584,6 +584,26 @@ esac MOZ_DOING_LTO(lto_is_enabled) +dnl ======================================================== +dnl Spidermonkey link-time optimization support +dnl ======================================================== + +# We want LTO enabled by default in Spidermonkey if we're building it shared. +if test -n "$JS_SHARED_LIBRARY"; then + JS_LTO=1 +fi + +MOZ_ARG_DISABLE_BOOL(js-lto, +[ --disable-js-lto Disable link-time optimization for the Spidermonkey library], + JS_LTO=, + JS_LTO=1) + +if test -n "$JS_LTO"; then + AC_DEFINE(JS_LTO) +fi + +AC_SUBST(JS_LTO) + dnl ======================================================== dnl System overrides of the defaults for target dnl ======================================================== diff --git a/modules/fdlibm/src/moz.build b/modules/fdlibm/src/moz.build index 541f840399..d1feeb62f9 100644 --- a/modules/fdlibm/src/moz.build +++ b/modules/fdlibm/src/moz.build @@ -38,6 +38,12 @@ if CONFIG['CC_TYPE'] == 'clang-cl': '-Wno-sign-compare', # signed/unsigned mismatch ] +# Explicitly enable WPO and LTCG in MSVC if we're doing LTO. +if CONFIG['JS_LTO']: + if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']: + CFLAGS += [ '-GL' ] + CXXFLAGS += [ '-GL' ] + SOURCES += [ 'e_acos.cpp', 'e_acosh.cpp', diff --git a/old-configure.in b/old-configure.in index 8f2381b81c..6bba6de680 100644 --- a/old-configure.in +++ b/old-configure.in @@ -768,6 +768,26 @@ AC_SUBST(MOZILLA_UAVERSION_U) MOZ_DOING_LTO(lto_is_enabled) +dnl ======================================================== +dnl Spidermonkey link-time optimization support +dnl ======================================================== + +# We want LTO enabled by default in Spidermonkey if we're building it shared. +if test -n "$JS_SHARED_LIBRARY"; then + JS_LTO=1 +fi + +MOZ_ARG_DISABLE_BOOL(js-lto, +[ --disable-js-lto Disable link-time optimization for the Spidermonkey library], + JS_LTO=, + JS_LTO=1) + +if test -n "$JS_LTO"; then + AC_DEFINE(JS_LTO) +fi + +AC_SUBST(JS_LTO) + dnl ======================================================== dnl System overrides of the defaults for target dnl ======================================================== From 45b34592b6fee3f3db7fbaf61cdda5569f0fc52b Mon Sep 17 00:00:00 2001 From: Job Bautista Date: Sun, 30 Apr 2023 21:11:01 +0800 Subject: [PATCH 06/13] Issue #1691 - Follow-up: Fix CallSelfHostedFunction deprot introduced by Part 4. --- js/src/builtin/ModuleObject.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 8e01ea2ac8..194959cf31 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -11,6 +11,7 @@ #include "frontend/SharedContext.h" #include "gc/Policy.h" #include "gc/Tracer.h" +#include "vm/SelfHosting.h" #include "jsobjinlines.h" #include "jsscriptinlines.h" From 51426d1053ac974361fdd5743828c3d2910d883b Mon Sep 17 00:00:00 2001 From: Job Bautista Date: Sun, 30 Apr 2023 21:20:06 +0800 Subject: [PATCH 07/13] Issue #1862 - Follow-up: Replace deprecated Harfbuzz functions with current ones. Based on Mozilla bug 1500356. --- gfx/thebes/gfxFT2FontList.cpp | 2 +- gfx/thebes/gfxFont.cpp | 14 ++++--- gfx/thebes/gfxFontEntry.cpp | 57 +++++++++++-------------- gfx/thebes/gfxFontEntry.h | 6 +-- gfx/thebes/gfxMacPlatformFontList.mm | 2 +- gfx/thebes/gfxPlatformFontList.cpp | 62 ++++++++++++++-------------- layout/media/symbols.def.in | 4 +- 7 files changed, 71 insertions(+), 76 deletions(-) diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index b032be13dc..93603f5167 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -484,7 +484,7 @@ FT2FontEntry::ReadCMAP(FontInfoData *aFontInfoData) // check to see if the cmap includes complex script codepoints if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) { // We check for GSUB here, as GPOS alone would not be ok. - if (hasGSUB && SupportsScriptInGSUB(sr->tags)) { + if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) { continue; } charmap->ClearRange(sr->rangeStart, sr->rangeEnd); diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 8ac64bc1b4..3857c4cd38 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1171,12 +1171,14 @@ gfxFont::CheckForFeaturesInvolvingSpace() sScriptTagToCode->Put(HB_TAG('D','F','L','T'), Script::COMMON); for (Script s = Script::ARABIC; s < Script::NUM_SCRIPT_CODES; s = Script(static_cast(s) + 1)) { - hb_script_t scriptTag = hb_script_t(GetScriptTagForCode(s)); - hb_tag_t s1, s2; - hb_ot_tags_from_script(scriptTag, &s1, &s2); - sScriptTagToCode->Put(s1, s); - if (s2 != HB_OT_TAG_DEFAULT_SCRIPT) { - sScriptTagToCode->Put(s2, s); + hb_script_t script = hb_script_t(GetScriptTagForCode(s)); + unsigned int scriptCount = 4; + hb_tag_t scriptTags[4]; + hb_ot_tags_from_script_and_language(script, HB_LANGUAGE_INVALID, + &scriptCount, scriptTags, nullptr, + nullptr); + for (unsigned int i = 0; i < scriptCount; i++) { + sScriptTagToCode->Put(scriptTags[i], s); } } diff --git a/gfx/thebes/gfxFontEntry.cpp b/gfx/thebes/gfxFontEntry.cpp index 90c0bc8585..765332aef5 100644 --- a/gfx/thebes/gfxFontEntry.cpp +++ b/gfx/thebes/gfxFontEntry.cpp @@ -233,7 +233,9 @@ uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS) return 0; } -bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags) +bool +gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags, + uint32_t aNumTags) { hb_face_t *face = GetHBFace(); if (!face) { @@ -242,9 +244,9 @@ bool gfxFontEntry::SupportsScriptInGSUB(const hb_tag_t* aScriptTags) unsigned int index; hb_tag_t chosenScript; - bool found = - hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'), - aScriptTags, &index, &chosenScript); + bool found = hb_ot_layout_table_select_script( + face, TRUETYPE_TAG('G', 'S', 'U', 'B'), aNumTags, aScriptTags, &index, + &chosenScript); hb_face_destroy(face); return found && chosenScript != TRUETYPE_TAG('D','F','L','T'); @@ -819,27 +821,22 @@ gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag) gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript); // Get the OpenType tag(s) that match this script code - hb_tag_t scriptTags[4] = { - HB_TAG_NONE, - HB_TAG_NONE, - HB_TAG_NONE, - HB_TAG_NONE - }; - hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]); + unsigned int scriptCount = 4; + hb_tag_t scriptTags[4]; + hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID, + &scriptCount, scriptTags, nullptr, + nullptr); - // Replace the first remaining NONE with DEFAULT - hb_tag_t* scriptTag = &scriptTags[0]; - while (*scriptTag != HB_TAG_NONE) { - ++scriptTag; + // Append DEFAULT to the returned tags, if room + if (scriptCount < 4) { + scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT; } - *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT; // Now check for 'smcp' under the first of those scripts that is present const hb_tag_t kGSUB = HB_TAG('G','S','U','B'); - scriptTag = &scriptTags[0]; - while (*scriptTag != HB_TAG_NONE) { + for (unsigned int i = 0; i < scriptCount; i++) { unsigned int scriptIndex; - if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag, + if (hb_ot_layout_table_find_script(face, kGSUB, scriptTags[i], &scriptIndex)) { if (hb_ot_layout_language_find_feature(face, kGSUB, scriptIndex, @@ -849,7 +846,6 @@ gfxFontEntry::SupportsOpenTypeFeature(Script aScript, uint32_t aFeatureTag) } break; } - ++scriptTag; } } @@ -886,20 +882,17 @@ gfxFontEntry::InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag) gfxHarfBuzzShaper::GetHBScriptUsedForShaping(aScript); // Get the OpenType tag(s) that match this script code - hb_tag_t scriptTags[4] = { - HB_TAG_NONE, - HB_TAG_NONE, - HB_TAG_NONE, - HB_TAG_NONE - }; - hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]); + unsigned int scriptCount = 4; + hb_tag_t scriptTags[5]; // space for null terminator + hb_ot_tags_from_script_and_language(hbScript, HB_LANGUAGE_INVALID, + &scriptCount, scriptTags, nullptr, + nullptr); - // Replace the first remaining NONE with DEFAULT - hb_tag_t* scriptTag = &scriptTags[0]; - while (*scriptTag != HB_TAG_NONE) { - ++scriptTag; + // Append DEFAULT to the returned tags, if room + if (scriptCount < 4) { + scriptTags[scriptCount++] = HB_OT_TAG_DEFAULT_SCRIPT; } - *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT; + scriptTags[scriptCount++] = 0; const hb_tag_t kGSUB = HB_TAG('G','S','U','B'); hb_tag_t features[2] = { aFeatureTag, HB_TAG_NONE }; diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index 7f0e7215be..77346f3ea3 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -320,11 +320,11 @@ public: struct ScriptRange { uint32_t rangeStart; uint32_t rangeEnd; - hb_tag_t tags[3]; // one or two OpenType script tags to check, - // plus a NULL terminator + uint32_t numTags; // number of entries in the tags[] array + hb_tag_t tags[3]; // up to three OpenType script tags to check }; - bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags); + bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags, uint32_t aNumTags); nsString mName; nsString mFamilyName; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 55263e7e6b..375d307230 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -204,7 +204,7 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData) } // We check for GSUB here, as GPOS alone would not be ok. - if (hasGSUB && SupportsScriptInGSUB(sr->tags)) { + if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) { continue; } diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 5f7bbb832f..1a4a72cb5a 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -52,39 +52,39 @@ const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = { // want to mask the basic Arabic block here? // This affects the arabic-fallback-*.html reftests, which rely on // loading a font that *doesn't* have any GSUB table. - { 0x0600, 0x06FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } }, - { 0x0700, 0x074F, { TRUETYPE_TAG('s','y','r','c'), 0, 0 } }, - { 0x0750, 0x077F, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } }, - { 0x08A0, 0x08FF, { TRUETYPE_TAG('a','r','a','b'), 0, 0 } }, - { 0x0900, 0x097F, { TRUETYPE_TAG('d','e','v','2'), - TRUETYPE_TAG('d','e','v','a'), 0 } }, - { 0x0980, 0x09FF, { TRUETYPE_TAG('b','n','g','2'), - TRUETYPE_TAG('b','e','n','g'), 0 } }, - { 0x0A00, 0x0A7F, { TRUETYPE_TAG('g','u','r','2'), - TRUETYPE_TAG('g','u','r','u'), 0 } }, - { 0x0A80, 0x0AFF, { TRUETYPE_TAG('g','j','r','2'), - TRUETYPE_TAG('g','u','j','r'), 0 } }, - { 0x0B00, 0x0B7F, { TRUETYPE_TAG('o','r','y','2'), - TRUETYPE_TAG('o','r','y','a'), 0 } }, - { 0x0B80, 0x0BFF, { TRUETYPE_TAG('t','m','l','2'), - TRUETYPE_TAG('t','a','m','l'), 0 } }, - { 0x0C00, 0x0C7F, { TRUETYPE_TAG('t','e','l','2'), - TRUETYPE_TAG('t','e','l','u'), 0 } }, - { 0x0C80, 0x0CFF, { TRUETYPE_TAG('k','n','d','2'), - TRUETYPE_TAG('k','n','d','a'), 0 } }, - { 0x0D00, 0x0D7F, { TRUETYPE_TAG('m','l','m','2'), - TRUETYPE_TAG('m','l','y','m'), 0 } }, - { 0x0D80, 0x0DFF, { TRUETYPE_TAG('s','i','n','h'), 0, 0 } }, - { 0x0E80, 0x0EFF, { TRUETYPE_TAG('l','a','o',' '), 0, 0 } }, - { 0x0F00, 0x0FFF, { TRUETYPE_TAG('t','i','b','t'), 0, 0 } }, - { 0x1000, 0x109f, { TRUETYPE_TAG('m','y','m','r'), - TRUETYPE_TAG('m','y','m','2'), 0 } }, - { 0x1780, 0x17ff, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } }, + {0x0600, 0x06FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}}, + {0x0700, 0x074F, 1, {TRUETYPE_TAG('s', 'y', 'r', 'c'), 0, 0}}, + {0x0750, 0x077F, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}}, + {0x08A0, 0x08FF, 1, {TRUETYPE_TAG('a', 'r', 'a', 'b'), 0, 0}}, + { 0x0900, 0x097F, 2, { TRUETYPE_TAG('d','e','v','2'), + TRUETYPE_TAG('d','e','v','a'), 0 } }, + { 0x0980, 0x09FF, 2, { TRUETYPE_TAG('b','n','g','2'), + TRUETYPE_TAG('b','e','n','g'), 0 } }, + { 0x0A00, 0x0A7F, 2, { TRUETYPE_TAG('g','u','r','2'), + TRUETYPE_TAG('g','u','r','u'), 0 } }, + { 0x0A80, 0x0AFF, 2, { TRUETYPE_TAG('g','j','r','2'), + TRUETYPE_TAG('g','u','j','r'), 0 } }, + { 0x0B00, 0x0B7F, 2, { TRUETYPE_TAG('o','r','y','2'), + TRUETYPE_TAG('o','r','y','a'), 0 } }, + { 0x0B80, 0x0BFF, 2, { TRUETYPE_TAG('t','m','l','2'), + TRUETYPE_TAG('t','a','m','l'), 0 } }, + { 0x0C00, 0x0C7F, 2, { TRUETYPE_TAG('t','e','l','2'), + TRUETYPE_TAG('t','e','l','u'), 0 } }, + { 0x0C80, 0x0CFF, 2, { TRUETYPE_TAG('k','n','d','2'), + TRUETYPE_TAG('k','n','d','a'), 0 } }, + { 0x0D00, 0x0D7F, 2, { TRUETYPE_TAG('m','l','m','2'), + TRUETYPE_TAG('m','l','y','m'), 0 } }, + {0x0D80, 0x0DFF, 1, {TRUETYPE_TAG('s', 'i', 'n', 'h'), 0, 0}}, + {0x0E80, 0x0EFF, 1, {TRUETYPE_TAG('l', 'a', 'o', ' '), 0, 0}}, + {0x0F00, 0x0FFF, 1, {TRUETYPE_TAG('t', 'i', 'b', 't'), 0, 0}}, + { 0x1000, 0x109f, 2, { TRUETYPE_TAG('m','y','m','r'), + TRUETYPE_TAG('m','y','m','2'), 0 } }, + { 0x1780, 0x17ff, 1, { TRUETYPE_TAG('k','h','m','r'), 0, 0 } }, // Khmer Symbols (19e0..19ff) don't seem to need any special shaping - { 0xaa60, 0xaa7f, { TRUETYPE_TAG('m','y','m','r'), - TRUETYPE_TAG('m','y','m','2'), 0 } }, + { 0xaa60, 0xaa7f, 2, { TRUETYPE_TAG('m','y','m','r'), + TRUETYPE_TAG('m','y','m','2'), 0 } }, // Thai seems to be "renderable" without AAT morphing tables - { 0, 0, { 0, 0, 0 } } // terminator + {0, 0, 0, {0, 0, 0}} // terminator }; // prefs for the font info loader diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 6e2364f51a..6b02400e9c 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -639,9 +639,9 @@ hb_ot_layout_language_get_feature_tags hb_ot_layout_language_get_required_feature_index hb_ot_layout_lookup_collect_glyphs hb_ot_layout_script_get_language_tags -hb_ot_layout_table_choose_script hb_ot_layout_table_find_script hb_ot_layout_table_get_script_tags +hb_ot_layout_table_select_script hb_ot_math_get_constant hb_ot_math_get_glyph_assembly hb_ot_math_get_glyph_italics_correction @@ -649,7 +649,7 @@ hb_ot_math_get_glyph_variants hb_ot_math_has_data hb_ot_tag_to_language hb_ot_tag_to_script -hb_ot_tags_from_script +hb_ot_tags_from_script_and_language hb_set_add hb_set_clear hb_set_create From 73a99c155d4f9623d72115df6aaf9d42a9af5c0f Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 30 Apr 2023 20:55:40 +0200 Subject: [PATCH 08/13] Issue #1691 - Follow-up: use error message with no arguments for bad import statements --- js/src/frontend/Parser.cpp | 2 +- js/src/js.msg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 23b479bfbb..cbdd40089e 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -10624,7 +10624,7 @@ Parser::importExpr(YieldHandling yieldHandling, bool allowCallSynt return handler.newCallImport(importHolder, arg); } else { - error(JSMSG_UNEXPECTED_TOKEN, TokenKindToDesc(next)); + error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(next)); return null(); } } diff --git a/js/src/js.msg b/js/src/js.msg index b98e6d860b..413469b808 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -339,6 +339,7 @@ MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local varia MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") +MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, 1, JSEXN_SYNTAXERR, "unexpected token: {0}") MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list") MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") From 014ebe8ae2e0deaa545f2fcfaf933bc7577a888a Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 23 Apr 2023 02:11:42 +0200 Subject: [PATCH 09/13] Issue #2142 - Fold BytecodeEmitter::checkTypeSet into BytecodeEmitter::emitCheck The bytecode emitter used to call checkTypeSet for each JOF_TYPESET op. Despite correctness asserts in the TypeScript code, this was pretty error prone. The solution is to move this check to BytecodeEmitter::emitCheck (called for each opcode we emit), so we don't have to worry about this anymore. Based-on: m-c 1521491/3 --- js/src/frontend/BytecodeEmitter.cpp | 53 +++++++++------------------- js/src/frontend/BytecodeEmitter.h | 6 +--- js/src/frontend/CallOrNewEmitter.cpp | 1 - 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 78b134cf58..51ebd81969 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -245,7 +245,7 @@ BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* } bool -BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset) +BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) { size_t oldLength = code().length(); *offset = ptrdiff_t(oldLength); @@ -260,6 +260,13 @@ BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset) ReportOutOfMemory(cx); return false; } + + // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h), + // reserve a type set to store its result. + if (CodeSpec[op].format & JOF_TYPESET) { + if (typesetCount < UINT16_MAX) + typesetCount++; + } return true; } @@ -297,7 +304,7 @@ BytecodeEmitter::emit1(JSOp op) MOZ_ASSERT(checkStrictOrSloppy(op)); ptrdiff_t offset; - if (!emitCheck(1, &offset)) + if (!emitCheck(op, 1, &offset)) return false; jsbytecode* code = this->code(offset); @@ -312,7 +319,7 @@ BytecodeEmitter::emit2(JSOp op, uint8_t op1) MOZ_ASSERT(checkStrictOrSloppy(op)); ptrdiff_t offset; - if (!emitCheck(2, &offset)) + if (!emitCheck(op, 2, &offset)) return false; jsbytecode* code = this->code(offset); @@ -332,7 +339,7 @@ BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) MOZ_ASSERT(!IsLocalOp(op)); ptrdiff_t offset; - if (!emitCheck(3, &offset)) + if (!emitCheck(op, 3, &offset)) return false; jsbytecode* code = this->code(offset); @@ -350,7 +357,7 @@ BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) ptrdiff_t length = 1 + ptrdiff_t(extra); ptrdiff_t off; - if (!emitCheck(length, &off)) + if (!emitCheck(op, length, &off)) return false; jsbytecode* code = this->code(off); @@ -391,7 +398,7 @@ bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) { ptrdiff_t offset; - if (!emitCheck(5, &offset)) + if (!emitCheck(op, 5, &offset)) return false; jsbytecode* code = this->code(offset); @@ -634,22 +641,12 @@ BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump) return emit2(JSOP_LOOPENTRY, loopDepthAndFlags); } -void -BytecodeEmitter::checkTypeSet(JSOp op) -{ - if (CodeSpec[op].format & JOF_TYPESET) { - if (typesetCount < UINT16_MAX) - typesetCount++; - } -} - bool BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand) { MOZ_ASSERT(operand <= UINT16_MAX); if (!emit3(op, UINT16_HI(operand), UINT16_LO(operand))) return false; - checkTypeSet(op); return true; } @@ -660,7 +657,6 @@ BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) if (!emitN(op, 4, &off)) return false; SET_UINT32(code(off), operand); - checkTypeSet(op); return true; } @@ -881,13 +877,12 @@ BytecodeEmitter::emitIndex32(JSOp op, uint32_t index) MOZ_ASSERT(len == size_t(CodeSpec[op].length)); ptrdiff_t offset; - if (!emitCheck(len, &offset)) + if (!emitCheck(op, len, &offset)) return false; jsbytecode* code = this->code(offset); code[0] = jsbytecode(op); SET_UINT32_INDEX(code, index); - checkTypeSet(op); updateDepth(offset); return true; } @@ -901,13 +896,12 @@ BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN); ptrdiff_t offset; - if (!emitCheck(len, &offset)) + if (!emitCheck(op, len, &offset)) return false; jsbytecode* code = this->code(offset); code[0] = jsbytecode(op); SET_UINT32_INDEX(code, index); - checkTypeSet(op); updateDepth(offset); return true; } @@ -1023,7 +1017,6 @@ BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) pc += ENVCOORD_HOPS_LEN; SET_ENVCOORD_SLOT(pc, ec.slot()); pc += ENVCOORD_SLOT_LEN; - checkTypeSet(op); return true; } @@ -1713,7 +1706,7 @@ BytecodeEmitter::emitNewInit(JSProtoKey key) { const size_t len = 1 + UINT32_INDEX_LEN; ptrdiff_t offset; - if (!emitCheck(len, &offset)) + if (!emitCheck(JSOP_NEWINIT, len, &offset)) return false; jsbytecode* code = this->code(offset); @@ -1722,7 +1715,6 @@ BytecodeEmitter::emitNewInit(JSProtoKey key) code[2] = 0; code[3] = 0; code[4] = 0; - checkTypeSet(JSOP_NEWINIT); updateDepth(offset); return true; } @@ -1953,7 +1945,6 @@ BytecodeEmitter::emitElemOpBase(JSOp op) if (!emit1(op)) return false; - checkTypeSet(op); return true; } @@ -2770,7 +2761,6 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = Iter if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT return false; - checkTypeSet(JSOP_CALL); return true; } @@ -2860,7 +2850,6 @@ BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope, if (!emitCall(JSOP_CALL, 0)) // ... ... RESULT return false; - checkTypeSet(JSOP_CALL); if (iterKind == IteratorKind::Async) { if (completionKind != CompletionKind::Throw) { @@ -4496,7 +4485,6 @@ BytecodeEmitter::emitRequireObjectCoercible() return false; if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED return false; - checkTypeSet(JSOP_CALL_IGNORES_RV); if (!emit1(JSOP_POP)) // VAL return false; @@ -4543,7 +4531,6 @@ BytecodeEmitter::emitCopyDataProperties(CopyOption option) } if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED return false; - checkTypeSet(JSOP_CALL_IGNORES_RV); if (!emit1(JSOP_POP)) // - return false; @@ -4566,7 +4553,6 @@ BytecodeEmitter::emitIterator() return false; if (!emitCall(JSOP_CALLITER, 0)) // ITER return false; - checkTypeSet(JSOP_CALLITER); if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER return false; return true; @@ -4605,7 +4591,6 @@ BytecodeEmitter::emitAsyncIterator() return false; if (!emitCall(JSOP_CALLITER, 0)) // ITER return false; - checkTypeSet(JSOP_CALLITER); if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER return false; @@ -4619,7 +4604,6 @@ BytecodeEmitter::emitAsyncIterator() return false; if (!emitCall(JSOP_CALLITER, 0)) // ITER return false; - checkTypeSet(JSOP_CALLITER); if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER return false; @@ -6425,7 +6409,6 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) return false; if (!emitCall(JSOP_CALL, 1, iter)) // ITER OLDRESULT RESULT return false; - checkTypeSet(JSOP_CALL); if (isAsyncGenerator) { if (!emitAwaitInInnermostScope()) // NEXT ITER OLDRESULT RESULT @@ -6496,7 +6479,6 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) return false; if (!emitCall(JSOP_CALL, 1)) // ITER OLDRESULT FTYPE FVALUE RESULT return false; - checkTypeSet(JSOP_CALL); if (iterKind == IteratorKind::Async) { if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT @@ -6577,7 +6559,6 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) return false; if (!emitCall(JSOP_CALL, 1, iter)) // ITER RESULT return false; - checkTypeSet(JSOP_CALL); if (isAsyncGenerator) { if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT RESULT @@ -7039,7 +7020,6 @@ BytecodeEmitter::emitSelfHostedCallFunction(BinaryNode* callNode) if (!emitCall(callOp, argc)) return false; - checkTypeSet(callOp); return true; } @@ -8329,7 +8309,6 @@ BytecodeEmitter::emitFunctionFormalParameters(ListNode* paramsBody) } else if (isRest) { if (!emit1(JSOP_REST)) return false; - checkTypeSet(JSOP_REST); } // Initialize the parameter name. diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 7a59cf0825..9cbf6ee38b 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -418,17 +418,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter // Emit function code for the tree rooted at body. MOZ_MUST_USE bool emitFunctionScript(FunctionNode* funNode); - // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h), - // reserve a type set to store its result. - void checkTypeSet(JSOp op); - void updateDepth(ptrdiff_t target); MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset); MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset); JSOp strictifySetNameOp(JSOp op); - MOZ_MUST_USE bool emitCheck(ptrdiff_t delta, ptrdiff_t* offset); + MOZ_MUST_USE bool emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset); // Emit one bytecode. MOZ_MUST_USE bool emit1(JSOp op); diff --git a/js/src/frontend/CallOrNewEmitter.cpp b/js/src/frontend/CallOrNewEmitter.cpp index bd1e32ab02..81e1956c25 100644 --- a/js/src/frontend/CallOrNewEmitter.cpp +++ b/js/src/frontend/CallOrNewEmitter.cpp @@ -305,7 +305,6 @@ CallOrNewEmitter::emitEnd(uint32_t argc, const Maybe& beginPos) return false; } } - bce_->checkTypeSet(op_); if (isEval() && beginPos) { uint32_t lineNum = bce_->parser->tokenStream.srcCoords.lineNum(*beginPos); From 6f56a494e6e69e7798fce21e591fff4a29046c16 Mon Sep 17 00:00:00 2001 From: Martok Date: Sat, 8 Apr 2023 02:06:06 +0200 Subject: [PATCH 10/13] Issue #2142 - Extend newSuperCall for JSOP_SPREADSUPERCALL Based-on: m-c 1537936 --- js/src/frontend/FullParseHandler.h | 6 ++++-- js/src/frontend/Parser.cpp | 5 +---- js/src/frontend/SyntaxParseHandler.h | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 173ffcb8d7..a9f7c6de09 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -345,8 +345,10 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) return new_(PNK_ARGUMENTS, JSOP_NOP, pos); } - BinaryNodeType newSuperCall(Node callee, Node args) { - return new_(PNK_SUPERCALL, JSOP_SUPERCALL, callee, args); + BinaryNodeType newSuperCall(Node callee, Node args, bool isSpread) { + JSOp op = isSpread ? JSOP_SPREADSUPERCALL : JSOP_SUPERCALL; + TokenPos pos(callee->pn_pos.begin, args->pn_pos.end); + return new_(PNK_SUPERCALL, op, pos, callee, args); } BinaryNodeType newTaggedTemplate(Node tag, Node args) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index cbdd40089e..94f798e754 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9448,13 +9448,10 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (!args) return null(); - nextMember = handler.newSuperCall(lhs, args); + nextMember = handler.newSuperCall(lhs, args, isSpread); if (!nextMember) return null(); - if (isSpread) - handler.setOp(nextMember, JSOP_SPREADSUPERCALL); - NameNodeType thisName = newThisName(); if (!thisName) return null(); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index e364f9d680..d8bc3e4959 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -307,7 +307,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) BinaryNodeType newCall(Node callee, Node args) { return NodeFunctionCall; } BinaryNodeType newOptionalCall(Node callee, Node args) { return NodeOptionalFunctionCall; } ListNodeType newArguments(const TokenPos& pos) { return NodeGeneric; } - BinaryNodeType newSuperCall(Node callee, Node args) { return NodeGeneric; } + BinaryNodeType newSuperCall(Node callee, Node args, bool isSpread) { return NodeGeneric; } BinaryNodeType newTaggedTemplate(Node callee, Node args) { return NodeGeneric; } Node newGenExp(Node callee, Node args) { return NodeGeneric; } From 627d0da7dc03013aeb51f3f65b0ba48d4ecf025d Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 9 Apr 2023 19:18:03 +0200 Subject: [PATCH 11/13] Issue #2142 - Change InitPropertyOperation to accept a PropertyName directy and use DefineDataProperty Based-on: m-c 1413907, 1547129 --- js/src/jit/BaselineIC.cpp | 2 +- js/src/jit/VMFunctions.cpp | 3 +-- js/src/vm/Interpreter-inl.h | 11 +++++++---- js/src/vm/Interpreter.cpp | 7 ++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 7dbe239a7e..61d77adc2e 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -4584,7 +4584,7 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ op == JSOP_INITLOCKEDPROP || op == JSOP_INITHIDDENPROP) { - if (!InitPropertyOperation(cx, op, obj, id, rhs)) + if (!InitPropertyOperation(cx, op, obj, name, rhs)) return false; } else if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 01a22482eb..f191ce7d6d 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -232,8 +232,7 @@ bool InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value, jsbytecode* pc) { - RootedId id(cx, NameToId(name)); - return InitPropertyOperation(cx, JSOp(*pc), obj, id, value); + return InitPropertyOperation(cx, JSOp(*pc), obj, name, value); } template diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 5c2320d3fb..79a4b90200 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -340,12 +340,15 @@ InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvAr } inline bool -InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs) +InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandlePropertyName name, HandleValue rhs) { - if (obj->is() || obj->is()) { + RootedId id(cx, NameToId(name)); + + // {Goanna} DefineProperty works on almost any JSObject, but there's no good way to check what works + // So instead, check what we don't handle explicitly. + if (!obj->is()) { unsigned propAttrs = GetInitDataPropAttrs(op); - return NativeDefineProperty(cx, obj.as(), id, rhs, nullptr, nullptr, - propAttrs); + return DefineProperty(cx, obj, id, rhs, nullptr, nullptr, propAttrs); } MOZ_ASSERT(obj->as().layout().lookup(id)); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 5fccc00d54..b17c762eae 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3744,12 +3744,9 @@ CASE(JSOP_INITHIDDENPROP) /* Load the object being initialized into lval/obj. */ ReservedRooted obj(&rootObject0, ®S.sp[-2].toObject()); - PropertyName* name = script->getName(REGS.pc); + ReservedRooted name(&rootName0, script->getName(REGS.pc)); - RootedId& id = rootId0; - id = NameToId(name); - - if (!InitPropertyOperation(cx, JSOp(*REGS.pc), obj, id, rval)) + if (!InitPropertyOperation(cx, JSOp(*REGS.pc), obj, name, rval)) goto error; REGS.sp--; From 3b9b111b2fd73aff0b02efd317b84a865fbfac12 Mon Sep 17 00:00:00 2001 From: Martok Date: Wed, 26 Apr 2023 17:32:55 +0200 Subject: [PATCH 12/13] Issue #2142 - Add predicate functions count_if and any_of to ListNode iterator --- js/src/frontend/ParseNode.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 54d2bef108..2f6311eace 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -6,6 +6,8 @@ #ifndef frontend_ParseNode_h #define frontend_ParseNode_h +#include + #include "mozilla/Attributes.h" #include "builtin/ModuleObject.h" @@ -1420,6 +1422,8 @@ class ListNode : public ParseNode } }; + typedef std::function predicate_fun; + #ifdef DEBUG MOZ_MUST_USE bool contains(ParseNode* target) const { MOZ_ASSERT(target); @@ -1460,6 +1464,24 @@ class ListNode : public ParseNode MOZ_ASSERT_IF(end, contains(end)); return range(head(), end); } + + // Predicate functions, like their counterparts in C++17 + size_t count_if(predicate_fun predicate) const { + size_t count = 0; + for (ParseNode* node = head(); node; node = node->pn_next) { + if (predicate(node)) + count++; + } + return count; + } + + bool any_of(predicate_fun predicate) const { + for (ParseNode* node = head(); node; node = node->pn_next) { + if (predicate(node)) + return true; + } + return false; + } }; inline bool From faed047e3fca0e4f7d69cc26914335d25ac0f7ef Mon Sep 17 00:00:00 2001 From: Martok Date: Wed, 26 Apr 2023 18:21:35 +0200 Subject: [PATCH 13/13] Issue #2142 - Ensure 'await' is always a restricted identifier when parsing modules Based-on: m-c 1356189 --- js/src/frontend/Parser.cpp | 38 +++++++++++++++++++++++++------------- js/src/frontend/Parser.h | 21 +++++++++++++-------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 94f798e754..7a5cef7d78 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -785,7 +785,7 @@ ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, #endif abortedSyntaxParse(false), isUnexpectedEOF_(false), - awaitIsKeyword_(false), + awaitHandling_(AwaitIsName), parseGoal_(uint8_t(parseGoal)) { cx->perThreadData->frontendCollectionPool.addActiveCompilation(); @@ -846,18 +846,18 @@ Parser::~Parser() template <> void -Parser::setAwaitIsKeyword(bool isKeyword) +Parser::setAwaitHandling(AwaitHandling awaitHandling) { - awaitIsKeyword_ = isKeyword; + awaitHandling_ = awaitHandling; } template <> void -Parser::setAwaitIsKeyword(bool isKeyword) +Parser::setAwaitHandling(AwaitHandling awaitHandling) { - awaitIsKeyword_ = isKeyword; + awaitHandling_ = awaitHandling; if (Parser* parser = handler.syntaxParser) - parser->setAwaitIsKeyword(isKeyword); + parser->setAwaitHandling(awaitHandling); } template @@ -2217,7 +2217,7 @@ Parser::moduleBody(ModuleSharedContext* modulesc) if (!moduleNode) return null(); - AutoAwaitIsKeyword awaitIsKeyword(this, true); + AutoAwaitIsKeyword awaitIsKeyword(this, AwaitIsModuleKeyword); ListNode* stmtList = statementList(YieldIsName); if (!stmtList) { return null(); @@ -2490,6 +2490,14 @@ GetYieldHandling(GeneratorKind generatorKind) return YieldIsKeyword; } +static AwaitHandling +GetAwaitHandling(FunctionAsyncKind asyncKind) +{ + if (asyncKind == SyncFunction) + return AwaitIsName; + return AwaitIsKeyword; +} + template <> FunctionNode* Parser::standaloneFunction(HandleFunction fun, @@ -2549,7 +2557,8 @@ Parser::standaloneFunction(HandleFunction fun, funpc.setIsStandaloneFunctionBody(); YieldHandling yieldHandling = GetYieldHandling(generatorKind); - AutoAwaitIsKeyword awaitIsKeyword(this, asyncKind == AsyncFunction); + AwaitHandling awaitHandling = GetAwaitHandling(asyncKind); + AutoAwaitIsKeyword awaitIsKeyword(this, awaitHandling); if (!functionFormalParametersAndBody(InAllowed, yieldHandling, funNode, FunctionSyntaxKind::Statement, parameterListEnd, /* isStandaloneFunction = */ true)) { @@ -3641,9 +3650,11 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // See below for an explanation why arrow function parameters and arrow // function bodies are parsed with different yield/await settings. { - bool asyncOrArrowInAsync = funbox->isAsync() || - (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()); - AutoAwaitIsKeyword awaitIsKeyword(this, asyncOrArrowInAsync); + AwaitHandling awaitHandling = funbox->isAsync() || + (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()) + ? AwaitIsKeyword + : AwaitIsName; + AutoAwaitIsKeyword awaitIsKeyword(this, awaitHandling); if (!functionArguments(yieldHandling, kind, funNode)) return false; } @@ -3713,9 +3724,10 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, // Whereas the |yield| in the function body is always parsed as a name. // The same goes when parsing |await| in arrow functions. YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind()); + AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc->asyncKind()); LexicalScopeNodeType body; { - AutoAwaitIsKeyword awaitIsKeyword(this, funbox->isAsync()); + AutoAwaitIsKeyword awaitIsKeyword(this, bodyAwaitHandling); body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); if (!body) return false; @@ -3873,7 +3885,7 @@ Parser::functionExpr(uint32_t toStringStart, InvokedPrediction inv { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); - AutoAwaitIsKeyword awaitIsKeyword(this, asyncKind == AsyncFunction); + AutoAwaitIsKeyword awaitIsKeyword(this, GetAwaitHandling(asyncKind)); GeneratorKind generatorKind = NotGenerator; TokenKind tt; if (!tokenStream.getToken(&tt)) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index fce6ead17d..4dd9f64178 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -591,6 +591,7 @@ enum class PropertyType { // we're in a function box -- easier and simpler than passing an extra // parameter everywhere. enum YieldHandling { YieldIsName, YieldIsKeyword }; +enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword }; enum InHandling { InAllowed, InProhibited }; enum DefaultHandling { NameRequired, AllowDefaultName }; enum TripledotHandling { TripledotAllowed, TripledotProhibited }; @@ -800,13 +801,13 @@ class ParserBase : public StrictModeGetter /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ bool isUnexpectedEOF_:1; - bool awaitIsKeyword_:1; + /* AwaitHandling */ uint8_t awaitHandling_:2; uint8_t parseGoal_:1; public: bool awaitIsKeyword() const { - return awaitIsKeyword_; + return awaitHandling_ != AwaitIsName; } ParseGoal parseGoal() const { @@ -1058,7 +1059,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) ~Parser(); friend class AutoAwaitIsKeyword; - void setAwaitIsKeyword(bool isKeyword); + void setAwaitHandling(AwaitHandling awaitHandling); bool checkOptions(); @@ -1643,17 +1644,21 @@ class MOZ_STACK_CLASS AutoAwaitIsKeyword { private: Parser* parser_; - bool oldAwaitIsKeyword_; + AwaitHandling oldAwaitHandling_; public: - AutoAwaitIsKeyword(Parser* parser, bool awaitIsKeyword) { + AutoAwaitIsKeyword(Parser* parser, AwaitHandling awaitHandling) { parser_ = parser; - oldAwaitIsKeyword_ = parser_->awaitIsKeyword_; - parser_->setAwaitIsKeyword(awaitIsKeyword); + oldAwaitHandling_ = static_cast(parser_->awaitHandling_); + + // 'await' is always a keyword in module contexts, so we don't modify + // the state when the original handling is AwaitIsModuleKeyword. + if (oldAwaitHandling_ != AwaitIsModuleKeyword) + parser_->setAwaitHandling(awaitHandling); } ~AutoAwaitIsKeyword() { - parser_->setAwaitIsKeyword(oldAwaitIsKeyword_); + parser_->setAwaitHandling(oldAwaitHandling_); } };