diff --git a/configure.in b/configure.in index 4728332707..adadf35ce6 100644 --- a/configure.in +++ b/configure.in @@ -92,8 +92,8 @@ _PTHREAD_LDFLAGS="" dnl Do not allow objdir == srcdir builds. dnl ============================================================== -_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd` -_objdir=`pwd` +_topsrcdir=`cd \`dirname $0\`; pwd -W 2>/dev/null || pwd -P` +_objdir=`pwd -P` dnl TODO Don't exempt L10N builds once bug 842760 is resolved. if test "$_topsrcdir" = "$_objdir" -a "${with_l10n_base+set}" != set; then @@ -134,7 +134,7 @@ EOF exit 1 break fi -MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd` +MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P` DIST="$MOZ_BUILD_ROOT/dist" MOZ_PYTHON @@ -157,7 +157,7 @@ if test -n "$L10NBASEDIR"; then if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then AC_MSG_ERROR([--with-l10n-base must specify a path]) elif test -d "$L10NBASEDIR"; then - L10NBASEDIR=`cd "$L10NBASEDIR" && pwd` + L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -P` else AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist]) fi @@ -9015,6 +9015,23 @@ export JS_STANDALONE=no export DIST export MOZ_LINKER export ZLIB_IN_MOZGLUE +export MOZ_MEMORY +export AR +export RANLIB +export CPP +export CC +export CXX +export LD +export ARFLAGS +export CPPFLAGS +export CFLAGS +export CXXFLAGS +export LDFLAGS +export HOST_CC +export HOST_CXX +export HOST_CFLAGS +export HOST_CXXFLAGS +export HOST_LDFLAGS if ! test -e js; then mkdir js diff --git a/dom/base/test/test_fileapi.html b/dom/base/test/test_fileapi.html index e0299866ec..fc33c7ae6c 100644 --- a/dom/base/test/test_fileapi.html +++ b/dom/base/test/test_fileapi.html @@ -382,7 +382,7 @@ function onFilesOpened(message) { testHasRun(); }; r.onload = function (event) { - todo(false, "nonexistent file shouldn't load! (FIXME: bug 1122788)"); + is(false, "nonexistent file shouldn't load! (FIXME: bug 1122788)"); testHasRun(); }; try { diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index e2ae557277..c96238b198 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -1165,9 +1165,9 @@ RemoteInputStream::ReallyBlockAndWaitForStream() #ifdef DEBUG if (waited && mWeakSeekableStream) { int64_t position; - MOZ_ASSERT(NS_SUCCEEDED(mWeakSeekableStream->Tell(&position)), - "Failed to determine initial stream position!"); - MOZ_ASSERT(!position, "Stream not starting at 0!"); + if (NS_SUCCEEDED(mWeakSeekableStream->Tell(&position))) { + MOZ_ASSERT(!position, "Stream not starting at 0!"); + } } #endif } diff --git a/dom/webidl/HeapSnapshot.webidl b/dom/webidl/HeapSnapshot.webidl index a3ff116830..bec4503648 100644 --- a/dom/webidl/HeapSnapshot.webidl +++ b/dom/webidl/HeapSnapshot.webidl @@ -57,6 +57,17 @@ interface HeapSnapshot { [Throws] any takeCensus(object? options); + /** + * Describe `node` with the specified `breakdown`. See the comment above + * `takeCensus` or `js/src/doc/Debugger/Debugger.Memory.md` for detailed + * documentation on breakdowns. + * + * Throws an error when `node` is not the id of a node in the heap snapshot, + * or if the breakdown is invalid. + */ + [Throws] + any describeNode(object breakdown, NodeId node); + /** * Compute the dominator tree for this heap snapshot. * diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 8cc2b27896..4bb2784e5b 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2389,10 +2389,15 @@ gfxFont::NotifyGlyphsChanged() } } -static bool +// If aChar is a "word boundary" for shaped-word caching purposes, return it; +// else return 0. +static char16_t IsBoundarySpace(char16_t aChar, char16_t aNextChar) { - return (aChar == ' ' || aChar == 0x00A0) && !IsClusterExtender(aNextChar); + if ((aChar == ' ' || aChar == 0x00A0) && !IsClusterExtender(aNextChar)) { + return aChar; + } + return 0; } #ifdef __GNUC__ @@ -2822,7 +2827,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, for (uint32_t i = 0; i <= aRunLength; ++i) { T ch = nextCh; nextCh = (i < aRunLength - 1) ? aString[i + 1] : '\n'; - bool boundary = IsBoundarySpace(ch, nextCh); + T boundary = IsBoundarySpace(ch, nextCh); bool invalid = !boundary && gfxFontGroup::IsInvalidChar(ch); uint32_t length = i - wordStart; @@ -2884,16 +2889,20 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT : gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT; } - if (!aTextRun->SetSpaceGlyphIfSimple(this, aContext, - aRunStart + i, ch, - orientation)) - { - static const uint8_t space = ' '; + if (boundary != ' ' || + !aTextRun->SetSpaceGlyphIfSimple(this, aRunStart + i, ch, + orientation)) { + // Currently, the only "boundary" characters we recognize are + // space and no-break space, which are both 8-bit, so we force + // that flag (below). If we ever change IsBoundarySpace, we + // may need to revise this. + // Avoid tautological-constant-out-of-range-compare in 8-bit: + DebugOnly boundary16 = boundary; + NS_ASSERTION(boundary16 < 256, "unexpected boundary!"); gfxShapedWord *sw = - GetShapedWord(aContext, - &space, 1, - gfxShapedWord::HashMix(0, ' '), aRunScript, aVertical, - appUnitsPerDevUnit, + GetShapedWord(aContext, &boundary, 1, + gfxShapedWord::HashMix(0, boundary), + aRunScript, aVertical, appUnitsPerDevUnit, flags | gfxTextRunFactory::TEXT_IS_8BIT, tp); if (sw) { aTextRun->CopyGlyphDataFrom(sw, aRunStart + i); diff --git a/gfx/thebes/gfxGraphiteShaper.cpp b/gfx/thebes/gfxGraphiteShaper.cpp index 11e24c6015..fe4744eb8c 100644 --- a/gfx/thebes/gfxGraphiteShaper.cpp +++ b/gfx/thebes/gfxGraphiteShaper.cpp @@ -34,7 +34,6 @@ gfxGraphiteShaper::gfxGraphiteShaper(gfxFont *aFont) mGrFont(nullptr), mFallbackToSmallCaps(false) { mCallbackData.mFont = aFont; - mCallbackData.mShaper = this; } gfxGraphiteShaper::~gfxGraphiteShaper() @@ -50,8 +49,7 @@ gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle, uint16_t glyphid) { const CallbackData *cb = static_cast(appFontHandle); - return FixedToFloat(cb->mFont->GetGlyphWidth(*cb->mContext->GetDrawTarget(), - glyphid)); + return FixedToFloat(cb->mFont->GetGlyphWidth(*cb->mDrawTarget, glyphid)); } static inline uint32_t @@ -97,7 +95,7 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext, return false; } - mCallbackData.mContext = aContext; + mCallbackData.mDrawTarget = aContext->GetDrawTarget(); const gfxFontStyle *style = mFont->GetStyle(); diff --git a/gfx/thebes/gfxGraphiteShaper.h b/gfx/thebes/gfxGraphiteShaper.h index 8127a84056..1075e9d1b8 100644 --- a/gfx/thebes/gfxGraphiteShaper.h +++ b/gfx/thebes/gfxGraphiteShaper.h @@ -8,6 +8,8 @@ #include "gfxFont.h" +#include "mozilla/gfx/2D.h" + struct gr_face; struct gr_font; struct gr_segment; @@ -42,9 +44,8 @@ protected: gr_font *mGrFont; // owned by the shaper itself struct CallbackData { - gfxFont *mFont; - gfxGraphiteShaper *mShaper; - gfxContext *mContext; + gfxFont* mFont; + mozilla::gfx::DrawTarget* mDrawTarget; }; CallbackData mCallbackData; diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index 92d7c5f96a..ea2be0ac7b 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -335,7 +335,7 @@ gfxHarfBuzzShaper::HBGetGlyphHAdvance(hb_font_t *font, void *font_data, static_cast(font_data); gfxFont *gfxfont = fcd->mShaper->GetFont(); if (gfxfont->ProvidesGlyphWidths()) { - return gfxfont->GetGlyphWidth(*fcd->mContext->GetDrawTarget(), glyph); + return gfxfont->GetGlyphWidth(*fcd->mDrawTarget, glyph); } return fcd->mShaper->GetGlyphHAdvance(glyph); } @@ -1475,7 +1475,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext, return false; } - mCallbackData.mContext = aContext; + mCallbackData.mDrawTarget = aContext->GetDrawTarget(); mUseVerticalPresentationForms = false; if (!Initialize()) { diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h index 643e75b204..1e8417ba4b 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.h +++ b/gfx/thebes/gfxHarfBuzzShaper.h @@ -10,6 +10,7 @@ #include "harfbuzz/hb.h" #include "nsUnicodeProperties.h" +#include "mozilla/gfx/2D.h" class gfxHarfBuzzShaper : public gfxFontShaper { public: @@ -21,8 +22,8 @@ public: * FontCallbackData struct */ struct FontCallbackData { - gfxHarfBuzzShaper *mShaper; - gfxContext *mContext; + gfxHarfBuzzShaper* mShaper; + mozilla::gfx::DrawTarget* mDrawTarget; }; bool Initialize(); diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index cff2de1093..a114b771e1 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1321,8 +1321,7 @@ void gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex, uint16_t aOrientation) { - if (SetSpaceGlyphIfSimple(aFont, aContext, aCharIndex, ' ', - aOrientation)) { + if (SetSpaceGlyphIfSimple(aFont, aCharIndex, ' ', aOrientation)) { return; } @@ -1350,9 +1349,8 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, } bool -gfxTextRun::SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, - uint32_t aCharIndex, char16_t aSpaceChar, - uint16_t aOrientation) +gfxTextRun::SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex, + char16_t aSpaceChar, uint16_t aOrientation) { uint32_t spaceGlyph = aFont->GetSpaceGlyph(); if (!spaceGlyph || !CompressedGlyph::IsSimpleGlyphID(spaceGlyph)) { diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index d1274fdb15..1d6aa4ee8a 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -514,9 +514,8 @@ public: // Returns true if it was able to set simple glyph data for the space; // if it returns false, the caller needs to fall back to some other // means to create the necessary (detailed) glyph data. - bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, - uint32_t aCharIndex, char16_t aSpaceChar, - uint16_t aOrientation); + bool SetSpaceGlyphIfSimple(gfxFont *aFont, uint32_t aCharIndex, + char16_t aSpaceChar, uint16_t aOrientation); // Record the positions of specific characters that layout may need to // detect in the textrun, even though it doesn't have an explicit copy diff --git a/js/public/UbiNodeCensus.h b/js/public/UbiNodeCensus.h index 9c6b21a836..004d1b26e3 100644 --- a/js/public/UbiNodeCensus.h +++ b/js/public/UbiNodeCensus.h @@ -87,7 +87,7 @@ using CountBasePtr = UniquePtr; // Abstract base class for CountType nodes. struct JS_FRIEND_API(CountType) { - explicit CountType(Census& census) : census(census) { } + explicit CountType() { } virtual ~CountType() { } // Destruct a count tree node that this type instance constructed. @@ -102,14 +102,13 @@ struct JS_FRIEND_API(CountType) { // Implement the 'count' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool count(CountBase& count, const Node& node) = 0; + virtual bool count(CountBase& count, + mozilla::MallocSizeOf mallocSizeOf, + const Node& node) = 0; // Implement the 'report' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool report(CountBase& count, MutableHandleValue report) = 0; - - protected: - Census& census; + virtual bool report(JSContext* cx, CountBase& count, MutableHandleValue report) = 0; }; using CountTypePtr = UniquePtr>; @@ -129,12 +128,16 @@ class JS_FRIEND_API(CountBase) { explicit CountBase(CountType& type) : type(type), total_(0) { } // Categorize and count |node| as appropriate for this count's type. - bool count(const Node& node) { return type.count(*this, node); } + bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { + return type.count(*this, mallocSizeOf, node); + } // Construct a JavaScript object reporting the counts recorded in this // count, and store it in |report|. Return true on success, or false on // failure. - bool report(MutableHandleValue report) { return type.report(*this, report); } + bool report(JSContext* cx, MutableHandleValue report) { + return type.report(cx, *this, report); + } // Down-cast this CountBase to its true type, based on its 'type' member, // and run its destructor. @@ -173,18 +176,6 @@ struct JS_FRIEND_API(Census) { explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } bool init(); - - // A 'new' work-alike that behaves like TempAllocPolicy: report OOM on this - // census's context, but don't charge the memory allocated to our context's - // GC pressure counters. - template - T* new_(Args&&... args) MOZ_HEAP_ALLOCATOR { - void* memory = js_malloc(sizeof(T)); - if (MOZ_UNLIKELY(!memory)) { - return nullptr; - } - return new(memory) T(mozilla::Forward(args)...); - } }; // A BreadthFirst handler type that conducts a census, using a CountBase to @@ -192,15 +183,17 @@ struct JS_FRIEND_API(Census) { class JS_FRIEND_API(CensusHandler) { Census& census; CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; public: - CensusHandler(Census& census, CountBasePtr& rootCount) + CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) : census(census), - rootCount(rootCount) + rootCount(rootCount), + mallocSizeOf(mallocSizeOf) { } - bool report(MutableHandleValue report) { - return rootCount->report(report); + bool report(JSContext* cx, MutableHandleValue report) { + return rootCount->report(cx, report); } // This class needs to retain no per-node data. @@ -213,11 +206,17 @@ class JS_FRIEND_API(CensusHandler) { using CensusTraversal = BreadthFirst; -// Examine the census options supplied by the API consumer, and use that to -// build a CountType tree. +// Examine the census options supplied by the API consumer, and (among other +// things) use that to build a CountType tree. JS_FRIEND_API(bool) ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTypePtr& outResult); +// Parse the breakdown language (as described in +// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer +// is returned on error and is reported to the cx. +JS_FRIEND_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue); + + } // namespace ubi } // namespace JS diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 30bc1a5dbe..d74c40201c 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -136,7 +136,7 @@ function ArrayEvery(callbackfn/*, thisArg*/) { /* Step b */ if (k in O) { /* Step c. */ - if (!callFunction(callbackfn, T, O[k], k, O)) + if (!callContentFunction(callbackfn, T, O[k], k, O)) return false; } } @@ -177,7 +177,7 @@ function ArraySome(callbackfn/*, thisArg*/) { /* Step b */ if (k in O) { /* Step c. */ - if (callFunction(callbackfn, T, O[k], k, O)) + if (callContentFunction(callbackfn, T, O[k], k, O)) return true; } } @@ -218,7 +218,7 @@ function ArrayForEach(callbackfn/*, thisArg*/) { /* Step b */ if (k in O) { /* Step c. */ - callFunction(callbackfn, T, O[k], k, O); + callContentFunction(callbackfn, T, O[k], k, O); } } @@ -261,7 +261,7 @@ function ArrayMap(callbackfn/*, thisArg*/) { /* Step b */ if (k in O) { /* Step c.i-iii. */ - var mappedValue = callFunction(callbackfn, T, O[k], k, O); + var mappedValue = callContentFunction(callbackfn, T, O[k], k, O); _DefineDataProperty(A, k, mappedValue); } } @@ -307,7 +307,7 @@ function ArrayFilter(callbackfn/*, thisArg*/) { /* Steps 11.c.i-ii. */ var kValue = O[k]; /* Steps 11.c.iii-iv. */ - var selected = callFunction(callbackfn, T, kValue, k, O); + var selected = callContentFunction(callbackfn, T, kValue, k, O); /* Step 11.c.v. */ if (selected) _DefineDataProperty(A, to++, kValue); @@ -489,7 +489,7 @@ function ArrayFind(predicate/*, thisArg*/) { /* Steps a-c. */ var kValue = O[k]; /* Steps d-f. */ - if (callFunction(predicate, T, kValue, k, O)) + if (callContentFunction(predicate, T, kValue, k, O)) return kValue; } @@ -523,7 +523,7 @@ function ArrayFindIndex(predicate/*, thisArg*/) { */ for (var k = 0; k < len; k++) { /* Steps a-f. */ - if (callFunction(predicate, T, O[k], k, O)) + if (callContentFunction(predicate, T, O[k], k, O)) return k; } @@ -771,7 +771,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) { // See . while (true) { // Steps 6.g.i-iii. - var next = callFunction(iterator.next, iterator); + var next = callContentFunction(iterator.next, iterator); if (!IsObject(next)) ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE); @@ -785,7 +785,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) { var nextValue = next.value; // Steps 6.g.vii-viii. - var mappedValue = mapping ? callFunction(mapfn, thisArg, nextValue, k) : nextValue; + var mappedValue = mapping ? callContentFunction(mapfn, thisArg, nextValue, k) : nextValue; // Steps 6.g.ix-xi. _DefineDataProperty(A, k++, mappedValue); @@ -810,7 +810,7 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) { var kValue = items[k]; // Steps 16.d-e. - var mappedValue = mapping ? callFunction(mapfn, thisArg, kValue, k) : kValue; + var mappedValue = mapping ? callContentFunction(mapfn, thisArg, kValue, k) : kValue; // Steps 16.f-g. _DefineDataProperty(A, k, mappedValue); @@ -834,5 +834,5 @@ function ArrayToString() { // Steps 5-6. if (!IsCallable(func)) return callFunction(std_Object_toString, array); - return callFunction(func, array); + return callContentFunction(func, array); } diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 2fda15e48f..bd257d8d1c 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -139,13 +139,6 @@ CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidat oldval, newval); return oldval; } - case Scalar::Uint8Clamped: { - uint8_t oldval = ClampIntForUint8Array(oldCandidate); - uint8_t newval = ClampIntForUint8Array(newCandidate); - oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast() + offset, - oldval, newval); - return oldval; - } case Scalar::Int16: { int16_t oldval = (int16_t)oldCandidate; int16_t newval = (int16_t)newCandidate; @@ -235,8 +228,7 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp) SharedMem viewData = view->viewDataShared(); switch (view->type()) { - case Scalar::Uint8: - case Scalar::Uint8Clamped: { + case Scalar::Uint8: { uint8_t v = jit::AtomicOperations::loadSeqCst(viewData.cast() + offset); r.setInt32(v); return true; @@ -300,11 +292,6 @@ ExchangeOrStore(Scalar::Type viewType, int32_t numberValue, SharedMem vie INT_OP(viewData.cast() + offset, value); return value; } - case Scalar::Uint8Clamped: { - uint8_t value = ClampIntForUint8Array(numberValue); - INT_OP(viewData.cast() + offset, value); - return value; - } case Scalar::Int16: { int16_t value = (int16_t)numberValue; INT_OP(viewData.cast() + offset, value); @@ -406,26 +393,6 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv r.setInt32(T::operate(viewData.cast() + offset, v)); return true; } - case Scalar::Uint8Clamped: { - // Spec says: - // - clamp the input value - // - perform the operation - // - clamp the result - // - store the result - // This requires a CAS loop. - int32_t value = ClampIntForUint8Array(numberValue); - SharedMem loc = viewData.cast() + offset; - for (;;) { - uint8_t old = jit::AtomicOperations::loadSafeWhenRacy(loc); - uint8_t result = (uint8_t)ClampIntForUint8Array(T::perform(old, value)); - uint8_t tmp = jit::AtomicOperations::compareExchangeSeqCst(loc, old, result); - if (tmp == old) { - r.setInt32(old); - break; - } - } - return true; - } case Scalar::Int16: { int16_t v = (int16_t)numberValue; r.setInt32(T::operate(viewData.cast() + offset, v)); diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js index a56b7228aa..735eec7a06 100644 --- a/js/src/builtin/Iterator.js +++ b/js/src/builtin/Iterator.js @@ -11,7 +11,7 @@ var LegacyIteratorWrapperMap = new std_WeakMap(); function LegacyIteratorNext(arg) { var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this); try { - return { value: callFunction(iter.next, iter, arg), done: false }; + return { value: callContentFunction(iter.next, iter, arg), done: false }; } catch (e) { if (e instanceof std_StopIteration) return { value: undefined, done: true }; @@ -22,7 +22,7 @@ function LegacyIteratorNext(arg) { function LegacyIteratorThrow(exn) { var iter = callFunction(std_WeakMap_get, LegacyIteratorWrapperMap, this); try { - return { value: callFunction(iter.throw, iter, exn), done: false }; + return { value: callContentFunction(iter.throw, iter, exn), done: false }; } catch (e) { if (e instanceof std_StopIteration) return { value: undefined, done: true }; diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 852e1895bd..fbc8ffc089 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -29,7 +29,7 @@ function MapForEach(callbackfn, thisArg = undefined) { if (result.done) break; var entry = result.value; - callFunction(callbackfn, thisArg, entry[1], entry[0], M); + callContentFunction(callbackfn, thisArg, entry[1], entry[0], M); } } diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 50bea4f3eb..89337802d8 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1411,7 +1411,7 @@ const JSFunctionSpec selfhosting_collection_iterator_methods[] = { bool js::InitSelfHostingCollectionIteratorFunctions(JSContext* cx, HandleObject obj) { - return JS_DefineFunctions(cx, obj, selfhosting_collection_iterator_methods); + return DefineFunctions(cx, obj, selfhosting_collection_iterator_methods, AsIntrinsic); } /*** JS static utility functions *********************************************/ diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index 12f4bb2fa0..72d0f95694 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -57,7 +57,7 @@ function Object_toLocaleString() { var O = this; // Step 2. - return callFunction(O.toString, O); + return callContentFunction(O.toString, O); } function ObjectDefineSetter(name, setter) { diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 3df7d4ec25..5bc4ecb6bb 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -14,12 +14,14 @@ #include "jit/InlinableNatives.h" #include "vm/RegExpStatics.h" #include "vm/StringBuffer.h" +#include "vm/Unicode.h" #include "jsobjinlines.h" #include "vm/NativeObject-inl.h" using namespace js; +using namespace js::unicode; using mozilla::ArrayLength; using mozilla::Maybe; @@ -174,8 +176,11 @@ RegExpInitialize(JSContext* cx, Handle obj, HandleValue patternVa /* Steps 9-10. */ CompileOptions options(cx); frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); - if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern)) + if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), pattern, + flags & UnicodeFlag)) + { return false; + } if (staticsUse == UseRegExpStatics) { RegExpStatics* res = cx->global()->getRegExpStatics(cx); @@ -557,6 +562,24 @@ regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp) return CallNonGenericMethod(cx, args); } +/* ES6 21.2.5.15. */ +MOZ_ALWAYS_INLINE bool +regexp_unicode_impl(JSContext* cx, const CallArgs& args) +{ + MOZ_ASSERT(IsRegExpObject(args.thisv())); + /* Steps 4-6. */ + args.rval().setBoolean(args.thisv().toObject().as().unicode()); + return true; +} + +static bool +regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp) +{ + /* Steps 1-3. */ + CallArgs args = CallArgsFromVp(argc, vp); + return CallNonGenericMethod(cx, args); +} + const JSPropertySpec js::regexp_properties[] = { JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0), JS_PSG("global", regexp_global, 0), @@ -564,6 +587,7 @@ const JSPropertySpec js::regexp_properties[] = { JS_PSG("multiline", regexp_multiline, 0), JS_PSG("source", regexp_source, 0), JS_PSG("sticky", regexp_sticky, 0), + JS_PSG("unicode", regexp_unicode, 0), JS_PS_END }; @@ -610,8 +634,6 @@ const JSFunctionSpec js::regexp_methods[] = { } DEFINE_STATIC_GETTER(static_input_getter, return res->createPendingInput(cx, args.rval())) -DEFINE_STATIC_GETTER(static_multiline_getter, args.rval().setBoolean(res->multiline()); - return true) DEFINE_STATIC_GETTER(static_lastMatch_getter, return res->createLastMatch(cx, args.rval())) DEFINE_STATIC_GETTER(static_lastParen_getter, return res->createLastParen(cx, args.rval())) DEFINE_STATIC_GETTER(static_leftContext_getter, return res->createLeftContext(cx, args.rval())) @@ -655,6 +677,36 @@ static_input_setter(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +WarnOnceAboutRegExpMultiline(JSContext* cx) +{ + if (!cx->compartment()->warnedAboutRegExpMultiline) { + if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr, + JSMSG_DEPRECATED_REGEXP_MULTILINE)) + { + return false; + } + cx->compartment()->warnedAboutRegExpMultiline = true; + } + + return true; +} + +static bool +static_multiline_getter(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + RegExpStatics* res = cx->global()->getRegExpStatics(cx); + if (!res) + return false; + + if (!WarnOnceAboutRegExpMultiline(cx)) + return false; + + args.rval().setBoolean(res->multiline()); + return true; +} + static bool static_multiline_setter(JSContext* cx, unsigned argc, Value* vp) { @@ -663,6 +715,9 @@ static_multiline_setter(JSContext* cx, unsigned argc, Value* vp) if (!res) return false; + if (!WarnOnceAboutRegExpMultiline(cx)) + return false; + bool b = ToBoolean(args.get(0)); res->setMultiline(cx, b); args.rval().setBoolean(b); @@ -729,6 +784,29 @@ SetLastIndex(JSContext* cx, Handle reobj, double lastIndex) return true; } +template +static bool +IsTrailSurrogateWithLeadSurrogateImpl(JSContext* cx, HandleLinearString input, size_t index) +{ + JS::AutoCheckCannotGC nogc; + MOZ_ASSERT(index > 0 && index < input->length()); + const CharT* inputChars = input->chars(nogc); + + return unicode::IsTrailSurrogate(inputChars[index]) && + unicode::IsLeadSurrogate(inputChars[index - 1]); +} + +static bool +IsTrailSurrogateWithLeadSurrogate(JSContext* cx, HandleLinearString input, int32_t index) +{ + if (index <= 0 || size_t(index) >= input->length()) + return false; + + return input->hasLatin1Chars() + ? IsTrailSurrogateWithLeadSurrogateImpl(cx, input, index) + : IsTrailSurrogateWithLeadSurrogateImpl(cx, input, index); +} + /* ES6 final draft 21.2.5.2.2. */ RegExpRunStatus js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, @@ -811,6 +889,33 @@ js::ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, return RegExpRunStatus_Success_NotFound; } + /* Steps 12-13. */ + if (reobj->unicode()) { + /* + * ES6 21.2.2.2 step 2. + * Let listIndex be the index into Input of the character that was + * obtained from element index of str. + * + * In the spec, pattern match is performed with decoded Unicode code + * points, but our implementation performs it with UTF-16 encoded + * string. In step 2, we should decrement searchIndex (index) if it + * points the trail surrogate that has corresponding lead surrogate. + * + * var r = /\uD83D\uDC38/ug; + * r.lastIndex = 1; + * var str = "\uD83D\uDC38"; + * var result = r.exec(str); // pattern match starts from index 0 + * print(result.index); // prints 0 + * + * Note: this doesn't match the current spec text and result in + * different values for `result.index` under certain conditions. + * However, the spec will change to match our implementation's + * behavior. See https://github.com/tc39/ecma262/issues/128. + */ + if (IsTrailSurrogateWithLeadSurrogate(cx, input, searchIndex)) + searchIndex--; + } + /* Step 14-29. */ RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, searchIndex, matches); if (status == RegExpRunStatus_Error) diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 49a52b3ac8..25cc7cd34e 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -25,9 +25,8 @@ function RegExpFlagsGetter() { result += "m"; // Steps 13-15. - // TODO: Uncomment these steps when bug 1135377 is fixed. - // if (R.unicode) - // result += "u"; + if (R.unicode) + result += "u"; // Steps 16-18. if (R.sticky) diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index 7ed34712b9..35c1fd8e39 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -29,7 +29,7 @@ function SetForEach(callbackfn, thisArg = undefined) { if (result.done) break; var value = result.value; - callFunction(callbackfn, thisArg, value, value, S); + callContentFunction(callbackfn, thisArg, value, value, S); } } diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index e3e76d51dd..b6efc629c6 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -121,7 +121,7 @@ function TypedArrayEvery(callbackfn, thisArg = undefined) { var kValue = O[k]; // Steps 9.d.iii-9.d.iv. - var testResult = callFunction(callbackfn, T, kValue, k, O); + var testResult = callContentFunction(callbackfn, T, kValue, k, O); // Step 9.d.v. if (!testResult) @@ -212,7 +212,7 @@ function TypedArrayFilter(callbackfn, thisArg = undefined) { // Steps 13.b-c. var kValue = O[k]; // Steps 13.d-e. - var selected = ToBoolean(callFunction(callbackfn, T, kValue, k, O)); + var selected = ToBoolean(callContentFunction(callbackfn, T, kValue, k, O)); // Step 13.f. if (selected) { // Step 13.f.i. @@ -264,7 +264,7 @@ function TypedArrayFind(predicate, thisArg = undefined) { // Steps a-c. var kValue = O[k]; // Steps d-f. - if (callFunction(predicate, T, kValue, k, O)) + if (callContentFunction(predicate, T, kValue, k, O)) return kValue; } @@ -299,7 +299,7 @@ function TypedArrayFindIndex(predicate, thisArg = undefined) { // Steps a (implicit), and g. for (var k = 0; k < len; k++) { // Steps a-f. - if (callFunction(predicate, T, O[k], k, O)) + if (callContentFunction(predicate, T, O[k], k, O)) return k; } @@ -311,8 +311,8 @@ function TypedArrayFindIndex(predicate, thisArg = undefined) { function TypedArrayForEach(callbackfn, thisArg = undefined) { // This function is not generic. if (!IsObject(this) || !IsTypedArray(this)) { - return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg, - "TypedArrayForEach"); + return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg, + "TypedArrayForEach"); } // Step 1-2. @@ -323,9 +323,9 @@ function TypedArrayForEach(callbackfn, thisArg = undefined) { // Step 5. if (arguments.length === 0) - ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'TypedArray.prototype.forEach'); + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'TypedArray.prototype.forEach'); if (!IsCallable(callbackfn)) - ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); // Step 6. var T = thisArg; @@ -333,9 +333,9 @@ function TypedArrayForEach(callbackfn, thisArg = undefined) { // Step 7-8. // Step 7, 8a (implicit) and 8e. for (var k = 0; k < len; k++) { - // Step 8b-8c are unnecessary since the condition always holds true for TypedArray. - // Step 8d. - callFunction(callbackfn, T, O[k], k, O); + // Step 8b-8c are unnecessary since the condition always holds true for TypedArray. + // Step 8d. + callContentFunction(callbackfn, T, O[k], k, O); } // Step 9. @@ -526,7 +526,7 @@ function TypedArrayMap(callbackfn, thisArg = undefined) { // Steps 12, 13.a (implicit) and 13.h. for (var k = 0; k < len; k++) { // Steps 13.d-e. - var mappedValue = callFunction(callbackfn, T, O[k], k, O); + var mappedValue = callContentFunction(callbackfn, T, O[k], k, O); // Steps 13.f-g. A[k] = mappedValue; } @@ -567,7 +567,7 @@ function TypedArrayReduce(callbackfn/*, initialValue*/) { // Step 11. // Omit steps 11.b-11.c and the 'if' clause in step 11.d, since there are no holes in typed arrays. for (; k < len; k++) { - accumulator = callFunction(callbackfn, undefined, accumulator, O[k], k, O); + accumulator = callContentFunction(callbackfn, undefined, accumulator, O[k], k, O); } // Step 12. @@ -606,7 +606,7 @@ function TypedArrayReduceRight(callbackfn/*, initialValue*/) { // Step 11. // Omit steps 11.b-11.c and the 'if' clause in step 11.d, since there are no holes in typed arrays. for (; k >= 0; k--) { - accumulator = callFunction(callbackfn, undefined, accumulator, O[k], k, O); + accumulator = callContentFunction(callbackfn, undefined, accumulator, O[k], k, O); } // Step 12. @@ -715,15 +715,15 @@ function SetFromNonTypedArray(target, array, targetOffset, targetLength, targetB // Step 24d. This explicit check will be unnecessary when we implement // throw-on-getting/setting-element-in-detached-buffer semantics. - if (!isShared) { + if (!isShared) { if (targetBuffer === null) { - // A typed array previously using inline storage may acquire a - // buffer, so we must check with the source. - targetBuffer = ViewedArrayBufferIfReified(target); + // A typed array previously using inline storage may acquire a + // buffer, so we must check with the source. + targetBuffer = ViewedArrayBufferIfReified(target); } if (IsDetachedBuffer(targetBuffer)) - ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - } + ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + } // Step 24e. target[targetOffset] = kNumber; @@ -892,7 +892,7 @@ function TypedArraySome(callbackfn, thisArg = undefined) { var kValue = O[k]; // Steps 9.d.iii-9.d.iv. - var testResult = callFunction(callbackfn, T, kValue, k, O); + var testResult = callContentFunction(callbackfn, T, kValue, k, O); // Step 9.d.v. if (testResult) @@ -1075,7 +1075,7 @@ function TypedArrayFrom(constructor, target, items, mapfn, thisArg) { // Steps 10.d-e. while (true) { // Steps 10.e.i-ii. - var next = callFunction(iterator.next, iterator); + var next = callContentFunction(iterator.next, iterator); if (!IsObject(next)) ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE); @@ -1099,7 +1099,7 @@ function TypedArrayFrom(constructor, target, items, mapfn, thisArg) { var kValue = values[k]; // Steps 10.j.iii-iv. - var mappedValue = mapping ? callFunction(mapfn, T, kValue, k) : kValue; + var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue; // Steps 10.j.v-vi. targetObj[k] = mappedValue; @@ -1133,7 +1133,7 @@ function TypedArrayFrom(constructor, target, items, mapfn, thisArg) { var kValue = arrayLike[k]; // Steps 20.d-e. - var mappedValue = mapping ? callFunction(mapfn, T, kValue, k) : kValue; + var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue; // Steps 20.f-g. targetObj[k] = mappedValue; diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 93e576a319..7f836ebe01 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -142,7 +142,7 @@ function GetIterator(obj, method) { method = GetMethod(obj, std_iterator); // Steps 3-4. - var iterator = callFunction(method, obj); + var iterator = callContentFunction(method, obj); // Step 5. if (!IsObject(iterator)) diff --git a/js/src/configure.in b/js/src/configure.in index aecf3fa1a1..7aaeb1d98d 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -73,8 +73,8 @@ _PTHREAD_LDFLAGS="" dnl Do not allow objdir == srcdir builds dnl ============================================================== -_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd` -_objdir=`pwd` +_topsrcdir=`cd $srcdir; pwd -W 2>/dev/null || pwd -P` +_objdir=`pwd -P` if test "$_topsrcdir" = "$_objdir" then @@ -112,7 +112,7 @@ if test "$_conflict_files"; then exit 1 break fi -MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd` +MOZ_BUILD_ROOT=`pwd -W 2>/dev/null || pwd -P` dnl Choose where to put the 'dist' directory. dnl ============================================================== diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index dea201d175..6c13497846 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2783,27 +2783,31 @@ BytecodeEmitter::emitNameIncDec(ParseNode* pn) } bool -BytecodeEmitter::emitElemOperands(ParseNode* pn, JSOp op) +BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts) { MOZ_ASSERT(pn->isArity(PN_BINARY)); if (!emitTree(pn->pn_left)) return false; - if (op == JSOP_CALLELEM && !emit1(JSOP_DUP)) - return false; + if (opts == EmitElemOption::IncDec) { + if (!emit1(JSOP_CHECKOBJCOERCIBLE)) + return false; + } else if (opts == EmitElemOption::Call) { + if (!emit1(JSOP_DUP)) + return false; + } if (!emitTree(pn->pn_right)) return false; - bool isSetElem = op == JSOP_SETELEM || op == JSOP_STRICTSETELEM; - if (isSetElem && !emit2(JSOP_PICK, 2)) + if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 2)) return false; return true; } bool -BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts) +BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts) { MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as().isSuper()); @@ -2817,13 +2821,13 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts) // We need to convert the key to an object id first, so that we do not do // it inside both the GETELEM and the SETELEM. - if (opts == SuperElem_IncDec && !emit1(JSOP_TOID)) + if (opts == EmitElemOption::IncDec && !emit1(JSOP_TOID)) return false; if (!emitGetThisForSuperBase(pn->pn_left)) return false; - if (opts == SuperElem_Call) { + if (opts == EmitElemOption::Call) { if (!emit1(JSOP_SWAP)) return false; @@ -2835,7 +2839,7 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts) if (!emit1(JSOP_SUPERBASE)) return false; - if (opts == SuperElem_Set && !emit2(JSOP_PICK, 3)) + if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3)) return false; return true; @@ -2854,17 +2858,23 @@ BytecodeEmitter::emitElemOpBase(JSOp op) bool BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op) { - return emitElemOperands(pn, op) && emitElemOpBase(op); + EmitElemOption opts = EmitElemOption::Get; + if (op == JSOP_CALLELEM) + opts = EmitElemOption::Call; + else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM) + opts = EmitElemOption::Set; + + return emitElemOperands(pn, opts) && emitElemOpBase(op); } bool BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall) { - SuperElemOptions opts = SuperElem_Get; + EmitElemOption opts = EmitElemOption::Get; if (isCall) - opts = SuperElem_Call; + opts = EmitElemOption::Call; else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER) - opts = SuperElem_Set; + opts = EmitElemOption::Set; if (!emitSuperElemOperands(pn, opts)) return false; @@ -2885,10 +2895,10 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn) bool isSuper = pn->pn_kid->as().isSuper(); if (isSuper) { - if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec)) + if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec)) return false; } else { - if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM)) + if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec)) return false; } @@ -7157,6 +7167,13 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) if (!emitTree(funNode)) return false; +#ifdef DEBUG + if (pn2->name() != cx->names().callContentFunction) { + if (!emit1(JSOP_DEBUGCHECKSELFHOSTED)) + return false; + } +#endif + ParseNode* thisArg = funNode->pn_next; if (!emitTree(thisArg)) return false; @@ -7257,8 +7274,11 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) // Calls to "forceInterpreter", "callFunction" or "resumeGenerator" // in self-hosted code generate inline bytecode. - if (pn2->name() == cx->names().callFunction) + if (pn2->name() == cx->names().callFunction || + pn2->name() == cx->names().callContentFunction) + { return emitSelfHostedCallFunction(pn); + } if (pn2->name() == cx->names().resumeGenerator) return emitSelfHostedResumeGenerator(pn); if (pn2->name() == cx->names().forceInterpreter) diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 8e452e2367..7d4b31d1cc 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -519,7 +519,8 @@ struct BytecodeEmitter // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM // opcode onto the stack in the right order. In the case of SETELEM, the // value to be assigned must already be pushed. - bool emitElemOperands(ParseNode* pn, JSOp op); + enum class EmitElemOption { Get, Set, Call, IncDec }; + bool emitElemOperands(ParseNode* pn, EmitElemOption opts); bool emitElemOpBase(JSOp op); bool emitElemOp(ParseNode* pn, JSOp op); @@ -654,8 +655,7 @@ struct BytecodeEmitter bool emitClass(ParseNode* pn); bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false); bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false); - enum SuperElemOptions { SuperElem_Get, SuperElem_Set, SuperElem_Call, SuperElem_IncDec }; - bool emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts = SuperElem_Get); + bool emitSuperElemOperands(ParseNode* pn, EmitElemOption opts = EmitElemOption::Get); bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false); }; diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 1e47ed5ade..b82d5a89a3 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -1597,6 +1597,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) reflags = RegExpFlag(reflags | MultilineFlag); else if (c == 'y' && !(reflags & StickyFlag)) reflags = RegExpFlag(reflags | StickyFlag); + else if (c == 'u' && !(reflags & UnicodeFlag)) + reflags = RegExpFlag(reflags | UnicodeFlag); else break; getChar(); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 9ba98ce36e..55826176f1 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -429,7 +429,7 @@ js::TraceWeakEdge(JSTracer* trc, WeakRef* thingp, const char* name) { // Non-marking tracers treat the edge strongly. if (!trc->isMarkingTracer()) - DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name); + return DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name); NoteWeakEdge(static_cast(trc), ConvertToBase(thingp->unsafeUnbarrieredForTracing())); diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index a699f5bf11..d0b47f7fb8 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -719,9 +719,10 @@ NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_ma } void -NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match) +NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match, + bool unicode) { - JitSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d)", start_reg); + JitSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d, %d)", start_reg, unicode); Label fallthrough; @@ -833,8 +834,13 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label masm.passABIArg(current_character); masm.passABIArg(current_position); masm.passABIArg(temp1); - int (*fun)(const char16_t*, const char16_t*, size_t) = CaseInsensitiveCompareStrings; - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun)); + if (!unicode) { + int (*fun)(const char16_t*, const char16_t*, size_t) = CaseInsensitiveCompareStrings; + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun)); + } else { + int (*fun)(const char16_t*, const char16_t*, size_t) = CaseInsensitiveCompareUCStrings; + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun)); + } masm.storeCallResult(temp0); masm.PopRegsInMask(volatileRegs); diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.h b/js/src/irregexp/NativeRegExpMacroAssembler.h index 996e4e6d2d..4b2674c4c4 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.h +++ b/js/src/irregexp/NativeRegExpMacroAssembler.h @@ -104,7 +104,7 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler : public RegExpMacroAssembler void CheckGreedyLoop(jit::Label* on_tos_equals_current_position); void CheckNotAtStart(jit::Label* on_not_at_start); void CheckNotBackReference(int start_reg, jit::Label* on_no_match); - void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match); + void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode); void CheckNotCharacter(unsigned c, jit::Label* on_not_equal); void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal); void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with, diff --git a/js/src/irregexp/RegExpAST.h b/js/src/irregexp/RegExpAST.h index b7e27a4f3d..ae76f64d4b 100644 --- a/js/src/irregexp/RegExpAST.h +++ b/js/src/irregexp/RegExpAST.h @@ -138,7 +138,9 @@ class RegExpAssertion : public RegExpTree { END_OF_LINE, END_OF_INPUT, BOUNDARY, - NON_BOUNDARY + NON_BOUNDARY, + NOT_AFTER_LEAD_SURROGATE, + NOT_IN_SURROGATE_PAIR }; explicit RegExpAssertion(AssertionType type) : assertion_type_(type) { } virtual void* Accept(RegExpVisitor* visitor, void* data); diff --git a/js/src/irregexp/RegExpBytecode.h b/js/src/irregexp/RegExpBytecode.h index da035c7b52..f31b78c593 100644 --- a/js/src/irregexp/RegExpBytecode.h +++ b/js/src/irregexp/RegExpBytecode.h @@ -90,7 +90,8 @@ V(CHECK_AT_START, 43, 8) /* bc8 pad24 addr32 */ \ V(CHECK_NOT_AT_START, 44, 8) /* bc8 pad24 addr32 */ \ V(CHECK_GREEDY, 45, 8) /* bc8 pad24 addr32 */ \ V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32 */ \ -V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */ +V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */ \ +V(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, 48, 8) /* bc8 reg_idx24 addr32 */ #define DECLARE_BYTECODES(name, code, length) \ static const int BC_##name = code; diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index 6c073ead7d..d2482071e4 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -72,12 +72,45 @@ static const int kSpaceRanges[] = { '\t', '\r' + 1, ' ', ' ' + 1, 0xFEFF, 0xFF00, 0x10000 }; static const int kSpaceRangeCount = ArrayLength(kSpaceRanges); +static const int kSpaceAndSurrogateRanges[] = { '\t', '\r' + 1, ' ', ' ' + 1, + 0x00A0, 0x00A1, 0x1680, 0x1681, 0x180E, 0x180F, 0x2000, 0x200B, + 0x2028, 0x202A, 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001, + unicode::LeadSurrogateMin, unicode::TrailSurrogateMax + 1, + 0xFEFF, 0xFF00, 0x10000 }; +static const int kSpaceAndSurrogateRangeCount = ArrayLength(kSpaceAndSurrogateRanges); static const int kWordRanges[] = { '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, 0x10000 }; static const int kWordRangeCount = ArrayLength(kWordRanges); +static const int kIgnoreCaseWordRanges[] = { + '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, + 0x017F, 0x017F + 1, 0x212A, 0x212A + 1, + 0x10000 }; +static const int kIgnoreCaseWordCount = ArrayLength(kIgnoreCaseWordRanges); +static const int kWordAndSurrogateRanges[] = { + '0', '9' + 1, 'A', 'Z' + 1, '_', '_' + 1, 'a', 'z' + 1, + unicode::LeadSurrogateMin, unicode::TrailSurrogateMax + 1, + 0x10000 }; +static const int kWordAndSurrogateRangeCount = ArrayLength(kWordAndSurrogateRanges); +static const int kNegatedIgnoreCaseWordAndSurrogateRanges[] = { + 0, '0', '9' + 1, 'A', + 'K', 'K' + 1, 'S', 'S' + 1, + 'Z' + 1, '_', '_' + 1, 'a', + 'k', 'k' + 1, 's', 's' + 1, + 'z' + 1, unicode::LeadSurrogateMin, + unicode::TrailSurrogateMax + 1, 0x10000, + 0x10000 }; +static const int kNegatedIgnoreCaseWordAndSurrogateRangeCount = + ArrayLength(kNegatedIgnoreCaseWordAndSurrogateRanges); static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 }; static const int kDigitRangeCount = ArrayLength(kDigitRanges); -static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 }; +static const int kDigitAndSurrogateRanges[] = { + '0', '9' + 1, + unicode::LeadSurrogateMin, unicode::TrailSurrogateMax + 1, + 0x10000 }; +static const int kDigitAndSurrogateRangeCount = ArrayLength(kDigitAndSurrogateRanges); +static const int kSurrogateRanges[] = { + unicode::LeadSurrogateMin, unicode::TrailSurrogateMax + 1, + 0x10000 }; static const int kSurrogateRangeCount = ArrayLength(kSurrogateRanges); static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E, 0x2028, 0x202A, 0x10000 }; @@ -164,20 +197,74 @@ CharacterRange::AddClassEscape(LifoAlloc* alloc, char16_t type, } } +// Add class escape, excluding surrogate pair range. +void +CharacterRange::AddClassEscapeUnicode(LifoAlloc* alloc, char16_t type, + CharacterRangeVector* ranges, bool ignore_case) +{ + switch (type) { + case 's': + case 'd': + return AddClassEscape(alloc, type, ranges); + break; + case 'S': + AddClassNegated(kSpaceAndSurrogateRanges, kSpaceAndSurrogateRangeCount, ranges); + break; + case 'w': + if (ignore_case) + AddClass(kIgnoreCaseWordRanges, kIgnoreCaseWordCount, ranges); + else + AddClassEscape(alloc, type, ranges); + break; + case 'W': + if (ignore_case) { + AddClass(kNegatedIgnoreCaseWordAndSurrogateRanges, + kNegatedIgnoreCaseWordAndSurrogateRangeCount, ranges); + } else { + AddClassNegated(kWordAndSurrogateRanges, kWordAndSurrogateRangeCount, ranges); + } + break; + case 'D': + AddClassNegated(kDigitAndSurrogateRanges, kDigitAndSurrogateRangeCount, ranges); + break; + default: + MOZ_CRASH("Bad type!"); + } +} + +#define FOR_EACH_NON_ASCII_TO_ASCII_FOLDING(macro) \ + /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ \ + macro(0x0178, 0x00FF) \ + /* LATIN SMALL LETTER LONG S */ \ + macro(0x017F, 0x0073) \ + /* LATIN CAPITAL LETTER SHARP S */ \ + macro(0x1E9E, 0x00DF) \ + /* KELVIN SIGN */ \ + macro(0x212A, 0x006B) \ + /* ANGSTROM SIGN */ \ + macro(0x212B, 0x00E5) + // We need to check for the following characters: 0x39c 0x3bc 0x178. static inline bool -RangeContainsLatin1Equivalents(CharacterRange range) +RangeContainsLatin1Equivalents(CharacterRange range, bool unicode) { - // TODO(dcarney): this could be a lot more efficient. + /* TODO(dcarney): this could be a lot more efficient. */ + if (unicode) { +#define CHECK_RANGE(C, F) \ + if (range.Contains(C)) return true; +FOR_EACH_NON_ASCII_TO_ASCII_FOLDING(CHECK_RANGE) +#undef CHECK_RANGE + } + return range.Contains(0x39c) || range.Contains(0x3bc) || range.Contains(0x178); } static bool -RangesContainLatin1Equivalents(const CharacterRangeVector& ranges) +RangesContainLatin1Equivalents(const CharacterRangeVector& ranges, bool unicode) { for (size_t i = 0; i < ranges.length(); i++) { // TODO(dcarney): this could be a lot more efficient. - if (RangeContainsLatin1Equivalents(ranges[i])) + if (RangeContainsLatin1Equivalents(ranges[i], unicode)) return true; } return false; @@ -190,27 +277,24 @@ static const size_t kEcma262UnCanonicalizeMaxWidth = 4; static int GetCaseIndependentLetters(char16_t character, bool ascii_subject, + bool unicode, + const char16_t* choices, + size_t choices_length, char16_t* letters) { - const char16_t choices[] = { - character, - unicode::ToLowerCase(character), - unicode::ToUpperCase(character) - }; - size_t count = 0; - for (size_t i = 0; i < ArrayLength(choices); i++) { + for (size_t i = 0; i < choices_length; i++) { char16_t c = choices[i]; // The standard requires that non-ASCII characters cannot have ASCII // character codes in their equivalence class, even though this // situation occurs multiple times in the unicode tables. static const unsigned kMaxAsciiCharCode = 127; - if (character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode) + if (!unicode && character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode) continue; // Skip characters that can't appear in one byte strings. - if (ascii_subject && c > kMaxOneByteCharCode) + if (!unicode && ascii_subject && c > kMaxOneByteCharCode) continue; // Watch for duplicates. @@ -230,10 +314,45 @@ GetCaseIndependentLetters(char16_t character, return count; } +static int +GetCaseIndependentLetters(char16_t character, + bool ascii_subject, + bool unicode, + char16_t* letters) +{ + if (unicode) { + const char16_t choices[] = { + character, + unicode::FoldCase(character), + unicode::ReverseFoldCase1(character), + unicode::ReverseFoldCase2(character), + unicode::ReverseFoldCase3(character), + }; + return GetCaseIndependentLetters(character, ascii_subject, unicode, + choices, ArrayLength(choices), letters); + } + + const char16_t choices[] = { + character, + unicode::ToLowerCase(character), + unicode::ToUpperCase(character) + }; + return GetCaseIndependentLetters(character, ascii_subject, unicode, + choices, ArrayLength(choices), letters); +} + static char16_t -ConvertNonLatin1ToLatin1(char16_t c) +ConvertNonLatin1ToLatin1(char16_t c, bool unicode) { MOZ_ASSERT(c > kMaxOneByteCharCode); + if (unicode) { + switch (c) { +#define CONVERT(C, F) case C: return F; +FOR_EACH_NON_ASCII_TO_ASCII_FOLDING(CONVERT) +#undef CONVERT + } + } + switch (c) { // This are equivalent characters in unicode. case 0x39c: @@ -248,12 +367,12 @@ ConvertNonLatin1ToLatin1(char16_t c) } void -CharacterRange::AddCaseEquivalents(bool is_ascii, CharacterRangeVector* ranges) +CharacterRange::AddCaseEquivalents(bool is_ascii, bool unicode, CharacterRangeVector* ranges) { char16_t bottom = from(); char16_t top = to(); - if (is_ascii && !RangeContainsLatin1Equivalents(*this)) { + if (is_ascii && !RangeContainsLatin1Equivalents(*this, unicode)) { if (bottom > kMaxOneByteCharCode) return; if (top > kMaxOneByteCharCode) @@ -262,7 +381,7 @@ CharacterRange::AddCaseEquivalents(bool is_ascii, CharacterRangeVector* ranges) for (char16_t c = bottom;; c++) { char16_t chars[kEcma262UnCanonicalizeMaxWidth]; - size_t length = GetCaseIndependentLetters(c, is_ascii, chars); + size_t length = GetCaseIndependentLetters(c, is_ascii, unicode, chars); for (size_t i = 0; i < length; i++) { char16_t other = chars[i]; @@ -542,7 +661,7 @@ SeqRegExpNode::FillInBMInfo(int offset, } RegExpNode* -SeqRegExpNode::FilterASCII(int depth, bool ignore_case) +SeqRegExpNode::FilterASCII(int depth, bool ignore_case, bool unicode) { if (info()->replacement_calculated) return replacement(); @@ -552,13 +671,13 @@ SeqRegExpNode::FilterASCII(int depth, bool ignore_case) MOZ_ASSERT(!info()->visited); VisitMarker marker(info()); - return FilterSuccessor(depth - 1, ignore_case); + return FilterSuccessor(depth - 1, ignore_case, unicode); } RegExpNode* -SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case) +SeqRegExpNode::FilterSuccessor(int depth, bool ignore_case, bool unicode) { - RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case); + RegExpNode* next = on_success_->FilterASCII(depth - 1, ignore_case, unicode); if (next == nullptr) return set_replacement(nullptr); @@ -701,7 +820,7 @@ TextNode::GreedyLoopTextLength() } RegExpNode* -TextNode::FilterASCII(int depth, bool ignore_case) +TextNode::FilterASCII(int depth, bool ignore_case, bool unicode) { if (info()->replacement_calculated) return replacement(); @@ -725,7 +844,7 @@ TextNode::FilterASCII(int depth, bool ignore_case) // Here, we need to check for characters whose upper and lower cases // are outside the Latin-1 range. - char16_t converted = ConvertNonLatin1ToLatin1(c); + char16_t converted = ConvertNonLatin1ToLatin1(c, unicode); if (converted == 0) { // Character is outside Latin-1 completely return set_replacement(nullptr); @@ -750,7 +869,7 @@ TextNode::FilterASCII(int depth, bool ignore_case) ranges[0].to() >= kMaxOneByteCharCode) { // This will be handled in a later filter. - if (ignore_case && RangesContainLatin1Equivalents(ranges)) + if (ignore_case && RangesContainLatin1Equivalents(ranges, unicode)) continue; return set_replacement(nullptr); } @@ -759,14 +878,14 @@ TextNode::FilterASCII(int depth, bool ignore_case) ranges[0].from() > kMaxOneByteCharCode) { // This will be handled in a later filter. - if (ignore_case && RangesContainLatin1Equivalents(ranges)) + if (ignore_case && RangesContainLatin1Equivalents(ranges, unicode)) continue; return set_replacement(nullptr); } } } } - return FilterSuccessor(depth - 1, ignore_case); + return FilterSuccessor(depth - 1, ignore_case, unicode); } void @@ -784,7 +903,7 @@ TextNode::CalculateOffsets() } } -void TextNode::MakeCaseIndependent(bool is_ascii) +void TextNode::MakeCaseIndependent(bool is_ascii, bool unicode) { int element_count = elements().length(); for (int i = 0; i < element_count; i++) { @@ -800,7 +919,7 @@ void TextNode::MakeCaseIndependent(bool is_ascii) CharacterRangeVector& ranges = cc->ranges(alloc()); int range_count = ranges.length(); for (int j = 0; j < range_count; j++) - ranges[j].AddCaseEquivalents(is_ascii, &ranges); + ranges[j].AddCaseEquivalents(is_ascii, unicode, &ranges); } } } @@ -949,7 +1068,7 @@ ChoiceNode::FillInBMInfo(int offset, } RegExpNode* -ChoiceNode::FilterASCII(int depth, bool ignore_case) +ChoiceNode::FilterASCII(int depth, bool ignore_case, bool unicode) { if (info()->replacement_calculated) return replacement(); @@ -973,7 +1092,7 @@ ChoiceNode::FilterASCII(int depth, bool ignore_case) for (int i = 0; i < choice_count; i++) { GuardedAlternative alternative = alternatives()[i]; RegExpNode* replacement = - alternative.node()->FilterASCII(depth - 1, ignore_case); + alternative.node()->FilterASCII(depth - 1, ignore_case, unicode); MOZ_ASSERT(replacement != this); // No missing EMPTY_MATCH_CHECK. if (replacement != nullptr) { alternatives()[i].set_node(replacement); @@ -994,7 +1113,7 @@ ChoiceNode::FilterASCII(int depth, bool ignore_case) new_alternatives.reserve(surviving); for (int i = 0; i < choice_count; i++) { RegExpNode* replacement = - alternatives()[i].node()->FilterASCII(depth - 1, ignore_case); + alternatives()[i].node()->FilterASCII(depth - 1, ignore_case, unicode); if (replacement != nullptr) { alternatives()[i].set_node(replacement); AutoEnterOOMUnsafeRegion oomUnsafe; @@ -1051,7 +1170,7 @@ NegativeLookaheadChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details, } RegExpNode* -NegativeLookaheadChoiceNode::FilterASCII(int depth, bool ignore_case) +NegativeLookaheadChoiceNode::FilterASCII(int depth, bool ignore_case, bool unicode) { if (info()->replacement_calculated) return replacement(); @@ -1065,14 +1184,14 @@ NegativeLookaheadChoiceNode::FilterASCII(int depth, bool ignore_case) // Alternative 0 is the negative lookahead, alternative 1 is what comes // afterwards. RegExpNode* node = alternatives()[1].node(); - RegExpNode* replacement = node->FilterASCII(depth - 1, ignore_case); + RegExpNode* replacement = node->FilterASCII(depth - 1, ignore_case, unicode); if (replacement == nullptr) return set_replacement(nullptr); alternatives()[1].set_node(replacement); RegExpNode* neg_node = alternatives()[0].node(); - RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1, ignore_case); + RegExpNode* neg_replacement = neg_node->FilterASCII(depth - 1, ignore_case, unicode); // If the negative lookahead is always going to fail then // we don't need to check it. @@ -1153,7 +1272,7 @@ LoopChoiceNode::FillInBMInfo(int offset, } RegExpNode* -LoopChoiceNode::FilterASCII(int depth, bool ignore_case) +LoopChoiceNode::FilterASCII(int depth, bool ignore_case, bool unicode) { if (info()->replacement_calculated) return replacement(); @@ -1166,7 +1285,7 @@ LoopChoiceNode::FilterASCII(int depth, bool ignore_case) VisitMarker marker(info()); RegExpNode* continue_replacement = - continue_node_->FilterASCII(depth - 1, ignore_case); + continue_node_->FilterASCII(depth - 1, ignore_case, unicode); // If we can't continue after the loop then there is no sense in doing the // loop. @@ -1174,7 +1293,7 @@ LoopChoiceNode::FilterASCII(int depth, bool ignore_case) return set_replacement(nullptr); } - return ChoiceNode::FilterASCII(depth - 1, ignore_case); + return ChoiceNode::FilterASCII(depth - 1, ignore_case, unicode); } // ------------------------------------------------------------------- @@ -1203,7 +1322,7 @@ void Analysis::VisitText(TextNode* that) { if (ignore_case_) - that->MakeCaseIndependent(is_ascii_); + that->MakeCaseIndependent(is_ascii_, unicode_); EnsureAnalyzed(that->on_success()); if (!has_failed()) { that->CalculateOffsets(); @@ -1495,7 +1614,7 @@ class irregexp::RegExpCompiler { public: RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_count, - bool ignore_case, bool is_ascii, bool match_only); + bool ignore_case, bool is_ascii, bool match_only, bool unicode); int AllocateRegister() { if (next_register_ >= RegExpMacroAssembler::kMaxRegister) { @@ -1532,6 +1651,7 @@ class irregexp::RegExpCompiler inline bool ignore_case() { return ignore_case_; } inline bool ascii() { return ascii_; } + inline bool unicode() { return unicode_; } FrequencyCollator* frequency_collator() { return &frequency_collator_; } int current_expansion_factor() { return current_expansion_factor_; } @@ -1553,6 +1673,7 @@ class irregexp::RegExpCompiler bool ignore_case_; bool ascii_; bool match_only_; + bool unicode_; bool reg_exp_too_big_; int current_expansion_factor_; FrequencyCollator frequency_collator_; @@ -1575,12 +1696,13 @@ class RecursionCheck // Attempts to compile the regexp using an Irregexp code generator. Returns // a fixed array or a null handle depending on whether it succeeded. RegExpCompiler::RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_count, - bool ignore_case, bool ascii, bool match_only) + bool ignore_case, bool ascii, bool match_only, bool unicode) : next_register_(2 * (capture_count + 1)), recursion_depth_(0), ignore_case_(ignore_case), ascii_(ascii), match_only_(match_only), + unicode_(unicode), reg_exp_too_big_(false), current_expansion_factor_(1), frequency_collator_(), @@ -1653,7 +1775,8 @@ IsNativeRegExpEnabled(JSContext* cx) RegExpCode irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data, HandleLinearString sample, bool is_global, bool ignore_case, - bool is_ascii, bool match_only, bool force_bytecode, bool sticky) + bool is_ascii, bool match_only, bool force_bytecode, bool sticky, + bool unicode) { if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) { JS_ReportError(cx, "regexp too big"); @@ -1661,7 +1784,8 @@ irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* } LifoAlloc& alloc = cx->tempLifoAlloc(); - RegExpCompiler compiler(cx, &alloc, data->capture_count, ignore_case, is_ascii, match_only); + RegExpCompiler compiler(cx, &alloc, data->capture_count, ignore_case, is_ascii, match_only, + unicode); // Sample some characters from the middle of the string. if (sample->hasLatin1Chars()) { @@ -1707,18 +1831,18 @@ irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* } } if (is_ascii) { - node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case); + node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case, unicode); // Do it again to propagate the new nodes to places where they were not // put because they had not been calculated yet. if (node != nullptr) { - node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case); + node = node->FilterASCII(RegExpCompiler::kMaxRecursion, ignore_case, unicode); } } if (node == nullptr) node = alloc.newInfallible(&alloc, EndNode::BACKTRACK); - Analysis analysis(cx, ignore_case, is_ascii); + Analysis analysis(cx, ignore_case, is_ascii, unicode); analysis.EnsureAnalyzed(node); if (analysis.has_failed()) { JS_ReportError(cx, analysis.errorMessage()); @@ -2056,6 +2180,10 @@ RegExpAssertion::ToNode(RegExpCompiler* compiler, result->AddAlternative(end_alternative); return result; } + case NOT_AFTER_LEAD_SURROGATE: + return AssertionNode::NotAfterLeadSurrogate(on_success); + case NOT_IN_SURROGATE_PAIR: + return AssertionNode::NotInSurrogatePair(on_success); default: MOZ_CRASH("Bad assertion type"); } @@ -2843,6 +2971,65 @@ EmitHat(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace) on_success->Emit(compiler, &new_trace); } +// Assert that the next character cannot be a part of a surrogate pair. +static void +EmitNotAfterLeadSurrogate(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace) +{ + RegExpMacroAssembler* assembler = compiler->macro_assembler(); + + // We will be loading the previous character into the current character + // register. + Trace new_trace(*trace); + new_trace.InvalidateCurrentCharacter(); + + jit::Label ok; + if (new_trace.cp_offset() == 0) + assembler->CheckAtStart(&ok); + + // We already checked that we are not at the start of input so it must be + // OK to load the previous character. + assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, new_trace.backtrack(), false); + assembler->CheckCharacterInRange(unicode::LeadSurrogateMin, unicode::LeadSurrogateMax, + new_trace.backtrack()); + + assembler->Bind(&ok); + on_success->Emit(compiler, &new_trace); +} + +// Assert that the next character is not a trail surrogate that has a +// corresponding lead surrogate. +static void +EmitNotInSurrogatePair(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace) +{ + RegExpMacroAssembler* assembler = compiler->macro_assembler(); + + jit::Label ok; + assembler->CheckPosition(trace->cp_offset(), &ok); + + // We will be loading the next and previous characters into the current + // character register. + Trace new_trace(*trace); + new_trace.InvalidateCurrentCharacter(); + + if (new_trace.cp_offset() == 0) + assembler->CheckAtStart(&ok); + + // First check if next character is a trail surrogate. + assembler->LoadCurrentCharacter(new_trace.cp_offset(), new_trace.backtrack(), false); + assembler->CheckCharacterNotInRange(unicode::TrailSurrogateMin, unicode::TrailSurrogateMax, + &ok); + + // Next check if previous character is a lead surrogate. + // We already checked that we are not at the start of input so it must be + // OK to load the previous character. + assembler->LoadCurrentCharacter(new_trace.cp_offset() - 1, new_trace.backtrack(), false); + assembler->CheckCharacterInRange(unicode::LeadSurrogateMin, unicode::LeadSurrogateMax, + new_trace.backtrack()); + + assembler->Bind(&ok); + on_success->Emit(compiler, &new_trace); +} + // Check for [0-9A-Z_a-z]. static void EmitWordCheck(RegExpMacroAssembler* assembler, @@ -2996,6 +3183,12 @@ AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) EmitBoundaryCheck(compiler, trace); return; } + case NOT_AFTER_LEAD_SURROGATE: + EmitNotAfterLeadSurrogate(compiler, on_success(), trace); + return; + case NOT_IN_SURROGATE_PAIR: + EmitNotInSurrogatePair(compiler, on_success(), trace); + return; } on_success()->Emit(compiler, trace); } @@ -3524,7 +3717,7 @@ EmitAtomNonLetter(RegExpCompiler* compiler, RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); bool ascii = compiler->ascii(); char16_t chars[kEcma262UnCanonicalizeMaxWidth]; - int length = GetCaseIndependentLetters(c, ascii, chars); + int length = GetCaseIndependentLetters(c, ascii, compiler->unicode(), chars); if (length < 1) { // This can't match. Must be an ASCII subject and a non-ASCII character. // We do not need to do anything since the ASCII pass already handled this. @@ -3600,7 +3793,7 @@ EmitAtomLetter(RegExpCompiler* compiler, RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); bool ascii = compiler->ascii(); char16_t chars[kEcma262UnCanonicalizeMaxWidth]; - int length = GetCaseIndependentLetters(c, ascii, chars); + int length = GetCaseIndependentLetters(c, ascii, compiler->unicode(), chars); if (length <= 1) return false; // We may not need to check against the end of the input string // if this character lies before a character that matched. @@ -4469,7 +4662,8 @@ BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) MOZ_ASSERT(start_reg_ + 1 == end_reg_); if (compiler->ignore_case()) { assembler->CheckNotBackReferenceIgnoreCase(start_reg_, - trace->backtrack()); + trace->backtrack(), + compiler->unicode()); } else { assembler->CheckNotBackReference(start_reg_, trace->backtrack()); } @@ -4615,6 +4809,7 @@ TextNode::FillInBMInfo(int initial_offset, char16_t chars[kEcma262UnCanonicalizeMaxWidth]; int length = GetCaseIndependentLetters(character, bm->max_char() == kMaxOneByteCharCode, + bm->compiler()->unicode(), chars); for (int j = 0; j < length; j++) bm->Set(offset, chars[j]); @@ -4706,7 +4901,8 @@ TextNode::GetQuickCheckDetails(QuickCheckDetails* details, } if (compiler->ignore_case()) { char16_t chars[kEcma262UnCanonicalizeMaxWidth]; - size_t length = GetCaseIndependentLetters(c, compiler->ascii(), chars); + size_t length = GetCaseIndependentLetters(c, compiler->ascii(), + compiler->unicode(), chars); MOZ_ASSERT(length != 0); // Can only happen if c > char_mask (see above). if (length == 1) { // This letter has no case equivalents, so it's nice and simple diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h index b687c6c52d..ca315c2adc 100644 --- a/js/src/irregexp/RegExpEngine.h +++ b/js/src/irregexp/RegExpEngine.h @@ -88,7 +88,8 @@ struct RegExpCode RegExpCode CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data, HandleLinearString sample, bool is_global, bool ignore_case, - bool is_ascii, bool match_only, bool force_bytecode, bool sticky); + bool is_ascii, bool match_only, bool force_bytecode, bool sticky, + bool unicode); // Note: this may return RegExpRunStatus_Error if an interrupt was requested // while the code was executing. @@ -144,6 +145,8 @@ class CharacterRange {} static void AddClassEscape(LifoAlloc* alloc, char16_t type, CharacterRangeVector* ranges); + static void AddClassEscapeUnicode(LifoAlloc* alloc, char16_t type, + CharacterRangeVector* ranges, bool ignoreCase); static inline CharacterRange Singleton(char16_t value) { return CharacterRange(value, value); @@ -163,7 +166,7 @@ class CharacterRange bool is_valid() { return from_ <= to_; } bool IsEverything(char16_t max) { return from_ == 0 && to_ >= max; } bool IsSingleton() { return (from_ == to_); } - void AddCaseEquivalents(bool is_ascii, CharacterRangeVector* ranges); + void AddCaseEquivalents(bool is_ascii, bool unicode, CharacterRangeVector* ranges); static void Split(const LifoAlloc* alloc, CharacterRangeVector base, @@ -516,7 +519,7 @@ class RegExpNode // If we know that the input is ASCII then there are some nodes that can // never match. This method returns a node that can be substituted for // itself, or nullptr if the node can never match. - virtual RegExpNode* FilterASCII(int depth, bool ignore_case) { return this; } + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode) { return this; } // Helper for FilterASCII. RegExpNode* replacement() { @@ -623,14 +626,14 @@ class SeqRegExpNode : public RegExpNode RegExpNode* on_success() { return on_success_; } void set_on_success(RegExpNode* node) { on_success_ = node; } - virtual RegExpNode* FilterASCII(int depth, bool ignore_case); + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode); virtual bool FillInBMInfo(int offset, int budget, BoyerMooreLookahead* bm, bool not_at_start); protected: - RegExpNode* FilterSuccessor(int depth, bool ignore_case); + RegExpNode* FilterSuccessor(int depth, bool ignore_case, bool unicode); private: RegExpNode* on_success_; @@ -748,7 +751,7 @@ class TextNode : public SeqRegExpNode int characters_filled_in, bool not_at_start); TextElementVector& elements() { return *elements_; } - void MakeCaseIndependent(bool is_ascii); + void MakeCaseIndependent(bool is_ascii, bool unicode); virtual int GreedyLoopTextLength(); virtual RegExpNode* GetSuccessorOfOmnivorousTextNode( RegExpCompiler* compiler); @@ -757,7 +760,7 @@ class TextNode : public SeqRegExpNode BoyerMooreLookahead* bm, bool not_at_start); void CalculateOffsets(); - virtual RegExpNode* FilterASCII(int depth, bool ignore_case); + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode); private: enum TextEmitPassType { @@ -788,7 +791,9 @@ class AssertionNode : public SeqRegExpNode AT_START, AT_BOUNDARY, AT_NON_BOUNDARY, - AFTER_NEWLINE + AFTER_NEWLINE, + NOT_AFTER_LEAD_SURROGATE, + NOT_IN_SURROGATE_PAIR }; AssertionNode(AssertionType t, RegExpNode* on_success) : SeqRegExpNode(on_success), assertion_type_(t) @@ -809,6 +814,14 @@ class AssertionNode : public SeqRegExpNode static AssertionNode* AfterNewline(RegExpNode* on_success) { return on_success->alloc()->newInfallible(AFTER_NEWLINE, on_success); } + static AssertionNode* NotAfterLeadSurrogate(RegExpNode* on_success) { + return on_success->alloc()->newInfallible(NOT_AFTER_LEAD_SURROGATE, + on_success); + } + static AssertionNode* NotInSurrogatePair(RegExpNode* on_success) { + return on_success->alloc()->newInfallible(NOT_IN_SURROGATE_PAIR, + on_success); + } virtual void Accept(NodeVisitor* visitor); virtual void Emit(RegExpCompiler* compiler, Trace* trace); virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start); @@ -1006,7 +1019,7 @@ class ChoiceNode : public RegExpNode void set_not_at_start() { not_at_start_ = true; } void set_being_calculated(bool b) { being_calculated_ = b; } virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } - virtual RegExpNode* FilterASCII(int depth, bool ignore_case); + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode); protected: int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative); @@ -1059,7 +1072,7 @@ class NegativeLookaheadChoiceNode : public ChoiceNode // characters, but on a negative lookahead the negative branch did not take // part in that calculation (EatsAtLeast) so the assumptions don't hold. virtual bool try_to_emit_quick_check_for_alternative(int i) { return i != 0; } - virtual RegExpNode* FilterASCII(int depth, bool ignore_case); + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode); }; class LoopChoiceNode : public ChoiceNode @@ -1088,7 +1101,7 @@ class LoopChoiceNode : public ChoiceNode RegExpNode* continue_node() { return continue_node_; } bool body_can_be_zero_length() { return body_can_be_zero_length_; } virtual void Accept(NodeVisitor* visitor); - virtual RegExpNode* FilterASCII(int depth, bool ignore_case); + virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode); private: // AddAlternative is made private for loop nodes because alternatives @@ -1459,10 +1472,11 @@ class NodeVisitor class Analysis : public NodeVisitor { public: - Analysis(JSContext* cx, bool ignore_case, bool is_ascii) + Analysis(JSContext* cx, bool ignore_case, bool is_ascii, bool unicode) : cx(cx), ignore_case_(ignore_case), is_ascii_(is_ascii), + unicode_(unicode), error_message_(nullptr) {} @@ -1487,6 +1501,7 @@ class Analysis : public NodeVisitor JSContext* cx; bool ignore_case_; bool is_ascii_; + bool unicode_; const char* error_message_; Analysis(Analysis&) = delete; diff --git a/js/src/irregexp/RegExpInterpreter.cpp b/js/src/irregexp/RegExpInterpreter.cpp index 2a4bfb20a6..1258c203dd 100644 --- a/js/src/irregexp/RegExpInterpreter.cpp +++ b/js/src/irregexp/RegExpInterpreter.cpp @@ -442,6 +442,27 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha } break; } + BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE) { + int from = registers[insn >> BYTECODE_SHIFT]; + int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from; + if (from < 0 || len <= 0) { + pc += BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_LENGTH; + break; + } + if (current + len > length) { + pc = byteCode + Load32Aligned(pc + 4); + break; + } + if (CaseInsensitiveCompareUCStrings(chars + from, chars + current, + len * sizeof(CharT))) + { + current += len; + pc += BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_LENGTH; + } else { + pc = byteCode + Load32Aligned(pc + 4); + } + break; + } BYTECODE(CHECK_AT_START) if (current == 0) pc = byteCode + Load32Aligned(pc + 4); diff --git a/js/src/irregexp/RegExpMacroAssembler.cpp b/js/src/irregexp/RegExpMacroAssembler.cpp index 197c3f3b45..d66d0d204a 100644 --- a/js/src/irregexp/RegExpMacroAssembler.cpp +++ b/js/src/irregexp/RegExpMacroAssembler.cpp @@ -65,6 +65,38 @@ template int irregexp::CaseInsensitiveCompareStrings(const char16_t* substring1, const char16_t* substring2, size_t byteLength); +template +int +irregexp::CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2, + size_t byteLength) +{ + MOZ_ASSERT(byteLength % sizeof(CharT) == 0); + size_t length = byteLength / sizeof(CharT); + + for (size_t i = 0; i < length; i++) { + char16_t c1 = substring1[i]; + char16_t c2 = substring2[i]; + if (c1 != c2) { + c1 = unicode::FoldCase(c1); + c2 = unicode::FoldCase(c2); + if (c1 != c2) + return 0; + } + } + + return 1; +} + +template int +irregexp::CaseInsensitiveCompareUCStrings(const Latin1Char* substring1, + const Latin1Char* substring2, + size_t byteLength); + +template int +irregexp::CaseInsensitiveCompareUCStrings(const char16_t* substring1, + const char16_t* substring2, + size_t byteLength); + InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc* alloc, RegExpShared* shared, size_t numSavedRegisters) : RegExpMacroAssembler(*alloc, shared, numSavedRegisters), @@ -210,11 +242,16 @@ InterpretedRegExpMacroAssembler::CheckNotBackReference(int start_reg, jit::Label } void -InterpretedRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match) +InterpretedRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, + jit::Label* on_no_match, + bool unicode) { MOZ_ASSERT(start_reg >= 0); MOZ_ASSERT(start_reg <= kMaxRegister); - Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg); + if (unicode) + Emit(BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE, start_reg); + else + Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg); EmitOrLink(on_no_match); } diff --git a/js/src/irregexp/RegExpMacroAssembler.h b/js/src/irregexp/RegExpMacroAssembler.h index 0111e37e0d..940033d312 100644 --- a/js/src/irregexp/RegExpMacroAssembler.h +++ b/js/src/irregexp/RegExpMacroAssembler.h @@ -112,7 +112,8 @@ class MOZ_STACK_CLASS RegExpMacroAssembler virtual void CheckGreedyLoop(jit::Label* on_tos_equals_current_position) = 0; virtual void CheckNotAtStart(jit::Label* on_not_at_start) = 0; virtual void CheckNotBackReference(int start_reg, jit::Label* on_no_match) = 0; - virtual void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match) = 0; + virtual void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, + bool unicode) = 0; // Check the current character for a match with a literal character. If we // fail to match then goto the on_failure label. End of input always @@ -221,6 +222,11 @@ template int CaseInsensitiveCompareStrings(const CharT* substring1, const CharT* substring2, size_t byteLength); +template +int +CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2, + size_t byteLength); + class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler : public RegExpMacroAssembler { public: @@ -241,7 +247,7 @@ class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler : public RegExpMacroAssemb void CheckGreedyLoop(jit::Label* on_tos_equals_current_position); void CheckNotAtStart(jit::Label* on_not_at_start); void CheckNotBackReference(int start_reg, jit::Label* on_no_match); - void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match); + void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode); void CheckNotCharacter(unsigned c, jit::Label* on_not_equal); void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal); void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with, diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp index e63092349d..1874368a5b 100644 --- a/js/src/irregexp/RegExpParser.cpp +++ b/js/src/irregexp/RegExpParser.cpp @@ -205,7 +205,8 @@ RegExpBuilder::AddQuantifierToAtom(int min, int max, template RegExpParser::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc, - const CharT* chars, const CharT* end, bool multiline_mode) + const CharT* chars, const CharT* end, bool multiline_mode, + bool unicode, bool ignore_case) : ts(ts), alloc(alloc), captures_(nullptr), @@ -215,6 +216,8 @@ RegExpParser::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc, capture_count_(0), has_more_(true), multiline_(multiline_mode), + unicode_(unicode), + ignore_case_(ignore_case), simple_(false), contains_anchor_(false), is_scanned_for_captures_(false) @@ -300,6 +303,133 @@ RegExpParser::ParseHexEscape(int length, size_t* value) return true; } +template +bool +RegExpParser::ParseBracedHexEscape(size_t* value) +{ + MOZ_ASSERT(current() == '{'); + Advance(); + + bool first = true; + uint32_t code = 0; + while (true) { + widechar c = current(); + if (c == kEndMarker) { + ReportError(JSMSG_INVALID_UNICODE_ESCAPE); + return false; + } + if (c == '}') { + if (first) { + ReportError(JSMSG_INVALID_UNICODE_ESCAPE); + return false; + } + Advance(); + break; + } + + int d = HexValue(c); + if (d < 0) { + ReportError(JSMSG_INVALID_UNICODE_ESCAPE); + return false; + } + code = (code << 4) | d; + if (code > unicode::NonBMPMax) { + ReportError(JSMSG_UNICODE_OVERFLOW); + return false; + } + Advance(); + first = false; + } + + *value = code; + return true; +} + +template +bool +RegExpParser::ParseTrailSurrogate(size_t* value) +{ + if (current() != '\\') + return false; + + const CharT* start = position(); + Advance(); + if (current() != 'u') { + Reset(start); + return false; + } + Advance(); + if (!ParseHexEscape(4, value)) { + Reset(start); + return false; + } + if (!unicode::IsTrailSurrogate(*value)) { + Reset(start); + return false; + } + return true; +} + +template +bool +RegExpParser::ParseRawSurrogatePair(char16_t* lead, char16_t* trail) +{ + widechar c1 = current(); + if (!unicode::IsLeadSurrogate(c1)) + return false; + + const CharT* start = position(); + Advance(); + widechar c2 = current(); + if (!unicode::IsTrailSurrogate(c2)) { + Reset(start); + return false; + } + Advance(); + *lead = c1; + *trail = c2; + return true; +} + +static inline RegExpTree* +RangeAtom(LifoAlloc* alloc, char16_t from, char16_t to) +{ + CharacterRangeVector* ranges = alloc->newInfallible(*alloc); + ranges->append(CharacterRange::Range(from, to)); + return alloc->newInfallible(ranges, false); +} + +static inline RegExpTree* +NegativeLookahead(LifoAlloc* alloc, char16_t from, char16_t to) +{ + return alloc->newInfallible(RangeAtom(alloc, from, to), false, 0, 0); +} + +static bool +IsSyntaxCharacter(widechar c) +{ + switch (c) { + case '^': + case '$': + case '\\': + case '.': + case '*': + case '+': + case '?': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + case '/': + return true; + default: + return false; + } +} + #ifdef DEBUG // Currently only used in an assert.kASSERT. static bool @@ -317,8 +447,8 @@ IsSpecialClassEscape(widechar c) #endif template -widechar -RegExpParser::ParseClassCharacterEscape() +bool +RegExpParser::ParseClassCharacterEscape(widechar* code) { MOZ_ASSERT(current() == '\\'); MOZ_ASSERT(has_next() && !IsSpecialClassEscape(Next())); @@ -326,92 +456,519 @@ RegExpParser::ParseClassCharacterEscape() switch (current()) { case 'b': Advance(); - return '\b'; + *code = '\b'; + return true; // ControlEscape :: one of // f n r t v case 'f': Advance(); - return '\f'; + *code = '\f'; + return true; case 'n': Advance(); - return '\n'; + *code = '\n'; + return true; case 'r': Advance(); - return '\r'; + *code = '\r'; + return true; case 't': Advance(); - return '\t'; + *code = '\t'; + return true; case 'v': Advance(); - return '\v'; + *code = '\v'; + return true; case 'c': { widechar controlLetter = Next(); widechar letter = controlLetter & ~('A' ^ 'a'); // For compatibility with JSC, inside a character class - // we also accept digits and underscore as control characters. - if ((controlLetter >= '0' && controlLetter <= '9') || - controlLetter == '_' || - (letter >= 'A' && letter <= 'Z')) { + // we also accept digits and underscore as control characters, + // but only in non-unicode mode + if ((!unicode_ && + ((controlLetter >= '0' && controlLetter <= '9') || + controlLetter == '_')) || + (letter >= 'A' && letter <= 'Z')) + { Advance(2); // Control letters mapped to ASCII control characters in the range // 0x00-0x1f. - return controlLetter & 0x1f; + *code = controlLetter & 0x1f; + return true; + } + if (unicode_) { + ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); + return false; } // We match JSC in reading the backslash as a literal // character instead of as starting an escape. - return '\\'; + *code = '\\'; + return true; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - // For compatibility, we interpret a decimal escape that isn't - // a back reference (and therefore either \0 or not valid according - // to the specification) as a 1..3 digit octal character code. - return ParseOctalLiteral(); + if (unicode_) { + if (current() == '0') { + *code = 0; + return true; + } + ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); + return false; + } + // For compatibility, outside of unicode mode, we interpret a decimal + // escape that isn't a back reference (and therefore either \0 or not + // valid according to the specification) as a 1..3 digit octal + // character code. + *code = ParseOctalLiteral(); + return true; case 'x': { Advance(); size_t value; - if (ParseHexEscape(2, &value)) - return value; + if (ParseHexEscape(2, &value)) { + *code = value; + return true; + } + if (unicode_) { + ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); + return false; + } // If \x is not followed by a two-digit hexadecimal, treat it - // as an identity escape. - return 'x'; + // as an identity escape in non-unicode mode. + *code = 'x'; + return true; } case 'u': { Advance(); size_t value; - if (ParseHexEscape(4, &value)) - return value; - // If \u is not followed by a four-digit hexadecimal, treat it + if (unicode_) { + if (current() == '{') { + if (!ParseBracedHexEscape(&value)) + return false; + *code = value; + return true; + } + if (ParseHexEscape(4, &value)) { + if (unicode::IsLeadSurrogate(value)) { + size_t trail; + if (ParseTrailSurrogate(&trail)) { + *code = unicode::UTF16Decode(value, trail); + return true; + } + } + *code = value; + return true; + } + ReportError(JSMSG_INVALID_UNICODE_ESCAPE); + return false; + } + if (ParseHexEscape(4, &value)) { + *code = value; + return true; + } + // If \u is not followed by a four-digit or braced hexadecimal, treat it // as an identity escape. - return 'u'; + *code = 'u'; + return true; } default: { - // Extended identity escape. We accept any character that hasn't - // been matched by a more specific case, not just the subset required - // by the ECMAScript specification. + // Extended identity escape (non-unicode only). We accept any character + // that hasn't been matched by a more specific case, not just the subset + // required by the ECMAScript specification. widechar result = current(); + if (unicode_ && result != '-' && !IsSyntaxCharacter(result)) { + ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); + return false; + } Advance(); - return result; + *code = result; + return true; } } - return 0; + return true; +} + +class WideCharRange +{ + public: + WideCharRange() + : from_(0), to_(0) + {} + + WideCharRange(widechar from, widechar to) + : from_(from), to_(to) + {} + + static inline WideCharRange Singleton(widechar value) { + return WideCharRange(value, value); + } + static inline WideCharRange Range(widechar from, widechar to) { + MOZ_ASSERT(from <= to); + return WideCharRange(from, to); + } + + bool Contains(widechar i) const { return from_ <= i && i <= to_; } + widechar from() const { return from_; } + widechar to() const { return to_; } + + private: + widechar from_; + widechar to_; +}; + +typedef Vector > WideCharRangeVector; + +static inline CharacterRange +LeadSurrogateRange() +{ + return CharacterRange::Range(unicode::LeadSurrogateMin, unicode::LeadSurrogateMax); +} + +static inline CharacterRange +TrailSurrogateRange() +{ + return CharacterRange::Range(unicode::TrailSurrogateMin, unicode::TrailSurrogateMax); +} + +static inline WideCharRange +NonBMPRange() +{ + return WideCharRange::Range(unicode::NonBMPMin, unicode::NonBMPMax); } static const char16_t kNoCharClass = 0; -// Adds range or pre-defined character class to character ranges. +// Adds a character or pre-defined character class to character ranges. // If char_class is not kInvalidClass, it's interpreted as a class // escape (i.e., 's' means whitespace, from '\s'). static inline void -AddRangeOrEscape(LifoAlloc* alloc, - CharacterRangeVector* ranges, - char16_t char_class, - CharacterRange range) +AddCharOrEscape(LifoAlloc* alloc, + CharacterRangeVector* ranges, + char16_t char_class, + widechar c) { if (char_class != kNoCharClass) CharacterRange::AddClassEscape(alloc, char_class, ranges); else - ranges->append(range); + ranges->append(CharacterRange::Singleton(c)); +} + +static inline void +AddCharOrEscapeUnicode(LifoAlloc* alloc, + CharacterRangeVector* ranges, + CharacterRangeVector* lead_ranges, + CharacterRangeVector* trail_ranges, + WideCharRangeVector* wide_ranges, + char16_t char_class, + widechar c, + bool ignore_case) +{ + if (char_class != kNoCharClass) { + CharacterRange::AddClassEscapeUnicode(alloc, char_class, ranges, ignore_case); + switch (char_class) { + case 'S': + case 'W': + case 'D': + lead_ranges->append(LeadSurrogateRange()); + trail_ranges->append(TrailSurrogateRange()); + wide_ranges->append(NonBMPRange()); + break; + case '.': + MOZ_CRASH("Bad char_class!"); + } + return; + } + + if (unicode::IsLeadSurrogate(c)) + lead_ranges->append(CharacterRange::Singleton(c)); + else if (unicode::IsTrailSurrogate(c)) + trail_ranges->append(CharacterRange::Singleton(c)); + else if (c >= unicode::NonBMPMin) + wide_ranges->append(WideCharRange::Singleton(c)); + else + ranges->append(CharacterRange::Singleton(c)); +} + +static inline void +AddUnicodeRange(LifoAlloc* alloc, + CharacterRangeVector* ranges, + CharacterRangeVector* lead_ranges, + CharacterRangeVector* trail_ranges, + WideCharRangeVector* wide_ranges, + widechar first, + widechar next) +{ + MOZ_ASSERT(first <= next); + if (first < unicode::LeadSurrogateMin) { + if (next < unicode::LeadSurrogateMin) { + ranges->append(CharacterRange::Range(first, next)); + return; + } + ranges->append(CharacterRange::Range(first, unicode::LeadSurrogateMin - 1)); + first = unicode::LeadSurrogateMin; + } + if (first <= unicode::LeadSurrogateMax) { + if (next <= unicode::LeadSurrogateMax) { + lead_ranges->append(CharacterRange::Range(first, next)); + return; + } + lead_ranges->append(CharacterRange::Range(first, unicode::LeadSurrogateMax)); + first = unicode::LeadSurrogateMax + 1; + } + MOZ_ASSERT(unicode::LeadSurrogateMax + 1 == unicode::TrailSurrogateMin); + if (first <= unicode::TrailSurrogateMax) { + if (next <= unicode::TrailSurrogateMax) { + trail_ranges->append(CharacterRange::Range(first, next)); + return; + } + trail_ranges->append(CharacterRange::Range(first, unicode::TrailSurrogateMax)); + first = unicode::TrailSurrogateMax + 1; + } + if (first <= unicode::UTF16Max) { + if (next <= unicode::UTF16Max) { + ranges->append(CharacterRange::Range(first, next)); + return; + } + ranges->append(CharacterRange::Range(first, unicode::UTF16Max)); + first = unicode::NonBMPMin; + } + MOZ_ASSERT(unicode::UTF16Max + 1 == unicode::NonBMPMin); + wide_ranges->append(WideCharRange::Range(first, next)); +} + +// Negate a vector of ranges by subtracting its ranges from a range +// encompassing the full range of possible values. +template +static inline void +NegateUnicodeRanges(LifoAlloc* alloc, Vector >** ranges, + RangeType full_range) +{ + typedef Vector > RangeVector; + RangeVector* tmp_ranges = alloc->newInfallible(*alloc); + tmp_ranges->append(full_range); + RangeVector* result_ranges = alloc->newInfallible(*alloc); + + // Perform the following calculation: + // result_ranges = tmp_ranges - ranges + // with the following steps: + // result_ranges = tmp_ranges - ranges[0] + // SWAP(result_ranges, tmp_ranges) + // result_ranges = tmp_ranges - ranges[1] + // SWAP(result_ranges, tmp_ranges) + // ... + // result_ranges = tmp_ranges - ranges[N-1] + // SWAP(result_ranges, tmp_ranges) + // The last SWAP is just for simplicity of the loop. + for (size_t i = 0; i < (*ranges)->length(); i++) { + result_ranges->clear(); + + const RangeType& range = (**ranges)[i]; + for (size_t j = 0; j < tmp_ranges->length(); j++) { + const RangeType& tmpRange = (*tmp_ranges)[j]; + size_t from1 = tmpRange.from(); + size_t to1 = tmpRange.to(); + size_t from2 = range.from(); + size_t to2 = range.to(); + + if (from1 < from2) { + if (to1 < from2) { + result_ranges->append(tmpRange); + } else if (to1 <= to2) { + result_ranges->append(RangeType::Range(from1, from2 - 1)); + } else { + result_ranges->append(RangeType::Range(from1, from2 - 1)); + result_ranges->append(RangeType::Range(to2 + 1, to1)); + } + } else if (from1 <= to2) { + if (to1 > to2) + result_ranges->append(RangeType::Range(to2 + 1, to1)); + } else { + result_ranges->append(tmpRange); + } + } + + auto tmp = tmp_ranges; + tmp_ranges = result_ranges; + result_ranges = tmp; + } + + // After the loop, result is pointed at by tmp_ranges, instead of + // result_ranges. + *ranges = tmp_ranges; +} + +static bool +WideCharRangesContain(WideCharRangeVector* wide_ranges, widechar c) +{ + for (size_t i = 0; i < wide_ranges->length(); i++) { + const WideCharRange& range = (*wide_ranges)[i]; + if (range.Contains(c)) + return true; + } + return false; +} + +static void +CalculateCaseInsensitiveRanges(LifoAlloc* alloc, widechar from, widechar to, int32_t diff, + WideCharRangeVector* wide_ranges, + WideCharRangeVector** tmp_wide_ranges) +{ + widechar contains_from = 0; + widechar contains_to = 0; + for (widechar c = from; c <= to; c++) { + if (WideCharRangesContain(wide_ranges, c) && + !WideCharRangesContain(wide_ranges, c + diff)) + { + if (contains_from == 0) + contains_from = c; + contains_to = c; + } else if (contains_from != 0) { + if (!*tmp_wide_ranges) + *tmp_wide_ranges = alloc->newInfallible(*alloc); + + (*tmp_wide_ranges)->append(WideCharRange::Range(contains_from + diff, + contains_to + diff)); + contains_from = 0; + } + } + + if (contains_from != 0) { + if (!*tmp_wide_ranges) + *tmp_wide_ranges = alloc->newInfallible(*alloc); + + (*tmp_wide_ranges)->append(WideCharRange::Range(contains_from + diff, + contains_to + diff)); + } +} + +static RegExpTree* +UnicodeRangesAtom(LifoAlloc* alloc, + CharacterRangeVector* ranges, + CharacterRangeVector* lead_ranges, + CharacterRangeVector* trail_ranges, + WideCharRangeVector* wide_ranges, + bool is_negated, + bool ignore_case) +{ + // Calculate case folding for non-BMP first and negate the range if needed. + if (ignore_case) { + WideCharRangeVector* tmp_wide_ranges = nullptr; +#define CALL_CALC(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF) \ + CalculateCaseInsensitiveRanges(alloc, FROM, TO, DIFF, wide_ranges, &tmp_wide_ranges); + FOR_EACH_NON_BMP_CASE_FOLDING(CALL_CALC) +#undef CALL_CALC + + if (tmp_wide_ranges) { + for (size_t i = 0; i < tmp_wide_ranges->length(); i++) + wide_ranges->append((*tmp_wide_ranges)[i]); + } + } + + if (is_negated) { + NegateUnicodeRanges(alloc, &lead_ranges, LeadSurrogateRange()); + NegateUnicodeRanges(alloc, &trail_ranges, TrailSurrogateRange()); + NegateUnicodeRanges(alloc, &wide_ranges, NonBMPRange()); + } + + RegExpBuilder* builder = alloc->newInfallible(alloc); + + bool added = false; + + if (is_negated) { + ranges->append(LeadSurrogateRange()); + ranges->append(TrailSurrogateRange()); + } + if (ranges->length() > 0) { + builder->AddAtom(alloc->newInfallible(ranges, is_negated)); + added = true; + } + + if (lead_ranges->length() > 0) { + if (added) + builder->NewAlternative(); + builder->AddAtom(alloc->newInfallible(lead_ranges, false)); + builder->AddAtom(NegativeLookahead(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + added = true; + } + + if (trail_ranges->length() > 0) { + if (added) + builder->NewAlternative(); + builder->AddAssertion(alloc->newInfallible( + RegExpAssertion::NOT_AFTER_LEAD_SURROGATE)); + builder->AddAtom(alloc->newInfallible(trail_ranges, false)); + added = true; + } + + for (size_t i = 0; i < wide_ranges->length(); i++) { + if (added) + builder->NewAlternative(); + + const WideCharRange& range = (*wide_ranges)[i]; + widechar from = range.from(); + widechar to = range.to(); + size_t from_lead, from_trail; + size_t to_lead, to_trail; + + unicode::UTF16Encode(from, &from_lead, &from_trail); + if (from == to) { + builder->AddCharacter(from_lead); + builder->AddCharacter(from_trail); + } else { + unicode::UTF16Encode(to, &to_lead, &to_trail); + if (from_lead == to_lead) { + MOZ_ASSERT(from_trail != to_trail); + builder->AddCharacter(from_lead); + builder->AddAtom(RangeAtom(alloc, from_trail, to_trail)); + } else if (from_trail == unicode::TrailSurrogateMin && + to_trail == unicode::TrailSurrogateMax) + { + builder->AddAtom(RangeAtom(alloc, from_lead, to_lead)); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + } else if (from_lead + 1 == to_lead) { + builder->AddCharacter(from_lead); + builder->AddAtom(RangeAtom(alloc, from_trail, unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddCharacter(to_lead); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, to_trail)); + } else if (from_lead + 2 == to_lead) { + builder->AddCharacter(from_lead); + builder->AddAtom(RangeAtom(alloc, from_trail, unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddCharacter(from_lead + 1); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddCharacter(to_lead); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, to_trail)); + } else { + builder->AddCharacter(from_lead); + builder->AddAtom(RangeAtom(alloc, from_trail, unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddAtom(RangeAtom(alloc, from_lead + 1, to_lead - 1)); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddCharacter(to_lead); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, to_trail)); + } + } + added = true; + } + + return builder->ToRegExp(); } template @@ -426,9 +983,19 @@ RegExpParser::ParseCharacterClass() Advance(); } CharacterRangeVector* ranges = alloc->newInfallible(*alloc); + CharacterRangeVector* lead_ranges = nullptr; + CharacterRangeVector* trail_ranges = nullptr; + WideCharRangeVector* wide_ranges = nullptr; + + if (unicode_) { + lead_ranges = alloc->newInfallible(*alloc); + trail_ranges = alloc->newInfallible(*alloc); + wide_ranges = alloc->newInfallible(*alloc); + } + while (has_more() && current() != ']') { char16_t char_class = kNoCharClass; - CharacterRange first; + widechar first = 0; if (!ParseClassAtom(&char_class, &first)) return nullptr; if (current() == '-') { @@ -438,41 +1005,69 @@ RegExpParser::ParseCharacterClass() // following code report an error. break; } else if (current() == ']') { - AddRangeOrEscape(alloc, ranges, char_class, first); + if (unicode_) { + AddCharOrEscapeUnicode(alloc, ranges, lead_ranges, trail_ranges, wide_ranges, + char_class, first, ignore_case_); + } else { + AddCharOrEscape(alloc, ranges, char_class, first); + } ranges->append(CharacterRange::Singleton('-')); break; } char16_t char_class_2 = kNoCharClass; - CharacterRange next; + widechar next = 0; if (!ParseClassAtom(&char_class_2, &next)) return nullptr; if (char_class != kNoCharClass || char_class_2 != kNoCharClass) { + if (unicode_) + return ReportError(JSMSG_RANGE_WITH_CLASS_ESCAPE); + // Either end is an escaped character class. Treat the '-' verbatim. - AddRangeOrEscape(alloc, ranges, char_class, first); + AddCharOrEscape(alloc, ranges, char_class, first); ranges->append(CharacterRange::Singleton('-')); - AddRangeOrEscape(alloc, ranges, char_class_2, next); + AddCharOrEscape(alloc, ranges, char_class_2, next); continue; } - if (first.from() > next.to()) + if (first > next) return ReportError(JSMSG_BAD_CLASS_RANGE); - ranges->append(CharacterRange::Range(first.from(), next.to())); + if (unicode_) + AddUnicodeRange(alloc, ranges, lead_ranges, trail_ranges,wide_ranges, first, next); + else + ranges->append(CharacterRange::Range(first, next)); } else { - AddRangeOrEscape(alloc, ranges, char_class, first); + if (unicode_) { + AddCharOrEscapeUnicode(alloc, ranges, lead_ranges, trail_ranges, wide_ranges, + char_class, first, ignore_case_); + } else { + AddCharOrEscape(alloc, ranges, char_class, first); + } } } if (!has_more()) return ReportError(JSMSG_UNTERM_CLASS); Advance(); - if (ranges->length() == 0) { - ranges->append(CharacterRange::Everything()); - is_negated = !is_negated; + if (!unicode_) { + if (ranges->length() == 0) { + ranges->append(CharacterRange::Everything()); + is_negated = !is_negated; + } + return alloc->newInfallible(ranges, is_negated); } - return alloc->newInfallible(ranges, is_negated); + + if (!is_negated && ranges->length() == 0 && lead_ranges->length() == 0 && + trail_ranges->length() == 0 && wide_ranges->length() == 0) + { + ranges->append(CharacterRange::Everything()); + return alloc->newInfallible(ranges, true); + } + + return UnicodeRangesAtom(alloc, ranges, lead_ranges, trail_ranges, wide_ranges, is_negated, + ignore_case_); } template bool -RegExpParser::ParseClassAtom(char16_t* char_class, CharacterRange* char_range) +RegExpParser::ParseClassAtom(char16_t* char_class, widechar* value) { MOZ_ASSERT(*char_class == kNoCharClass); widechar first = current(); @@ -486,13 +1081,20 @@ RegExpParser::ParseClassAtom(char16_t* char_class, CharacterRange* char_r case kEndMarker: return ReportError(JSMSG_ESCAPE_AT_END_OF_REGEXP); default: - widechar c = ParseClassCharacterEscape(); - *char_range = CharacterRange::Singleton(c); + if (!ParseClassCharacterEscape(value)) + return false; return true; } } else { + if (unicode_) { + char16_t lead, trail; + if (ParseRawSurrogatePair(&lead, &trail)) { + *value = unicode::UTF16Decode(lead, trail); + return true; + } + } Advance(); - *char_range = CharacterRange::Singleton(first); + *value = first; return true; } } @@ -673,6 +1275,120 @@ RegExpParser::ParsePattern() return result; } +static inline RegExpTree* +CaseFoldingSurrogatePairAtom(LifoAlloc* alloc, char16_t lead, char16_t trail, int32_t diff) +{ + RegExpBuilder* builder = alloc->newInfallible(alloc); + + builder->AddCharacter(lead); + CharacterRangeVector* ranges = alloc->newInfallible(*alloc); + ranges->append(CharacterRange::Range(trail, trail)); + ranges->append(CharacterRange::Range(trail + diff, trail + diff)); + builder->AddAtom(alloc->newInfallible(ranges, false)); + + return builder->ToRegExp(); +} + +static inline RegExpTree* +SurrogatePairAtom(LifoAlloc* alloc, char16_t lead, char16_t trail, bool ignore_case) +{ + if (ignore_case) { +#define CALL_ATOM(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF) \ + if (lead == LEAD &&trail >= TRAIL_FROM && trail <= TRAIL_TO) \ + return CaseFoldingSurrogatePairAtom(alloc, lead, trail, DIFF); + FOR_EACH_NON_BMP_CASE_FOLDING(CALL_ATOM) +#undef CALL_ATOM + } + + RegExpBuilder* builder = alloc->newInfallible(alloc); + builder->AddCharacter(lead); + builder->AddCharacter(trail); + return builder->ToRegExp(); +} + +static inline RegExpTree* +LeadSurrogateAtom(LifoAlloc* alloc, char16_t value) +{ + RegExpBuilder* builder = alloc->newInfallible(alloc); + builder->AddCharacter(value); + builder->AddAtom(NegativeLookahead(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + return builder->ToRegExp(); +} + +static inline RegExpTree* +TrailSurrogateAtom(LifoAlloc* alloc, char16_t value) +{ + RegExpBuilder* builder = alloc->newInfallible(alloc); + builder->AddAssertion(alloc->newInfallible( + RegExpAssertion::NOT_AFTER_LEAD_SURROGATE)); + builder->AddCharacter(value); + return builder->ToRegExp(); +} + +static inline RegExpTree* +UnicodeEverythingAtom(LifoAlloc* alloc) +{ + RegExpBuilder* builder = alloc->newInfallible(alloc); + + // everything except \x0a, \x0d, \u2028 and \u2029 + + CharacterRangeVector* ranges = alloc->newInfallible(*alloc); + ranges->append(CharacterRange::Range(0x0, 0x09)); + ranges->append(CharacterRange::Range(0x0b, 0x0c)); + ranges->append(CharacterRange::Range(0x0e, 0x2027)); + ranges->append(CharacterRange::Range(0x202A, unicode::LeadSurrogateMin - 1)); + ranges->append(CharacterRange::Range(unicode::TrailSurrogateMax + 1, unicode::UTF16Max)); + builder->AddAtom(alloc->newInfallible(ranges, false)); + + builder->NewAlternative(); + + builder->AddAtom(RangeAtom(alloc, unicode::LeadSurrogateMin, unicode::LeadSurrogateMax)); + builder->AddAtom(NegativeLookahead(alloc, unicode::TrailSurrogateMin, + unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddAssertion(alloc->newInfallible( + RegExpAssertion::NOT_AFTER_LEAD_SURROGATE)); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, unicode::TrailSurrogateMax)); + + builder->NewAlternative(); + + builder->AddAtom(RangeAtom(alloc, unicode::LeadSurrogateMin, unicode::LeadSurrogateMax)); + builder->AddAtom(RangeAtom(alloc, unicode::TrailSurrogateMin, unicode::TrailSurrogateMax)); + + return builder->ToRegExp(); +} + +RegExpTree* +UnicodeCharacterClassEscapeAtom(LifoAlloc* alloc, char16_t char_class, bool ignore_case) +{ + CharacterRangeVector* ranges = alloc->newInfallible(*alloc); + CharacterRangeVector* lead_ranges = alloc->newInfallible(*alloc); + CharacterRangeVector* trail_ranges = alloc->newInfallible(*alloc); + WideCharRangeVector* wide_ranges = alloc->newInfallible(*alloc); + AddCharOrEscapeUnicode(alloc, ranges, lead_ranges, trail_ranges, wide_ranges, char_class, 0, + ignore_case); + + return UnicodeRangesAtom(alloc, ranges, lead_ranges, trail_ranges, wide_ranges, false, false); +} + +static inline RegExpTree* +UnicodeBackReferenceAtom(LifoAlloc* alloc, RegExpTree* atom) +{ + // If a back reference has a standalone lead surrogate as its last + // character, then that lead surrogate shouldn't match lead surrogates that + // are paired with a corresponding trail surrogate. + RegExpBuilder* builder = alloc->newInfallible(alloc); + + builder->AddAtom(atom); + builder->AddAssertion(alloc->newInfallible( + RegExpAssertion::NOT_IN_SURROGATE_PAIR)); + + return builder->ToRegExp(); +} + // Disjunction :: // Alternative // Alternative | Disjunction @@ -736,6 +1452,8 @@ RegExpParser::ParseDisjunction() capture_index); } builder->AddAtom(body); + if (unicode_ && (group_type == POSITIVE_LOOKAHEAD || group_type == NEGATIVE_LOOKAHEAD)) + continue; // For compatability with JSC and ES3, we allow quantifiers after // lookaheads, and break in all cases. break; @@ -770,6 +1488,10 @@ RegExpParser::ParseDisjunction() case '.': { Advance(); // everything except \x0a, \x0d, \u2028 and \u2029 + if (unicode_) { + builder->AddAtom(UnicodeEverythingAtom(alloc)); + break; + } CharacterRangeVector* ranges = alloc->newInfallible(*alloc); CharacterRange::AddClassEscape(alloc, '.', ranges); RegExpTree* atom = alloc->newInfallible(ranges, false); @@ -833,12 +1555,24 @@ RegExpParser::ParseDisjunction() // // CharacterClassEscape :: one of // d D s S w W - case 'd': case 'D': case 's': case 'S': case 'w': case 'W': { + case 'D': case 'S': case 'W': + if (unicode_) { + Advance(); + builder->AddAtom(UnicodeCharacterClassEscapeAtom(alloc, current(), + ignore_case_)); + Advance(); + break; + } + // Fall through + case 'd': case 's': case 'w': { widechar c = Next(); Advance(2); CharacterRangeVector* ranges = alloc->newInfallible(*alloc); - CharacterRange::AddClassEscape(alloc, c, ranges); + if (unicode_) + CharacterRange::AddClassEscapeUnicode(alloc, c, ranges, ignore_case_); + else + CharacterRange::AddClassEscape(alloc, c, ranges); RegExpTree* atom = alloc->newInfallible(ranges, false); builder->AddAtom(atom); break; @@ -856,9 +1590,14 @@ RegExpParser::ParseDisjunction() break; } RegExpTree* atom = alloc->newInfallible(capture); - builder->AddAtom(atom); + if (unicode_) + builder->AddAtom(UnicodeBackReferenceAtom(alloc, atom)); + else + builder->AddAtom(atom); break; } + if (unicode_) + return ReportError(JSMSG_BACK_REF_OUT_OF_RANGE); widechar first_digit = Next(); if (first_digit == '8' || first_digit == '9') { // Treat as identity escape @@ -869,6 +1608,14 @@ RegExpParser::ParseDisjunction() } // FALLTHROUGH case '0': { + if (unicode_) { + Advance(2); + if (IsDecimalDigit(current())) + return ReportError(JSMSG_INVALID_DECIMAL_ESCAPE); + builder->AddCharacter(0); + break; + } + Advance(); size_t octal = ParseOctalLiteral(); builder->AddCharacter(octal); @@ -903,6 +1650,8 @@ RegExpParser::ParseDisjunction() // Convert lower case letters to uppercase. widechar letter = controlLetter & ~('a' ^ 'A'); if (letter < 'A' || 'Z' < letter) { + if (unicode_) + return ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); // controlLetter is not in range 'A'-'Z' or 'a'-'z'. // This is outside the specification. We match JSC in // reading the backslash as a literal character instead @@ -920,6 +1669,8 @@ RegExpParser::ParseDisjunction() if (ParseHexEscape(2, &value)) { builder->AddCharacter(value); } else { + if (unicode_) + return ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); builder->AddCharacter('x'); } break; @@ -927,6 +1678,41 @@ RegExpParser::ParseDisjunction() case 'u': { Advance(2); size_t value; + if (unicode_) { + if (current() == '{') { + if (!ParseBracedHexEscape(&value)) + return nullptr; + if (unicode::IsLeadSurrogate(value)) { + builder->AddAtom(LeadSurrogateAtom(alloc, value)); + } else if (unicode::IsTrailSurrogate(value)) { + builder->AddAtom(TrailSurrogateAtom(alloc, value)); + } else if (value >= unicode::NonBMPMin) { + size_t lead, trail; + unicode::UTF16Encode(value, &lead, &trail); + builder->AddAtom(SurrogatePairAtom(alloc, lead, trail, + ignore_case_)); + } else { + builder->AddCharacter(value); + } + } else if (ParseHexEscape(4, &value)) { + if (unicode::IsLeadSurrogate(value)) { + size_t trail; + if (ParseTrailSurrogate(&trail)) { + builder->AddAtom(SurrogatePairAtom(alloc, value, trail, + ignore_case_)); + } else { + builder->AddAtom(LeadSurrogateAtom(alloc, value)); + } + } else if (unicode::IsTrailSurrogate(value)) { + builder->AddAtom(TrailSurrogateAtom(alloc, value)); + } else { + builder->AddCharacter(value); + } + } else { + return ReportError(JSMSG_INVALID_UNICODE_ESCAPE); + } + break; + } if (ParseHexEscape(4, &value)) { builder->AddCharacter(value); } else { @@ -936,18 +1722,42 @@ RegExpParser::ParseDisjunction() } default: // Identity escape. + if (unicode_ && !IsSyntaxCharacter(Next())) + return ReportError(JSMSG_INVALID_IDENTITY_ESCAPE); builder->AddCharacter(Next()); Advance(2); break; } break; case '{': { + if (unicode_) + return ReportError(JSMSG_RAW_BRACE_IN_REGEP); int dummy; if (ParseIntervalQuantifier(&dummy, &dummy)) return ReportError(JSMSG_NOTHING_TO_REPEAT); // fallthrough } default: + if (unicode_) { + char16_t lead, trail; + if (ParseRawSurrogatePair(&lead, &trail)) { + builder->AddAtom(SurrogatePairAtom(alloc, lead, trail, ignore_case_)); + } else { + widechar c = current(); + if (unicode::IsLeadSurrogate(c)) + builder->AddAtom(LeadSurrogateAtom(alloc, c)); + else if (unicode::IsTrailSurrogate(c)) + builder->AddAtom(TrailSurrogateAtom(alloc, c)); + else if (c == ']') + return ReportError(JSMSG_RAW_BRACKET_IN_REGEP); + else if (c == '}') + return ReportError(JSMSG_RAW_BRACE_IN_REGEP); + else + builder->AddCharacter(c); + Advance(); + } + break; + } builder->AddCharacter(current()); Advance(); break; @@ -1002,7 +1812,8 @@ template class irregexp::RegExpParser; template static bool ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, size_t length, - bool multiline, bool match_only, RegExpCompileData* data) + bool multiline, bool match_only, bool unicode, bool ignore_case, + RegExpCompileData* data) { if (match_only) { // Try to strip a leading '.*' from the RegExp, but only if it is not @@ -1025,7 +1836,7 @@ ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, si } } - RegExpParser parser(ts, &alloc, chars, chars + length, multiline); + RegExpParser parser(ts, &alloc, chars, chars + length, multiline, unicode, ignore_case); data->tree = parser.ParsePattern(); if (!data->tree) return false; @@ -1038,32 +1849,34 @@ ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, si bool irregexp::ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str, - bool multiline, bool match_only, + bool multiline, bool match_only, bool unicode, bool ignore_case, RegExpCompileData* data) { JS::AutoCheckCannotGC nogc; return str->hasLatin1Chars() ? ::ParsePattern(ts, alloc, str->latin1Chars(nogc), str->length(), - multiline, match_only, data) + multiline, match_only, unicode, ignore_case, data) : ::ParsePattern(ts, alloc, str->twoByteChars(nogc), str->length(), - multiline, match_only, data); + multiline, match_only, unicode, ignore_case, data); } template static bool -ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, size_t length) +ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, const CharT* chars, size_t length, + bool unicode) { LifoAllocScope scope(&alloc); - RegExpParser parser(ts, &alloc, chars, chars + length, false); + RegExpParser parser(ts, &alloc, chars, chars + length, false, unicode, false); return parser.ParsePattern() != nullptr; } bool -irregexp::ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str) +irregexp::ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str, + bool unicode) { JS::AutoCheckCannotGC nogc; return str->hasLatin1Chars() - ? ::ParsePatternSyntax(ts, alloc, str->latin1Chars(nogc), str->length()) - : ::ParsePatternSyntax(ts, alloc, str->twoByteChars(nogc), str->length()); + ? ::ParsePatternSyntax(ts, alloc, str->latin1Chars(nogc), str->length(), unicode) + : ::ParsePatternSyntax(ts, alloc, str->twoByteChars(nogc), str->length(), unicode); } diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h index e36a47f750..34d0620d6c 100644 --- a/js/src/irregexp/RegExpParser.h +++ b/js/src/irregexp/RegExpParser.h @@ -43,11 +43,12 @@ namespace irregexp { bool ParsePattern(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str, - bool multiline, bool match_only, + bool multiline, bool match_only, bool unicode, bool ignore_case, RegExpCompileData* data); bool -ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str); +ParsePatternSyntax(frontend::TokenStream& ts, LifoAlloc& alloc, JSAtom* str, + bool unicode); // A BufferedVector is an automatically growing list, just like (and backed // by) a Vector, that is optimized for the case of adding and removing @@ -174,7 +175,8 @@ class RegExpParser { public: RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc, - const CharT* chars, const CharT* end, bool multiline_mode); + const CharT* chars, const CharT* end, bool multiline_mode, bool unicode, + bool ignore_case); RegExpTree* ParsePattern(); RegExpTree* ParseDisjunction(); @@ -184,14 +186,20 @@ class RegExpParser // out parameters. bool ParseIntervalQuantifier(int* min_out, int* max_out); - // Parses and returns a single escaped character. The character - // must not be 'b' or 'B' since they are usually handled specially. - widechar ParseClassCharacterEscape(); + // Tries to parse the input as a single escaped character. If successful + // it stores the result in the output parameter and returns true. + // Otherwise it throws an error and returns false. The character must not + // be 'b' or 'B' since they are usually handled specially. + bool ParseClassCharacterEscape(widechar* code); // Checks whether the following is a length-digit hexadecimal number, // and sets the value if it is. bool ParseHexEscape(int length, size_t* value); + bool ParseBracedHexEscape(size_t* value); + bool ParseTrailSurrogate(size_t* value); + bool ParseRawSurrogatePair(char16_t* lead, char16_t* trail); + size_t ParseOctalLiteral(); // Tries to parse the input as a back reference. If successful it @@ -200,7 +208,7 @@ class RegExpParser // can be reparsed. bool ParseBackReferenceIndex(int* index_out); - bool ParseClassAtom(char16_t* char_class, CharacterRange* char_range); + bool ParseClassAtom(char16_t* char_class, widechar *value); RegExpTree* ReportError(unsigned errorNumber); void Advance(); void Advance(int dist) { @@ -288,6 +296,8 @@ class RegExpParser int capture_count_; bool has_more_; bool multiline_; + bool unicode_; + bool ignore_case_; bool simple_; bool contains_anchor_; bool is_scanned_for_captures_; diff --git a/js/src/jit-test/tests/atomics/basic-tests.js b/js/src/jit-test/tests/atomics/basic-tests.js index 8d8aea6a91..2ccbaef800 100644 --- a/js/src/jit-test/tests/atomics/basic-tests.js +++ b/js/src/jit-test/tests/atomics/basic-tests.js @@ -409,6 +409,19 @@ function testIsLockFree() { assertEq(Atomics.isLockFree(12), false); } +function testUint8Clamped(sab) { + var ta = new Uint8ClampedArray(sab); + var thrown = false; + try { + CLONE(testMethod)(ta, 0); + } + catch (e) { + thrown = true; + assertEq(e instanceof TypeError, true); + } + assertEq(thrown, true); +} + function isLittleEndian() { var xxx = new ArrayBuffer(2); var xxa = new Int16Array(xxx); @@ -440,7 +453,6 @@ function runTests() { // Test that invoking as Atomics.whatever() works, on correct arguments. CLONE(testMethod)(new Int8Array(sab), 0, 42, 4095); CLONE(testMethod)(new Uint8Array(sab), 0, 42, 4095); - CLONE(testMethod)(new Uint8ClampedArray(sab), 0, 42, 4095); CLONE(testMethod)(new Int16Array(sab), 0, 42, 2047); CLONE(testMethod)(new Uint16Array(sab), 0, 42, 2047); CLONE(testMethod)(new Int32Array(sab), 0, 42, 1023); @@ -460,7 +472,6 @@ function runTests() { CLONE(testFunction)(new Int8Array(sab), 0, 42, 4095); CLONE(testFunction)(new Uint8Array(sab), 0, 42, 4095); - CLONE(testFunction)(new Uint8ClampedArray(sab), 0, 42, 4095); CLONE(testFunction)(new Int16Array(sab), 0, 42, 2047); CLONE(testFunction)(new Uint16Array(sab), 0, 42, 2047); CLONE(testFunction)(new Int32Array(sab), 0, 42, 1023); @@ -497,6 +508,9 @@ function runTests() { testInt16Extremes(new Int16Array(sab)); testUint32(new Uint32Array(sab)); + // Test that Uint8ClampedArray is not accepted. + testUint8Clamped(sab); + // Misc ad-hoc tests adHocExchange(); diff --git a/js/src/jit-test/tests/basic/regexp-multiline-warning.js b/js/src/jit-test/tests/basic/regexp-multiline-warning.js new file mode 100644 index 0000000000..91760f86f6 --- /dev/null +++ b/js/src/jit-test/tests/basic/regexp-multiline-warning.js @@ -0,0 +1,23 @@ +// RegExp.multiline access should be warned once and only once. + +function testWarn(code) { + enableLastWarning(); + var g = newGlobal(); + g.code = code; + g.eval('eval(code)'); + var warning = getLastWarning(); + assertEq(warning !== null, true, "warning should be caught for " + code); + assertEq(warning.name, "SyntaxError"); + + clearLastWarning(); + g.eval('eval(code)'); + warning = getLastWarning(); + assertEq(warning, null, "warning should not be caught for 2nd ocurrence"); + disableLastWarning(); +} + +testWarn("var a = RegExp.multiline;"); +testWarn("RegExp.multiline = true;"); + +testWarn("var a = RegExp['$*'];"); +testWarn("RegExp['$*'] = true;"); diff --git a/js/src/jit-test/tests/gc/bug-1231386.js b/js/src/jit-test/tests/gc/bug-1231386.js new file mode 100644 index 0000000000..35cfc7a913 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1231386.js @@ -0,0 +1,19 @@ +if (!('oomTest' in this)) + quit(); + +function f1() {} +function f2() {} +r = [function() {}, function() {}, [], function() {}, f1, function() {}, f2]; +l = [0]; +function f3() { + return { + a: 0 + }; +} +var x = f3(); +var h = newGlobal(); +var dbg = new Debugger; +dbg.addDebuggee(h); +oomTest(() => getBacktrace({ + thisprops: gc() +})); diff --git a/js/src/jit-test/tests/ion/lexical-check-6.js b/js/src/jit-test/tests/ion/lexical-check-6.js new file mode 100644 index 0000000000..5af7686aee --- /dev/null +++ b/js/src/jit-test/tests/ion/lexical-check-6.js @@ -0,0 +1,39 @@ +// This function uses UCE to test when the if branch is removed by +// IonMonkey. Some optimization such as Scalar Replacement are able to remove +// the scope chain, which can cause issues when the scope chain properties are +// not initialized properly. +var uceFault = function (i) { + if (i % 1500 == 0) { + uceFault = function (i) { return i % 1500 == 0; }; + } + return false; +}; + +function f(i) { + if (uceFault(i) || uceFault(i)) + g(); + const x = 42; + function g() { + return x; + } + return g; +} + +function loop() { + for (; i < 4000; i++) + assertEq(f(i)(), 42); +} + +var caught = 0; +var i = 1; +while (i < 4000) { + try { + loop(); + } catch(e) { + assertEq(e instanceof ReferenceError, true); + assertEq(i == 1500 || i == 3000, true); + caught += 1; + i++; + } +} +assertEq(caught, 2); diff --git a/js/src/jit-test/tests/modules/eval-module-oom.js b/js/src/jit-test/tests/modules/eval-module-oom.js new file mode 100644 index 0000000000..a1bd9db2a9 --- /dev/null +++ b/js/src/jit-test/tests/modules/eval-module-oom.js @@ -0,0 +1,26 @@ +// OOM tests for module parsing. + +if (!('oomTest' in this)) + quit(); + +load(libdir + "dummyModuleResolveHook.js"); + +const sa = +`export default 20; + export let a = 22; + export function f(x, y) { return x + y } +`; + +const sb = +`import x from "a"; + import { a as y } from "a"; + import * as ns from "a"; + ns.f(x, y); +`; + +oomTest(() => { + let a = moduleRepo['a'] = parseModule(sa); + let b = moduleRepo['b'] = parseModule(sb); + b.declarationInstantiation(); + assertEq(b.evaluation(), 42); +}); diff --git a/js/src/jit-test/tests/tracelogger/bug1231170.js b/js/src/jit-test/tests/tracelogger/bug1231170.js new file mode 100644 index 0000000000..023e93eb6b --- /dev/null +++ b/js/src/jit-test/tests/tracelogger/bug1231170.js @@ -0,0 +1,3 @@ +var du = new Debugger(); +if (typeof du.drainTraceLogger === "function") + du.drainTraceLogger(); diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 25127b71c4..c20fb31b8a 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -1006,12 +1006,12 @@ BacktrackingAllocator::tryMergeReusedRegister(VirtualRegister& def, VirtualRegis if (iter->pos <= inputOf(def.ins())) continue; - LUse* use = iter->use; + LUse* use = iter->use(); if (FindReusingDefinition(insData[iter->pos], use)) { def.setMustCopyInput(); return true; } - if (use->policy() != LUse::ANY && use->policy() != LUse::KEEPALIVE) { + if (iter->usePolicy() != LUse::ANY && iter->usePolicy() != LUse::KEEPALIVE) { def.setMustCopyInput(); return true; } @@ -1134,6 +1134,9 @@ BacktrackingAllocator::mergeAndQueueRegisters() LiveRange* range = LiveRange::get(*iter); LiveBundle* bundle = range->bundle(); if (range == bundle->firstRange()) { + if (!alloc().ensureBallast()) + return false; + SpillSet* spill = SpillSet::New(alloc()); if (!spill) return false; @@ -1225,7 +1228,7 @@ BacktrackingAllocator::processBundle(LiveBundle* bundle) { if (JitSpewEnabled(JitSpew_RegAlloc)) { JitSpew(JitSpew_RegAlloc, "Allocating %s [priority %lu] [weight %lu]", - bundle->toString(), computePriority(bundle), computeSpillWeight(bundle)); + bundle->toString().get(), computePriority(bundle), computeSpillWeight(bundle)); } // A bundle can be processed by doing any of the following: @@ -1318,7 +1321,7 @@ BacktrackingAllocator::computeRequirement(LiveBundle* bundle, if (policy == LDefinition::FIXED) { // Fixed policies get a FIXED requirement. JitSpew(JitSpew_RegAlloc, " Requirement %s, fixed by definition", - reg.def()->output()->toString()); + reg.def()->output()->toString().get()); if (!requirement->merge(Requirement(*reg.def()->output()))) return false; } else if (reg.ins()->isPhi()) { @@ -1333,9 +1336,9 @@ BacktrackingAllocator::computeRequirement(LiveBundle* bundle, // Search uses for requirements. for (UsePositionIterator iter = range->usesBegin(); iter; iter++) { - LUse::Policy policy = iter->use->policy(); + LUse::Policy policy = iter->usePolicy(); if (policy == LUse::FIXED) { - AnyRegister required = GetFixedRegister(reg.def(), iter->use); + AnyRegister required = GetFixedRegister(reg.def(), iter->use()); JitSpew(JitSpew_RegAlloc, " Requirement %s, due to use at %u", required.name(), iter->pos.bits()); @@ -1394,7 +1397,7 @@ BacktrackingAllocator::tryAllocateRegister(PhysicalRegister& r, LiveBundle* bund return false; } else { JitSpew(JitSpew_RegAlloc, " %s collides with fixed use %s", - rAlias.reg.name(), existing->toString()); + rAlias.reg.name(), existing->toString().get()); *pfixed = true; return true; } @@ -1413,13 +1416,13 @@ BacktrackingAllocator::tryAllocateRegister(PhysicalRegister& r, LiveBundle* bund if (aliasedConflicting.length() == 1) { LiveBundle* existing = aliasedConflicting[0]; JitSpew(JitSpew_RegAlloc, " %s collides with %s [weight %lu]", - r.reg.name(), existing->toString(), computeSpillWeight(existing)); + r.reg.name(), existing->toString().get(), computeSpillWeight(existing)); } else { JitSpew(JitSpew_RegAlloc, " %s collides with the following", r.reg.name()); for (size_t i = 0; i < aliasedConflicting.length(); i++) { LiveBundle* existing = aliasedConflicting[i]; JitSpew(JitSpew_RegAlloc, " %s [weight %lu]", - existing->toString(), computeSpillWeight(existing)); + existing->toString().get(), computeSpillWeight(existing)); } } } @@ -1456,7 +1459,7 @@ BacktrackingAllocator::evictBundle(LiveBundle* bundle) { if (JitSpewEnabled(JitSpew_RegAlloc)) { JitSpew(JitSpew_RegAlloc, " Evicting %s [priority %lu] [weight %lu]", - bundle->toString(), computePriority(bundle), computeSpillWeight(bundle)); + bundle->toString().get(), computePriority(bundle), computeSpillWeight(bundle)); } AnyRegister reg(bundle->allocation().toRegister()); @@ -1479,9 +1482,9 @@ BacktrackingAllocator::splitAndRequeueBundles(LiveBundle* bundle, const LiveBundleVector& newBundles) { if (JitSpewEnabled(JitSpew_RegAlloc)) { - JitSpew(JitSpew_RegAlloc, " splitting bundle %s into:", bundle->toString()); + JitSpew(JitSpew_RegAlloc, " splitting bundle %s into:", bundle->toString().get()); for (size_t i = 0; i < newBundles.length(); i++) - JitSpew(JitSpew_RegAlloc, " %s", newBundles[i]->toString()); + JitSpew(JitSpew_RegAlloc, " %s", newBundles[i]->toString().get()); } // Remove all ranges in the old bundle from their register's list. @@ -1722,6 +1725,9 @@ BacktrackingAllocator::resolveControlFlow() if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg loop)")) return false; + if (!alloc().ensureBallast()) + return false; + for (LiveRange::RegisterLinkIterator iter = reg.rangesBegin(); iter; ) { LiveRange* range = LiveRange::get(*iter); @@ -1858,11 +1864,11 @@ BacktrackingAllocator::isReusedInput(LUse* use, LNode* ins, bool considerCopy) } bool -BacktrackingAllocator::isRegisterUse(LUse* use, LNode* ins, bool considerCopy) +BacktrackingAllocator::isRegisterUse(UsePosition* use, LNode* ins, bool considerCopy) { - switch (use->policy()) { + switch (use->usePolicy()) { case LUse::ANY: - return isReusedInput(use, ins, considerCopy); + return isReusedInput(use->use(), ins, considerCopy); case LUse::REGISTER: case LUse::FIXED: @@ -1917,7 +1923,7 @@ BacktrackingAllocator::reifyAllocations() } for (UsePositionIterator iter(range->usesBegin()); iter; iter++) { - LAllocation* alloc = iter->use; + LAllocation* alloc = iter->use(); *alloc = range->bundle()->allocation(); // For any uses which feed into MUST_REUSE_INPUT definitions, @@ -2213,69 +2219,55 @@ BacktrackingAllocator::annotateMoveGroups() // Debugging methods ///////////////////////////////////////////////////////////////////// -#ifdef DEBUG +#ifdef JS_JITSPEW -const char* +UniqueChars LiveRange::toString() const { - // Not reentrant! - static char buf[2000]; + AutoEnterOOMUnsafeRegion oomUnsafe; - char* cursor = buf; - char* end = cursor + sizeof(buf); + char* buf = JS_smprintf("v%u [%u,%u)", hasVreg() ? vreg() : 0, from().bits(), to().bits()); - int n = JS_snprintf(cursor, end - cursor, "v%u [%u,%u)", - hasVreg() ? vreg() : 0, from().bits(), to().bits()); - if (n < 0) MOZ_CRASH(); - cursor += n; + if (buf && bundle() && !bundle()->allocation().isBogus()) + buf = JS_sprintf_append(buf, " %s", bundle()->allocation().toString().get()); - if (bundle() && !bundle()->allocation().isBogus()) { - n = JS_snprintf(cursor, end - cursor, " %s", bundle()->allocation().toString()); - if (n < 0) MOZ_CRASH(); - cursor += n; - } + if (buf && hasDefinition()) + buf = JS_sprintf_append(buf, " (def)"); - if (hasDefinition()) { - n = JS_snprintf(cursor, end - cursor, " (def)"); - if (n < 0) MOZ_CRASH(); - cursor += n; - } + for (UsePositionIterator iter = usesBegin(); buf && iter; iter++) + buf = JS_sprintf_append(buf, " %s@%u", iter->use()->toString().get(), iter->pos.bits()); - for (UsePositionIterator iter = usesBegin(); iter; iter++) { - n = JS_snprintf(cursor, end - cursor, " %s@%u", iter->use->toString(), iter->pos.bits()); - if (n < 0) MOZ_CRASH(); - cursor += n; - } + if (!buf) + oomUnsafe.crash("LiveRange::toString()"); - return buf; + return UniqueChars(buf); } -const char* +UniqueChars LiveBundle::toString() const { - // Not reentrant! - static char buf[2000]; + AutoEnterOOMUnsafeRegion oomUnsafe; - char* cursor = buf; - char* end = cursor + sizeof(buf); + char *buf = JS_smprintf(""); - for (LiveRange::BundleLinkIterator iter = rangesBegin(); iter; iter++) { - int n = JS_snprintf(cursor, end - cursor, "%s %s", - (iter == rangesBegin()) ? "" : " ##", - LiveRange::get(*iter)->toString()); - if (n < 0) MOZ_CRASH(); - cursor += n; + for (LiveRange::BundleLinkIterator iter = rangesBegin(); buf && iter; iter++) { + buf = JS_smprintf(buf, "%s %s", + (iter == rangesBegin()) ? "" : " ##", + LiveRange::get(*iter)->toString().get()); } - return buf; + if (!buf) + oomUnsafe.crash("LiveBundle::toString()"); + + return UniqueChars(buf); } -#endif // DEBUG +#endif // JS_JITSPEW void BacktrackingAllocator::dumpVregs() { -#ifdef DEBUG +#ifdef JS_JITSPEW MOZ_ASSERT(!vregs[0u].hasRanges()); fprintf(stderr, "Live ranges by virtual register:\n"); @@ -2286,7 +2278,7 @@ BacktrackingAllocator::dumpVregs() for (LiveRange::RegisterLinkIterator iter = reg.rangesBegin(); iter; iter++) { if (iter != reg.rangesBegin()) fprintf(stderr, " ## "); - fprintf(stderr, "%s", LiveRange::get(*iter)->toString()); + fprintf(stderr, "%s", LiveRange::get(*iter)->toString().get()); } fprintf(stderr, "\n"); } @@ -2303,7 +2295,7 @@ BacktrackingAllocator::dumpVregs() for (LiveRange::BundleLinkIterator iter = bundle->rangesBegin(); iter; iter++) { if (iter != bundle->rangesBegin()) fprintf(stderr, " ## "); - fprintf(stderr, "%s", LiveRange::get(*iter)->toString()); + fprintf(stderr, "%s", LiveRange::get(*iter)->toString().get()); } fprintf(stderr, "\n"); } @@ -2315,12 +2307,12 @@ BacktrackingAllocator::dumpVregs() void BacktrackingAllocator::dumpFixedRanges() { -#ifdef DEBUG - fprintf(stderr, "Live ranges by physical register: %s\n", callRanges->toString()); -#endif // DEBUG +#ifdef JS_JITSPEW + fprintf(stderr, "Live ranges by physical register: %s\n", callRanges->toString().get()); +#endif // JS_JITSPEW } -#ifdef DEBUG +#ifdef JS_JITSPEW struct BacktrackingAllocator::PrintLiveRange { bool& first_; @@ -2333,7 +2325,7 @@ struct BacktrackingAllocator::PrintLiveRange first_ = false; else fprintf(stderr, " /"); - fprintf(stderr, " %s", range->toString()); + fprintf(stderr, " %s", range->toString().get()); } }; #endif @@ -2341,7 +2333,7 @@ struct BacktrackingAllocator::PrintLiveRange void BacktrackingAllocator::dumpAllocations() { -#ifdef DEBUG +#ifdef JS_JITSPEW fprintf(stderr, "Allocations:\n"); dumpVregs(); @@ -2358,7 +2350,7 @@ BacktrackingAllocator::dumpAllocations() } fprintf(stderr, "\n"); -#endif // DEBUG +#endif // JS_JITSPEW } /////////////////////////////////////////////////////////////////////////////// @@ -2395,7 +2387,7 @@ BacktrackingAllocator::minimalUse(LiveRange* range, UsePosition* use) // Whether this is a minimal range capturing |use|. LNode* ins = insData[use->pos]; return (range->from() == inputOf(ins)) && - (range->to() == (use->use->usedAtStart() ? outputOf(ins) : outputOf(ins).next())); + (range->to() == (use->use()->usedAtStart() ? outputOf(ins) : outputOf(ins).next())); } bool @@ -2426,9 +2418,8 @@ BacktrackingAllocator::minimalBundle(LiveBundle* bundle, bool* pfixed) for (UsePositionIterator iter = range->usesBegin(); iter; iter++) { if (iter != range->usesBegin()) multiple = true; - LUse* use = iter->use; - switch (use->policy()) { + switch (iter->usePolicy()) { case LUse::FIXED: if (fixed) return false; @@ -2483,9 +2474,7 @@ BacktrackingAllocator::computeSpillWeight(LiveBundle* bundle) } for (UsePositionIterator iter = range->usesBegin(); iter; iter++) { - LUse* use = iter->use; - - switch (use->policy()) { + switch (iter->usePolicy()) { case LUse::ANY: usesTotal += 1000; break; @@ -2560,7 +2549,7 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveBundle* bundle, bool* success) return true; } - JitSpew(JitSpew_RegAlloc, " split across hot range %s", hotRange->toString()); + JitSpew(JitSpew_RegAlloc, " split across hot range %s", hotRange->toString().get()); // Tweak the splitting method when compiling asm.js code to look at actual // uses within the hot/cold code. This heuristic is in place as the below @@ -2677,7 +2666,6 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveBundle* bundle, LiveBund } for (UsePositionIterator iter(range->usesBegin()); iter; iter++) { - LUse* use = iter->use; LNode* ins = insData[iter->pos]; // Uses in the bundle should be sorted. @@ -2685,7 +2673,7 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveBundle* bundle, LiveBund lastUse = inputOf(ins); if (!conflict || outputOf(ins) < conflict->firstRange()->from()) { - if (isRegisterUse(use, ins, /* considerCopy = */ true)) { + if (isRegisterUse(*iter, ins, /* considerCopy = */ true)) { lastRegisterFrom = inputOf(ins); lastRegisterTo = iter->pos.next(); } @@ -2744,11 +2732,10 @@ BacktrackingAllocator::trySplitBeforeFirstRegisterUse(LiveBundle* bundle, LiveBu LiveRange* range = LiveRange::get(*iter); for (UsePositionIterator iter(range->usesBegin()); iter; iter++) { - LUse* use = iter->use; LNode* ins = insData[iter->pos]; if (!conflict || outputOf(ins) >= conflictEnd) { - if (isRegisterUse(use, ins, /* considerCopy = */ true)) { + if (isRegisterUse(*iter, ins, /* considerCopy = */ true)) { firstRegisterFrom = inputOf(ins); break; } @@ -2774,7 +2761,7 @@ BacktrackingAllocator::trySplitBeforeFirstRegisterUse(LiveBundle* bundle, LiveBu // When splitting a bundle according to a list of split positions, return // whether a use or range at |pos| should use a different bundle than the last -// position this was called for. +// position this was called for. static bool UseNewBundle(const SplitPositionVector& splitPositions, CodePosition pos, size_t* activeSplitPosition) @@ -2913,7 +2900,7 @@ BacktrackingAllocator::splitAt(LiveBundle* bundle, const SplitPositionVector& sp // finished must be associated with the range for that definition. if (isRegisterDefinition(range) && use->pos <= minimalDefEnd(insData[range->from()])) { activeRange->addUse(use); - } else if (isRegisterUse(use->use, ins)) { + } else if (isRegisterUse(use, ins)) { // Place this register use into a different bundle from the // last one if there are any split points between the two uses. // UseNewBundle always returns true if we are splitting at all @@ -2924,8 +2911,8 @@ BacktrackingAllocator::splitAt(LiveBundle* bundle, const SplitPositionVector& sp if (UseNewBundle(splitPositions, use->pos, &activeSplitPosition) && (!activeRange->hasUses() || activeRange->usesBegin()->pos != use->pos || - activeRange->usesBegin()->use->policy() == LUse::FIXED || - use->use->policy() == LUse::FIXED)) + activeRange->usesBegin()->usePolicy() == LUse::FIXED || + use->usePolicy() == LUse::FIXED)) { activeBundle = LiveBundle::New(alloc(), bundle->spillSet(), spillBundle); if (!newBundles.append(activeBundle)) diff --git a/js/src/jit/BacktrackingAllocator.h b/js/src/jit/BacktrackingAllocator.h index 20df6179c7..0a3af0f333 100644 --- a/js/src/jit/BacktrackingAllocator.h +++ b/js/src/jit/BacktrackingAllocator.h @@ -126,11 +126,38 @@ class Requirement struct UsePosition : public TempObject, public InlineForwardListNode { - LUse* use; + private: + // Packed LUse* with a copy of the LUse::Policy value, in order to avoid + // making cache misses while reaching out to the policy value. + uintptr_t use_; + + void setUse(LUse* use) { + // Assert that we can safely pack the LUse policy in the last 2 bits of + // the LUse pointer. + static_assert((LUse::ANY | LUse::REGISTER | LUse::FIXED | LUse::KEEPALIVE) <= 0x3, + "Cannot pack the LUse::Policy value on 32 bits architectures."); + + // RECOVERED_INPUT is used by snapshots and ignored when building the + // liveness information. Thus we can safely assume that no such value + // would be seen. + MOZ_ASSERT(use->policy() != LUse::RECOVERED_INPUT); + use_ = uintptr_t(use) | (use->policy() & 0x3); + } + + public: CodePosition pos; + LUse* use() const { + return reinterpret_cast(use_ & ~0x3); + } + + LUse::Policy usePolicy() const { + LUse::Policy policy = LUse::Policy(use_ & 0x3); + MOZ_ASSERT(use()->policy() == policy); + return policy; + } + UsePosition(LUse* use, CodePosition pos) : - use(use), pos(pos) { // Verify that the usedAtStart() flag is consistent with the @@ -140,6 +167,7 @@ struct UsePosition : public TempObject, pos.subpos() == (use->usedAtStart() ? CodePosition::INPUT : CodePosition::OUTPUT)); + setUse(use); } }; @@ -316,11 +344,9 @@ class LiveRange : public TempObject hasDefinition_ = true; } - // Return a string describing this range. This is not re-entrant! -#ifdef DEBUG - const char* toString() const; -#else - const char* toString() const { return "???"; } +#ifdef JS_JITSPEW + // Return a string describing this range. + UniqueChars toString() const; #endif // Comparator for use in range splay trees. @@ -439,11 +465,9 @@ class LiveBundle : public TempObject return spillParent_; } - // Return a string describing this bundle. This is not re-entrant! -#ifdef DEBUG - const char* toString() const; -#else - const char* toString() const { return "???"; } +#ifdef JS_JITSPEW + // Return a string describing this bundle. + UniqueChars toString() const; #endif }; @@ -672,7 +696,7 @@ class BacktrackingAllocator : protected RegisterAllocator bool spill(LiveBundle* bundle); bool isReusedInput(LUse* use, LNode* ins, bool considerCopy); - bool isRegisterUse(LUse* use, LNode* ins, bool considerCopy = false); + bool isRegisterUse(UsePosition* use, LNode* ins, bool considerCopy = false); bool isRegisterDefinition(LiveRange* range); bool pickStackSlot(SpillSet* spill); bool insertAllRanges(LiveRangeSet& set, LiveBundle* bundle); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 3615385e4a..2e08057121 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -3588,8 +3588,7 @@ BaselineCompiler::emit_JSOP_RETRVAL() return emitReturn(); } -typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue, - MutableHandleValue); +typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, MutableHandleValue); static const VMFunction ToIdInfo = FunctionInfo(js::ToIdOperation); bool @@ -3605,10 +3604,7 @@ BaselineCompiler::emit_JSOP_TOID() prepareVMCall(); - masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1); - pushArg(R0); - pushArg(R1); pushArg(ImmPtr(pc)); pushArg(ImmGCPtr(script)); @@ -3621,6 +3617,32 @@ BaselineCompiler::emit_JSOP_TOID() return true; } +typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue); +static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo(ThrowObjectCoercible); + +bool +BaselineCompiler::emit_JSOP_CHECKOBJCOERCIBLE() +{ + frame.syncStack(0); + masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0); + + Label fail, done; + + masm.branchTestUndefined(Assembler::Equal, R0, &fail); + masm.branchTestNull(Assembler::NotEqual, R0, &done); + + masm.bind(&fail); + prepareVMCall(); + + pushArg(R0); + + if (!callVM(ThrowObjectCoercibleInfo)) + return false; + + masm.bind(&done); + return true; +} + typedef JSString* (*ToStringFn)(JSContext*, HandleValue); static const VMFunction ToStringInfo = FunctionInfo(ToStringSlow); @@ -4239,3 +4261,22 @@ BaselineCompiler::emit_JSOP_RESUME() return true; } +typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue); +static const VMFunction CheckSelfHostedInfo = FunctionInfo(js::Debug_CheckSelfHosted); + +bool +BaselineCompiler::emit_JSOP_DEBUGCHECKSELFHOSTED() +{ +#ifdef DEBUG + frame.syncStack(0); + + masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0); + + prepareVMCall(); + pushArg(R0); + if (!callVM(CheckSelfHostedInfo)) + return false; +#endif + return true; + +} diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index e249d59e12..e1938ec2ba 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -219,7 +219,9 @@ namespace jit { _(JSOP_INITHIDDENPROP_SETTER) \ _(JSOP_INITHIDDENELEM) \ _(JSOP_INITHIDDENELEM_GETTER) \ - _(JSOP_INITHIDDENELEM_SETTER) + _(JSOP_INITHIDDENELEM_SETTER) \ + _(JSOP_CHECKOBJCOERCIBLE) \ + _(JSOP_DEBUGCHECKSELFHOSTED) class BaselineCompiler : public BaselineCompilerSpecific { diff --git a/js/src/jit/C1Spewer.cpp b/js/src/jit/C1Spewer.cpp index f1df190ca2..4ab3913d8f 100644 --- a/js/src/jit/C1Spewer.cpp +++ b/js/src/jit/C1Spewer.cpp @@ -97,7 +97,7 @@ C1Spewer::spewRanges(GenericPrinter& out, BacktrackingAllocator* regalloc, LNode for (LiveRange::RegisterLinkIterator iter = vreg->rangesBegin(); iter; iter++) { LiveRange* range = LiveRange::get(*iter); out.printf("%d object \"", id); - out.printf("%s", range->bundle()->allocation().toString()); + out.printf("%s", range->bundle()->allocation().toString().get()); out.printf("\" %d -1", id); out.printf(" [%u, %u[", range->from().bits(), range->to().bits()); for (UsePositionIterator usePos(range->usesBegin()); usePos; usePos++) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 19e6b9e81c..8b2353a7d6 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -9063,7 +9063,7 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool) masm.jump(ool->rejoin()); } -typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, HandleValue, +typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue, MutableHandleValue); static const VMFunction ToIdInfo = FunctionInfo(ToIdOperation); @@ -9078,7 +9078,6 @@ CodeGenerator::visitToIdV(LToIdV* lir) OutOfLineCode* ool = oolCallVM(ToIdInfo, lir, ArgList(ImmGCPtr(current->mir()->info().script()), ImmPtr(lir->mir()->resumePoint()->pc()), - ToValue(lir, LToIdV::Object), ToValue(lir, LToIdV::Index)), StoreValueTo(out)); @@ -10371,6 +10370,33 @@ CodeGenerator::visitCheckReturn(LCheckReturn* ins) masm.bind(&noChecks); } +typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue); +static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo(ThrowObjectCoercible); + +void +CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins) +{ + ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue); + Label fail, done; + masm.branchTestNull(Assembler::Equal, checkValue, &fail); + masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done); + masm.bind(&fail); + pushArg(checkValue); + callVM(ThrowObjectCoercibleInfo, ins); + masm.bind(&done); +} + +typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue); +static const VMFunction CheckSelfHostedInfo = FunctionInfo(js::Debug_CheckSelfHosted); + +void +CodeGenerator::visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins) +{ + ValueOperand checkValue = ToValue(ins, LDebugCheckSelfHosted::CheckValue); + pushArg(checkValue); + callVM(CheckSelfHostedInfo, ins); +} + void CodeGenerator::visitRandom(LRandom* ins) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 0576c0cde7..0467cd935b 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -345,6 +345,8 @@ class CodeGenerator : public CodeGeneratorSpecific void visitNewTarget(LNewTarget* ins); void visitArrowNewTarget(LArrowNewTarget* ins); void visitCheckReturn(LCheckReturn* ins); + void visitCheckObjCoercible(LCheckObjCoercible* ins); + void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins); void visitCheckOverRecursed(LCheckOverRecursed* lir); void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 961c6e901c..ea878a7f50 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -3123,17 +3123,17 @@ jit::Invalidate(JSContext* cx, const RecompileInfoVector& invalid, bool resetUse cancelOffThread); } -bool +void jit::IonScript::invalidate(JSContext* cx, bool resetUses, const char* reason) { JitSpew(JitSpew_IonInvalidate, " Invalidate IonScript %p: %s", this, reason); + + // RecompileInfoVector has inline space for at least one element. RecompileInfoVector list; - if (!list.append(recompileInfo())) { - ReportOutOfMemory(cx); - return false; - } + MOZ_RELEASE_ASSERT(list.reserve(1)); + list.infallibleAppend(recompileInfo()); + Invalidate(cx, list, resetUses, true); - return true; } bool @@ -3162,12 +3162,11 @@ jit::Invalidate(JSContext* cx, JSScript* script, bool resetUses, bool cancelOffT js_free(buf); } + // RecompileInfoVector has inline space for at least one element. RecompileInfoVector scripts; MOZ_ASSERT(script->hasIonScript()); - if (!scripts.append(script->ionScript()->recompileInfo())) { - ReportOutOfMemory(cx); - return false; - } + MOZ_RELEASE_ASSERT(scripts.reserve(1)); + scripts.infallibleAppend(script->ionScript()->recompileInfo()); Invalidate(cx, scripts, resetUses, cancelOffThread); return true; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 9027b5ebd4..bafca869db 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2106,6 +2106,22 @@ IonBuilder::inspectOpcode(JSOp op) case JSOP_NEWTARGET: return jsop_newtarget(); + case JSOP_CHECKOBJCOERCIBLE: + return jsop_checkobjcoercible(); + + case JSOP_DEBUGCHECKSELFHOSTED: + { +#ifdef DEBUG + MDebugCheckSelfHosted* check = MDebugCheckSelfHosted::New(alloc(), current->pop()); + current->add(check); + current->push(check); + if (!resumeAfter(check)) + return false; +#endif + return true; + } + + #ifdef DEBUG case JSOP_PUSHBLOCKSCOPE: case JSOP_FRESHENBLOCKSCOPE: @@ -8157,11 +8173,9 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticKey, name, types, /* updateObserved = */ true); - JSObject* singleton = types->maybeSingleton(); - - MIRType knownType = types->getKnownMIRType(); if (barrier == BarrierKind::NoBarrier) { // Try to inline properties holding a known constant object. + JSObject* singleton = types->maybeSingleton(); if (singleton) { if (testSingletonProperty(staticObject, id) == singleton) return pushConstant(ObjectValue(*singleton)); @@ -8171,8 +8185,23 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc Value constantValue; if (property.constant(constraints(), &constantValue)) return pushConstant(constantValue); + } + if (!loadStaticSlot(staticObject, barrier, types, property.maybeTypes()->definiteSlot())) { + *psucceeded = false; + return false; + } + + return true; +} + +bool +IonBuilder::loadStaticSlot(JSObject* staticObject, BarrierKind barrier, TemporaryTypeSet* types, + uint32_t slot) +{ + if (barrier == BarrierKind::NoBarrier) { // Try to inline properties that can only have one value. + MIRType knownType = types->getKnownMIRType(); if (knownType == MIRType_Undefined) return pushConstant(UndefinedValue()); if (knownType == MIRType_Null) @@ -8185,13 +8214,7 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc if (barrier != BarrierKind::NoBarrier) rvalType = MIRType_Value; - if (!loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject), - rvalType, barrier, types)) { - *psucceeded = false; - return false; - } - - return true; + return loadSlot(obj, slot, NumFixedSlots(staticObject), rvalType, barrier, types); } // Whether a write of the given value may need a post-write barrier for GC purposes. @@ -8395,7 +8418,16 @@ IonBuilder::jsop_getimport(PropertyName* name) if (!getStaticName(targetEnv, localName, &emitted)) return false; - MOZ_ASSERT(emitted); + if (!emitted) { + // This can happen if we don't have type information. + TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(targetEnv); + TemporaryTypeSet* types = bytecodeTypes(pc); + BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticKey, + name, types, /* updateObserved = */ true); + + if (!loadStaticSlot(targetEnv, barrier, types, shape->slot())) + return false; + } // In the rare case where this import hasn't been initialized already (we // have an import cycle where modules reference each other's imports), emit @@ -10310,6 +10342,31 @@ IonBuilder::jsop_rest() return true; } +bool +IonBuilder::jsop_checkobjcoercible() +{ + MDefinition* toCheck = current->peek(-1); + + if (!toCheck->mightBeType(MIRType_Undefined) && + !toCheck->mightBeType(MIRType_Null)) + { + toCheck->setImplicitlyUsedUnchecked(); + return true; + } + + MOZ_ASSERT(toCheck->type() == MIRType_Value || + toCheck->type() == MIRType_Null || + toCheck->type() == MIRType_Undefined); + + // If we want to squeeze more perf here, we can throw without checking, + // if IsNullOrUndefined(toCheck->type()). Since this is a failure case, + // it should be OK. + MCheckObjCoercible* check = MCheckObjCoercible::New(alloc(), current->pop()); + current->add(check); + current->push(check); + return resumeAfter(check); +} + uint32_t IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed) { @@ -13027,7 +13084,7 @@ IonBuilder::jsop_toid() return true; MDefinition* index = current->pop(); - MToId* ins = MToId::New(alloc(), current->peek(-1), index); + MToId* ins = MToId::New(alloc(), index); current->add(ins); current->push(ins); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 41995b0a77..be976f2a83 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -683,6 +683,8 @@ class IonBuilder bool jsop_compare(JSOp op, MDefinition* left, MDefinition* right); bool getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded, MDefinition* lexicalCheck = nullptr); + bool loadStaticSlot(JSObject* staticObject, BarrierKind barrier, TemporaryTypeSet* types, + uint32_t slot); bool setStaticName(JSObject* staticObject, PropertyName* name); bool jsop_getgname(PropertyName* name); bool jsop_getname(PropertyName* name); @@ -738,6 +740,7 @@ class IonBuilder bool jsop_setaliasedvar(ScopeCoordinate sc); bool jsop_debugger(); bool jsop_newtarget(); + bool jsop_checkobjcoercible(); /* Inlining. */ diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 085a9076c3..f31d688506 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -533,7 +533,7 @@ struct IonScript } // Invalidate the current compilation. - bool invalidate(JSContext* cx, bool resetUses, const char* reason); + void invalidate(JSContext* cx, bool resetUses, const char* reason); size_t invalidationCount() const { return invalidationCount_; diff --git a/js/src/jit/JSONSpewer.cpp b/js/src/jit/JSONSpewer.cpp index a3d6046453..39dc0a50fd 100644 --- a/js/src/jit/JSONSpewer.cpp +++ b/js/src/jit/JSONSpewer.cpp @@ -371,7 +371,7 @@ JSONSpewer::spewRanges(BacktrackingAllocator* regalloc) beginObject(); property("allocation"); - out_.printf("\"%s\"", range->bundle()->allocation().toString()); + out_.printf("\"%s\"", range->bundle()->allocation().toString().get()); integerProperty("start", range->from().bits()); integerProperty("end", range->to().bits()); endObject(); diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 76d8de1aae..0533bb0669 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2195,11 +2195,8 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback) // same reason, we need to recompile without optimizing away the // observable stack slots. The script would later be recompiled to have // support for Argument objects. - if (fallback.consequence == MaybeReadFallback::Fallback_Invalidate && - !ionScript_->invalidate(cx, /* resetUses = */ false, "Observe recovered instruction.")) - { - return false; - } + if (fallback.consequence == MaybeReadFallback::Fallback_Invalidate) + ionScript_->invalidate(cx, /* resetUses = */ false, "Observe recovered instruction."); // Register the list of result on the activation. We need to do that // before we initialize the list such as if any recover instruction diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp index 6d72352abf..a4ac19ec65 100644 --- a/js/src/jit/LIR.cpp +++ b/js/src/jit/LIR.cpp @@ -358,109 +358,107 @@ static const char * const TypeChars[] = #endif }; -static void -PrintDefinition(char* buf, size_t size, const LDefinition& def) -{ - char* cursor = buf; - char* end = buf + size; - - cursor += JS_snprintf(cursor, end - cursor, "v%u", def.virtualRegister()); - cursor += JS_snprintf(cursor, end - cursor, "<%s>", TypeChars[def.type()]); - - if (def.policy() == LDefinition::FIXED) - cursor += JS_snprintf(cursor, end - cursor, ":%s", def.output()->toString()); - else if (def.policy() == LDefinition::MUST_REUSE_INPUT) - cursor += JS_snprintf(cursor, end - cursor, ":tied(%u)", def.getReusedInput()); -} - -const char* +UniqueChars LDefinition::toString() const { - // Not reentrant! - static char buf[40]; + AutoEnterOOMUnsafeRegion oomUnsafe; - if (isBogusTemp()) - return "bogus"; + char* buf; + if (isBogusTemp()) { + buf = JS_smprintf("bogus"); + } else { + buf = JS_smprintf("v%u<%s>", virtualRegister(), TypeChars[type()]); + if (buf) { + if (policy() == LDefinition::FIXED) + buf = JS_sprintf_append(buf, ":%s", output()->toString().get()); + else if (policy() == LDefinition::MUST_REUSE_INPUT) + buf = JS_sprintf_append(buf, ":tied(%u)", getReusedInput()); + } + } - PrintDefinition(buf, sizeof(buf), *this); - return buf; + if (!buf) + oomUnsafe.crash("LDefinition::toString()"); + + return UniqueChars(buf); } -static void -PrintUse(char* buf, size_t size, const LUse* use) +static char* +PrintUse(const LUse* use) { switch (use->policy()) { case LUse::REGISTER: - JS_snprintf(buf, size, "v%d:r", use->virtualRegister()); - break; + return JS_smprintf("v%d:r", use->virtualRegister()); case LUse::FIXED: - JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(), - AnyRegister::FromCode(use->registerCode()).name()); - break; + return JS_smprintf("v%d:%s", use->virtualRegister(), + AnyRegister::FromCode(use->registerCode()).name()); case LUse::ANY: - JS_snprintf(buf, size, "v%d:r?", use->virtualRegister()); - break; + return JS_smprintf("v%d:r?", use->virtualRegister()); case LUse::KEEPALIVE: - JS_snprintf(buf, size, "v%d:*", use->virtualRegister()); - break; + return JS_smprintf("v%d:*", use->virtualRegister()); case LUse::RECOVERED_INPUT: - JS_snprintf(buf, size, "v%d:**", use->virtualRegister()); - break; + return JS_smprintf("v%d:**", use->virtualRegister()); default: MOZ_CRASH("invalid use policy"); } } -const char* +UniqueChars LAllocation::toString() const { - // Not reentrant! - static char buf[40]; + AutoEnterOOMUnsafeRegion oomUnsafe; - if (isBogus()) - return "bogus"; - - switch (kind()) { - case LAllocation::CONSTANT_VALUE: - case LAllocation::CONSTANT_INDEX: - return "c"; - case LAllocation::GPR: - JS_snprintf(buf, sizeof(buf), "%s", toGeneralReg()->reg().name()); - return buf; - case LAllocation::FPU: - JS_snprintf(buf, sizeof(buf), "%s", toFloatReg()->reg().name()); - return buf; - case LAllocation::STACK_SLOT: - JS_snprintf(buf, sizeof(buf), "stack:%d", toStackSlot()->slot()); - return buf; - case LAllocation::ARGUMENT_SLOT: - JS_snprintf(buf, sizeof(buf), "arg:%d", toArgument()->index()); - return buf; - case LAllocation::USE: - PrintUse(buf, sizeof(buf), toUse()); - return buf; - default: - MOZ_CRASH("what?"); + char* buf; + if (isBogus()) { + buf = JS_smprintf("bogus"); + } else { + switch (kind()) { + case LAllocation::CONSTANT_VALUE: + case LAllocation::CONSTANT_INDEX: + buf = JS_smprintf("c"); + break; + case LAllocation::GPR: + buf = JS_smprintf("%s", toGeneralReg()->reg().name()); + break; + case LAllocation::FPU: + buf = JS_smprintf("%s", toFloatReg()->reg().name()); + break; + case LAllocation::STACK_SLOT: + buf = JS_smprintf("stack:%d", toStackSlot()->slot()); + break; + case LAllocation::ARGUMENT_SLOT: + buf = JS_smprintf("arg:%d", toArgument()->index()); + break; + case LAllocation::USE: + buf = PrintUse(toUse()); + break; + default: + MOZ_CRASH("what?"); + } } + + if (!buf) + oomUnsafe.crash("LAllocation::toString()"); + + return UniqueChars(buf); } void LAllocation::dump() const { - fprintf(stderr, "%s\n", toString()); + fprintf(stderr, "%s\n", toString().get()); } void LDefinition::dump() const { - fprintf(stderr, "%s\n", toString()); + fprintf(stderr, "%s\n", toString().get()); } void LNode::printOperands(GenericPrinter& out) { for (size_t i = 0, e = numOperands(); i < e; i++) { - out.printf(" (%s)", getOperand(i)->toString()); + out.printf(" (%s)", getOperand(i)->toString().get()); if (i != numOperands() - 1) out.printf(","); } @@ -490,7 +488,7 @@ LNode::dump(GenericPrinter& out) if (numDefs() != 0) { out.printf("{"); for (size_t i = 0; i < numDefs(); i++) { - out.printf("%s", getDef(i)->toString()); + out.printf("%s", getDef(i)->toString().get()); if (i != numDefs() - 1) out.printf(", "); } @@ -503,7 +501,7 @@ LNode::dump(GenericPrinter& out) if (numTemps()) { out.printf(" t=("); for (size_t i = 0; i < numTemps(); i++) { - out.printf("%s", getTemp(i)->toString()); + out.printf("%s", getTemp(i)->toString().get()); if (i != numTemps() - 1) out.printf(", "); } @@ -599,9 +597,7 @@ LMoveGroup::printOperands(GenericPrinter& out) { for (size_t i = 0; i < numMoves(); i++) { const LMove& move = getMove(i); - // Use two printfs, as LAllocation::toString is not reentrant. - out.printf(" [%s", move.from().toString()); - out.printf(" -> %s", move.to().toString()); + out.printf(" [%s -> %s", move.from().toString().get(), move.to().toString().get()); #ifdef DEBUG out.printf(", %s", TypeChars[move.type()]); #endif diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index b4ff10a4c6..102d7300aa 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -183,7 +183,7 @@ class LAllocation : public TempObject return bits_; } - const char* toString() const; + UniqueChars toString() const; bool aliases(const LAllocation& other) const; void dump() const; @@ -577,7 +577,7 @@ class LDefinition } } - const char* toString() const; + UniqueChars toString() const; void dump() const; }; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index ab2fb2d459..f7a94d38b2 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -1097,8 +1097,7 @@ void LIRGenerator::visitToId(MToId* ins) { LToIdV* lir = new(alloc()) LToIdV(tempDouble()); - useBox(lir, LToIdV::Object, ins->lhs()); - useBox(lir, LToIdV::Index, ins->rhs()); + useBox(lir, LToIdV::Index, ins->input()); defineBox(lir, ins); assignSafepoint(lir, ins); } @@ -4331,6 +4330,32 @@ LIRGenerator::visitCheckReturn(MCheckReturn* ins) redefine(ins, retVal); } +void +LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) +{ + MDefinition* checkVal = ins->checkValue(); + MOZ_ASSERT(checkVal->type() == MIRType_Value); + + LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible(); + useBoxAtStart(lir, LCheckObjCoercible::CheckValue, checkVal); + redefine(ins, checkVal); + add(lir, ins); + assignSafepoint(lir, ins); +} + +void +LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) +{ + MDefinition* checkVal = ins->checkValue(); + MOZ_ASSERT(checkVal->type() == MIRType_Value); + + LDebugCheckSelfHosted* lir = new (alloc()) LDebugCheckSelfHosted(); + useBoxAtStart(lir, LDebugCheckSelfHosted::CheckValue, checkVal); + redefine(ins, checkVal); + add(lir, ins); + assignSafepoint(lir, ins); +} + static void SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 95a5c4a763..dff0e64203 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -310,6 +310,8 @@ class LIRGenerator : public LIRGeneratorSpecific void visitAtomicIsLockFree(MAtomicIsLockFree* ins); void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins); void visitCheckReturn(MCheckReturn* ins); + void visitCheckObjCoercible(MCheckObjCoercible* ins); + void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins); }; } // namespace jit diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index c6e04000ed..e9806448f0 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -2967,7 +2967,7 @@ IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayTyp // be. return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType_Double; default: - // Excludes floating types and Uint8Clamped + // Excludes floating types and Uint8Clamped. return false; } } diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 52350051b6..cf7a0c959c 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3993,7 +3993,6 @@ OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject) const UnboxedLayout& layout = templateObject->as().layoutDontCheckGeneration(); - // 0 is used as an error code. const UnboxedLayout::PropertyVector& properties = layout.properties(); MOZ_ASSERT(properties.length() < 255); @@ -4068,8 +4067,54 @@ MObjectState::init(TempAllocator& alloc, MDefinition* obj) return true; } +bool +MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal) +{ + JSObject* templateObject = templateObjectOf(object()); + + // Initialize all the slots of the object state with the value contained in + // the template object. This is needed to account values which are baked in + // the template objects and not visible in IonMonkey, such as the + // uninitialized-lexical magic value of call objects. + if (templateObject->is()) { + UnboxedPlainObject& unboxedObject = templateObject->as(); + const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration(); + const UnboxedLayout::PropertyVector& properties = layout.properties(); + + for (size_t i = 0; i < properties.length(); i++) { + Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true); + MDefinition *def = undefinedVal; + if (!val.isUndefined()) { + MConstant* ins = val.isObject() ? + MConstant::NewConstraintlessObject(alloc, &val.toObject()) : + MConstant::New(alloc, val); + block()->insertBefore(this, ins); + def = ins; + } + initSlot(i, def); + } + } else { + NativeObject& nativeObject = templateObject->as(); + MOZ_ASSERT(nativeObject.slotSpan() == numSlots()); + + for (size_t i = 0; i < numSlots(); i++) { + Value val = nativeObject.getSlot(i); + MDefinition *def = undefinedVal; + if (!val.isUndefined()) { + MConstant* ins = val.isObject() ? + MConstant::NewConstraintlessObject(alloc, &val.toObject()) : + MConstant::New(alloc, val); + block()->insertBefore(this, ins); + def = ins; + } + initSlot(i, def); + } + } + return true; +} + MObjectState* -MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal) +MObjectState::New(TempAllocator& alloc, MDefinition* obj) { JSObject* templateObject = templateObjectOf(obj); MOZ_ASSERT(templateObject, "Unexpected object creation."); @@ -4084,8 +4129,6 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefined MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex); if (!res || !res->init(alloc, obj)) return nullptr; - for (size_t i = 0; i < res->numSlots(); i++) - res->initSlot(i, undefinedVal); return res; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index c77d6f70fd..bf222623d9 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3399,9 +3399,13 @@ class MObjectState // on bailout. static JSObject* templateObjectOf(MDefinition* obj); - static MObjectState* New(TempAllocator& alloc, MDefinition* obj, MDefinition* undefinedVal); + static MObjectState* New(TempAllocator& alloc, MDefinition* obj); static MObjectState* Copy(TempAllocator& alloc, MObjectState* state); + // As we might do read of uninitialized properties, we have to copy the + // initial values from the template object. + bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal); + MDefinition* object() const { return getOperand(0); } @@ -5372,11 +5376,11 @@ class MTypeOf }; class MToId - : public MBinaryInstruction, + : public MUnaryInstruction, public BoxInputsPolicy::Data { - MToId(MDefinition* object, MDefinition* index) - : MBinaryInstruction(object, index) + explicit MToId(MDefinition* index) + : MUnaryInstruction(index) { setResultType(MIRType_Value); } @@ -5384,8 +5388,8 @@ class MToId public: INSTRUCTION_HEADER(ToId) - static MToId* New(TempAllocator& alloc, MDefinition* object, MDefinition* index) { - return new(alloc) MToId(object, index); + static MToId* New(TempAllocator& alloc, MDefinition* index) { + return new(alloc) MToId(index); } }; @@ -13223,8 +13227,7 @@ class MCompareExchangeTypedArrayElement } bool isByteArray() const { return (arrayType_ == Scalar::Int8 || - arrayType_ == Scalar::Uint8 || - arrayType_ == Scalar::Uint8Clamped); + arrayType_ == Scalar::Uint8); } MDefinition* elements() { return getOperand(0); @@ -13278,8 +13281,7 @@ class MAtomicExchangeTypedArrayElement bool isByteArray() const { return (arrayType_ == Scalar::Int8 || - arrayType_ == Scalar::Uint8 || - arrayType_ == Scalar::Uint8Clamped); + arrayType_ == Scalar::Uint8); } MDefinition* elements() { return getOperand(0); @@ -13330,8 +13332,7 @@ class MAtomicTypedArrayElementBinop bool isByteArray() const { return (arrayType_ == Scalar::Int8 || - arrayType_ == Scalar::Uint8 || - arrayType_ == Scalar::Uint8Clamped); + arrayType_ == Scalar::Uint8); } AtomicOp operation() const { return op_; @@ -13363,6 +13364,52 @@ class MDebugger : public MNullaryInstruction } }; +class MCheckObjCoercible + : public MUnaryInstruction, + public BoxInputsPolicy::Data +{ + explicit MCheckObjCoercible(MDefinition* toCheck) + : MUnaryInstruction(toCheck) + { + setGuard(); + setResultType(MIRType_Value); + setResultTypeSet(toCheck->resultTypeSet()); + } + + public: + INSTRUCTION_HEADER(CheckObjCoercible) + static MCheckObjCoercible* New(TempAllocator& alloc, MDefinition* toCheck) { + return new(alloc) MCheckObjCoercible(toCheck); + } + + MDefinition* checkValue() { + return getOperand(0); + } +}; + +class MDebugCheckSelfHosted + : public MUnaryInstruction, + public BoxInputsPolicy::Data +{ + explicit MDebugCheckSelfHosted(MDefinition* toCheck) + : MUnaryInstruction(toCheck) + { + setGuard(); + setResultType(MIRType_Value); + setResultTypeSet(toCheck->resultTypeSet()); + } + + public: + INSTRUCTION_HEADER(DebugCheckSelfHosted) + static MDebugCheckSelfHosted* New(TempAllocator& alloc, MDefinition* toCheck) { + return new(alloc) MDebugCheckSelfHosted(toCheck); + } + + MDefinition* checkValue() { + return getOperand(0); + } +}; + class MAsmJSNeg : public MUnaryInstruction, public NoTypePolicy::Data diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 1fd92ff2f7..d1fcddbb5c 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -279,7 +279,9 @@ namespace jit { _(Debugger) \ _(NewTarget) \ _(ArrowNewTarget) \ - _(CheckReturn) + _(CheckReturn) \ + _(CheckObjCoercible) \ + _(DebugCheckSelfHosted) // Forward declarations of MIR types. #define FORWARD_DECLARE(op) class M##op; diff --git a/js/src/jit/RegisterAllocator.cpp b/js/src/jit/RegisterAllocator.cpp index e30c9f0b86..c67f5074e4 100644 --- a/js/src/jit/RegisterAllocator.cpp +++ b/js/src/jit/RegisterAllocator.cpp @@ -291,7 +291,7 @@ AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins, case LDefinition::OBJECT: if (populateSafepoints) { JitSpew(JitSpew_RegAlloc, "Safepoint object v%u i%u %s", - vreg, ins->id(), alloc.toString()); + vreg, ins->id(), alloc.toString().get()); if (!safepoint->addGcPointer(alloc)) return false; } @@ -300,7 +300,7 @@ AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins, case LDefinition::SLOTS: if (populateSafepoints) { JitSpew(JitSpew_RegAlloc, "Safepoint slots v%u i%u %s", - vreg, ins->id(), alloc.toString()); + vreg, ins->id(), alloc.toString().get()); if (!safepoint->addSlotsOrElementsPointer(alloc)) return false; } @@ -314,7 +314,7 @@ AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins, case LDefinition::TYPE: if (populateSafepoints) { JitSpew(JitSpew_RegAlloc, "Safepoint type v%u i%u %s", - vreg, ins->id(), alloc.toString()); + vreg, ins->id(), alloc.toString().get()); if (!safepoint->addNunboxType(vreg, alloc)) return false; } @@ -322,7 +322,7 @@ AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins, case LDefinition::PAYLOAD: if (populateSafepoints) { JitSpew(JitSpew_RegAlloc, "Safepoint payload v%u i%u %s", - vreg, ins->id(), alloc.toString()); + vreg, ins->id(), alloc.toString().get()); if (!safepoint->addNunboxPayload(vreg, alloc)) return false; } @@ -332,7 +332,7 @@ AllocationIntegrityState::checkSafepointAllocation(LInstruction* ins, case LDefinition::BOX: if (populateSafepoints) { JitSpew(JitSpew_RegAlloc, "Safepoint boxed value v%u i%u %s", - vreg, ins->id(), alloc.toString()); + vreg, ins->id(), alloc.toString().get()); if (!safepoint->addBoxedValue(alloc)) return false; } @@ -391,9 +391,9 @@ AllocationIntegrityState::dump() fprintf(stderr, "[%u,%u Phi] [def %s] ", input.bits(), output.bits(), - phi->getDef(0)->toString()); + phi->getDef(0)->toString().get()); for (size_t j = 0; j < phi->numOperands(); j++) - fprintf(stderr, " [use %s]", info.inputs[j].toString()); + fprintf(stderr, " [use %s]", info.inputs[j].toString().get()); fprintf(stderr, "\n"); } @@ -412,29 +412,29 @@ AllocationIntegrityState::dump() if (ins->isMoveGroup()) { LMoveGroup* group = ins->toMoveGroup(); for (int i = group->numMoves() - 1; i >= 0; i--) { - // Use two printfs, as LAllocation::toString is not reentrant. - fprintf(stderr, " [%s", group->getMove(i).from().toString()); - fprintf(stderr, " -> %s]", group->getMove(i).to().toString()); + fprintf(stderr, " [%s -> %s]", + group->getMove(i).from().toString().get(), + group->getMove(i).to().toString().get()); } fprintf(stderr, "\n"); continue; } for (size_t i = 0; i < ins->numDefs(); i++) - fprintf(stderr, " [def %s]", ins->getDef(i)->toString()); + fprintf(stderr, " [def %s]", ins->getDef(i)->toString().get()); for (size_t i = 0; i < ins->numTemps(); i++) { LDefinition* temp = ins->getTemp(i); if (!temp->isBogusTemp()) fprintf(stderr, " [temp v%u %s]", info.temps[i].virtualRegister(), - temp->toString()); + temp->toString().get()); } size_t index = 0; for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) { - fprintf(stderr, " [use %s", info.inputs[index++].toString()); + fprintf(stderr, " [use %s", info.inputs[index++].toString().get()); if (!alloc->isConstant()) - fprintf(stderr, " %s", alloc->toString()); + fprintf(stderr, " %s", alloc->toString().get()); fprintf(stderr, "]"); } @@ -462,7 +462,7 @@ AllocationIntegrityState::dump() for (size_t i = 0; i < seenOrdered.length(); i++) { IntegrityItem item = seenOrdered[i]; fprintf(stderr, " block %u reg v%u alloc %s\n", - item.block->mir()->id(), item.vreg, item.alloc.toString()); + item.block->mir()->id(), item.vreg, item.alloc.toString().get()); } } @@ -538,9 +538,9 @@ RegisterAllocator::dumpInstructions() fprintf(stderr, "[%u,%u Phi] [def %s]", inputOf(phi).bits(), outputOf(phi).bits(), - phi->getDef(0)->toString()); + phi->getDef(0)->toString().get()); for (size_t j = 0; j < phi->numOperands(); j++) - fprintf(stderr, " [use %s]", phi->getOperand(j)->toString()); + fprintf(stderr, " [use %s]", phi->getOperand(j)->toString().get()); fprintf(stderr, "\n"); } @@ -556,25 +556,25 @@ RegisterAllocator::dumpInstructions() LMoveGroup* group = ins->toMoveGroup(); for (int i = group->numMoves() - 1; i >= 0; i--) { // Use two printfs, as LAllocation::toString is not reentant. - fprintf(stderr, " [%s", group->getMove(i).from().toString()); - fprintf(stderr, " -> %s]", group->getMove(i).to().toString()); + fprintf(stderr, " [%s", group->getMove(i).from().toString().get()); + fprintf(stderr, " -> %s]", group->getMove(i).to().toString().get()); } fprintf(stderr, "\n"); continue; } for (size_t i = 0; i < ins->numDefs(); i++) - fprintf(stderr, " [def %s]", ins->getDef(i)->toString()); + fprintf(stderr, " [def %s]", ins->getDef(i)->toString().get()); for (size_t i = 0; i < ins->numTemps(); i++) { LDefinition* temp = ins->getTemp(i); if (!temp->isBogusTemp()) - fprintf(stderr, " [temp %s]", temp->toString()); + fprintf(stderr, " [temp %s]", temp->toString().get()); } for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) { if (!alloc->isBogus()) - fprintf(stderr, " [use %s]", alloc->toString()); + fprintf(stderr, " [use %s]", alloc->toString().get()); } fprintf(stderr, "\n"); diff --git a/js/src/jit/ScalarReplacement.cpp b/js/src/jit/ScalarReplacement.cpp index 46a76dfbc1..f90b2bd812 100644 --- a/js/src/jit/ScalarReplacement.cpp +++ b/js/src/jit/ScalarReplacement.cpp @@ -349,12 +349,16 @@ ObjectMemoryView::initStartingState(BlockState** pState) startBlock_->insertBefore(obj_, undefinedVal_); // Create a new block state and insert at it at the location of the new object. - BlockState* state = BlockState::New(alloc_, obj_, undefinedVal_); + BlockState* state = BlockState::New(alloc_, obj_); if (!state) return false; startBlock_->insertAfter(obj_, state); + // Initialize the properties of the object state. + if (!state->initFromTemplateObject(alloc_, undefinedVal_)) + return false; + // Hold out of resume point until it is visited. state->setInWorklist(); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index cf4a144abd..28f67c2adf 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1311,6 +1311,15 @@ BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame) return ThrowUninitializedThis(cx, frame); } + +bool +ThrowObjectCoercible(JSContext* cx, HandleValue v) +{ + MOZ_ASSERT(v.isUndefined() || v.isNull()); + MOZ_ALWAYS_FALSE(ToObjectSlow(cx, v, false)); + return false; +} + bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index bb5084d5ec..67177905d2 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -738,6 +738,8 @@ bool ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber); bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame); bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v); +bool ThrowObjectCoercible(JSContext* cx, HandleValue v); + bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res); } // namespace jit diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index ac38aea524..c2a3bfde19 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -1742,7 +1742,6 @@ CodeGeneratorARM::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType MOZ_ASSERT(flagTemp != InvalidReg); MOZ_ASSERT_IF(arrayType == Scalar::Uint32, outTemp != InvalidReg); - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: switch (op) { @@ -1908,7 +1907,6 @@ CodeGeneratorARM::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType { MOZ_ASSERT(flagTemp != InvalidReg); - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: case Scalar::Uint8: diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 3e47e8c142..41741528a5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4828,9 +4828,6 @@ MacroAssemblerARMCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, case Scalar::Uint8: compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); break; - case Scalar::Uint8Clamped: - compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); - break; case Scalar::Int16: compareExchange16SignExtend(mem, oldval, newval, output.gpr()); break; @@ -4873,9 +4870,6 @@ MacroAssemblerARMCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, c case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, output.gpr()); break; - case Scalar::Uint8Clamped: - atomicExchange8ZeroExtend(mem, value, output.gpr()); - break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, output.gpr()); break; diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index ede1f162a3..c7060b57a2 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -273,9 +273,6 @@ MacroAssemblerCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, con case Scalar::Uint8: compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); break; - case Scalar::Uint8Clamped: - compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); - break; case Scalar::Int16: compareExchange16SignExtend(mem, oldval, newval, output.gpr()); break; @@ -318,9 +315,6 @@ MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, cons case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, output.gpr()); break; - case Scalar::Uint8Clamped: - atomicExchange8ZeroExtend(mem, value, output.gpr()); - break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, output.gpr()); break; diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 5b3b53bc35..aed21a4000 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -2042,7 +2042,6 @@ CodeGeneratorMIPSShared::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type ar MOZ_ASSERT(flagTemp != InvalidReg); MOZ_ASSERT_IF(arrayType == Scalar::Uint32, outTemp != InvalidReg); - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: switch (op) { @@ -2213,7 +2212,6 @@ CodeGeneratorMIPSShared::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type ar { MOZ_ASSERT(flagTemp != InvalidReg); - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: case Scalar::Uint8: diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index e7b0977da0..462c1d0a87 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -2434,9 +2434,6 @@ MacroAssemblerMIPSCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, case Scalar::Uint8: compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); break; - case Scalar::Uint8Clamped: - compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); - break; case Scalar::Int16: compareExchange16SignExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); break; @@ -2483,9 +2480,6 @@ MacroAssemblerMIPSCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); break; - case Scalar::Uint8Clamped: - atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); - break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); break; diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 0a708860f9..6b30781854 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -2537,9 +2537,6 @@ MacroAssemblerMIPS64Compat::compareExchangeToTypedIntArray(Scalar::Type arrayTyp case Scalar::Uint8: compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); break; - case Scalar::Uint8Clamped: - compareExchange8ZeroExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); - break; case Scalar::Int16: compareExchange16SignExtend(mem, oldval, newval, valueTemp, offsetTemp, maskTemp, output.gpr()); break; @@ -2586,9 +2583,6 @@ MacroAssemblerMIPS64Compat::atomicExchangeToTypedIntArray(Scalar::Type arrayType case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); break; - case Scalar::Uint8Clamped: - atomicExchange8ZeroExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); - break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, valueTemp, offsetTemp, maskTemp, output.gpr()); break; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index b42df7cf88..77564f5abc 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1276,7 +1276,7 @@ class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1> } }; -class LToIdV : public LInstructionHelper +class LToIdV : public LInstructionHelper { public: LIR_HEADER(ToIdV) @@ -1286,8 +1286,7 @@ class LToIdV : public LInstructionHelper setTemp(0, temp); } - static const size_t Object = 0; - static const size_t Index = BOX_PIECES; + static const size_t Index = 0; MToId* mir() const { return mir_->toToId(); @@ -7397,6 +7396,22 @@ class LCheckReturn : public LCallInstructionHelper +{ + public: + static const size_t CheckValue = 0; + + LIR_HEADER(CheckObjCoercible) +}; + +class LDebugCheckSelfHosted : public LCallInstructionHelper +{ + public: + static const size_t CheckValue = 0; + + LIR_HEADER(DebugCheckSelfHosted) +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 51b4686204..48e91e579e 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -367,6 +367,8 @@ _(Debugger) \ _(NewTarget) \ _(ArrowNewTarget) \ - _(CheckReturn) + _(CheckReturn) \ + _(CheckObjCoercible) \ + _(DebugCheckSelfHosted) #endif /* jit_shared_LOpcodes_shared_h */ diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index ca48dced60..9ce69fa525 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -3366,7 +3366,6 @@ void CodeGeneratorX86Shared::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value, const T& mem, Register temp1, Register temp2, AnyRegister output) { - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: switch (op) { @@ -3526,7 +3525,6 @@ void CodeGeneratorX86Shared::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value, const T& mem) { - // Uint8Clamped is explicitly not supported here switch (arrayType) { case Scalar::Int8: case Scalar::Uint8: diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index e135d5091f..ebea1fc30a 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -156,9 +156,6 @@ MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, case Scalar::Uint8: compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); break; - case Scalar::Uint8Clamped: - compareExchange8ZeroExtend(mem, oldval, newval, output.gpr()); - break; case Scalar::Int16: compareExchange16SignExtend(mem, oldval, newval, output.gpr()); break; @@ -201,9 +198,6 @@ MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, c case Scalar::Uint8: atomicExchange8ZeroExtend(mem, value, output.gpr()); break; - case Scalar::Uint8Clamped: - atomicExchange8ZeroExtend(mem, value, output.gpr()); - break; case Scalar::Int16: atomicExchange16SignExtend(mem, value, output.gpr()); break; diff --git a/js/src/js.msg b/js/src/js.msg index f779d26a66..16926cbf66 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -107,6 +107,7 @@ MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not a MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") +MSG_DEF(JSMSG_NOT_SELFHOSTED, 1, JSEXN_TYPEERR, "callFunction() used on non self-hosted builtin {0}") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -446,14 +447,23 @@ MSG_DEF(JSMSG_INVALID_TIME_ZONE, 1, JSEXN_RANGEERR, "invalid time zone in MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style") // RegExp +MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression") MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class") +MSG_DEF(JSMSG_DEPRECATED_REGEXP_MULTILINE, 0, JSEXN_SYNTAXERR, "RegExp.multiline is deprecated. Use m flag instead") MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern") +MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression") MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group") +MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression") +MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression") MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another") MSG_DEF(JSMSG_NOTHING_TO_REPEAT, 0, JSEXN_SYNTAXERR, "nothing to repeat") MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER, 0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.") +MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class escape cannot be used in class range in regular expression") +MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag") +MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") +MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d6a1eb294d..e1cd386b1a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3109,7 +3109,7 @@ PropertySpecNameToSymbolCode(const char* name) return JS::SymbolCode(u - 1); } -static bool +bool PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id, js::PinningBehavior pin = js::DoNotPinAtom) { @@ -3626,87 +3626,6 @@ JS_IsConstructor(JSFunction* fun) return fun->isConstructor(); } -static bool -GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - const JSFunctionSpec* fs = (JSFunctionSpec*) - args.callee().as().getExtendedSlot(0).toPrivate(); - MOZ_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0); - - if (argc < 1) { - ReportMissingArg(cx, args.calleev(), 0); - return false; - } - - /* - * Copy all actual (argc) arguments down over our |this| parameter, vp[1], - * which is almost always the class constructor object, e.g. Array. Then - * call the corresponding prototype native method with our first argument - * passed as |this|. - */ - memmove(vp + 1, vp + 2, argc * sizeof(Value)); - - /* Clear the last parameter in case too few arguments were passed. */ - vp[2 + --argc].setUndefined(); - - return fs->call.op(cx, argc, vp); -} - -static bool -DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags) -{ - GetterOp gop; - SetterOp sop; - if (flags & JSFUN_STUB_GSOPS) { - // JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or - // the defined property's attributes. - flags &= ~JSFUN_STUB_GSOPS; - gop = nullptr; - sop = nullptr; - } else { - gop = obj->getClass()->getProperty; - sop = obj->getClass()->setProperty; - MOZ_ASSERT(gop != JS_PropertyStub); - MOZ_ASSERT(sop != JS_StrictPropertyStub); - } - - RootedId id(cx); - if (!PropertySpecNameToId(cx, fs->name, &id)) - return false; - - // Define a generic arity N+1 static method for the arity N prototype - // method if flags contains JSFUN_GENERIC_NATIVE. - if (flags & JSFUN_GENERIC_NATIVE) { - // We require that any consumers using JSFUN_GENERIC_NATIVE stash - // the prototype and constructor in the global slots before invoking - // JS_DefineFunctions on the proto. - JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); - MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject()); - RootedObject ctor(cx, &obj->global().getConstructor(key).toObject()); - - flags &= ~JSFUN_GENERIC_NATIVE; - JSFunction* fun = DefineFunction(cx, ctor, id, - GenericNativeMethodDispatcher, - fs->nargs + 1, flags, - gc::AllocKind::FUNCTION_EXTENDED); - if (!fun) - return false; - - // As jsapi.h notes, fs must point to storage that lives as long - // as fun->object lives. - fun->setExtendedSlot(0, PrivateValue(const_cast(fs))); - } - - JSFunction* fun = NewFunctionFromSpec(cx, fs, id); - if (!fun) - return false; - - RootedValue funVal(cx, ObjectValue(*fun)); - return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK); -} - JS_PUBLIC_API(bool) JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, PropertyDefinitionBehavior behavior) @@ -3716,25 +3635,7 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - for (; fs->name; fs++) { - unsigned flags = fs->flags; - switch (behavior) { - case DefineAllProperties: - break; - case OnlyDefineLateProperties: - if (!(flags & JSPROP_DEFINE_LATE)) - continue; - break; - default: - MOZ_ASSERT(behavior == DontDefineLateProperties); - if (flags & JSPROP_DEFINE_LATE) - continue; - } - - if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE)) - return false; - } - return true; + return DefineFunctions(cx, obj, fs, NotIntrinsic, behavior); } JS_PUBLIC_API(JSFunction*) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 297fc3ef59..5da1900ac1 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4954,6 +4954,7 @@ JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate); #define JSREG_GLOB 0x02u /* global exec, creates array of matches */ #define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */ #define JSREG_STICKY 0x08u /* only match starting at lastIndex */ +#define JSREG_UNICODE 0x10u /* unicode */ extern JS_PUBLIC_API(JSObject*) JS_NewRegExpObject(JSContext* cx, JS::HandleObject obj, const char* bytes, size_t length, diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 9ef1f8aad5..566d114431 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -50,6 +50,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = marked(true), warnedAboutFlagsArgument(false), warnedAboutExprClosure(false), + warnedAboutRegExpMultiline(false), addonId(options.addonIdOrNull()), #ifdef DEBUG firedOnNewGlobalObject(false), diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 95d73bafd8..6df3a1992a 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -278,6 +278,7 @@ struct JSCompartment bool marked; bool warnedAboutFlagsArgument; bool warnedAboutExprClosure; + bool warnedAboutRegExpMultiline; // A null add-on ID means that the compartment is not associated with an // add-on. diff --git a/js/src/jsfun.h b/js/src/jsfun.h index e844ddcff0..4ed9bf6c8b 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -187,7 +187,6 @@ class JSFunction : public js::NativeObject bool isExprBody() const { return flags() & EXPR_BODY; } bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } bool isLambda() const { return flags() & LAMBDA; } - bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; } bool hasRest() const { return flags() & HAS_REST; } bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; } bool hasScript() const { return flags() & INTERPRETED; } @@ -209,6 +208,10 @@ class JSFunction : public js::NativeObject bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; } bool hasResolvedName() const { return flags() & RESOLVED_NAME; } + bool isSelfHostedOrIntrinsic() const { return flags() & SELF_HOSTED; } + bool isSelfHostedBuiltin() const { return isSelfHostedOrIntrinsic() && !isNative(); } + bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); } + bool hasJITCode() const { if (!hasScript()) return false; @@ -263,11 +266,17 @@ class JSFunction : public js::NativeObject } void setIsSelfHostedBuiltin() { + MOZ_ASSERT(isInterpreted()); MOZ_ASSERT(!isSelfHostedBuiltin()); flags_ |= SELF_HOSTED; // Self-hosted functions should not be constructable. flags_ &= ~CONSTRUCTOR; } + void setIsIntrinsic() { + MOZ_ASSERT(isNative()); + MOZ_ASSERT(!isIntrinsic()); + flags_ |= SELF_HOSTED; + } void setIsFunctionPrototype() { MOZ_ASSERT(!isFunctionPrototype()); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index c6db20ee15..4a47045570 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -348,8 +348,7 @@ static const AllocKind IncrementalPhaseStrings[] = { }; static const AllocKind IncrementalPhaseScripts[] = { - AllocKind::SCRIPT, - AllocKind::LAZY_SCRIPT + AllocKind::SCRIPT }; static const AllocKind IncrementalPhaseJitCode[] = { @@ -377,6 +376,10 @@ static const AllocKind BackgroundPhaseObjects[] = { AllocKind::OBJECT16_BACKGROUND }; +static const AllocKind BackgroundPhaseScripts[] = { + AllocKind::LAZY_SCRIPT +}; + static const AllocKind BackgroundPhaseStringsAndSymbols[] = { AllocKind::FAT_INLINE_STRING, AllocKind::STRING, @@ -391,6 +394,7 @@ static const AllocKind BackgroundPhaseShapes[] = { }; static const FinalizePhase BackgroundFinalizePhases[] = { + PHASE(BackgroundPhaseScripts, gcstats::PHASE_SWEEP_SCRIPT), PHASE(BackgroundPhaseObjects, gcstats::PHASE_SWEEP_OBJECT), PHASE(BackgroundPhaseStringsAndSymbols, gcstats::PHASE_SWEEP_STRING), PHASE(BackgroundPhaseShapes, gcstats::PHASE_SWEEP_SHAPE) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index a254a0b3ae..56f0999a87 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -167,7 +167,7 @@ IsBackgroundFinalized(AllocKind kind) false, /* AllocKind::OBJECT16 */ true, /* AllocKind::OBJECT16_BACKGROUND */ false, /* AllocKind::SCRIPT */ - false, /* AllocKind::LAZY_SCRIPT */ + true, /* AllocKind::LAZY_SCRIPT */ true, /* AllocKind::SHAPE */ true, /* AllocKind::ACCESSOR_SHAPE */ true, /* AllocKind::BASE_SHAPE */ diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 87bac37d89..d78f12d5a6 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2870,6 +2870,118 @@ js::HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp) return false; } +static bool +GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + const JSFunctionSpec* fs = (JSFunctionSpec*) + args.callee().as().getExtendedSlot(0).toPrivate(); + MOZ_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0); + + if (argc < 1) { + ReportMissingArg(cx, args.calleev(), 0); + return false; + } + + /* + * Copy all actual (argc) arguments down over our |this| parameter, vp[1], + * which is almost always the class constructor object, e.g. Array. Then + * call the corresponding prototype native method with our first argument + * passed as |this|. + */ + memmove(vp + 1, vp + 2, argc * sizeof(Value)); + + /* Clear the last parameter in case too few arguments were passed. */ + vp[2 + --argc].setUndefined(); + + return fs->call.op(cx, argc, vp); +} + +extern bool +PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id, + js::PinningBehavior pin = js::DoNotPinAtom); + +static bool +DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags, + DefineAsIntrinsic intrinsic) +{ + GetterOp gop; + SetterOp sop; + if (flags & JSFUN_STUB_GSOPS) { + // JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or + // the defined property's attributes. + flags &= ~JSFUN_STUB_GSOPS; + gop = nullptr; + sop = nullptr; + } else { + gop = obj->getClass()->getProperty; + sop = obj->getClass()->setProperty; + MOZ_ASSERT(gop != JS_PropertyStub); + MOZ_ASSERT(sop != JS_StrictPropertyStub); + } + + RootedId id(cx); + if (!PropertySpecNameToId(cx, fs->name, &id)) + return false; + + // Define a generic arity N+1 static method for the arity N prototype + // method if flags contains JSFUN_GENERIC_NATIVE. + if (flags & JSFUN_GENERIC_NATIVE) { + // We require that any consumers using JSFUN_GENERIC_NATIVE stash + // the prototype and constructor in the global slots before invoking + // JS_DefineFunctions on the proto. + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); + MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject()); + RootedObject ctor(cx, &obj->global().getConstructor(key).toObject()); + + flags &= ~JSFUN_GENERIC_NATIVE; + JSFunction* fun = DefineFunction(cx, ctor, id, + GenericNativeMethodDispatcher, + fs->nargs + 1, flags, + gc::AllocKind::FUNCTION_EXTENDED); + if (!fun) + return false; + + fun->setExtendedSlot(0, PrivateValue(const_cast(fs))); + } + + JSFunction* fun = NewFunctionFromSpec(cx, fs, id); + if (!fun) + return false; + + if (intrinsic == AsIntrinsic) + fun->setIsIntrinsic(); + + RootedValue funVal(cx, ObjectValue(*fun)); + return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK); +} + +bool +js::DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, + DefineAsIntrinsic intrinsic, PropertyDefinitionBehavior behavior) +{ + for (; fs->name; fs++) { + unsigned flags = fs->flags; + switch (behavior) { + case DefineAllProperties: + break; + case OnlyDefineLateProperties: + if (!(flags & JSPROP_DEFINE_LATE)) + continue; + break; + default: + MOZ_ASSERT(behavior == DontDefineLateProperties); + if (flags & JSPROP_DEFINE_LATE) + continue; + } + + if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE, intrinsic)) + return false; + } + return true; +} + /*** ToPrimitive *************************************************************/ diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 0ea0ec5fff..0d8f789054 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -982,6 +982,20 @@ LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name, extern bool HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result); +/** + * This enum is used to select whether the defined functions should be marked as + * builtin native instrinsics for self-hosted code. + */ +enum DefineAsIntrinsic { + NotIntrinsic, + AsIntrinsic +}; + +extern bool +DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, + DefineAsIntrinsic intrinsic, + PropertyDefinitionBehavior behavior = DefineAllProperties); + /* * Set a watchpoint: a synchronous callback when the given property of the * given object is set. diff --git a/js/src/jsprf.cpp b/js/src/jsprf.cpp index ed8c35edc3..0d367de047 100644 --- a/js/src/jsprf.cpp +++ b/js/src/jsprf.cpp @@ -996,8 +996,8 @@ JS_snprintf(char* out, uint32_t outlen, const char* fmt, ...) va_list ap; int rv; - MOZ_ASSERT(int32_t(outlen) > 0); - if (int32_t(outlen) <= 0) + MOZ_ASSERT(outlen > 0); + if (outlen == 0) return 0; va_start(ap, fmt); diff --git a/js/src/jsprf.h b/js/src/jsprf.h index e8c9b6d27e..4c3ffde822 100644 --- a/js/src/jsprf.h +++ b/js/src/jsprf.h @@ -25,14 +25,17 @@ ** %g - float */ +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizePrintfMacros.h" + #include #include "jstypes.h" /* ** sprintf into a fixed size buffer. Guarantees that a NUL is at the end -** of the buffer. Returns the length of the written output, NOT including -** the NUL, or (uint32_t)-1 if an error occurs. +** of the buffer. The return value is the length of the written output, +** NOT including the NUL, which is guaranteed less than "outlen" on success. */ extern JS_PUBLIC_API(uint32_t) JS_snprintf(char* out, uint32_t outlen, const char* fmt, ...); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d81d7cf6ca..029689f9d4 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3962,8 +3962,7 @@ JSScript::traceChildren(JSTracer* trc) void LazyScript::finalize(FreeOp* fop) { - if (table_) - fop->free_(table_); + fop->free_(table_); } size_t diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 716931d75d..b5a32e264a 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2271,6 +2271,41 @@ DoMatchLocal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLine return true; } +/* ES6 21.2.5.2.3. */ +static size_t +AdvanceStringIndex(HandleLinearString input, size_t length, size_t index, bool unicode) +{ + /* Steps 1-3 (implicit). */ + + /* Step 4: If input is latin1, there is no surrogate pair. */ + if (!unicode || input->hasLatin1Chars()) + return index + 1; + + JS::AutoCheckCannotGC nogc; + const char16_t* S = input->twoByteChars(nogc); + + /* Step 6. */ + if (index + 1 >= length) + return index + 1; + + /* Step 7. */ + char16_t first = S[index]; + + /* Step 8. */ + if (!unicode::IsLeadSurrogate(first)) + return index + 1; + + /* Step 9. */ + char16_t second = S[index + 1]; + + /* Step 10. */ + if (!unicode::IsTrailSurrogate(second)) + return index + 1; + + /* Step 11. */ + return index + 2; +} + /* ES5 15.5.4.10 step 8. */ static bool DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input, @@ -2326,6 +2361,7 @@ DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLin ScopedMatchPairs matches(&cx->tempLifoAlloc()); size_t charsLen = input->length(); RegExpShared& re = g.regExp(); + bool unicode = re.unicode(); for (size_t searchIndex = 0; searchIndex <= charsLen; ) { if (!CheckForInterrupt(cx)) return false; @@ -2343,7 +2379,9 @@ DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLin MatchPair& match = matches[0]; // Steps 8f(iii)(1-3). - searchIndex = match.isEmpty() ? match.limit + 1 : match.limit; + searchIndex = match.isEmpty() + ? AdvanceStringIndex(input, charsLen, match.limit, unicode) + : match.limit; // Step 8f(iii)(4-5). JSLinearString* str = NewDependentString(cx, input, match.start, match.length()); @@ -2610,6 +2648,7 @@ static bool DoMatchForReplaceGlobal(JSContext* cx, RegExpStatics* res, HandleLinearString linearStr, RegExpShared& re, ReplaceData& rdata, size_t* rightContextOffset) { + bool unicode = re.unicode(); size_t charsLen = linearStr->length(); ScopedMatchPairs matches(&cx->tempLifoAlloc()); for (size_t count = 0, searchIndex = 0; searchIndex <= charsLen; ++count) { @@ -2624,7 +2663,9 @@ DoMatchForReplaceGlobal(JSContext* cx, RegExpStatics* res, HandleLinearString li break; MatchPair& match = matches[0]; - searchIndex = match.isEmpty() ? match.limit + 1 : match.limit; + searchIndex = match.isEmpty() + ? AdvanceStringIndex(linearStr, charsLen, match.limit, unicode) + : match.limit; *rightContextOffset = match.limit; if (!res->updateFromMatchPairs(cx, linearStr, matches)) @@ -3224,6 +3265,7 @@ StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) size_t lazyIndex = 0; /* Index before last successful match. */ /* Accumulate StringRanges for unmatched substrings. */ + bool unicode = re.unicode(); while (startIndex <= charsLen) { if (!CheckForInterrupt(cx)) return nullptr; @@ -3244,7 +3286,9 @@ StrReplaceRegexpRemove(JSContext* cx, HandleString str, RegExpShared& re) lazyIndex = lastIndex; lastIndex = match.limit; - startIndex = match.isEmpty() ? match.limit + 1 : match.limit; + startIndex = match.isEmpty() + ? AdvanceStringIndex(linearStr, charsLen, match.limit, unicode) + : match.limit; /* Non-global removal executes at most once. */ if (!re.global()) @@ -3627,7 +3671,7 @@ class SplitMatchResult { template static JSObject* SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher& splitMatch, - HandleObjectGroup group) + HandleObjectGroup group, bool unicode) { size_t strLength = str->length(); SplitMatchResult result; @@ -3692,7 +3736,7 @@ SplitHelper(JSContext* cx, HandleLinearString str, uint32_t limit, const Matcher /* Step 13(c)(ii). */ if (endIndex == lastEndIndex) { - index++; + index = AdvanceStringIndex(str, strLength, index, unicode); continue; } @@ -3921,14 +3965,14 @@ js::str_split(JSContext* cx, unsigned argc, Value* vp) aobj = CharSplitHelper(cx, linearStr, limit, group); } else { SplitStringMatcher matcher(cx, sepstr); - aobj = SplitHelper(cx, linearStr, limit, matcher, group); + aobj = SplitHelper(cx, linearStr, limit, matcher, group, false); } } else { RegExpStatics* res = cx->global()->getRegExpStatics(cx); if (!res) return false; SplitRegExpMatcher matcher(*re, res); - aobj = SplitHelper(cx, linearStr, limit, matcher, group); + aobj = SplitHelper(cx, linearStr, limit, matcher, group, re->unicode()); } if (!aobj) return false; @@ -3956,7 +4000,7 @@ js::str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, H return CharSplitHelper(cx, linearStr, limit, group); SplitStringMatcher matcher(cx, linearSep); - return SplitHelper(cx, linearStr, limit, matcher, group); + return SplitHelper(cx, linearStr, limit, matcher, group, false); } /* diff --git a/js/src/tests/ecma_6/Class/superPropIncDecElem.js b/js/src/tests/ecma_6/Class/superPropIncDecElem.js new file mode 100644 index 0000000000..12b369d3ed --- /dev/null +++ b/js/src/tests/ecma_6/Class/superPropIncDecElem.js @@ -0,0 +1,31 @@ +var test = ` + +// #1 +function base() { } + +base.prototype = { + test() { + --super[1]; + } +} + +var d = new base(); +d.test(); + +// #2 +class test2 { + test() { + super[1]++; + } +} + +var d = new test2(); +d.test() + +`; + +if (classesEnabled()) + eval(test); + +if (typeof reportCompare === 'function') + reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/RegExp/descriptor.js b/js/src/tests/ecma_6/RegExp/descriptor.js index 1174773dd8..cc545b3a6a 100644 --- a/js/src/tests/ecma_6/RegExp/descriptor.js +++ b/js/src/tests/ecma_6/RegExp/descriptor.js @@ -8,8 +8,9 @@ var getters = [ "global", "ignoreCase", "multiline", + "source", "sticky", - //"unicode", + "unicode", ]; for (var name of getters) { @@ -20,9 +21,5 @@ for (var name of getters) { assertEq("get" in desc, true); } -// When the /u flag is supported, remove this comment and the next line, and -// uncomment "unicode" in |props| above. -assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError); - if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/flag-accessors.js b/js/src/tests/ecma_6/RegExp/flag-accessors.js index 4f169c8a4b..848b916c50 100644 --- a/js/src/tests/ecma_6/RegExp/flag-accessors.js +++ b/js/src/tests/ecma_6/RegExp/flag-accessors.js @@ -8,17 +8,14 @@ var props = [ "ignoreCase", "multiline", "sticky", - //"unicode", + "unicode", ]; testThrows(RegExp.prototype); test(/foo/iymg, [true, true, true, true, false]); test(RegExp(""), [false, false, false, false, false]); test(RegExp("", "mygi"), [true, true, true, true, false]); -// When the /u flag is supported, remove the following line, uncomment the -// next line, and uncomment "unicode" in |props| above. -assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError); -// test(RegExp("", "mygiu"), [true, true, true, true, true]); +test(RegExp("", "mygiu"), [true, true, true, true, true]); testThrowsGeneric(); testThrowsGeneric(1); diff --git a/js/src/tests/ecma_6/RegExp/flags.js b/js/src/tests/ecma_6/RegExp/flags.js index 5a0245d991..292fa4f3f5 100644 --- a/js/src/tests/ecma_6/RegExp/flags.js +++ b/js/src/tests/ecma_6/RegExp/flags.js @@ -7,16 +7,12 @@ assertEq(RegExp.prototype.flags, ""); assertEq(/foo/iymg.flags, "gimy"); assertEq(RegExp("").flags, ""); assertEq(RegExp("", "mygi").flags, "gimy"); -// TODO: Uncomment lines 12, 16, 19 and remove lines 11, 15, 18 when bug 1135377 is fixed. -assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError); -// assertEq(RegExp("", "mygui").flags, "gimuy"); +assertEq(RegExp("", "mygui").flags, "gimuy"); assertEq(genericFlags({}), ""); assertEq(genericFlags({ignoreCase: true}), "i"); -assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "y"); -// assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "uy"); +assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "uy"); assertEq(genericFlags({__proto__: {multiline: true}}), "m"); -assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimy"); -// assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimuy"); +assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimuy"); assertThrowsInstanceOf(() => genericFlags(), TypeError); assertThrowsInstanceOf(() => genericFlags(1), TypeError); diff --git a/js/src/tests/ecma_6/RegExp/unicode-back-reference.js b/js/src/tests/ecma_6/RegExp/unicode-back-reference.js new file mode 100644 index 0000000000..2a65432a1d --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-back-reference.js @@ -0,0 +1,39 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- back reference should not match lead surrogate that has corresponding trail surrogate."; + +print(BUGNUMBER + ": " + summary); + +// The last character of back reference is not a surrogate. +assertEqArray(/foo(.+)bar\1/u.exec("fooAbarA\uDC00"), + ["fooAbarA", "A"]); +assertEqArray(/foo(.+)bar\1/u.exec("fooAbarA\uD834"), + ["fooAbarA", "A"]); +assertEqArray(/foo(.+)bar\1/u.exec("fooAbarAA"), + ["fooAbarA", "A"]); +assertEqArray(/foo(.+)bar\1/u.exec("fooAbarA"), + ["fooAbarA", "A"]); + +// The last character of back reference is a lead surrogate. +assertEq(/foo(.+)bar\1/u.exec("foo\uD834bar\uD834\uDC00"), null); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uD834bar\uD834\uD834"), + ["foo\uD834bar\uD834", "\uD834"]); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uD834bar\uD834A"), + ["foo\uD834bar\uD834", "\uD834"]); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uD834bar\uD834"), + ["foo\uD834bar\uD834", "\uD834"]); + +// The last character of back reference is a trail surrogate. +assertEqArray(/foo(.+)bar\1/u.exec("foo\uDC00bar\uDC00\uDC00"), + ["foo\uDC00bar\uDC00", "\uDC00"]); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uDC00bar\uDC00\uD834"), + ["foo\uDC00bar\uDC00", "\uDC00"]); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uDC00bar\uDC00A"), + ["foo\uDC00bar\uDC00", "\uDC00"]); +assertEqArray(/foo(.+)bar\1/u.exec("foo\uDC00bar\uDC00"), + ["foo\uDC00bar\uDC00", "\uDC00"]); + +// Pattern should not match to surrogate pair partially. +assertEq(/^(.+)\1$/u.exec("\uDC00foobar\uD834\uDC00foobar\uD834"), null); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-braced.js b/js/src/tests/ecma_6/RegExp/unicode-braced.js new file mode 100644 index 0000000000..97df7acabf --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-braced.js @@ -0,0 +1,166 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- braced pattern in RegExpUnicodeEscapeSequence."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(/\u{41}/u.exec("ABC"), + ["A"]); +assertEqArray(/\u{41}/.exec("ABC" + "u".repeat(41)), + ["u".repeat(41)]); + +assertEqArray(/\u{4A}/u.exec("JKL"), + ["J"]); +assertEqArray(/\u{4A}/.exec("JKLu{4A}"), + ["u{4A}"]); + +assertEqArray(/\u{1F438}/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\u{1F438}/.exec("u{1F438}"), + ["u{1F438}"]); + +assertEqArray(/\u{0}/u.exec("\u{0}"), + ["\u{0}"]); +assertEqArray(/\u{10FFFF}/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); +assertEqArray(/\u{10ffff}/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +// leading 0 +assertEqArray(/\u{0000000000000000000000}/u.exec("\u{0}"), + ["\u{0}"]); +assertEqArray(/\u{000000000000000010FFFF}/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +// RegExp constructor +assertEqArray(new RegExp("\\u{0}", "u").exec("\u{0}"), + ["\u{0}"]); +assertEqArray(new RegExp("\\u{41}", "u").exec("ABC"), + ["A"]); +assertEqArray(new RegExp("\\u{1F438}", "u").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(new RegExp("\\u{10FFFF}", "u").exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +assertEqArray(new RegExp("\\u{0000000000000000}", "u").exec("\u{0}"), + ["\u{0}"]); + +assertEqArray(eval(`/\\u{${"0".repeat(Math.pow(2, 24)) + "1234"}}/u`).exec("\u{1234}"), + ["\u{1234}"]); +assertEqArray(new RegExp(`\\u{${"0".repeat(Math.pow(2, 24)) + "1234"}}`, "u").exec("\u{1234}"), + ["\u{1234}"]); + +// ==== ? ==== + +assertEqArray(/\u{1F438}?/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\u{1F438}?/u.exec(""), + [""]); + +// lead-only target +assertEqArray(/\u{1F438}?/u.exec("\uD83D"), + [""]); + +// RegExp constructor +assertEqArray(new RegExp("\\u{1F438}?", "u").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(new RegExp("\\u{1F438}?", "u").exec(""), + [""]); +assertEqArray(new RegExp("\\u{1F438}?", "u").exec("\uD83D"), + [""]); + +// ==== + ==== + +assertEqArray(/\u{1F438}+/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\u{1F438}+/u.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}\u{1F438}"]); +assertEq(/\u{1F438}+/u.exec(""), + null); + +// lead-only target +assertEq(/\u{1F438}+/u.exec("\uD83D"), + null); +assertEqArray(/\u{1F438}+/u.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38"]); + +// ==== * ==== + +assertEqArray(/\u{1F438}*/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\u{1F438}*/u.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}\u{1F438}"]); +assertEqArray(/\u{1F438}*/u.exec(""), + [""]); + +// lead-only target +assertEqArray(/\u{1F438}*/u.exec("\uD83D"), + [""]); +assertEqArray(/\u{1F438}*/u.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38"]); + +// ==== lead-only ==== + +// match only non-surrogate pair +assertEqArray(/\u{D83D}/u.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEq(/\u{D83D}/u.exec("\uD83D\uDC00"), + null); +assertEq(/\u{D83D}/u.exec("\uD83D\uDFFF"), + null); +assertEqArray(/\u{D83D}/u.exec("\uD83D\uE000"), + ["\uD83D"]); + +// match before non-tail char +assertEqArray(/\u{D83D}/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\u{D83D}/u.exec("\uD83DA"), + ["\uD83D"]); + +// ==== trail-only ==== + +// match only non-surrogate pair +assertEqArray(/\u{DC38}/u.exec("\uD7FF\uDC38"), + ["\uDC38"]); +assertEq(/\u{DC38}/u.exec("\uD800\uDC38"), + null); +assertEq(/\u{DC38}/u.exec("\uDBFF\uDC38"), + null); +assertEqArray(/\u{DC38}/u.exec("\uDC00\uDC38"), + ["\uDC38"]); + +// match after non-lead char +assertEqArray(/\u{DC38}/u.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/\u{DC38}/u.exec("A\uDC38"), + ["\uDC38"]); + +// ==== wrong patterns ==== + +assertThrowsInstanceOf(() => eval(`/\\u{-1}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{0.0}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{G}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{{/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{110000}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{00110000}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{100000000000000000000000000000}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{ FFFF}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{FFFF }/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{FF FF}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{F F F F}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u{100000001}/u`), SyntaxError); + +// surrogate pair with braced +assertEq(/\u{D83D}\u{DC38}+/u.exec("\uD83D\uDC38\uDC38"), + null); +assertEq(/\uD83D\u{DC38}+/u.exec("\uD83D\uDC38\uDC38"), + null); +assertEq(/\u{D83D}\uDC38+/u.exec("\uD83D\uDC38\uDC38"), + null); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-character-class-escape.js b/js/src/tests/ecma_6/RegExp/unicode-character-class-escape.js new file mode 100644 index 0000000000..175207d5ae --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-character-class-escape.js @@ -0,0 +1,75 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- CharacterClassEscape."; + +print(BUGNUMBER + ": " + summary); + +// BMP + +assertEqArray(/\d+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["0123456789"]); +assertEqArray(/\D+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ"]); + +assertEqArray(/\s+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\t\r\n\v\x0c\xa0\uFEFF"]); +assertEqArray(/\S+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ0123456789_"]); + +assertEqArray(/\w+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ0123456789_"]); +assertEqArray(/\W+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\t\r\n\v\x0c\xa0\uFEFF*"]); + +assertEqArray(/\n+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\n"]); + +assertEqArray(/[\d]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["0123456789"]); +assertEqArray(/[\D]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ"]); + +assertEqArray(/[\s]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\t\r\n\v\x0c\xa0\uFEFF"]); +assertEqArray(/[\S]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ0123456789_"]); + +assertEqArray(/[\w]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["abcxyzABCXYZ0123456789_"]); +assertEqArray(/[\W]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\t\r\n\v\x0c\xa0\uFEFF*"]); + +assertEqArray(/[\n]+/u.exec("abcxyzABCXYZ0123456789_\t\r\n\v\x0c\xa0\uFEFF*"), + ["\n"]); + +// non-BMP + +function testNonBMP(re) { + assertEqArray(re.exec("\uD83D\uDBFF"), + ["\uD83D"]); + assertEqArray(re.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); + assertEqArray(re.exec("\uD83D\uDFFF"), + ["\uD83D\uDFFF"]); + assertEqArray(re.exec("\uD83D\uE000"), + ["\uD83D"]); + + assertEqArray(re.exec("\uD7FF\uDC38"), + ["\uD7FF"]); + assertEqArray(re.exec("\uD800\uDC38"), + ["\uD800\uDC38"]); + assertEqArray(re.exec("\uDBFF\uDC38"), + ["\uDBFF\uDC38"]); + assertEqArray(re.exec("\uDC00\uDC38"), + ["\uDC00"]); +} + +testNonBMP(/\D/u); +testNonBMP(/\S/u); +testNonBMP(/\W/u); + +testNonBMP(/[\D]/u); +testNonBMP(/[\S]/u); +testNonBMP(/[\W]/u); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-braced.js b/js/src/tests/ecma_6/RegExp/unicode-class-braced.js new file mode 100644 index 0000000000..4b59540129 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-braced.js @@ -0,0 +1,236 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- braced pattern in RegExpUnicodeEscapeSequence in CharacterClass."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(/[\u{41}]/u.exec("ABC"), + ["A"]); + +assertEqArray(/[\u{1F438}]/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(/[\u{1F438}]/u.exec("\uD83D"), + null); +assertEq(/[\u{1F438}]/u.exec("\uDC38"), + null); + +assertEqArray(/[\u{0}]/u.exec("\u{0}"), + ["\u{0}"]); +assertEqArray(/[\u{10FFFF}]/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); +assertEqArray(/[\u{10ffff}]/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +// leading 0 +assertEqArray(/[\u{0000000000000000000000}]/u.exec("\u{0}"), + ["\u{0}"]); +assertEqArray(/[\u{000000000000000010FFFF}]/u.exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +// RegExp constructor +assertEqArray(new RegExp("[\\u{0}]", "u").exec("\u{0}"), + ["\u{0}"]); +assertEqArray(new RegExp("[\\u{41}]", "u").exec("ABC"), + ["A"]); +assertEqArray(new RegExp("[\\u{1F438}]", "u").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(new RegExp("[\\u{10FFFF}]", "u").exec("\u{10FFFF}"), + ["\u{10FFFF}"]); + +assertEqArray(new RegExp("[\\u{0000000000000000}]", "u").exec("\u{0}"), + ["\u{0}"]); + +assertEqArray(eval(`/[\\u{${"0".repeat(Math.pow(2, 24)) + "1234"}}]/u`).exec("\u{1234}"), + ["\u{1234}"]); +assertEqArray(new RegExp(`[\\u{${"0".repeat(Math.pow(2, 24)) + "1234"}}]`, "u").exec("\u{1234}"), + ["\u{1234}"]); + +// ==== BMP + non-BMP ==== + +assertEqArray(/[A\u{1F438}]/u.exec("A\u{1F438}"), + ["A"]); +assertEqArray(/[A\u{1F438}]/u.exec("\u{1F438}A"), + ["\u{1F438}"]); + +// lead-only target +assertEqArray(/[A\u{1F438}]/u.exec("\uD83DA"), + ["A"]); +assertEq(/[A\u{1F438}]/u.exec("\uD83D"), + null); + +// + +assertEqArray(/[A\u{1F438}]+/u.exec("\u{1F438}A\u{1F438}A"), + ["\u{1F438}A\u{1F438}A"]); + +// trail surrogate + lead surrogate +assertEqArray(/[A\u{1F438}]+/u.exec("\uD83D\uDC38A\uDC38\uD83DA"), + ["\uD83D\uDC38A"]); + +// ==== non-BMP + non-BMP ==== + +assertEqArray(/[\u{1F418}\u{1F438}]/u.exec("\u{1F418}\u{1F438}"), + ["\u{1F418}"]); + +assertEqArray(/[\u{1F418}\u{1F438}]+/u.exec("\u{1F418}\u{1F438}"), + ["\u{1F418}\u{1F438}"]); +assertEqArray(/[\u{1F418}\u{1F438}]+/u.exec("\u{1F418}\uDC38\uD83D"), + ["\u{1F418}"]); +assertEqArray(/[\u{1F418}\u{1F438}]+/u.exec("\uDC18\uD83D\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/[\u{1F418}\u{1F438}]+/u.exec("\uDC18\u{1F438}\uD83D"), + ["\u{1F438}"]); + +// trail surrogate + lead surrogate +assertEq(/[\u{1F418}\u{1F438}]+/u.exec("\uDC18\uDC38\uD83D\uD83D"), + null); + +// ==== non-BMP + non-BMP range (from_lead == to_lead) ==== + +assertEqArray(/[\u{1F418}-\u{1F438}]/u.exec("\u{1F418}"), + ["\u{1F418}"]); +assertEqArray(/[\u{1F418}-\u{1F438}]/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/[\u{1F418}-\u{1F438}]/u.exec("\u{1F427}"), + ["\u{1F427}"]); + +assertEq(/[\u{1F418}-\u{1F438}]/u.exec("\u{1F417}"), + null); +assertEq(/[\u{1F418}-\u{1F438}]/u.exec("\u{1F439}"), + null); + +// ==== non-BMP + non-BMP range (from_lead + 1 == to_lead) ==== + +assertEqArray(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83C\uDD7C"), + ["\uD83C\uDD7C"]); +assertEqArray(/[\u{1F17C}-\u{1F438}]/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83C\uDF99"), + ["\uD83C\uDF99"]); +assertEqArray(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); + +assertEq(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83C\uDD7B"), + null); +assertEq(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83C\uE000"), + null); +assertEq(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83D\uDB99"), + null); +assertEq(/[\u{1F17C}-\u{1F438}]/u.exec("\uD83D\uDC39"), + null); + +// ==== non-BMP + non-BMP range (from_lead + 2 == to_lead) ==== + +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83C\uDD7C"), + ["\uD83C\uDD7C"]); +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83E\uDC29"), + ["\uD83E\uDC29"]); + +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83C\uDF99"), + ["\uD83C\uDF99"]); +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83D\uDF99"), + ["\uD83D\uDF99"]); +assertEqArray(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83E\uDC00"), + ["\uD83E\uDC00"]); + +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83C\uDD7B"), + null); +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83C\uE000"), + null); +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83D\uDB99"), + null); +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83D\uE000"), + null); +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83E\uDB99"), + null); +assertEq(/[\u{1F17C}-\u{1F829}]/u.exec("\uD83E\uDC30"), + null); + +// ==== non-BMP + non-BMP range (other) ==== + +assertEqArray(/[\u{1D164}-\u{1F438}]/u.exec("\uD834\uDD64"), + ["\uD834\uDD64"]); +assertEqArray(/[\u{1D164}-\u{1F438}]/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/[\u{1D164}-\u{1F438}]/u.exec("\uD836\uDF99"), + ["\uD836\uDF99"]); +assertEqArray(/[\u{1D164}-\u{1F438}]/u.exec("\uD838\uDC00"), + ["\uD838\uDC00"]); + +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD834\uDD63"), + null); +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD83D\uDC39"), + null); + +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD834\uE000"), + null); +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD835\uDB99"), + null); +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD83C\uE000"), + null); +assertEq(/[\u{1D164}-\u{1F438}]/u.exec("\uD83D\uDB99"), + null); + +// ==== BMP + non-BMP range ==== + +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("B"), + ["B"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("C"), + ["C"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uFFFF"), + ["\uFFFF"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD800\uDC00"), + ["\uD800\uDC00"]); + +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD800"), + ["\uD800"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uDBFF"), + ["\uDBFF"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uDC00"), + ["\uDC00"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uDFFF"), + ["\uDFFF"]); + +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uDC38"), + ["\uDC38"]); + +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uDC38"), + ["\uD83D\uDC38"]); +assertEq(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uDC39"), + null); +assertEq(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uDFFF"), + null); +assertEqArray(/[\u{42}-\u{1F438}]/u.exec("\uD83D\uE000"), + ["\uD83D"]); + +assertEq(/[\u{42}-\u{1F438}]/u.exec("A"), + null); + +// ==== wrong patterns ==== + +assertThrowsInstanceOf(() => eval(`/[\\u{-1}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{0.0}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{G}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{{]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{110000}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{00110000}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{100000000000000000000000000000}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{ FFFF}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{FFFF }]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{FF FF}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{F F F F}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u{100000001}]/u`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-empty.js b/js/src/tests/ecma_6/RegExp/unicode-class-empty.js new file mode 100644 index 0000000000..4d187551f6 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-empty.js @@ -0,0 +1,25 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- empty class should not match anything."; + +print(BUGNUMBER + ": " + summary); + +assertEq(/[]/u.exec("A"), + null); +assertEq(/[]/u.exec("\uD83D"), + null); +assertEq(/[]/u.exec("\uDC38"), + null); +assertEq(/[]/u.exec("\uD83D\uDC38"), + null); + +assertEqArray(/[^]/u.exec("A"), + ["A"]); +assertEqArray(/[^]/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[^]/u.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/[^]/u.exec("\uD83D\uDC38"), + ["\uD83D\uDC38"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-ignoreCase.js b/js/src/tests/ecma_6/RegExp/unicode-class-ignoreCase.js new file mode 100644 index 0000000000..afa7705c72 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-ignoreCase.js @@ -0,0 +1,28 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag for CharacterClass."; + +print(BUGNUMBER + ": " + summary); + +assertEqArray(/[ABC]+/iu.exec("DCBAabcd"), + ["CBAabc"]); + +assertEqArray(/[A\u{10401}]+/iu.exec("A\u{10401}a\u{10429}"), + ["A\u{10401}a\u{10429}"]); + +assertEqArray(/[\u{10401}-\u{10404}\u{10408}-\u{1040B}]+/iu.exec("\u{10400}\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}\u{1040C}"), + ["\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}"]); +assertEqArray(/[\u{10401}-\u{10404}\u{10408}-\u{1040B}]+/iu.exec("\u{10428}\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}\u{10434}"), + ["\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}"]); + +assertEqArray(/[\u{10429}-\u{1042C}\u{10430}-\u{10433}]+/iu.exec("\u{10400}\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}\u{1040C}"), + ["\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}"]); +assertEqArray(/[\u{10429}-\u{1042C}\u{10430}-\u{10433}]+/iu.exec("\u{10428}\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}\u{10434}"), + ["\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}"]); + +assertEqArray(/[\u{10401}-\u{10404}\u{10430}-\u{10433}]+/iu.exec("\u{10400}\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}\u{1040C}"), + ["\u{10401}\u{10402}\u{10403}\u{10404}\u{10408}\u{10409}\u{1040A}\u{1040B}"]); +assertEqArray(/[\u{10401}-\u{10404}\u{10430}-\u{10433}]+/iu.exec("\u{10428}\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}\u{10434}"), + ["\u{10429}\u{1042A}\u{1042B}\u{1042C}\u{10430}\u{10431}\u{10432}\u{10433}"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-lead-trail.js b/js/src/tests/ecma_6/RegExp/unicode-class-lead-trail.js new file mode 100644 index 0000000000..c83bf937d4 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-lead-trail.js @@ -0,0 +1,142 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- lead and trail pattern in RegExpUnicodeEscapeSequence in CharacterClass."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(/[\uD83D\uDC38]/u.exec("\uD83D\uDC38"), + ["\uD83D\uDC38"]); +assertEq(/[\uD83D\uDC38]/u.exec("\uD83D"), + null); +assertEq(/[\uD83D\uDC38]/u.exec("\uDC38"), + null); + +// no unicode flag +assertEqArray(/[\uD83D\uDC38]/.exec("\uD83D\uDC38"), + ["\uD83D"]); +assertEqArray(/[\uD83D\uDC38]/.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83D\uDC38]/.exec("\uDC38"), + ["\uDC38"]); + +// RegExp constructor +assertEqArray(new RegExp("[\uD83D\uDC38]", "u").exec("\uD83D\uDC38"), + ["\uD83D\uDC38"]); +assertEq(new RegExp("[\uD83D\uDC38]", "u").exec("\uD83D"), + null); +assertEq(new RegExp("[\uD83D\uDC38]", "u").exec("\uDC38"), + null); + +// RegExp constructor, no unicode flag +assertEqArray(new RegExp("[\uD83D\uDC38]", "").exec("\uD83D\uDC38"), + ["\uD83D"]); +assertEqArray(new RegExp("[\uD83D\uDC38]", "").exec("\uD83D"), + ["\uD83D"]); +assertEqArray(new RegExp("[\uD83D\uDC38]", "").exec("\uDC38"), + ["\uDC38"]); + +// ==== lead-only ==== + +// match only non-surrogate pair +assertEqArray(/[\uD83D]/u.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEq(/[\uD83D]/u.exec("\uD83D\uDC00"), + null); +assertEq(/[\uD83D]/u.exec("\uD83D\uDFFF"), + null); +assertEqArray(/[\uD83D]/u.exec("\uD83D\uE000"), + ["\uD83D"]); + +// match before non-tail char +assertEqArray(/[\uD83D]/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/u.exec("\uD83DA"), + ["\uD83D"]); + +// no unicode flag +assertEqArray(/[\uD83D]/.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/.exec("\uD83D\uDC00"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/.exec("\uD83D\uDFFF"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/.exec("\uD83D\uE000"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83D]/.exec("\uD83DA"), + ["\uD83D"]); + +// ==== trail-only ==== + +// match only non-surrogate pair +assertEqArray(/[\uDC38]/u.exec("\uD7FF\uDC38"), + ["\uDC38"]); +assertEq(/[\uDC38]/u.exec("\uD800\uDC38"), + null); +assertEq(/[\uDC38]/u.exec("\uDBFF\uDC38"), + null); +assertEqArray(/[\uDC38]/u.exec("\uDC00\uDC38"), + ["\uDC38"]); + +// match after non-lead char +assertEqArray(/[\uDC38]/u.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/u.exec("A\uDC38"), + ["\uDC38"]); + +// no unicode flag +assertEqArray(/[\uDC38]/.exec("\uD7FF\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/.exec("\uD800\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/.exec("\uDBFF\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/.exec("\uDC00\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/[\uDC38]/.exec("A\uDC38"), + ["\uDC38"]); + +// ==== invalid trail ==== + +assertEqArray(/[\uD83D\u3042]*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83D\u3042]*/u.exec("\uD83D\u3042"), + ["\uD83D\u3042"]); +assertEqArray(/[\uD83D\u3042]*/u.exec("\uD83D\u3042\u3042\uD83D"), + ["\uD83D\u3042\u3042\uD83D"]); + +assertEqArray(/[\uD83D\u{3042}]*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83D\u{3042}]*/u.exec("\uD83D\u3042"), + ["\uD83D\u3042"]); +assertEqArray(/[\uD83D\u{3042}]*/u.exec("\uD83D\u3042\u3042\uD83D"), + ["\uD83D\u3042\u3042\uD83D"]); + +assertEqArray(/[\uD83DA]*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/[\uD83DA]*/u.exec("\uD83DA"), + ["\uD83DA"]); +assertEqArray(/[\uD83DA]*/u.exec("\uD83DAA\uD83D"), + ["\uD83DAA\uD83D"]); + +// ==== wrong patterns ==== + +assertThrowsInstanceOf(() => eval(`/[\\u]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u0]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u00]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u000]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u000G]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\u0.00]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u0]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u00]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u000]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u000G]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\u0.00]/u`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-negated.js b/js/src/tests/ecma_6/RegExp/unicode-class-negated.js new file mode 100644 index 0000000000..0b573f6dcf --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-negated.js @@ -0,0 +1,64 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- negated CharacterClass."; + +print(BUGNUMBER + ": " + summary); + +// ==== BMP ==== + +assertEqArray(/[^A]/u.exec("ABC"), + ["B"]); +assertEqArray(/[^A]/u.exec("A\u{1F438}C"), + ["\u{1F438}"]); +assertEqArray(/[^A]/u.exec("A\uD83DC"), + ["\uD83D"]); +assertEqArray(/[^A]/u.exec("A\uDC38C"), + ["\uDC38"]); + +assertEqArray(/[^\uE000]/u.exec("\uE000\uE001"), + ["\uE001"]); +assertEqArray(/[^\uE000]/u.exec("\uE000\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/[^\uE000]/u.exec("\uE000\uD83D"), + ["\uD83D"]); +assertEqArray(/[^\uE000]/u.exec("\uE000\uDC38"), + ["\uDC38"]); + +// ==== non-BMP ==== + +assertEqArray(/[^\u{1F438}]/u.exec("\u{1F438}A"), + ["A"]); +assertEqArray(/[^\u{1F438}]/u.exec("\u{1F438}\u{1F439}"), + ["\u{1F439}"]); +assertEqArray(/[^\u{1F438}]/u.exec("\u{1F438}\uD83D"), + ["\uD83D"]); +assertEqArray(/[^\u{1F438}]/u.exec("\u{1F438}\uDC38"), + ["\uDC38"]); + +// ==== lead-only ==== + +assertEqArray(/[^\uD83D]/u.exec("\u{1F438}A"), + ["\u{1F438}"]); +assertEqArray(/[^\uD83D]/u.exec("\uD83D\uDBFF"), + ["\uDBFF"]); +assertEqArray(/[^\uD83D]/u.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); +assertEqArray(/[^\uD83D]/u.exec("\uD83D\uDFFF"), + ["\uD83D\uDFFF"]); +assertEqArray(/[^\uD83D]/u.exec("\uD83D\uE000"), + ["\uE000"]); + +// ==== trail-only ==== + +assertEqArray(/[^\uDC38]/u.exec("\u{1F438}A"), + ["\u{1F438}"]); +assertEqArray(/[^\uDC38]/u.exec("\uD7FF\uDC38"), + ["\uD7FF"]); +assertEqArray(/[^\uDC38]/u.exec("\uD800\uDC38"), + ["\uD800\uDC38"]); +assertEqArray(/[^\uDC38]/u.exec("\uDBFF\uDC38"), + ["\uDBFF\uDC38"]); +assertEqArray(/[^\uDC38]/u.exec("\uDC00\uDC38"), + ["\uDC00"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-range.js b/js/src/tests/ecma_6/RegExp/unicode-class-range.js new file mode 100644 index 0000000000..5bb7575601 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-range.js @@ -0,0 +1,28 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- disallow range with CharacterClassEscape."; + +print(BUGNUMBER + ": " + summary); + +assertThrowsInstanceOf(() => eval(`/[\\w-\\uFFFF]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\W-\\uFFFF]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\d-\\uFFFF]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\D-\\uFFFF]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\s-\\uFFFF]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\S-\\uFFFF]/u`), SyntaxError); + +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\w]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\W]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\d]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\D]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\s]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uFFFF-\\S]/u`), SyntaxError); + +assertThrowsInstanceOf(() => eval(`/[\\w-\\w]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\W-\\W]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\d-\\d]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\D-\\D]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\s-\\s]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\S-\\S]/u`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-class-raw.js b/js/src/tests/ecma_6/RegExp/unicode-class-raw.js new file mode 100644 index 0000000000..742fec2b4d --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-class-raw.js @@ -0,0 +1,65 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- raw unicode."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(eval(`/[\uD83D\uDC38]/u`).exec("\u{1F438}"), + ["\u{1F438}"]); + +// no unicode flag +assertEqArray(eval(`/[\uD83D\uDC38]/`).exec("\u{1F438}"), + ["\uD83D"]); + +// escaped (lead) +assertEq(eval(`/[\\uD83D\uDC38]/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/[\\u{D83D}\uDC38]/u`).exec("\u{1F438}"), + null); + +// escaped (trail) +assertEq(eval(`/[\uD83D\\uDC38]/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/[\uD83D\\u{DC38}]/u`).exec("\u{1F438}"), + null); + +// escaped (lead), no unicode flag +assertEqArray(eval(`/[\\uD83D\uDC38]/`).exec("\u{1F438}"), + ["\uD83D"]); + +// escaped (trail), no unicode flag +assertEqArray(eval(`/[\uD83D\\uDC38]/`).exec("\u{1F438}"), + ["\uD83D"]); + +// ==== RegExp constructor ==== + +assertEqArray(new RegExp("[\uD83D\uDC38]", "u").exec("\u{1F438}"), + ["\u{1F438}"]); + +// no unicode flag +assertEqArray(new RegExp("[\uD83D\uDC38]", "").exec("\u{1F438}"), + ["\uD83D"]); + +// escaped(lead) +assertEq(new RegExp("[\\uD83D\uDC38]", "u").exec("\u{1F438}"), + null); +assertEq(new RegExp("[\\u{D83D}\uDC38]", "u").exec("\u{1F438}"), + null); + +// escaped(trail) +assertEq(new RegExp("[\uD83D\\uDC38]", "u").exec("\u{1F438}"), + null); +assertEq(new RegExp("[\uD83D\\u{DC38}]", "u").exec("\u{1F438}"), + null); + +// escaped(lead), no unicode flag +assertEqArray(new RegExp("[\\uD83D\uDC38]", "").exec("\u{1F438}"), + ["\uD83D"]); + +// escaped(trail), no unicode flag +assertEqArray(new RegExp("[\uD83D\\uDC38]", "").exec("\u{1F438}"), + ["\uD83D"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-disallow-extended.js b/js/src/tests/ecma_6/RegExp/unicode-disallow-extended.js new file mode 100644 index 0000000000..d1f775fac2 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-disallow-extended.js @@ -0,0 +1,117 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- disallow extended patterns."; + +print(BUGNUMBER + ": " + summary); + +// IdentityEscape + +assertEqArray(/\^\$\\\.\*\+\?\(\)\[\]\{\}\|/u.exec("^$\\.*+?()[]{}|"), + ["^$\\.*+?()[]{}|"]); +assertThrowsInstanceOf(() => eval(`/\\A/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\-/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\U{10}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\U0000/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\U0000/u`), SyntaxError); + +assertEqArray(/[\^\$\\\.\*\+\?\(\)\[\]\{\}\|]+/u.exec("^$\\.*+?()[]{}|"), + ["^$\\.*+?()[]{}|"]); +assertThrowsInstanceOf(() => eval(`/[\\A]/u`), SyntaxError); +assertEqArray(/[A\-Z]+/u.exec("a-zABC"), + ["-"]); +assertThrowsInstanceOf(() => eval(`/[\\U{10}]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\U0000]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\uD83D\\U0000]/u`), SyntaxError); + +// PatternCharacter +assertThrowsInstanceOf(() => eval(`/{}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/{/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/{0}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/{1,}/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/{1,2}/u`), SyntaxError); + +// QuantifiableAssertion +assertEqArray(/.B(?=A)/u.exec("cBaCBA"), + ["CB"]); +assertEqArray(/.B(?!A)/u.exec("CBAcBa"), + ["cB"]); +assertEqArray(/.B(?:A)/u.exec("cBaCBA"), + ["CBA"]); +assertEqArray(/.B(A)/u.exec("cBaCBA"), + ["CBA", "A"]); + +assertThrowsInstanceOf(() => eval(`/.B(?=A)+/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/.B(?!A)+/u`), SyntaxError); +assertEqArray(/.B(?:A)+/u.exec("cBaCBA"), + ["CBA"]); +assertEqArray(/.B(A)+/u.exec("cBaCBA"), + ["CBA", "A"]); + +// ControlLetter +assertEqArray(/\cA/u.exec("\u0001"), + ["\u0001"]); +assertEqArray(/\cZ/u.exec("\u001a"), + ["\u001a"]); +assertEqArray(/\ca/u.exec("\u0001"), + ["\u0001"]); +assertEqArray(/\cz/u.exec("\u001a"), + ["\u001a"]); + +assertEqArray(/[\cA]/u.exec("\u0001"), + ["\u0001"]); +assertEqArray(/[\cZ]/u.exec("\u001a"), + ["\u001a"]); +assertEqArray(/[\ca]/u.exec("\u0001"), + ["\u0001"]); +assertEqArray(/[\cz]/u.exec("\u001a"), + ["\u001a"]); + +assertThrowsInstanceOf(() => eval(`/\\c/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\c1/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\c_/u`), SyntaxError); + +assertThrowsInstanceOf(() => eval(`/[\\c]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\c1]/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/[\\c_]/u`), SyntaxError); + +// HexEscapeSequence +assertThrowsInstanceOf(() => eval(`/\\x/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\x0/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\x1/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\x1G/u`), SyntaxError); + +// LegacyOctalEscapeSequence +assertThrowsInstanceOf(() => eval(`/\\52/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\052/u`), SyntaxError); + +// DecimalEscape +assertEqArray(/\0/u.exec("\0"), + ["\0"]); +assertEqArray(/[\0]/u.exec("\0"), + ["\0"]); +assertEqArray(/\0A/u.exec("\0A"), + ["\0A"]); +assertEqArray(/\0G/u.exec("\0G"), + ["\0G"]); +assertEqArray(/(A.)\1/u.exec("ABACABAB"), + ["ABAB", "AB"]); +assertEqArray(/(A.)(B.)(C.)(D.)(E.)(F.)(G.)(H.)(I.)(J.)(K.)\10/u.exec("A1B2C3D4E5F6G7H8I9JaKbJa"), + ["A1B2C3D4E5F6G7H8I9JaKbJa", "A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "I9", "Ja", "Kb"]); + +assertThrowsInstanceOf(() => eval(`/\\00/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\01/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\09/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\1/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\2/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\3/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\4/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\5/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\6/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\7/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\8/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\9/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\10/u`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-everything.js b/js/src/tests/ecma_6/RegExp/unicode-everything.js new file mode 100644 index 0000000000..a18ac2867a --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-everything.js @@ -0,0 +1,59 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- everything Atom."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(/./u.exec("ABC"), + ["A"]); +assertEqArray(/./u.exec("\u{1F438}BC"), + ["\u{1F438}"]); + +assertEqArray(/./u.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEqArray(/./u.exec("\uD83D\uDC00"), + ["\uD83D\uDC00"]); +assertEqArray(/./u.exec("\uD83D\uDFFF"), + ["\uD83D\uDFFF"]); +assertEqArray(/./u.exec("\uD83D\uE000"), + ["\uD83D"]); +assertEqArray(/./u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/./u.exec("\uD83DA"), + ["\uD83D"]); + +assertEqArray(/./u.exec("\uD7FF\uDC38"), + ["\uD7FF"]); +assertEqArray(/./u.exec("\uD800\uDC38"), + ["\uD800\uDC38"]); +assertEqArray(/./u.exec("\uDBFF\uDC38"), + ["\uDBFF\uDC38"]); +assertEqArray(/./u.exec("\uDC00\uDC38"), + ["\uDC00"]); +assertEqArray(/./u.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/./u.exec("A\uDC38"), + ["A"]); + +assertEqArray(/.A/u.exec("\uD7FF\uDC38A"), + ["\uDC38A"]); +assertEqArray(/.A/u.exec("\uD800\uDC38A"), + ["\uD800\uDC38A"]); +assertEqArray(/.A/u.exec("\uDBFF\uDC38A"), + ["\uDBFF\uDC38A"]); +assertEqArray(/.A/u.exec("\uDC00\uDC38A"), + ["\uDC38A"]); + +// ==== leading multiple ==== + +assertEqArray(/.*A/u.exec("\u{1F438}\u{1F438}\u{1F438}A"), + ["\u{1F438}\u{1F438}\u{1F438}A"]); + +// ==== trailing multiple ==== + +assertEqArray(/A.*/u.exec("A\u{1F438}\u{1F438}\u{1F438}"), + ["A\u{1F438}\u{1F438}\u{1F438}"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-ascii.js b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-ascii.js new file mode 100644 index 0000000000..6d453290e9 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-ascii.js @@ -0,0 +1,45 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag with non-ascii to ascii map."; + +print(BUGNUMBER + ": " + summary); + +// LATIN CAPITAL LETTER Y WITH DIAERESIS +assertEqArray(/\u0178/iu.exec("\u00FF"), + ["\u00FF"]); +assertEqArray(/\u00FF/iu.exec("\u0178"), + ["\u0178"]); + +// LATIN SMALL LETTER LONG S +assertEqArray(/\u017F/iu.exec("S"), + ["S"]); +assertEqArray(/\u017F/iu.exec("s"), + ["s"]); +assertEqArray(/S/iu.exec("\u017F"), + ["\u017F"]); +assertEqArray(/s/iu.exec("\u017F"), + ["\u017F"]); + +// LATIN CAPITAL LETTER SHARP S +assertEqArray(/\u1E9E/iu.exec("\u00DF"), + ["\u00DF"]); +assertEqArray(/\u00DF/iu.exec("\u1E9E"), + ["\u1E9E"]); + +// KELVIN SIGN +assertEqArray(/\u212A/iu.exec("K"), + ["K"]); +assertEqArray(/\u212A/iu.exec("k"), + ["k"]); +assertEqArray(/K/iu.exec("\u212A"), + ["\u212A"]); +assertEqArray(/k/iu.exec("\u212A"), + ["\u212A"]); + +// ANGSTROM SIGN +assertEqArray(/\u212B/iu.exec("\u00E5"), + ["\u00E5"]); +assertEqArray(/\u00E5/iu.exec("\u212B"), + ["\u212B"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-escape.js b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-escape.js new file mode 100644 index 0000000000..af5981be08 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-escape.js @@ -0,0 +1,39 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag with character class escape."; + +print(BUGNUMBER + ": " + summary); + +// LATIN SMALL LETTER LONG S + +assertEqArray(/\w/iu.exec("S"), + ["S"]); +assertEqArray(/\w/iu.exec("s"), + ["s"]); +assertEqArray(/\w/iu.exec("\u017F"), + ["\u017F"]); + +assertEqArray(/\W/iu.exec("S"), + ["S"]); +assertEqArray(/\W/iu.exec("s"), + ["s"]); +assertEqArray(/\W/iu.exec("\u017F"), + ["\u017F"]); + +// KELVIN SIGN + +assertEqArray(/\w/iu.exec("k"), + ["k"]); +assertEqArray(/\w/iu.exec("k"), + ["k"]); +assertEqArray(/\w/iu.exec("\u212A"), + ["\u212A"]); + +assertEqArray(/\W/iu.exec("k"), + ["k"]); +assertEqArray(/\W/iu.exec("k"), + ["k"]); +assertEqArray(/\W/iu.exec("\u212A"), + ["\u212A"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-negated.js b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-negated.js new file mode 100644 index 0000000000..30909a515a --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase-negated.js @@ -0,0 +1,19 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag with negated character class."; + +print(BUGNUMBER + ": " + summary); + +assertEq(/[^A]/iu.exec("A"), + null); +assertEq(/[^a]/iu.exec("A"), + null); +assertEq(/[^A]/iu.exec("a"), + null); +assertEq(/[^a]/iu.exec("a"), + null); + +assertEqArray(/[^A]/iu.exec("b"), + ["b"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-ignoreCase.js b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase.js new file mode 100644 index 0000000000..dac67abba8 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-ignoreCase.js @@ -0,0 +1,2491 @@ +/* Generated by make_unicode.py DO NOT MODIFY */ + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag."; + +print(BUGNUMBER + ": " + summary); + +function test(code, ...equivs) { + var codeRe = new RegExp(String.fromCodePoint(code) + "+", "iu"); + var ans = String.fromCodePoint(code) + equivs.map(c => String.fromCodePoint(c)).join(""); + assertEqArray(codeRe.exec("<" + ans + ">"), [ans]); + codeRe = new RegExp("[" + String.fromCodePoint(code) + "]+", "iu"); + assertEqArray(codeRe.exec("<" + ans + ">"), [ans]); +} +test(0x41,0x61); +test(0x42,0x62); +test(0x43,0x63); +test(0x44,0x64); +test(0x45,0x65); +test(0x46,0x66); +test(0x47,0x67); +test(0x48,0x68); +test(0x49,0x69); +test(0x4a,0x6a); +test(0x4b,0x6b,0x212a); +test(0x4c,0x6c); +test(0x4d,0x6d); +test(0x4e,0x6e); +test(0x4f,0x6f); +test(0x50,0x70); +test(0x51,0x71); +test(0x52,0x72); +test(0x53,0x73,0x17f); +test(0x54,0x74); +test(0x55,0x75); +test(0x56,0x76); +test(0x57,0x77); +test(0x58,0x78); +test(0x59,0x79); +test(0x5a,0x7a); +test(0x61,0x41); +test(0x62,0x42); +test(0x63,0x43); +test(0x64,0x44); +test(0x65,0x45); +test(0x66,0x46); +test(0x67,0x47); +test(0x68,0x48); +test(0x69,0x49); +test(0x6a,0x4a); +test(0x6b,0x4b,0x212a); +test(0x6c,0x4c); +test(0x6d,0x4d); +test(0x6e,0x4e); +test(0x6f,0x4f); +test(0x70,0x50); +test(0x71,0x51); +test(0x72,0x52); +test(0x73,0x53,0x17f); +test(0x74,0x54); +test(0x75,0x55); +test(0x76,0x56); +test(0x77,0x57); +test(0x78,0x58); +test(0x79,0x59); +test(0x7a,0x5a); +test(0xb5,0x3bc,0x39c); +test(0xc0,0xe0); +test(0xc1,0xe1); +test(0xc2,0xe2); +test(0xc3,0xe3); +test(0xc4,0xe4); +test(0xc5,0xe5,0x212b); +test(0xc6,0xe6); +test(0xc7,0xe7); +test(0xc8,0xe8); +test(0xc9,0xe9); +test(0xca,0xea); +test(0xcb,0xeb); +test(0xcc,0xec); +test(0xcd,0xed); +test(0xce,0xee); +test(0xcf,0xef); +test(0xd0,0xf0); +test(0xd1,0xf1); +test(0xd2,0xf2); +test(0xd3,0xf3); +test(0xd4,0xf4); +test(0xd5,0xf5); +test(0xd6,0xf6); +test(0xd8,0xf8); +test(0xd9,0xf9); +test(0xda,0xfa); +test(0xdb,0xfb); +test(0xdc,0xfc); +test(0xdd,0xfd); +test(0xde,0xfe); +test(0xdf,0x1e9e); +test(0xe0,0xc0); +test(0xe1,0xc1); +test(0xe2,0xc2); +test(0xe3,0xc3); +test(0xe4,0xc4); +test(0xe5,0xc5,0x212b); +test(0xe6,0xc6); +test(0xe7,0xc7); +test(0xe8,0xc8); +test(0xe9,0xc9); +test(0xea,0xca); +test(0xeb,0xcb); +test(0xec,0xcc); +test(0xed,0xcd); +test(0xee,0xce); +test(0xef,0xcf); +test(0xf0,0xd0); +test(0xf1,0xd1); +test(0xf2,0xd2); +test(0xf3,0xd3); +test(0xf4,0xd4); +test(0xf5,0xd5); +test(0xf6,0xd6); +test(0xf8,0xd8); +test(0xf9,0xd9); +test(0xfa,0xda); +test(0xfb,0xdb); +test(0xfc,0xdc); +test(0xfd,0xdd); +test(0xfe,0xde); +test(0xff,0x178); +test(0x100,0x101); +test(0x101,0x100); +test(0x102,0x103); +test(0x103,0x102); +test(0x104,0x105); +test(0x105,0x104); +test(0x106,0x107); +test(0x107,0x106); +test(0x108,0x109); +test(0x109,0x108); +test(0x10a,0x10b); +test(0x10b,0x10a); +test(0x10c,0x10d); +test(0x10d,0x10c); +test(0x10e,0x10f); +test(0x10f,0x10e); +test(0x110,0x111); +test(0x111,0x110); +test(0x112,0x113); +test(0x113,0x112); +test(0x114,0x115); +test(0x115,0x114); +test(0x116,0x117); +test(0x117,0x116); +test(0x118,0x119); +test(0x119,0x118); +test(0x11a,0x11b); +test(0x11b,0x11a); +test(0x11c,0x11d); +test(0x11d,0x11c); +test(0x11e,0x11f); +test(0x11f,0x11e); +test(0x120,0x121); +test(0x121,0x120); +test(0x122,0x123); +test(0x123,0x122); +test(0x124,0x125); +test(0x125,0x124); +test(0x126,0x127); +test(0x127,0x126); +test(0x128,0x129); +test(0x129,0x128); +test(0x12a,0x12b); +test(0x12b,0x12a); +test(0x12c,0x12d); +test(0x12d,0x12c); +test(0x12e,0x12f); +test(0x12f,0x12e); +test(0x132,0x133); +test(0x133,0x132); +test(0x134,0x135); +test(0x135,0x134); +test(0x136,0x137); +test(0x137,0x136); +test(0x139,0x13a); +test(0x13a,0x139); +test(0x13b,0x13c); +test(0x13c,0x13b); +test(0x13d,0x13e); +test(0x13e,0x13d); +test(0x13f,0x140); +test(0x140,0x13f); +test(0x141,0x142); +test(0x142,0x141); +test(0x143,0x144); +test(0x144,0x143); +test(0x145,0x146); +test(0x146,0x145); +test(0x147,0x148); +test(0x148,0x147); +test(0x14a,0x14b); +test(0x14b,0x14a); +test(0x14c,0x14d); +test(0x14d,0x14c); +test(0x14e,0x14f); +test(0x14f,0x14e); +test(0x150,0x151); +test(0x151,0x150); +test(0x152,0x153); +test(0x153,0x152); +test(0x154,0x155); +test(0x155,0x154); +test(0x156,0x157); +test(0x157,0x156); +test(0x158,0x159); +test(0x159,0x158); +test(0x15a,0x15b); +test(0x15b,0x15a); +test(0x15c,0x15d); +test(0x15d,0x15c); +test(0x15e,0x15f); +test(0x15f,0x15e); +test(0x160,0x161); +test(0x161,0x160); +test(0x162,0x163); +test(0x163,0x162); +test(0x164,0x165); +test(0x165,0x164); +test(0x166,0x167); +test(0x167,0x166); +test(0x168,0x169); +test(0x169,0x168); +test(0x16a,0x16b); +test(0x16b,0x16a); +test(0x16c,0x16d); +test(0x16d,0x16c); +test(0x16e,0x16f); +test(0x16f,0x16e); +test(0x170,0x171); +test(0x171,0x170); +test(0x172,0x173); +test(0x173,0x172); +test(0x174,0x175); +test(0x175,0x174); +test(0x176,0x177); +test(0x177,0x176); +test(0x178,0xff); +test(0x179,0x17a); +test(0x17a,0x179); +test(0x17b,0x17c); +test(0x17c,0x17b); +test(0x17d,0x17e); +test(0x17e,0x17d); +test(0x17f,0x73,0x53); +test(0x180,0x243); +test(0x181,0x253); +test(0x182,0x183); +test(0x183,0x182); +test(0x184,0x185); +test(0x185,0x184); +test(0x186,0x254); +test(0x187,0x188); +test(0x188,0x187); +test(0x189,0x256); +test(0x18a,0x257); +test(0x18b,0x18c); +test(0x18c,0x18b); +test(0x18e,0x1dd); +test(0x18f,0x259); +test(0x190,0x25b); +test(0x191,0x192); +test(0x192,0x191); +test(0x193,0x260); +test(0x194,0x263); +test(0x195,0x1f6); +test(0x196,0x269); +test(0x197,0x268); +test(0x198,0x199); +test(0x199,0x198); +test(0x19a,0x23d); +test(0x19c,0x26f); +test(0x19d,0x272); +test(0x19e,0x220); +test(0x19f,0x275); +test(0x1a0,0x1a1); +test(0x1a1,0x1a0); +test(0x1a2,0x1a3); +test(0x1a3,0x1a2); +test(0x1a4,0x1a5); +test(0x1a5,0x1a4); +test(0x1a6,0x280); +test(0x1a7,0x1a8); +test(0x1a8,0x1a7); +test(0x1a9,0x283); +test(0x1ac,0x1ad); +test(0x1ad,0x1ac); +test(0x1ae,0x288); +test(0x1af,0x1b0); +test(0x1b0,0x1af); +test(0x1b1,0x28a); +test(0x1b2,0x28b); +test(0x1b3,0x1b4); +test(0x1b4,0x1b3); +test(0x1b5,0x1b6); +test(0x1b6,0x1b5); +test(0x1b7,0x292); +test(0x1b8,0x1b9); +test(0x1b9,0x1b8); +test(0x1bc,0x1bd); +test(0x1bd,0x1bc); +test(0x1bf,0x1f7); +test(0x1c4,0x1c6,0x1c5); +test(0x1c5,0x1c6,0x1c4); +test(0x1c6,0x1c4,0x1c5); +test(0x1c7,0x1c9,0x1c8); +test(0x1c8,0x1c9,0x1c7); +test(0x1c9,0x1c7,0x1c8); +test(0x1ca,0x1cc,0x1cb); +test(0x1cb,0x1cc,0x1ca); +test(0x1cc,0x1ca,0x1cb); +test(0x1cd,0x1ce); +test(0x1ce,0x1cd); +test(0x1cf,0x1d0); +test(0x1d0,0x1cf); +test(0x1d1,0x1d2); +test(0x1d2,0x1d1); +test(0x1d3,0x1d4); +test(0x1d4,0x1d3); +test(0x1d5,0x1d6); +test(0x1d6,0x1d5); +test(0x1d7,0x1d8); +test(0x1d8,0x1d7); +test(0x1d9,0x1da); +test(0x1da,0x1d9); +test(0x1db,0x1dc); +test(0x1dc,0x1db); +test(0x1dd,0x18e); +test(0x1de,0x1df); +test(0x1df,0x1de); +test(0x1e0,0x1e1); +test(0x1e1,0x1e0); +test(0x1e2,0x1e3); +test(0x1e3,0x1e2); +test(0x1e4,0x1e5); +test(0x1e5,0x1e4); +test(0x1e6,0x1e7); +test(0x1e7,0x1e6); +test(0x1e8,0x1e9); +test(0x1e9,0x1e8); +test(0x1ea,0x1eb); +test(0x1eb,0x1ea); +test(0x1ec,0x1ed); +test(0x1ed,0x1ec); +test(0x1ee,0x1ef); +test(0x1ef,0x1ee); +test(0x1f1,0x1f3,0x1f2); +test(0x1f2,0x1f3,0x1f1); +test(0x1f3,0x1f1,0x1f2); +test(0x1f4,0x1f5); +test(0x1f5,0x1f4); +test(0x1f6,0x195); +test(0x1f7,0x1bf); +test(0x1f8,0x1f9); +test(0x1f9,0x1f8); +test(0x1fa,0x1fb); +test(0x1fb,0x1fa); +test(0x1fc,0x1fd); +test(0x1fd,0x1fc); +test(0x1fe,0x1ff); +test(0x1ff,0x1fe); +test(0x200,0x201); +test(0x201,0x200); +test(0x202,0x203); +test(0x203,0x202); +test(0x204,0x205); +test(0x205,0x204); +test(0x206,0x207); +test(0x207,0x206); +test(0x208,0x209); +test(0x209,0x208); +test(0x20a,0x20b); +test(0x20b,0x20a); +test(0x20c,0x20d); +test(0x20d,0x20c); +test(0x20e,0x20f); +test(0x20f,0x20e); +test(0x210,0x211); +test(0x211,0x210); +test(0x212,0x213); +test(0x213,0x212); +test(0x214,0x215); +test(0x215,0x214); +test(0x216,0x217); +test(0x217,0x216); +test(0x218,0x219); +test(0x219,0x218); +test(0x21a,0x21b); +test(0x21b,0x21a); +test(0x21c,0x21d); +test(0x21d,0x21c); +test(0x21e,0x21f); +test(0x21f,0x21e); +test(0x220,0x19e); +test(0x222,0x223); +test(0x223,0x222); +test(0x224,0x225); +test(0x225,0x224); +test(0x226,0x227); +test(0x227,0x226); +test(0x228,0x229); +test(0x229,0x228); +test(0x22a,0x22b); +test(0x22b,0x22a); +test(0x22c,0x22d); +test(0x22d,0x22c); +test(0x22e,0x22f); +test(0x22f,0x22e); +test(0x230,0x231); +test(0x231,0x230); +test(0x232,0x233); +test(0x233,0x232); +test(0x23a,0x2c65); +test(0x23b,0x23c); +test(0x23c,0x23b); +test(0x23d,0x19a); +test(0x23e,0x2c66); +test(0x23f,0x2c7e); +test(0x240,0x2c7f); +test(0x241,0x242); +test(0x242,0x241); +test(0x243,0x180); +test(0x244,0x289); +test(0x245,0x28c); +test(0x246,0x247); +test(0x247,0x246); +test(0x248,0x249); +test(0x249,0x248); +test(0x24a,0x24b); +test(0x24b,0x24a); +test(0x24c,0x24d); +test(0x24d,0x24c); +test(0x24e,0x24f); +test(0x24f,0x24e); +test(0x250,0x2c6f); +test(0x251,0x2c6d); +test(0x252,0x2c70); +test(0x253,0x181); +test(0x254,0x186); +test(0x256,0x189); +test(0x257,0x18a); +test(0x259,0x18f); +test(0x25b,0x190); +test(0x25c,0xa7ab); +test(0x260,0x193); +test(0x261,0xa7ac); +test(0x263,0x194); +test(0x265,0xa78d); +test(0x266,0xa7aa); +test(0x268,0x197); +test(0x269,0x196); +test(0x26b,0x2c62); +test(0x26c,0xa7ad); +test(0x26f,0x19c); +test(0x271,0x2c6e); +test(0x272,0x19d); +test(0x275,0x19f); +test(0x27d,0x2c64); +test(0x280,0x1a6); +test(0x283,0x1a9); +test(0x287,0xa7b1); +test(0x288,0x1ae); +test(0x289,0x244); +test(0x28a,0x1b1); +test(0x28b,0x1b2); +test(0x28c,0x245); +test(0x292,0x1b7); +test(0x29d,0xa7b2); +test(0x29e,0xa7b0); +test(0x345,0x3b9,0x399,0x1fbe); +test(0x370,0x371); +test(0x371,0x370); +test(0x372,0x373); +test(0x373,0x372); +test(0x376,0x377); +test(0x377,0x376); +test(0x37b,0x3fd); +test(0x37c,0x3fe); +test(0x37d,0x3ff); +test(0x37f,0x3f3); +test(0x386,0x3ac); +test(0x388,0x3ad); +test(0x389,0x3ae); +test(0x38a,0x3af); +test(0x38c,0x3cc); +test(0x38e,0x3cd); +test(0x38f,0x3ce); +test(0x391,0x3b1); +test(0x392,0x3b2,0x3d0); +test(0x393,0x3b3); +test(0x394,0x3b4); +test(0x395,0x3b5,0x3f5); +test(0x396,0x3b6); +test(0x397,0x3b7); +test(0x398,0x3b8,0x3d1,0x3f4); +test(0x399,0x3b9,0x345,0x1fbe); +test(0x39a,0x3ba,0x3f0); +test(0x39b,0x3bb); +test(0x39c,0x3bc,0xb5); +test(0x39d,0x3bd); +test(0x39e,0x3be); +test(0x39f,0x3bf); +test(0x3a0,0x3c0,0x3d6); +test(0x3a1,0x3c1,0x3f1); +test(0x3a3,0x3c3,0x3c2); +test(0x3a4,0x3c4); +test(0x3a5,0x3c5); +test(0x3a6,0x3c6,0x3d5); +test(0x3a7,0x3c7); +test(0x3a8,0x3c8); +test(0x3a9,0x3c9,0x2126); +test(0x3aa,0x3ca); +test(0x3ab,0x3cb); +test(0x3ac,0x386); +test(0x3ad,0x388); +test(0x3ae,0x389); +test(0x3af,0x38a); +test(0x3b1,0x391); +test(0x3b2,0x392,0x3d0); +test(0x3b3,0x393); +test(0x3b4,0x394); +test(0x3b5,0x395,0x3f5); +test(0x3b6,0x396); +test(0x3b7,0x397); +test(0x3b8,0x398,0x3d1,0x3f4); +test(0x3b9,0x345,0x399,0x1fbe); +test(0x3ba,0x39a,0x3f0); +test(0x3bb,0x39b); +test(0x3bc,0xb5,0x39c); +test(0x3bd,0x39d); +test(0x3be,0x39e); +test(0x3bf,0x39f); +test(0x3c0,0x3a0,0x3d6); +test(0x3c1,0x3a1,0x3f1); +test(0x3c2,0x3c3,0x3a3); +test(0x3c3,0x3a3,0x3c2); +test(0x3c4,0x3a4); +test(0x3c5,0x3a5); +test(0x3c6,0x3a6,0x3d5); +test(0x3c7,0x3a7); +test(0x3c8,0x3a8); +test(0x3c9,0x3a9,0x2126); +test(0x3ca,0x3aa); +test(0x3cb,0x3ab); +test(0x3cc,0x38c); +test(0x3cd,0x38e); +test(0x3ce,0x38f); +test(0x3cf,0x3d7); +test(0x3d0,0x3b2,0x392); +test(0x3d1,0x3b8,0x398,0x3f4); +test(0x3d5,0x3c6,0x3a6); +test(0x3d6,0x3c0,0x3a0); +test(0x3d7,0x3cf); +test(0x3d8,0x3d9); +test(0x3d9,0x3d8); +test(0x3da,0x3db); +test(0x3db,0x3da); +test(0x3dc,0x3dd); +test(0x3dd,0x3dc); +test(0x3de,0x3df); +test(0x3df,0x3de); +test(0x3e0,0x3e1); +test(0x3e1,0x3e0); +test(0x3e2,0x3e3); +test(0x3e3,0x3e2); +test(0x3e4,0x3e5); +test(0x3e5,0x3e4); +test(0x3e6,0x3e7); +test(0x3e7,0x3e6); +test(0x3e8,0x3e9); +test(0x3e9,0x3e8); +test(0x3ea,0x3eb); +test(0x3eb,0x3ea); +test(0x3ec,0x3ed); +test(0x3ed,0x3ec); +test(0x3ee,0x3ef); +test(0x3ef,0x3ee); +test(0x3f0,0x3ba,0x39a); +test(0x3f1,0x3c1,0x3a1); +test(0x3f2,0x3f9); +test(0x3f3,0x37f); +test(0x3f4,0x3b8,0x398,0x3d1); +test(0x3f5,0x3b5,0x395); +test(0x3f7,0x3f8); +test(0x3f8,0x3f7); +test(0x3f9,0x3f2); +test(0x3fa,0x3fb); +test(0x3fb,0x3fa); +test(0x3fd,0x37b); +test(0x3fe,0x37c); +test(0x3ff,0x37d); +test(0x400,0x450); +test(0x401,0x451); +test(0x402,0x452); +test(0x403,0x453); +test(0x404,0x454); +test(0x405,0x455); +test(0x406,0x456); +test(0x407,0x457); +test(0x408,0x458); +test(0x409,0x459); +test(0x40a,0x45a); +test(0x40b,0x45b); +test(0x40c,0x45c); +test(0x40d,0x45d); +test(0x40e,0x45e); +test(0x40f,0x45f); +test(0x410,0x430); +test(0x411,0x431); +test(0x412,0x432); +test(0x413,0x433); +test(0x414,0x434); +test(0x415,0x435); +test(0x416,0x436); +test(0x417,0x437); +test(0x418,0x438); +test(0x419,0x439); +test(0x41a,0x43a); +test(0x41b,0x43b); +test(0x41c,0x43c); +test(0x41d,0x43d); +test(0x41e,0x43e); +test(0x41f,0x43f); +test(0x420,0x440); +test(0x421,0x441); +test(0x422,0x442); +test(0x423,0x443); +test(0x424,0x444); +test(0x425,0x445); +test(0x426,0x446); +test(0x427,0x447); +test(0x428,0x448); +test(0x429,0x449); +test(0x42a,0x44a); +test(0x42b,0x44b); +test(0x42c,0x44c); +test(0x42d,0x44d); +test(0x42e,0x44e); +test(0x42f,0x44f); +test(0x430,0x410); +test(0x431,0x411); +test(0x432,0x412); +test(0x433,0x413); +test(0x434,0x414); +test(0x435,0x415); +test(0x436,0x416); +test(0x437,0x417); +test(0x438,0x418); +test(0x439,0x419); +test(0x43a,0x41a); +test(0x43b,0x41b); +test(0x43c,0x41c); +test(0x43d,0x41d); +test(0x43e,0x41e); +test(0x43f,0x41f); +test(0x440,0x420); +test(0x441,0x421); +test(0x442,0x422); +test(0x443,0x423); +test(0x444,0x424); +test(0x445,0x425); +test(0x446,0x426); +test(0x447,0x427); +test(0x448,0x428); +test(0x449,0x429); +test(0x44a,0x42a); +test(0x44b,0x42b); +test(0x44c,0x42c); +test(0x44d,0x42d); +test(0x44e,0x42e); +test(0x44f,0x42f); +test(0x450,0x400); +test(0x451,0x401); +test(0x452,0x402); +test(0x453,0x403); +test(0x454,0x404); +test(0x455,0x405); +test(0x456,0x406); +test(0x457,0x407); +test(0x458,0x408); +test(0x459,0x409); +test(0x45a,0x40a); +test(0x45b,0x40b); +test(0x45c,0x40c); +test(0x45d,0x40d); +test(0x45e,0x40e); +test(0x45f,0x40f); +test(0x460,0x461); +test(0x461,0x460); +test(0x462,0x463); +test(0x463,0x462); +test(0x464,0x465); +test(0x465,0x464); +test(0x466,0x467); +test(0x467,0x466); +test(0x468,0x469); +test(0x469,0x468); +test(0x46a,0x46b); +test(0x46b,0x46a); +test(0x46c,0x46d); +test(0x46d,0x46c); +test(0x46e,0x46f); +test(0x46f,0x46e); +test(0x470,0x471); +test(0x471,0x470); +test(0x472,0x473); +test(0x473,0x472); +test(0x474,0x475); +test(0x475,0x474); +test(0x476,0x477); +test(0x477,0x476); +test(0x478,0x479); +test(0x479,0x478); +test(0x47a,0x47b); +test(0x47b,0x47a); +test(0x47c,0x47d); +test(0x47d,0x47c); +test(0x47e,0x47f); +test(0x47f,0x47e); +test(0x480,0x481); +test(0x481,0x480); +test(0x48a,0x48b); +test(0x48b,0x48a); +test(0x48c,0x48d); +test(0x48d,0x48c); +test(0x48e,0x48f); +test(0x48f,0x48e); +test(0x490,0x491); +test(0x491,0x490); +test(0x492,0x493); +test(0x493,0x492); +test(0x494,0x495); +test(0x495,0x494); +test(0x496,0x497); +test(0x497,0x496); +test(0x498,0x499); +test(0x499,0x498); +test(0x49a,0x49b); +test(0x49b,0x49a); +test(0x49c,0x49d); +test(0x49d,0x49c); +test(0x49e,0x49f); +test(0x49f,0x49e); +test(0x4a0,0x4a1); +test(0x4a1,0x4a0); +test(0x4a2,0x4a3); +test(0x4a3,0x4a2); +test(0x4a4,0x4a5); +test(0x4a5,0x4a4); +test(0x4a6,0x4a7); +test(0x4a7,0x4a6); +test(0x4a8,0x4a9); +test(0x4a9,0x4a8); +test(0x4aa,0x4ab); +test(0x4ab,0x4aa); +test(0x4ac,0x4ad); +test(0x4ad,0x4ac); +test(0x4ae,0x4af); +test(0x4af,0x4ae); +test(0x4b0,0x4b1); +test(0x4b1,0x4b0); +test(0x4b2,0x4b3); +test(0x4b3,0x4b2); +test(0x4b4,0x4b5); +test(0x4b5,0x4b4); +test(0x4b6,0x4b7); +test(0x4b7,0x4b6); +test(0x4b8,0x4b9); +test(0x4b9,0x4b8); +test(0x4ba,0x4bb); +test(0x4bb,0x4ba); +test(0x4bc,0x4bd); +test(0x4bd,0x4bc); +test(0x4be,0x4bf); +test(0x4bf,0x4be); +test(0x4c0,0x4cf); +test(0x4c1,0x4c2); +test(0x4c2,0x4c1); +test(0x4c3,0x4c4); +test(0x4c4,0x4c3); +test(0x4c5,0x4c6); +test(0x4c6,0x4c5); +test(0x4c7,0x4c8); +test(0x4c8,0x4c7); +test(0x4c9,0x4ca); +test(0x4ca,0x4c9); +test(0x4cb,0x4cc); +test(0x4cc,0x4cb); +test(0x4cd,0x4ce); +test(0x4ce,0x4cd); +test(0x4cf,0x4c0); +test(0x4d0,0x4d1); +test(0x4d1,0x4d0); +test(0x4d2,0x4d3); +test(0x4d3,0x4d2); +test(0x4d4,0x4d5); +test(0x4d5,0x4d4); +test(0x4d6,0x4d7); +test(0x4d7,0x4d6); +test(0x4d8,0x4d9); +test(0x4d9,0x4d8); +test(0x4da,0x4db); +test(0x4db,0x4da); +test(0x4dc,0x4dd); +test(0x4dd,0x4dc); +test(0x4de,0x4df); +test(0x4df,0x4de); +test(0x4e0,0x4e1); +test(0x4e1,0x4e0); +test(0x4e2,0x4e3); +test(0x4e3,0x4e2); +test(0x4e4,0x4e5); +test(0x4e5,0x4e4); +test(0x4e6,0x4e7); +test(0x4e7,0x4e6); +test(0x4e8,0x4e9); +test(0x4e9,0x4e8); +test(0x4ea,0x4eb); +test(0x4eb,0x4ea); +test(0x4ec,0x4ed); +test(0x4ed,0x4ec); +test(0x4ee,0x4ef); +test(0x4ef,0x4ee); +test(0x4f0,0x4f1); +test(0x4f1,0x4f0); +test(0x4f2,0x4f3); +test(0x4f3,0x4f2); +test(0x4f4,0x4f5); +test(0x4f5,0x4f4); +test(0x4f6,0x4f7); +test(0x4f7,0x4f6); +test(0x4f8,0x4f9); +test(0x4f9,0x4f8); +test(0x4fa,0x4fb); +test(0x4fb,0x4fa); +test(0x4fc,0x4fd); +test(0x4fd,0x4fc); +test(0x4fe,0x4ff); +test(0x4ff,0x4fe); +test(0x500,0x501); +test(0x501,0x500); +test(0x502,0x503); +test(0x503,0x502); +test(0x504,0x505); +test(0x505,0x504); +test(0x506,0x507); +test(0x507,0x506); +test(0x508,0x509); +test(0x509,0x508); +test(0x50a,0x50b); +test(0x50b,0x50a); +test(0x50c,0x50d); +test(0x50d,0x50c); +test(0x50e,0x50f); +test(0x50f,0x50e); +test(0x510,0x511); +test(0x511,0x510); +test(0x512,0x513); +test(0x513,0x512); +test(0x514,0x515); +test(0x515,0x514); +test(0x516,0x517); +test(0x517,0x516); +test(0x518,0x519); +test(0x519,0x518); +test(0x51a,0x51b); +test(0x51b,0x51a); +test(0x51c,0x51d); +test(0x51d,0x51c); +test(0x51e,0x51f); +test(0x51f,0x51e); +test(0x520,0x521); +test(0x521,0x520); +test(0x522,0x523); +test(0x523,0x522); +test(0x524,0x525); +test(0x525,0x524); +test(0x526,0x527); +test(0x527,0x526); +test(0x528,0x529); +test(0x529,0x528); +test(0x52a,0x52b); +test(0x52b,0x52a); +test(0x52c,0x52d); +test(0x52d,0x52c); +test(0x52e,0x52f); +test(0x52f,0x52e); +test(0x531,0x561); +test(0x532,0x562); +test(0x533,0x563); +test(0x534,0x564); +test(0x535,0x565); +test(0x536,0x566); +test(0x537,0x567); +test(0x538,0x568); +test(0x539,0x569); +test(0x53a,0x56a); +test(0x53b,0x56b); +test(0x53c,0x56c); +test(0x53d,0x56d); +test(0x53e,0x56e); +test(0x53f,0x56f); +test(0x540,0x570); +test(0x541,0x571); +test(0x542,0x572); +test(0x543,0x573); +test(0x544,0x574); +test(0x545,0x575); +test(0x546,0x576); +test(0x547,0x577); +test(0x548,0x578); +test(0x549,0x579); +test(0x54a,0x57a); +test(0x54b,0x57b); +test(0x54c,0x57c); +test(0x54d,0x57d); +test(0x54e,0x57e); +test(0x54f,0x57f); +test(0x550,0x580); +test(0x551,0x581); +test(0x552,0x582); +test(0x553,0x583); +test(0x554,0x584); +test(0x555,0x585); +test(0x556,0x586); +test(0x561,0x531); +test(0x562,0x532); +test(0x563,0x533); +test(0x564,0x534); +test(0x565,0x535); +test(0x566,0x536); +test(0x567,0x537); +test(0x568,0x538); +test(0x569,0x539); +test(0x56a,0x53a); +test(0x56b,0x53b); +test(0x56c,0x53c); +test(0x56d,0x53d); +test(0x56e,0x53e); +test(0x56f,0x53f); +test(0x570,0x540); +test(0x571,0x541); +test(0x572,0x542); +test(0x573,0x543); +test(0x574,0x544); +test(0x575,0x545); +test(0x576,0x546); +test(0x577,0x547); +test(0x578,0x548); +test(0x579,0x549); +test(0x57a,0x54a); +test(0x57b,0x54b); +test(0x57c,0x54c); +test(0x57d,0x54d); +test(0x57e,0x54e); +test(0x57f,0x54f); +test(0x580,0x550); +test(0x581,0x551); +test(0x582,0x552); +test(0x583,0x553); +test(0x584,0x554); +test(0x585,0x555); +test(0x586,0x556); +test(0x10a0,0x2d00); +test(0x10a1,0x2d01); +test(0x10a2,0x2d02); +test(0x10a3,0x2d03); +test(0x10a4,0x2d04); +test(0x10a5,0x2d05); +test(0x10a6,0x2d06); +test(0x10a7,0x2d07); +test(0x10a8,0x2d08); +test(0x10a9,0x2d09); +test(0x10aa,0x2d0a); +test(0x10ab,0x2d0b); +test(0x10ac,0x2d0c); +test(0x10ad,0x2d0d); +test(0x10ae,0x2d0e); +test(0x10af,0x2d0f); +test(0x10b0,0x2d10); +test(0x10b1,0x2d11); +test(0x10b2,0x2d12); +test(0x10b3,0x2d13); +test(0x10b4,0x2d14); +test(0x10b5,0x2d15); +test(0x10b6,0x2d16); +test(0x10b7,0x2d17); +test(0x10b8,0x2d18); +test(0x10b9,0x2d19); +test(0x10ba,0x2d1a); +test(0x10bb,0x2d1b); +test(0x10bc,0x2d1c); +test(0x10bd,0x2d1d); +test(0x10be,0x2d1e); +test(0x10bf,0x2d1f); +test(0x10c0,0x2d20); +test(0x10c1,0x2d21); +test(0x10c2,0x2d22); +test(0x10c3,0x2d23); +test(0x10c4,0x2d24); +test(0x10c5,0x2d25); +test(0x10c7,0x2d27); +test(0x10cd,0x2d2d); +test(0x13a0,0xab70); +test(0x13a1,0xab71); +test(0x13a2,0xab72); +test(0x13a3,0xab73); +test(0x13a4,0xab74); +test(0x13a5,0xab75); +test(0x13a6,0xab76); +test(0x13a7,0xab77); +test(0x13a8,0xab78); +test(0x13a9,0xab79); +test(0x13aa,0xab7a); +test(0x13ab,0xab7b); +test(0x13ac,0xab7c); +test(0x13ad,0xab7d); +test(0x13ae,0xab7e); +test(0x13af,0xab7f); +test(0x13b0,0xab80); +test(0x13b1,0xab81); +test(0x13b2,0xab82); +test(0x13b3,0xab83); +test(0x13b4,0xab84); +test(0x13b5,0xab85); +test(0x13b6,0xab86); +test(0x13b7,0xab87); +test(0x13b8,0xab88); +test(0x13b9,0xab89); +test(0x13ba,0xab8a); +test(0x13bb,0xab8b); +test(0x13bc,0xab8c); +test(0x13bd,0xab8d); +test(0x13be,0xab8e); +test(0x13bf,0xab8f); +test(0x13c0,0xab90); +test(0x13c1,0xab91); +test(0x13c2,0xab92); +test(0x13c3,0xab93); +test(0x13c4,0xab94); +test(0x13c5,0xab95); +test(0x13c6,0xab96); +test(0x13c7,0xab97); +test(0x13c8,0xab98); +test(0x13c9,0xab99); +test(0x13ca,0xab9a); +test(0x13cb,0xab9b); +test(0x13cc,0xab9c); +test(0x13cd,0xab9d); +test(0x13ce,0xab9e); +test(0x13cf,0xab9f); +test(0x13d0,0xaba0); +test(0x13d1,0xaba1); +test(0x13d2,0xaba2); +test(0x13d3,0xaba3); +test(0x13d4,0xaba4); +test(0x13d5,0xaba5); +test(0x13d6,0xaba6); +test(0x13d7,0xaba7); +test(0x13d8,0xaba8); +test(0x13d9,0xaba9); +test(0x13da,0xabaa); +test(0x13db,0xabab); +test(0x13dc,0xabac); +test(0x13dd,0xabad); +test(0x13de,0xabae); +test(0x13df,0xabaf); +test(0x13e0,0xabb0); +test(0x13e1,0xabb1); +test(0x13e2,0xabb2); +test(0x13e3,0xabb3); +test(0x13e4,0xabb4); +test(0x13e5,0xabb5); +test(0x13e6,0xabb6); +test(0x13e7,0xabb7); +test(0x13e8,0xabb8); +test(0x13e9,0xabb9); +test(0x13ea,0xabba); +test(0x13eb,0xabbb); +test(0x13ec,0xabbc); +test(0x13ed,0xabbd); +test(0x13ee,0xabbe); +test(0x13ef,0xabbf); +test(0x13f0,0x13f8); +test(0x13f1,0x13f9); +test(0x13f2,0x13fa); +test(0x13f3,0x13fb); +test(0x13f4,0x13fc); +test(0x13f5,0x13fd); +test(0x13f8,0x13f0); +test(0x13f9,0x13f1); +test(0x13fa,0x13f2); +test(0x13fb,0x13f3); +test(0x13fc,0x13f4); +test(0x13fd,0x13f5); +test(0x1d79,0xa77d); +test(0x1d7d,0x2c63); +test(0x1e00,0x1e01); +test(0x1e01,0x1e00); +test(0x1e02,0x1e03); +test(0x1e03,0x1e02); +test(0x1e04,0x1e05); +test(0x1e05,0x1e04); +test(0x1e06,0x1e07); +test(0x1e07,0x1e06); +test(0x1e08,0x1e09); +test(0x1e09,0x1e08); +test(0x1e0a,0x1e0b); +test(0x1e0b,0x1e0a); +test(0x1e0c,0x1e0d); +test(0x1e0d,0x1e0c); +test(0x1e0e,0x1e0f); +test(0x1e0f,0x1e0e); +test(0x1e10,0x1e11); +test(0x1e11,0x1e10); +test(0x1e12,0x1e13); +test(0x1e13,0x1e12); +test(0x1e14,0x1e15); +test(0x1e15,0x1e14); +test(0x1e16,0x1e17); +test(0x1e17,0x1e16); +test(0x1e18,0x1e19); +test(0x1e19,0x1e18); +test(0x1e1a,0x1e1b); +test(0x1e1b,0x1e1a); +test(0x1e1c,0x1e1d); +test(0x1e1d,0x1e1c); +test(0x1e1e,0x1e1f); +test(0x1e1f,0x1e1e); +test(0x1e20,0x1e21); +test(0x1e21,0x1e20); +test(0x1e22,0x1e23); +test(0x1e23,0x1e22); +test(0x1e24,0x1e25); +test(0x1e25,0x1e24); +test(0x1e26,0x1e27); +test(0x1e27,0x1e26); +test(0x1e28,0x1e29); +test(0x1e29,0x1e28); +test(0x1e2a,0x1e2b); +test(0x1e2b,0x1e2a); +test(0x1e2c,0x1e2d); +test(0x1e2d,0x1e2c); +test(0x1e2e,0x1e2f); +test(0x1e2f,0x1e2e); +test(0x1e30,0x1e31); +test(0x1e31,0x1e30); +test(0x1e32,0x1e33); +test(0x1e33,0x1e32); +test(0x1e34,0x1e35); +test(0x1e35,0x1e34); +test(0x1e36,0x1e37); +test(0x1e37,0x1e36); +test(0x1e38,0x1e39); +test(0x1e39,0x1e38); +test(0x1e3a,0x1e3b); +test(0x1e3b,0x1e3a); +test(0x1e3c,0x1e3d); +test(0x1e3d,0x1e3c); +test(0x1e3e,0x1e3f); +test(0x1e3f,0x1e3e); +test(0x1e40,0x1e41); +test(0x1e41,0x1e40); +test(0x1e42,0x1e43); +test(0x1e43,0x1e42); +test(0x1e44,0x1e45); +test(0x1e45,0x1e44); +test(0x1e46,0x1e47); +test(0x1e47,0x1e46); +test(0x1e48,0x1e49); +test(0x1e49,0x1e48); +test(0x1e4a,0x1e4b); +test(0x1e4b,0x1e4a); +test(0x1e4c,0x1e4d); +test(0x1e4d,0x1e4c); +test(0x1e4e,0x1e4f); +test(0x1e4f,0x1e4e); +test(0x1e50,0x1e51); +test(0x1e51,0x1e50); +test(0x1e52,0x1e53); +test(0x1e53,0x1e52); +test(0x1e54,0x1e55); +test(0x1e55,0x1e54); +test(0x1e56,0x1e57); +test(0x1e57,0x1e56); +test(0x1e58,0x1e59); +test(0x1e59,0x1e58); +test(0x1e5a,0x1e5b); +test(0x1e5b,0x1e5a); +test(0x1e5c,0x1e5d); +test(0x1e5d,0x1e5c); +test(0x1e5e,0x1e5f); +test(0x1e5f,0x1e5e); +test(0x1e60,0x1e61,0x1e9b); +test(0x1e61,0x1e60,0x1e9b); +test(0x1e62,0x1e63); +test(0x1e63,0x1e62); +test(0x1e64,0x1e65); +test(0x1e65,0x1e64); +test(0x1e66,0x1e67); +test(0x1e67,0x1e66); +test(0x1e68,0x1e69); +test(0x1e69,0x1e68); +test(0x1e6a,0x1e6b); +test(0x1e6b,0x1e6a); +test(0x1e6c,0x1e6d); +test(0x1e6d,0x1e6c); +test(0x1e6e,0x1e6f); +test(0x1e6f,0x1e6e); +test(0x1e70,0x1e71); +test(0x1e71,0x1e70); +test(0x1e72,0x1e73); +test(0x1e73,0x1e72); +test(0x1e74,0x1e75); +test(0x1e75,0x1e74); +test(0x1e76,0x1e77); +test(0x1e77,0x1e76); +test(0x1e78,0x1e79); +test(0x1e79,0x1e78); +test(0x1e7a,0x1e7b); +test(0x1e7b,0x1e7a); +test(0x1e7c,0x1e7d); +test(0x1e7d,0x1e7c); +test(0x1e7e,0x1e7f); +test(0x1e7f,0x1e7e); +test(0x1e80,0x1e81); +test(0x1e81,0x1e80); +test(0x1e82,0x1e83); +test(0x1e83,0x1e82); +test(0x1e84,0x1e85); +test(0x1e85,0x1e84); +test(0x1e86,0x1e87); +test(0x1e87,0x1e86); +test(0x1e88,0x1e89); +test(0x1e89,0x1e88); +test(0x1e8a,0x1e8b); +test(0x1e8b,0x1e8a); +test(0x1e8c,0x1e8d); +test(0x1e8d,0x1e8c); +test(0x1e8e,0x1e8f); +test(0x1e8f,0x1e8e); +test(0x1e90,0x1e91); +test(0x1e91,0x1e90); +test(0x1e92,0x1e93); +test(0x1e93,0x1e92); +test(0x1e94,0x1e95); +test(0x1e95,0x1e94); +test(0x1e9b,0x1e61,0x1e60); +test(0x1e9e,0xdf); +test(0x1ea0,0x1ea1); +test(0x1ea1,0x1ea0); +test(0x1ea2,0x1ea3); +test(0x1ea3,0x1ea2); +test(0x1ea4,0x1ea5); +test(0x1ea5,0x1ea4); +test(0x1ea6,0x1ea7); +test(0x1ea7,0x1ea6); +test(0x1ea8,0x1ea9); +test(0x1ea9,0x1ea8); +test(0x1eaa,0x1eab); +test(0x1eab,0x1eaa); +test(0x1eac,0x1ead); +test(0x1ead,0x1eac); +test(0x1eae,0x1eaf); +test(0x1eaf,0x1eae); +test(0x1eb0,0x1eb1); +test(0x1eb1,0x1eb0); +test(0x1eb2,0x1eb3); +test(0x1eb3,0x1eb2); +test(0x1eb4,0x1eb5); +test(0x1eb5,0x1eb4); +test(0x1eb6,0x1eb7); +test(0x1eb7,0x1eb6); +test(0x1eb8,0x1eb9); +test(0x1eb9,0x1eb8); +test(0x1eba,0x1ebb); +test(0x1ebb,0x1eba); +test(0x1ebc,0x1ebd); +test(0x1ebd,0x1ebc); +test(0x1ebe,0x1ebf); +test(0x1ebf,0x1ebe); +test(0x1ec0,0x1ec1); +test(0x1ec1,0x1ec0); +test(0x1ec2,0x1ec3); +test(0x1ec3,0x1ec2); +test(0x1ec4,0x1ec5); +test(0x1ec5,0x1ec4); +test(0x1ec6,0x1ec7); +test(0x1ec7,0x1ec6); +test(0x1ec8,0x1ec9); +test(0x1ec9,0x1ec8); +test(0x1eca,0x1ecb); +test(0x1ecb,0x1eca); +test(0x1ecc,0x1ecd); +test(0x1ecd,0x1ecc); +test(0x1ece,0x1ecf); +test(0x1ecf,0x1ece); +test(0x1ed0,0x1ed1); +test(0x1ed1,0x1ed0); +test(0x1ed2,0x1ed3); +test(0x1ed3,0x1ed2); +test(0x1ed4,0x1ed5); +test(0x1ed5,0x1ed4); +test(0x1ed6,0x1ed7); +test(0x1ed7,0x1ed6); +test(0x1ed8,0x1ed9); +test(0x1ed9,0x1ed8); +test(0x1eda,0x1edb); +test(0x1edb,0x1eda); +test(0x1edc,0x1edd); +test(0x1edd,0x1edc); +test(0x1ede,0x1edf); +test(0x1edf,0x1ede); +test(0x1ee0,0x1ee1); +test(0x1ee1,0x1ee0); +test(0x1ee2,0x1ee3); +test(0x1ee3,0x1ee2); +test(0x1ee4,0x1ee5); +test(0x1ee5,0x1ee4); +test(0x1ee6,0x1ee7); +test(0x1ee7,0x1ee6); +test(0x1ee8,0x1ee9); +test(0x1ee9,0x1ee8); +test(0x1eea,0x1eeb); +test(0x1eeb,0x1eea); +test(0x1eec,0x1eed); +test(0x1eed,0x1eec); +test(0x1eee,0x1eef); +test(0x1eef,0x1eee); +test(0x1ef0,0x1ef1); +test(0x1ef1,0x1ef0); +test(0x1ef2,0x1ef3); +test(0x1ef3,0x1ef2); +test(0x1ef4,0x1ef5); +test(0x1ef5,0x1ef4); +test(0x1ef6,0x1ef7); +test(0x1ef7,0x1ef6); +test(0x1ef8,0x1ef9); +test(0x1ef9,0x1ef8); +test(0x1efa,0x1efb); +test(0x1efb,0x1efa); +test(0x1efc,0x1efd); +test(0x1efd,0x1efc); +test(0x1efe,0x1eff); +test(0x1eff,0x1efe); +test(0x1f00,0x1f08); +test(0x1f01,0x1f09); +test(0x1f02,0x1f0a); +test(0x1f03,0x1f0b); +test(0x1f04,0x1f0c); +test(0x1f05,0x1f0d); +test(0x1f06,0x1f0e); +test(0x1f07,0x1f0f); +test(0x1f08,0x1f00); +test(0x1f09,0x1f01); +test(0x1f0a,0x1f02); +test(0x1f0b,0x1f03); +test(0x1f0c,0x1f04); +test(0x1f0d,0x1f05); +test(0x1f0e,0x1f06); +test(0x1f0f,0x1f07); +test(0x1f10,0x1f18); +test(0x1f11,0x1f19); +test(0x1f12,0x1f1a); +test(0x1f13,0x1f1b); +test(0x1f14,0x1f1c); +test(0x1f15,0x1f1d); +test(0x1f18,0x1f10); +test(0x1f19,0x1f11); +test(0x1f1a,0x1f12); +test(0x1f1b,0x1f13); +test(0x1f1c,0x1f14); +test(0x1f1d,0x1f15); +test(0x1f20,0x1f28); +test(0x1f21,0x1f29); +test(0x1f22,0x1f2a); +test(0x1f23,0x1f2b); +test(0x1f24,0x1f2c); +test(0x1f25,0x1f2d); +test(0x1f26,0x1f2e); +test(0x1f27,0x1f2f); +test(0x1f28,0x1f20); +test(0x1f29,0x1f21); +test(0x1f2a,0x1f22); +test(0x1f2b,0x1f23); +test(0x1f2c,0x1f24); +test(0x1f2d,0x1f25); +test(0x1f2e,0x1f26); +test(0x1f2f,0x1f27); +test(0x1f30,0x1f38); +test(0x1f31,0x1f39); +test(0x1f32,0x1f3a); +test(0x1f33,0x1f3b); +test(0x1f34,0x1f3c); +test(0x1f35,0x1f3d); +test(0x1f36,0x1f3e); +test(0x1f37,0x1f3f); +test(0x1f38,0x1f30); +test(0x1f39,0x1f31); +test(0x1f3a,0x1f32); +test(0x1f3b,0x1f33); +test(0x1f3c,0x1f34); +test(0x1f3d,0x1f35); +test(0x1f3e,0x1f36); +test(0x1f3f,0x1f37); +test(0x1f40,0x1f48); +test(0x1f41,0x1f49); +test(0x1f42,0x1f4a); +test(0x1f43,0x1f4b); +test(0x1f44,0x1f4c); +test(0x1f45,0x1f4d); +test(0x1f48,0x1f40); +test(0x1f49,0x1f41); +test(0x1f4a,0x1f42); +test(0x1f4b,0x1f43); +test(0x1f4c,0x1f44); +test(0x1f4d,0x1f45); +test(0x1f51,0x1f59); +test(0x1f53,0x1f5b); +test(0x1f55,0x1f5d); +test(0x1f57,0x1f5f); +test(0x1f59,0x1f51); +test(0x1f5b,0x1f53); +test(0x1f5d,0x1f55); +test(0x1f5f,0x1f57); +test(0x1f60,0x1f68); +test(0x1f61,0x1f69); +test(0x1f62,0x1f6a); +test(0x1f63,0x1f6b); +test(0x1f64,0x1f6c); +test(0x1f65,0x1f6d); +test(0x1f66,0x1f6e); +test(0x1f67,0x1f6f); +test(0x1f68,0x1f60); +test(0x1f69,0x1f61); +test(0x1f6a,0x1f62); +test(0x1f6b,0x1f63); +test(0x1f6c,0x1f64); +test(0x1f6d,0x1f65); +test(0x1f6e,0x1f66); +test(0x1f6f,0x1f67); +test(0x1f70,0x1fba); +test(0x1f71,0x1fbb); +test(0x1f72,0x1fc8); +test(0x1f73,0x1fc9); +test(0x1f74,0x1fca); +test(0x1f75,0x1fcb); +test(0x1f76,0x1fda); +test(0x1f77,0x1fdb); +test(0x1f78,0x1ff8); +test(0x1f79,0x1ff9); +test(0x1f7a,0x1fea); +test(0x1f7b,0x1feb); +test(0x1f7c,0x1ffa); +test(0x1f7d,0x1ffb); +test(0x1f80,0x1f88); +test(0x1f81,0x1f89); +test(0x1f82,0x1f8a); +test(0x1f83,0x1f8b); +test(0x1f84,0x1f8c); +test(0x1f85,0x1f8d); +test(0x1f86,0x1f8e); +test(0x1f87,0x1f8f); +test(0x1f88,0x1f80); +test(0x1f89,0x1f81); +test(0x1f8a,0x1f82); +test(0x1f8b,0x1f83); +test(0x1f8c,0x1f84); +test(0x1f8d,0x1f85); +test(0x1f8e,0x1f86); +test(0x1f8f,0x1f87); +test(0x1f90,0x1f98); +test(0x1f91,0x1f99); +test(0x1f92,0x1f9a); +test(0x1f93,0x1f9b); +test(0x1f94,0x1f9c); +test(0x1f95,0x1f9d); +test(0x1f96,0x1f9e); +test(0x1f97,0x1f9f); +test(0x1f98,0x1f90); +test(0x1f99,0x1f91); +test(0x1f9a,0x1f92); +test(0x1f9b,0x1f93); +test(0x1f9c,0x1f94); +test(0x1f9d,0x1f95); +test(0x1f9e,0x1f96); +test(0x1f9f,0x1f97); +test(0x1fa0,0x1fa8); +test(0x1fa1,0x1fa9); +test(0x1fa2,0x1faa); +test(0x1fa3,0x1fab); +test(0x1fa4,0x1fac); +test(0x1fa5,0x1fad); +test(0x1fa6,0x1fae); +test(0x1fa7,0x1faf); +test(0x1fa8,0x1fa0); +test(0x1fa9,0x1fa1); +test(0x1faa,0x1fa2); +test(0x1fab,0x1fa3); +test(0x1fac,0x1fa4); +test(0x1fad,0x1fa5); +test(0x1fae,0x1fa6); +test(0x1faf,0x1fa7); +test(0x1fb0,0x1fb8); +test(0x1fb1,0x1fb9); +test(0x1fb3,0x1fbc); +test(0x1fb8,0x1fb0); +test(0x1fb9,0x1fb1); +test(0x1fba,0x1f70); +test(0x1fbb,0x1f71); +test(0x1fbc,0x1fb3); +test(0x1fbe,0x3b9,0x345,0x399); +test(0x1fc3,0x1fcc); +test(0x1fc8,0x1f72); +test(0x1fc9,0x1f73); +test(0x1fca,0x1f74); +test(0x1fcb,0x1f75); +test(0x1fcc,0x1fc3); +test(0x1fd0,0x1fd8); +test(0x1fd1,0x1fd9); +test(0x1fd8,0x1fd0); +test(0x1fd9,0x1fd1); +test(0x1fda,0x1f76); +test(0x1fdb,0x1f77); +test(0x1fe0,0x1fe8); +test(0x1fe1,0x1fe9); +test(0x1fe5,0x1fec); +test(0x1fe8,0x1fe0); +test(0x1fe9,0x1fe1); +test(0x1fea,0x1f7a); +test(0x1feb,0x1f7b); +test(0x1fec,0x1fe5); +test(0x1ff3,0x1ffc); +test(0x1ff8,0x1f78); +test(0x1ff9,0x1f79); +test(0x1ffa,0x1f7c); +test(0x1ffb,0x1f7d); +test(0x1ffc,0x1ff3); +test(0x2126,0x3c9,0x3a9); +test(0x212a,0x6b,0x4b); +test(0x212b,0xe5,0xc5); +test(0x2132,0x214e); +test(0x214e,0x2132); +test(0x2160,0x2170); +test(0x2161,0x2171); +test(0x2162,0x2172); +test(0x2163,0x2173); +test(0x2164,0x2174); +test(0x2165,0x2175); +test(0x2166,0x2176); +test(0x2167,0x2177); +test(0x2168,0x2178); +test(0x2169,0x2179); +test(0x216a,0x217a); +test(0x216b,0x217b); +test(0x216c,0x217c); +test(0x216d,0x217d); +test(0x216e,0x217e); +test(0x216f,0x217f); +test(0x2170,0x2160); +test(0x2171,0x2161); +test(0x2172,0x2162); +test(0x2173,0x2163); +test(0x2174,0x2164); +test(0x2175,0x2165); +test(0x2176,0x2166); +test(0x2177,0x2167); +test(0x2178,0x2168); +test(0x2179,0x2169); +test(0x217a,0x216a); +test(0x217b,0x216b); +test(0x217c,0x216c); +test(0x217d,0x216d); +test(0x217e,0x216e); +test(0x217f,0x216f); +test(0x2183,0x2184); +test(0x2184,0x2183); +test(0x24b6,0x24d0); +test(0x24b7,0x24d1); +test(0x24b8,0x24d2); +test(0x24b9,0x24d3); +test(0x24ba,0x24d4); +test(0x24bb,0x24d5); +test(0x24bc,0x24d6); +test(0x24bd,0x24d7); +test(0x24be,0x24d8); +test(0x24bf,0x24d9); +test(0x24c0,0x24da); +test(0x24c1,0x24db); +test(0x24c2,0x24dc); +test(0x24c3,0x24dd); +test(0x24c4,0x24de); +test(0x24c5,0x24df); +test(0x24c6,0x24e0); +test(0x24c7,0x24e1); +test(0x24c8,0x24e2); +test(0x24c9,0x24e3); +test(0x24ca,0x24e4); +test(0x24cb,0x24e5); +test(0x24cc,0x24e6); +test(0x24cd,0x24e7); +test(0x24ce,0x24e8); +test(0x24cf,0x24e9); +test(0x24d0,0x24b6); +test(0x24d1,0x24b7); +test(0x24d2,0x24b8); +test(0x24d3,0x24b9); +test(0x24d4,0x24ba); +test(0x24d5,0x24bb); +test(0x24d6,0x24bc); +test(0x24d7,0x24bd); +test(0x24d8,0x24be); +test(0x24d9,0x24bf); +test(0x24da,0x24c0); +test(0x24db,0x24c1); +test(0x24dc,0x24c2); +test(0x24dd,0x24c3); +test(0x24de,0x24c4); +test(0x24df,0x24c5); +test(0x24e0,0x24c6); +test(0x24e1,0x24c7); +test(0x24e2,0x24c8); +test(0x24e3,0x24c9); +test(0x24e4,0x24ca); +test(0x24e5,0x24cb); +test(0x24e6,0x24cc); +test(0x24e7,0x24cd); +test(0x24e8,0x24ce); +test(0x24e9,0x24cf); +test(0x2c00,0x2c30); +test(0x2c01,0x2c31); +test(0x2c02,0x2c32); +test(0x2c03,0x2c33); +test(0x2c04,0x2c34); +test(0x2c05,0x2c35); +test(0x2c06,0x2c36); +test(0x2c07,0x2c37); +test(0x2c08,0x2c38); +test(0x2c09,0x2c39); +test(0x2c0a,0x2c3a); +test(0x2c0b,0x2c3b); +test(0x2c0c,0x2c3c); +test(0x2c0d,0x2c3d); +test(0x2c0e,0x2c3e); +test(0x2c0f,0x2c3f); +test(0x2c10,0x2c40); +test(0x2c11,0x2c41); +test(0x2c12,0x2c42); +test(0x2c13,0x2c43); +test(0x2c14,0x2c44); +test(0x2c15,0x2c45); +test(0x2c16,0x2c46); +test(0x2c17,0x2c47); +test(0x2c18,0x2c48); +test(0x2c19,0x2c49); +test(0x2c1a,0x2c4a); +test(0x2c1b,0x2c4b); +test(0x2c1c,0x2c4c); +test(0x2c1d,0x2c4d); +test(0x2c1e,0x2c4e); +test(0x2c1f,0x2c4f); +test(0x2c20,0x2c50); +test(0x2c21,0x2c51); +test(0x2c22,0x2c52); +test(0x2c23,0x2c53); +test(0x2c24,0x2c54); +test(0x2c25,0x2c55); +test(0x2c26,0x2c56); +test(0x2c27,0x2c57); +test(0x2c28,0x2c58); +test(0x2c29,0x2c59); +test(0x2c2a,0x2c5a); +test(0x2c2b,0x2c5b); +test(0x2c2c,0x2c5c); +test(0x2c2d,0x2c5d); +test(0x2c2e,0x2c5e); +test(0x2c30,0x2c00); +test(0x2c31,0x2c01); +test(0x2c32,0x2c02); +test(0x2c33,0x2c03); +test(0x2c34,0x2c04); +test(0x2c35,0x2c05); +test(0x2c36,0x2c06); +test(0x2c37,0x2c07); +test(0x2c38,0x2c08); +test(0x2c39,0x2c09); +test(0x2c3a,0x2c0a); +test(0x2c3b,0x2c0b); +test(0x2c3c,0x2c0c); +test(0x2c3d,0x2c0d); +test(0x2c3e,0x2c0e); +test(0x2c3f,0x2c0f); +test(0x2c40,0x2c10); +test(0x2c41,0x2c11); +test(0x2c42,0x2c12); +test(0x2c43,0x2c13); +test(0x2c44,0x2c14); +test(0x2c45,0x2c15); +test(0x2c46,0x2c16); +test(0x2c47,0x2c17); +test(0x2c48,0x2c18); +test(0x2c49,0x2c19); +test(0x2c4a,0x2c1a); +test(0x2c4b,0x2c1b); +test(0x2c4c,0x2c1c); +test(0x2c4d,0x2c1d); +test(0x2c4e,0x2c1e); +test(0x2c4f,0x2c1f); +test(0x2c50,0x2c20); +test(0x2c51,0x2c21); +test(0x2c52,0x2c22); +test(0x2c53,0x2c23); +test(0x2c54,0x2c24); +test(0x2c55,0x2c25); +test(0x2c56,0x2c26); +test(0x2c57,0x2c27); +test(0x2c58,0x2c28); +test(0x2c59,0x2c29); +test(0x2c5a,0x2c2a); +test(0x2c5b,0x2c2b); +test(0x2c5c,0x2c2c); +test(0x2c5d,0x2c2d); +test(0x2c5e,0x2c2e); +test(0x2c60,0x2c61); +test(0x2c61,0x2c60); +test(0x2c62,0x26b); +test(0x2c63,0x1d7d); +test(0x2c64,0x27d); +test(0x2c65,0x23a); +test(0x2c66,0x23e); +test(0x2c67,0x2c68); +test(0x2c68,0x2c67); +test(0x2c69,0x2c6a); +test(0x2c6a,0x2c69); +test(0x2c6b,0x2c6c); +test(0x2c6c,0x2c6b); +test(0x2c6d,0x251); +test(0x2c6e,0x271); +test(0x2c6f,0x250); +test(0x2c70,0x252); +test(0x2c72,0x2c73); +test(0x2c73,0x2c72); +test(0x2c75,0x2c76); +test(0x2c76,0x2c75); +test(0x2c7e,0x23f); +test(0x2c7f,0x240); +test(0x2c80,0x2c81); +test(0x2c81,0x2c80); +test(0x2c82,0x2c83); +test(0x2c83,0x2c82); +test(0x2c84,0x2c85); +test(0x2c85,0x2c84); +test(0x2c86,0x2c87); +test(0x2c87,0x2c86); +test(0x2c88,0x2c89); +test(0x2c89,0x2c88); +test(0x2c8a,0x2c8b); +test(0x2c8b,0x2c8a); +test(0x2c8c,0x2c8d); +test(0x2c8d,0x2c8c); +test(0x2c8e,0x2c8f); +test(0x2c8f,0x2c8e); +test(0x2c90,0x2c91); +test(0x2c91,0x2c90); +test(0x2c92,0x2c93); +test(0x2c93,0x2c92); +test(0x2c94,0x2c95); +test(0x2c95,0x2c94); +test(0x2c96,0x2c97); +test(0x2c97,0x2c96); +test(0x2c98,0x2c99); +test(0x2c99,0x2c98); +test(0x2c9a,0x2c9b); +test(0x2c9b,0x2c9a); +test(0x2c9c,0x2c9d); +test(0x2c9d,0x2c9c); +test(0x2c9e,0x2c9f); +test(0x2c9f,0x2c9e); +test(0x2ca0,0x2ca1); +test(0x2ca1,0x2ca0); +test(0x2ca2,0x2ca3); +test(0x2ca3,0x2ca2); +test(0x2ca4,0x2ca5); +test(0x2ca5,0x2ca4); +test(0x2ca6,0x2ca7); +test(0x2ca7,0x2ca6); +test(0x2ca8,0x2ca9); +test(0x2ca9,0x2ca8); +test(0x2caa,0x2cab); +test(0x2cab,0x2caa); +test(0x2cac,0x2cad); +test(0x2cad,0x2cac); +test(0x2cae,0x2caf); +test(0x2caf,0x2cae); +test(0x2cb0,0x2cb1); +test(0x2cb1,0x2cb0); +test(0x2cb2,0x2cb3); +test(0x2cb3,0x2cb2); +test(0x2cb4,0x2cb5); +test(0x2cb5,0x2cb4); +test(0x2cb6,0x2cb7); +test(0x2cb7,0x2cb6); +test(0x2cb8,0x2cb9); +test(0x2cb9,0x2cb8); +test(0x2cba,0x2cbb); +test(0x2cbb,0x2cba); +test(0x2cbc,0x2cbd); +test(0x2cbd,0x2cbc); +test(0x2cbe,0x2cbf); +test(0x2cbf,0x2cbe); +test(0x2cc0,0x2cc1); +test(0x2cc1,0x2cc0); +test(0x2cc2,0x2cc3); +test(0x2cc3,0x2cc2); +test(0x2cc4,0x2cc5); +test(0x2cc5,0x2cc4); +test(0x2cc6,0x2cc7); +test(0x2cc7,0x2cc6); +test(0x2cc8,0x2cc9); +test(0x2cc9,0x2cc8); +test(0x2cca,0x2ccb); +test(0x2ccb,0x2cca); +test(0x2ccc,0x2ccd); +test(0x2ccd,0x2ccc); +test(0x2cce,0x2ccf); +test(0x2ccf,0x2cce); +test(0x2cd0,0x2cd1); +test(0x2cd1,0x2cd0); +test(0x2cd2,0x2cd3); +test(0x2cd3,0x2cd2); +test(0x2cd4,0x2cd5); +test(0x2cd5,0x2cd4); +test(0x2cd6,0x2cd7); +test(0x2cd7,0x2cd6); +test(0x2cd8,0x2cd9); +test(0x2cd9,0x2cd8); +test(0x2cda,0x2cdb); +test(0x2cdb,0x2cda); +test(0x2cdc,0x2cdd); +test(0x2cdd,0x2cdc); +test(0x2cde,0x2cdf); +test(0x2cdf,0x2cde); +test(0x2ce0,0x2ce1); +test(0x2ce1,0x2ce0); +test(0x2ce2,0x2ce3); +test(0x2ce3,0x2ce2); +test(0x2ceb,0x2cec); +test(0x2cec,0x2ceb); +test(0x2ced,0x2cee); +test(0x2cee,0x2ced); +test(0x2cf2,0x2cf3); +test(0x2cf3,0x2cf2); +test(0x2d00,0x10a0); +test(0x2d01,0x10a1); +test(0x2d02,0x10a2); +test(0x2d03,0x10a3); +test(0x2d04,0x10a4); +test(0x2d05,0x10a5); +test(0x2d06,0x10a6); +test(0x2d07,0x10a7); +test(0x2d08,0x10a8); +test(0x2d09,0x10a9); +test(0x2d0a,0x10aa); +test(0x2d0b,0x10ab); +test(0x2d0c,0x10ac); +test(0x2d0d,0x10ad); +test(0x2d0e,0x10ae); +test(0x2d0f,0x10af); +test(0x2d10,0x10b0); +test(0x2d11,0x10b1); +test(0x2d12,0x10b2); +test(0x2d13,0x10b3); +test(0x2d14,0x10b4); +test(0x2d15,0x10b5); +test(0x2d16,0x10b6); +test(0x2d17,0x10b7); +test(0x2d18,0x10b8); +test(0x2d19,0x10b9); +test(0x2d1a,0x10ba); +test(0x2d1b,0x10bb); +test(0x2d1c,0x10bc); +test(0x2d1d,0x10bd); +test(0x2d1e,0x10be); +test(0x2d1f,0x10bf); +test(0x2d20,0x10c0); +test(0x2d21,0x10c1); +test(0x2d22,0x10c2); +test(0x2d23,0x10c3); +test(0x2d24,0x10c4); +test(0x2d25,0x10c5); +test(0x2d27,0x10c7); +test(0x2d2d,0x10cd); +test(0xa640,0xa641); +test(0xa641,0xa640); +test(0xa642,0xa643); +test(0xa643,0xa642); +test(0xa644,0xa645); +test(0xa645,0xa644); +test(0xa646,0xa647); +test(0xa647,0xa646); +test(0xa648,0xa649); +test(0xa649,0xa648); +test(0xa64a,0xa64b); +test(0xa64b,0xa64a); +test(0xa64c,0xa64d); +test(0xa64d,0xa64c); +test(0xa64e,0xa64f); +test(0xa64f,0xa64e); +test(0xa650,0xa651); +test(0xa651,0xa650); +test(0xa652,0xa653); +test(0xa653,0xa652); +test(0xa654,0xa655); +test(0xa655,0xa654); +test(0xa656,0xa657); +test(0xa657,0xa656); +test(0xa658,0xa659); +test(0xa659,0xa658); +test(0xa65a,0xa65b); +test(0xa65b,0xa65a); +test(0xa65c,0xa65d); +test(0xa65d,0xa65c); +test(0xa65e,0xa65f); +test(0xa65f,0xa65e); +test(0xa660,0xa661); +test(0xa661,0xa660); +test(0xa662,0xa663); +test(0xa663,0xa662); +test(0xa664,0xa665); +test(0xa665,0xa664); +test(0xa666,0xa667); +test(0xa667,0xa666); +test(0xa668,0xa669); +test(0xa669,0xa668); +test(0xa66a,0xa66b); +test(0xa66b,0xa66a); +test(0xa66c,0xa66d); +test(0xa66d,0xa66c); +test(0xa680,0xa681); +test(0xa681,0xa680); +test(0xa682,0xa683); +test(0xa683,0xa682); +test(0xa684,0xa685); +test(0xa685,0xa684); +test(0xa686,0xa687); +test(0xa687,0xa686); +test(0xa688,0xa689); +test(0xa689,0xa688); +test(0xa68a,0xa68b); +test(0xa68b,0xa68a); +test(0xa68c,0xa68d); +test(0xa68d,0xa68c); +test(0xa68e,0xa68f); +test(0xa68f,0xa68e); +test(0xa690,0xa691); +test(0xa691,0xa690); +test(0xa692,0xa693); +test(0xa693,0xa692); +test(0xa694,0xa695); +test(0xa695,0xa694); +test(0xa696,0xa697); +test(0xa697,0xa696); +test(0xa698,0xa699); +test(0xa699,0xa698); +test(0xa69a,0xa69b); +test(0xa69b,0xa69a); +test(0xa722,0xa723); +test(0xa723,0xa722); +test(0xa724,0xa725); +test(0xa725,0xa724); +test(0xa726,0xa727); +test(0xa727,0xa726); +test(0xa728,0xa729); +test(0xa729,0xa728); +test(0xa72a,0xa72b); +test(0xa72b,0xa72a); +test(0xa72c,0xa72d); +test(0xa72d,0xa72c); +test(0xa72e,0xa72f); +test(0xa72f,0xa72e); +test(0xa732,0xa733); +test(0xa733,0xa732); +test(0xa734,0xa735); +test(0xa735,0xa734); +test(0xa736,0xa737); +test(0xa737,0xa736); +test(0xa738,0xa739); +test(0xa739,0xa738); +test(0xa73a,0xa73b); +test(0xa73b,0xa73a); +test(0xa73c,0xa73d); +test(0xa73d,0xa73c); +test(0xa73e,0xa73f); +test(0xa73f,0xa73e); +test(0xa740,0xa741); +test(0xa741,0xa740); +test(0xa742,0xa743); +test(0xa743,0xa742); +test(0xa744,0xa745); +test(0xa745,0xa744); +test(0xa746,0xa747); +test(0xa747,0xa746); +test(0xa748,0xa749); +test(0xa749,0xa748); +test(0xa74a,0xa74b); +test(0xa74b,0xa74a); +test(0xa74c,0xa74d); +test(0xa74d,0xa74c); +test(0xa74e,0xa74f); +test(0xa74f,0xa74e); +test(0xa750,0xa751); +test(0xa751,0xa750); +test(0xa752,0xa753); +test(0xa753,0xa752); +test(0xa754,0xa755); +test(0xa755,0xa754); +test(0xa756,0xa757); +test(0xa757,0xa756); +test(0xa758,0xa759); +test(0xa759,0xa758); +test(0xa75a,0xa75b); +test(0xa75b,0xa75a); +test(0xa75c,0xa75d); +test(0xa75d,0xa75c); +test(0xa75e,0xa75f); +test(0xa75f,0xa75e); +test(0xa760,0xa761); +test(0xa761,0xa760); +test(0xa762,0xa763); +test(0xa763,0xa762); +test(0xa764,0xa765); +test(0xa765,0xa764); +test(0xa766,0xa767); +test(0xa767,0xa766); +test(0xa768,0xa769); +test(0xa769,0xa768); +test(0xa76a,0xa76b); +test(0xa76b,0xa76a); +test(0xa76c,0xa76d); +test(0xa76d,0xa76c); +test(0xa76e,0xa76f); +test(0xa76f,0xa76e); +test(0xa779,0xa77a); +test(0xa77a,0xa779); +test(0xa77b,0xa77c); +test(0xa77c,0xa77b); +test(0xa77d,0x1d79); +test(0xa77e,0xa77f); +test(0xa77f,0xa77e); +test(0xa780,0xa781); +test(0xa781,0xa780); +test(0xa782,0xa783); +test(0xa783,0xa782); +test(0xa784,0xa785); +test(0xa785,0xa784); +test(0xa786,0xa787); +test(0xa787,0xa786); +test(0xa78b,0xa78c); +test(0xa78c,0xa78b); +test(0xa78d,0x265); +test(0xa790,0xa791); +test(0xa791,0xa790); +test(0xa792,0xa793); +test(0xa793,0xa792); +test(0xa796,0xa797); +test(0xa797,0xa796); +test(0xa798,0xa799); +test(0xa799,0xa798); +test(0xa79a,0xa79b); +test(0xa79b,0xa79a); +test(0xa79c,0xa79d); +test(0xa79d,0xa79c); +test(0xa79e,0xa79f); +test(0xa79f,0xa79e); +test(0xa7a0,0xa7a1); +test(0xa7a1,0xa7a0); +test(0xa7a2,0xa7a3); +test(0xa7a3,0xa7a2); +test(0xa7a4,0xa7a5); +test(0xa7a5,0xa7a4); +test(0xa7a6,0xa7a7); +test(0xa7a7,0xa7a6); +test(0xa7a8,0xa7a9); +test(0xa7a9,0xa7a8); +test(0xa7aa,0x266); +test(0xa7ab,0x25c); +test(0xa7ac,0x261); +test(0xa7ad,0x26c); +test(0xa7b0,0x29e); +test(0xa7b1,0x287); +test(0xa7b2,0x29d); +test(0xa7b3,0xab53); +test(0xa7b4,0xa7b5); +test(0xa7b5,0xa7b4); +test(0xa7b6,0xa7b7); +test(0xa7b7,0xa7b6); +test(0xab53,0xa7b3); +test(0xab70,0x13a0); +test(0xab71,0x13a1); +test(0xab72,0x13a2); +test(0xab73,0x13a3); +test(0xab74,0x13a4); +test(0xab75,0x13a5); +test(0xab76,0x13a6); +test(0xab77,0x13a7); +test(0xab78,0x13a8); +test(0xab79,0x13a9); +test(0xab7a,0x13aa); +test(0xab7b,0x13ab); +test(0xab7c,0x13ac); +test(0xab7d,0x13ad); +test(0xab7e,0x13ae); +test(0xab7f,0x13af); +test(0xab80,0x13b0); +test(0xab81,0x13b1); +test(0xab82,0x13b2); +test(0xab83,0x13b3); +test(0xab84,0x13b4); +test(0xab85,0x13b5); +test(0xab86,0x13b6); +test(0xab87,0x13b7); +test(0xab88,0x13b8); +test(0xab89,0x13b9); +test(0xab8a,0x13ba); +test(0xab8b,0x13bb); +test(0xab8c,0x13bc); +test(0xab8d,0x13bd); +test(0xab8e,0x13be); +test(0xab8f,0x13bf); +test(0xab90,0x13c0); +test(0xab91,0x13c1); +test(0xab92,0x13c2); +test(0xab93,0x13c3); +test(0xab94,0x13c4); +test(0xab95,0x13c5); +test(0xab96,0x13c6); +test(0xab97,0x13c7); +test(0xab98,0x13c8); +test(0xab99,0x13c9); +test(0xab9a,0x13ca); +test(0xab9b,0x13cb); +test(0xab9c,0x13cc); +test(0xab9d,0x13cd); +test(0xab9e,0x13ce); +test(0xab9f,0x13cf); +test(0xaba0,0x13d0); +test(0xaba1,0x13d1); +test(0xaba2,0x13d2); +test(0xaba3,0x13d3); +test(0xaba4,0x13d4); +test(0xaba5,0x13d5); +test(0xaba6,0x13d6); +test(0xaba7,0x13d7); +test(0xaba8,0x13d8); +test(0xaba9,0x13d9); +test(0xabaa,0x13da); +test(0xabab,0x13db); +test(0xabac,0x13dc); +test(0xabad,0x13dd); +test(0xabae,0x13de); +test(0xabaf,0x13df); +test(0xabb0,0x13e0); +test(0xabb1,0x13e1); +test(0xabb2,0x13e2); +test(0xabb3,0x13e3); +test(0xabb4,0x13e4); +test(0xabb5,0x13e5); +test(0xabb6,0x13e6); +test(0xabb7,0x13e7); +test(0xabb8,0x13e8); +test(0xabb9,0x13e9); +test(0xabba,0x13ea); +test(0xabbb,0x13eb); +test(0xabbc,0x13ec); +test(0xabbd,0x13ed); +test(0xabbe,0x13ee); +test(0xabbf,0x13ef); +test(0xff21,0xff41); +test(0xff22,0xff42); +test(0xff23,0xff43); +test(0xff24,0xff44); +test(0xff25,0xff45); +test(0xff26,0xff46); +test(0xff27,0xff47); +test(0xff28,0xff48); +test(0xff29,0xff49); +test(0xff2a,0xff4a); +test(0xff2b,0xff4b); +test(0xff2c,0xff4c); +test(0xff2d,0xff4d); +test(0xff2e,0xff4e); +test(0xff2f,0xff4f); +test(0xff30,0xff50); +test(0xff31,0xff51); +test(0xff32,0xff52); +test(0xff33,0xff53); +test(0xff34,0xff54); +test(0xff35,0xff55); +test(0xff36,0xff56); +test(0xff37,0xff57); +test(0xff38,0xff58); +test(0xff39,0xff59); +test(0xff3a,0xff5a); +test(0xff41,0xff21); +test(0xff42,0xff22); +test(0xff43,0xff23); +test(0xff44,0xff24); +test(0xff45,0xff25); +test(0xff46,0xff26); +test(0xff47,0xff27); +test(0xff48,0xff28); +test(0xff49,0xff29); +test(0xff4a,0xff2a); +test(0xff4b,0xff2b); +test(0xff4c,0xff2c); +test(0xff4d,0xff2d); +test(0xff4e,0xff2e); +test(0xff4f,0xff2f); +test(0xff50,0xff30); +test(0xff51,0xff31); +test(0xff52,0xff32); +test(0xff53,0xff33); +test(0xff54,0xff34); +test(0xff55,0xff35); +test(0xff56,0xff36); +test(0xff57,0xff37); +test(0xff58,0xff38); +test(0xff59,0xff39); +test(0xff5a,0xff3a); +test(0x10400,0x10428); +test(0x10401,0x10429); +test(0x10402,0x1042a); +test(0x10403,0x1042b); +test(0x10404,0x1042c); +test(0x10405,0x1042d); +test(0x10406,0x1042e); +test(0x10407,0x1042f); +test(0x10408,0x10430); +test(0x10409,0x10431); +test(0x1040a,0x10432); +test(0x1040b,0x10433); +test(0x1040c,0x10434); +test(0x1040d,0x10435); +test(0x1040e,0x10436); +test(0x1040f,0x10437); +test(0x10410,0x10438); +test(0x10411,0x10439); +test(0x10412,0x1043a); +test(0x10413,0x1043b); +test(0x10414,0x1043c); +test(0x10415,0x1043d); +test(0x10416,0x1043e); +test(0x10417,0x1043f); +test(0x10418,0x10440); +test(0x10419,0x10441); +test(0x1041a,0x10442); +test(0x1041b,0x10443); +test(0x1041c,0x10444); +test(0x1041d,0x10445); +test(0x1041e,0x10446); +test(0x1041f,0x10447); +test(0x10420,0x10448); +test(0x10421,0x10449); +test(0x10422,0x1044a); +test(0x10423,0x1044b); +test(0x10424,0x1044c); +test(0x10425,0x1044d); +test(0x10426,0x1044e); +test(0x10427,0x1044f); +test(0x10428,0x10400); +test(0x10429,0x10401); +test(0x1042a,0x10402); +test(0x1042b,0x10403); +test(0x1042c,0x10404); +test(0x1042d,0x10405); +test(0x1042e,0x10406); +test(0x1042f,0x10407); +test(0x10430,0x10408); +test(0x10431,0x10409); +test(0x10432,0x1040a); +test(0x10433,0x1040b); +test(0x10434,0x1040c); +test(0x10435,0x1040d); +test(0x10436,0x1040e); +test(0x10437,0x1040f); +test(0x10438,0x10410); +test(0x10439,0x10411); +test(0x1043a,0x10412); +test(0x1043b,0x10413); +test(0x1043c,0x10414); +test(0x1043d,0x10415); +test(0x1043e,0x10416); +test(0x1043f,0x10417); +test(0x10440,0x10418); +test(0x10441,0x10419); +test(0x10442,0x1041a); +test(0x10443,0x1041b); +test(0x10444,0x1041c); +test(0x10445,0x1041d); +test(0x10446,0x1041e); +test(0x10447,0x1041f); +test(0x10448,0x10420); +test(0x10449,0x10421); +test(0x1044a,0x10422); +test(0x1044b,0x10423); +test(0x1044c,0x10424); +test(0x1044d,0x10425); +test(0x1044e,0x10426); +test(0x1044f,0x10427); +test(0x10c80,0x10cc0); +test(0x10c81,0x10cc1); +test(0x10c82,0x10cc2); +test(0x10c83,0x10cc3); +test(0x10c84,0x10cc4); +test(0x10c85,0x10cc5); +test(0x10c86,0x10cc6); +test(0x10c87,0x10cc7); +test(0x10c88,0x10cc8); +test(0x10c89,0x10cc9); +test(0x10c8a,0x10cca); +test(0x10c8b,0x10ccb); +test(0x10c8c,0x10ccc); +test(0x10c8d,0x10ccd); +test(0x10c8e,0x10cce); +test(0x10c8f,0x10ccf); +test(0x10c90,0x10cd0); +test(0x10c91,0x10cd1); +test(0x10c92,0x10cd2); +test(0x10c93,0x10cd3); +test(0x10c94,0x10cd4); +test(0x10c95,0x10cd5); +test(0x10c96,0x10cd6); +test(0x10c97,0x10cd7); +test(0x10c98,0x10cd8); +test(0x10c99,0x10cd9); +test(0x10c9a,0x10cda); +test(0x10c9b,0x10cdb); +test(0x10c9c,0x10cdc); +test(0x10c9d,0x10cdd); +test(0x10c9e,0x10cde); +test(0x10c9f,0x10cdf); +test(0x10ca0,0x10ce0); +test(0x10ca1,0x10ce1); +test(0x10ca2,0x10ce2); +test(0x10ca3,0x10ce3); +test(0x10ca4,0x10ce4); +test(0x10ca5,0x10ce5); +test(0x10ca6,0x10ce6); +test(0x10ca7,0x10ce7); +test(0x10ca8,0x10ce8); +test(0x10ca9,0x10ce9); +test(0x10caa,0x10cea); +test(0x10cab,0x10ceb); +test(0x10cac,0x10cec); +test(0x10cad,0x10ced); +test(0x10cae,0x10cee); +test(0x10caf,0x10cef); +test(0x10cb0,0x10cf0); +test(0x10cb1,0x10cf1); +test(0x10cb2,0x10cf2); +test(0x10cc0,0x10c80); +test(0x10cc1,0x10c81); +test(0x10cc2,0x10c82); +test(0x10cc3,0x10c83); +test(0x10cc4,0x10c84); +test(0x10cc5,0x10c85); +test(0x10cc6,0x10c86); +test(0x10cc7,0x10c87); +test(0x10cc8,0x10c88); +test(0x10cc9,0x10c89); +test(0x10cca,0x10c8a); +test(0x10ccb,0x10c8b); +test(0x10ccc,0x10c8c); +test(0x10ccd,0x10c8d); +test(0x10cce,0x10c8e); +test(0x10ccf,0x10c8f); +test(0x10cd0,0x10c90); +test(0x10cd1,0x10c91); +test(0x10cd2,0x10c92); +test(0x10cd3,0x10c93); +test(0x10cd4,0x10c94); +test(0x10cd5,0x10c95); +test(0x10cd6,0x10c96); +test(0x10cd7,0x10c97); +test(0x10cd8,0x10c98); +test(0x10cd9,0x10c99); +test(0x10cda,0x10c9a); +test(0x10cdb,0x10c9b); +test(0x10cdc,0x10c9c); +test(0x10cdd,0x10c9d); +test(0x10cde,0x10c9e); +test(0x10cdf,0x10c9f); +test(0x10ce0,0x10ca0); +test(0x10ce1,0x10ca1); +test(0x10ce2,0x10ca2); +test(0x10ce3,0x10ca3); +test(0x10ce4,0x10ca4); +test(0x10ce5,0x10ca5); +test(0x10ce6,0x10ca6); +test(0x10ce7,0x10ca7); +test(0x10ce8,0x10ca8); +test(0x10ce9,0x10ca9); +test(0x10cea,0x10caa); +test(0x10ceb,0x10cab); +test(0x10cec,0x10cac); +test(0x10ced,0x10cad); +test(0x10cee,0x10cae); +test(0x10cef,0x10caf); +test(0x10cf0,0x10cb0); +test(0x10cf1,0x10cb1); +test(0x10cf2,0x10cb2); +test(0x118a0,0x118c0); +test(0x118a1,0x118c1); +test(0x118a2,0x118c2); +test(0x118a3,0x118c3); +test(0x118a4,0x118c4); +test(0x118a5,0x118c5); +test(0x118a6,0x118c6); +test(0x118a7,0x118c7); +test(0x118a8,0x118c8); +test(0x118a9,0x118c9); +test(0x118aa,0x118ca); +test(0x118ab,0x118cb); +test(0x118ac,0x118cc); +test(0x118ad,0x118cd); +test(0x118ae,0x118ce); +test(0x118af,0x118cf); +test(0x118b0,0x118d0); +test(0x118b1,0x118d1); +test(0x118b2,0x118d2); +test(0x118b3,0x118d3); +test(0x118b4,0x118d4); +test(0x118b5,0x118d5); +test(0x118b6,0x118d6); +test(0x118b7,0x118d7); +test(0x118b8,0x118d8); +test(0x118b9,0x118d9); +test(0x118ba,0x118da); +test(0x118bb,0x118db); +test(0x118bc,0x118dc); +test(0x118bd,0x118dd); +test(0x118be,0x118de); +test(0x118bf,0x118df); +test(0x118c0,0x118a0); +test(0x118c1,0x118a1); +test(0x118c2,0x118a2); +test(0x118c3,0x118a3); +test(0x118c4,0x118a4); +test(0x118c5,0x118a5); +test(0x118c6,0x118a6); +test(0x118c7,0x118a7); +test(0x118c8,0x118a8); +test(0x118c9,0x118a9); +test(0x118ca,0x118aa); +test(0x118cb,0x118ab); +test(0x118cc,0x118ac); +test(0x118cd,0x118ad); +test(0x118ce,0x118ae); +test(0x118cf,0x118af); +test(0x118d0,0x118b0); +test(0x118d1,0x118b1); +test(0x118d2,0x118b2); +test(0x118d3,0x118b3); +test(0x118d4,0x118b4); +test(0x118d5,0x118b5); +test(0x118d6,0x118b6); +test(0x118d7,0x118b7); +test(0x118d8,0x118b8); +test(0x118d9,0x118b9); +test(0x118da,0x118ba); +test(0x118db,0x118bb); +test(0x118dc,0x118bc); +test(0x118dd,0x118bd); +test(0x118de,0x118be); +test(0x118df,0x118bf); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-index.js b/js/src/tests/ecma_6/RegExp/unicode-index.js new file mode 100644 index 0000000000..a4b2eb2030 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-index.js @@ -0,0 +1,17 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- Pattern match should start from lead surrogate when lastIndex points corresponding trail surrogate."; + +print(BUGNUMBER + ": " + summary); + +var r = /\uD83D\uDC38/ug; +r.lastIndex = 1; +var str = "\uD83D\uDC38"; +var result = r.exec(str); +assertEq(result.length, 1); +assertEq(result[0], "\uD83D\uDC38"); + +// This does not match to ES6 spec, but the spec will be changed. +assertEq(result.index, 0); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-lead-trail.js b/js/src/tests/ecma_6/RegExp/unicode-lead-trail.js new file mode 100644 index 0000000000..7ecdb9ace4 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-lead-trail.js @@ -0,0 +1,218 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- lead and trail patterns in RegExpUnicodeEscapeSequence."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(/\uD83D\uDC38/u.exec("\u{1F438}"), + ["\u{1F438}"]); + +// no unicode flag +assertEqArray(/\uD83D\uDC38/.exec("\u{1F438}"), + ["\u{1F438}"]); + +// RegExp constructor +assertEqArray(new RegExp("\\uD83D\\uDC38", "u").exec("\u{1F438}"), + ["\u{1F438}"]); + +// RegExp constructor, no unicode flag +assertEqArray(new RegExp("\\uD83D\\uDC38", "").exec("\u{1F438}"), + ["\u{1F438}"]); + +// ==== ? ==== + +assertEqArray(/\uD83D\uDC38?/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38?/u.exec(""), + [""]); + +// lead-only target +assertEqArray(/\uD83D\uDC38?/u.exec("\uD83D"), + [""]); + +// no unicode flag +assertEqArray(/\uD83D\uDC38?/.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(/\uD83D\uDC38?/.exec(""), + null); + +assertEqArray(/\uD83D\uDC38?/.exec("\uD83D"), + ["\uD83D"]); + +// RegExp constructor +assertEqArray(new RegExp("\\uD83D\\uDC38?", "u").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(new RegExp("\\uD83D\\uDC38?", "u").exec(""), + [""]); + +assertEqArray(new RegExp("\\uD83D\\uDC38?", "u").exec("\uD83D"), + [""]); + +// RegExp constructor, no unicode flag +assertEqArray(new RegExp("\\uD83D\\uDC38?", "").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(new RegExp("\\uD83D\\uDC38?", "").exec(""), + null); + +assertEqArray(new RegExp("\\uD83D\\uDC38?", "").exec("\uD83D"), + ["\uD83D"]); + +// ==== + ==== + +assertEqArray(/\uD83D\uDC38+/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38+/u.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}\u{1F438}"]); +assertEq(/\uD83D\uDC38+/u.exec(""), + null); + +// lead-only target +assertEq(/\uD83D\uDC38+/u.exec("\uD83D"), + null); +assertEqArray(/\uD83D\uDC38+/u.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38"]); + +// no unicode flag +assertEqArray(/\uD83D\uDC38+/.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38+/.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}"]); +assertEq(/\uD83D\uDC38+/.exec("\uD83D"), + null); +assertEqArray(/\uD83D\uDC38+/.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38\uDC38"]); +assertEq(/\uD83D\uDC38+/.exec(""), + null); + +// ==== * ==== + +assertEqArray(/\uD83D\uDC38*/u.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38*/u.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}\u{1F438}"]); +assertEqArray(/\uD83D\uDC38*/u.exec(""), + [""]); + +// lead-only target +assertEqArray(/\uD83D\uDC38*/u.exec("\uD83D"), + [""]); +assertEqArray(/\uD83D\uDC38*/u.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38"]); + +// no unicode flag +assertEqArray(/\uD83D\uDC38*/.exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38*/.exec("\u{1F438}\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(/\uD83D\uDC38*/.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83D\uDC38*/.exec("\uD83D\uDC38\uDC38"), + ["\uD83D\uDC38\uDC38"]); +assertEq(/\uD83D\uDC38*/.exec(""), + null); + +// ==== lead-only ==== + +// match only non-surrogate pair +assertEqArray(/\uD83D/u.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEq(/\uD83D/u.exec("\uD83D\uDC00"), + null); +assertEq(/\uD83D/u.exec("\uD83D\uDFFF"), + null); +assertEqArray(/\uD83D/u.exec("\uD83D\uE000"), + ["\uD83D"]); + +// match before non-tail char +assertEqArray(/\uD83D/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83D/u.exec("\uD83DA"), + ["\uD83D"]); + +// no unicode flag +assertEqArray(/\uD83D/.exec("\uD83D\uDBFF"), + ["\uD83D"]); +assertEqArray(/\uD83D/.exec("\uD83D\uDC00"), + ["\uD83D"]); +assertEqArray(/\uD83D/.exec("\uD83D\uDFFF"), + ["\uD83D"]); +assertEqArray(/\uD83D/.exec("\uD83D\uE000"), + ["\uD83D"]); +assertEqArray(/\uD83D/.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83D/.exec("\uD83DA"), + ["\uD83D"]); + +// ==== trail-only ==== + +// match only non-surrogate pair +assertEqArray(/\uDC38/u.exec("\uD7FF\uDC38"), + ["\uDC38"]); +assertEq(/\uDC38/u.exec("\uD800\uDC38"), + null); +assertEq(/\uDC38/u.exec("\uDBFF\uDC38"), + null); +assertEqArray(/\uDC38/u.exec("\uDC00\uDC38"), + ["\uDC38"]); + +// match after non-lead char +assertEqArray(/\uDC38/u.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/u.exec("A\uDC38"), + ["\uDC38"]); + +// no unicode flag +assertEqArray(/\uDC38/.exec("\uD7FF\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/.exec("\uD800\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/.exec("\uDBFF\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/.exec("\uDC00\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/.exec("\uDC38"), + ["\uDC38"]); +assertEqArray(/\uDC38/.exec("A\uDC38"), + ["\uDC38"]); + +// ==== invalid trail ==== + +assertEqArray(/\uD83D\u3042*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83D\u3042*/u.exec("\uD83D\u3042"), + ["\uD83D\u3042"]); +assertEqArray(/\uD83D\u3042*/u.exec("\uD83D\u3042\u3042"), + ["\uD83D\u3042\u3042"]); + +assertEqArray(/\uD83D\u{3042}*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83D\u{3042}*/u.exec("\uD83D\u3042"), + ["\uD83D\u3042"]); +assertEqArray(/\uD83D\u{3042}*/u.exec("\uD83D\u3042\u3042"), + ["\uD83D\u3042\u3042"]); + +assertEqArray(/\uD83DA*/u.exec("\uD83D"), + ["\uD83D"]); +assertEqArray(/\uD83DA*/u.exec("\uD83DA"), + ["\uD83DA"]); +assertEqArray(/\uD83DA*/u.exec("\uD83DAA"), + ["\uD83DAA"]); + +// ==== wrong patterns ==== + +assertThrowsInstanceOf(() => eval(`/\\u/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u0/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u00/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u000/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u000G/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\u0.00/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u0/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u00/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u000/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u000G/u`), SyntaxError); +assertThrowsInstanceOf(() => eval(`/\\uD83D\\u0.00/u`), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/unicode-raw.js b/js/src/tests/ecma_6/RegExp/unicode-raw.js new file mode 100644 index 0000000000..37b572cd82 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/unicode-raw.js @@ -0,0 +1,139 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- raw unicode."; + +print(BUGNUMBER + ": " + summary); + +// ==== standalone ==== + +assertEqArray(eval(`/\uD83D\uDC38/u`).exec("\u{1F438}"), + ["\u{1F438}"]); + +// no unicode flag +assertEqArray(eval(`/\uD83D\uDC38/`).exec("\u{1F438}"), + ["\u{1F438}"]); + +// escaped (lead) +assertEq(eval(`/\\uD83D\uDC38/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/\\u{D83D}\uDC38/u`).exec("\u{1F438}"), + null); + +// escaped (trail) +assertEq(eval(`/\uD83D\\uDC38/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/\uD83D\\u{DC38}/u`).exec("\u{1F438}"), + null); + +// escaped (lead), no unicode flag +assertEqArray(eval(`/\\uD83D\uDC38/`).exec("\u{1F438}"), + ["\u{1F438}"]); + +// escaped (trail), no unicode flag +assertEqArray(eval(`/\uD83D\\uDC38/`).exec("\u{1F438}"), + ["\u{1F438}"]); + +// ==== RegExp constructor ==== + +assertEqArray(new RegExp("\uD83D\uDC38", "u").exec("\u{1F438}"), + ["\u{1F438}"]); + +// no unicode flag +assertEqArray(new RegExp("\uD83D\uDC38", "").exec("\u{1F438}"), + ["\u{1F438}"]); + +// escaped(lead) +assertEq(new RegExp("\\uD83D\uDC38", "u").exec("\u{1F438}"), + null); +assertEq(new RegExp("\\u{D83D}\uDC38", "u").exec("\u{1F438}"), + null); + +// escaped(trail) +assertEq(new RegExp("\uD83D\\uDC38", "u").exec("\u{1F438}"), + null); +assertEq(new RegExp("\uD83D\\u{DC38}", "u").exec("\u{1F438}"), + null); + +// escaped(lead), no unicode flag +assertEqArray(new RegExp("\\uD83D\uDC38", "").exec("\u{1F438}"), + ["\u{1F438}"]); + +// escaped(trail), no unicode flag +assertEqArray(new RegExp("\uD83D\\uDC38", "").exec("\u{1F438}"), + ["\u{1F438}"]); + +// ==== ? ==== + +assertEqArray(eval(`/\uD83D\uDC38?/u`).exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(eval(`/\uD83D\uDC38?/u`).exec(""), + [""]); + +assertEqArray(eval(`/\uD83D\uDC38?/u`).exec("\uD83D"), + [""]); + +// no unicode flag +assertEqArray(eval(`/\uD83D\uDC38?/`).exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(eval(`/\uD83D\uDC38?/`).exec(""), + null); + +assertEqArray(eval(`/\uD83D\uDC38?/`).exec("\uD83D"), + ["\uD83D"]); + +// escaped (lead) +assertEq(eval(`/\\uD83D\uDC38?/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/\\uD83D\uDC38?/u`).exec(""), + null); + +assertEqArray(eval(`/\\uD83D\uDC38?/u`).exec("\uD83D"), + ["\uD83D"]); + +// escaped (trail) +assertEq(eval(`/\uD83D\\uDC38?/u`).exec("\u{1F438}"), + null); +assertEq(eval(`/\uD83D\\uDC38?/u`).exec(""), + null); + +assertEqArray(eval(`/\uD83D\\uDC38?/u`).exec("\uD83D"), + ["\uD83D"]); + +// escaped (lead), no unicode flag +assertEqArray(eval(`/\\uD83D\uDC38?/`).exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(eval(`/\\uD83D\uDC38?/`).exec(""), + null); + +assertEqArray(eval(`/\\uD83D\uDC38?/`).exec("\uD83D"), + ["\uD83D"]); + +// escaped (trail), no unicode flag +assertEqArray(eval(`/\uD83D\\uDC38?/`).exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(eval(`/\uD83D\\uDC38?/`).exec(""), + null); + +assertEqArray(eval(`/\uD83D\\uDC38?/`).exec("\uD83D"), + ["\uD83D"]); + +// ==== RegExp constructor, ? ==== + +assertEqArray(new RegExp("\uD83D\uDC38?", "u").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEqArray(new RegExp("\uD83D\uDC38?", "u").exec(""), + [""]); + +assertEqArray(new RegExp("\uD83D\uDC38?", "u").exec("\uD83D"), + [""]); + +// no unicode flag +assertEqArray(new RegExp("\uD83D\uDC38?", "").exec("\u{1F438}"), + ["\u{1F438}"]); +assertEq(new RegExp("\uD83D\uDC38?", "").exec(""), + null); + +assertEqArray(new RegExp("\uD83D\uDC38?", "").exec("\uD83D"), + ["\uD83D"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/String/AdvanceStringIndex.js b/js/src/tests/ecma_6/String/AdvanceStringIndex.js new file mode 100644 index 0000000000..fc40466039 --- /dev/null +++ b/js/src/tests/ecma_6/String/AdvanceStringIndex.js @@ -0,0 +1,43 @@ +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- AdvanceStringIndex in global match and replace."; + +print(BUGNUMBER + ": " + summary); + +// ==== String.prototype.match ==== + +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".match(/\uD83D|X|/gu), + ["", "", "X", "", ""]); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".match(/\uDC38|X|/gu), + ["", "", "X", "", ""]); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".match(/\uD83D\uDC38|X|/gu), + ["\uD83D\uDC38", "", "X", "", ""]); + +// ==== String.prototype.replace ==== + +// empty string replacement (optimized) +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uD83D|X|/gu, ""), + "\uD83D\uDC38\uD83D\uDC39\uD83D\uDC3A"); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uDC38|X|/gu, ""), + "\uD83D\uDC38\uD83D\uDC39\uD83D\uDC3A"); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uD83D\uDC38|X|/gu, ""), + "\uD83D\uDC39\uD83D\uDC3A"); + +// non-empty string replacement +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uD83D|X|/gu, "x"), + "x\uD83D\uDC38x\uD83D\uDC39xx\uD83D\uDC3Ax"); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uDC38|X|/gu, "x"), + "x\uD83D\uDC38x\uD83D\uDC39xx\uD83D\uDC3Ax"); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".replace(/\uD83D\uDC38|X|/gu, "x"), + "xx\uD83D\uDC39xx\uD83D\uDC3Ax"); + +// ==== String.prototype.split ==== + +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".split(/\uD83D|X|/u), + ["\uD83D\uDC38", "\uD83D\uDC39", "\uD83D\uDC3A"]); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".split(/\uDC38|X|/u), + ["\uD83D\uDC38", "\uD83D\uDC39", "\uD83D\uDC3A"]); +assertEqArray("\uD83D\uDC38\uD83D\uDC39X\uD83D\uDC3A".split(/\uD83D\uDC38|X|/u), + ["", "\uD83D\uDC39", "\uD83D\uDC3A"]); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/js1_8_5/extensions/sharedtypedarray.js b/js/src/tests/js1_8_5/extensions/sharedtypedarray.js index b878a37315..ce56dbc387 100644 --- a/js/src/tests/js1_8_5/extensions/sharedtypedarray.js +++ b/js/src/tests/js1_8_5/extensions/sharedtypedarray.js @@ -191,10 +191,44 @@ function testClone2() { assertEq(ia2[10], 37); } +function testApplicable() { + var sab = b; + var x; + + // Just make sure we can create all the view types on shared memory. + + x = new Int32Array(sab); + assertEq(x.length, sab.byteLength / Int32Array.BYTES_PER_ELEMENT); + x = new Uint32Array(sab); + assertEq(x.length, sab.byteLength / Uint32Array.BYTES_PER_ELEMENT); + + x = new Int16Array(sab); + assertEq(x.length, sab.byteLength / Int16Array.BYTES_PER_ELEMENT); + x = new Uint16Array(sab); + assertEq(x.length, sab.byteLength / Uint16Array.BYTES_PER_ELEMENT); + + x = new Int8Array(sab); + assertEq(x.length, sab.byteLength / Int8Array.BYTES_PER_ELEMENT); + x = new Uint8Array(sab); + assertEq(x.length, sab.byteLength / Uint8Array.BYTES_PER_ELEMENT); + + // Though the atomic operations are illegal on Uint8ClampedArray and the + // float arrays, they can still be used to create views on shared memory. + + x = new Uint8ClampedArray(sab); + assertEq(x.length, sab.byteLength / Uint8ClampedArray.BYTES_PER_ELEMENT); + + x = new Float32Array(sab); + assertEq(x.length, sab.byteLength / Float32Array.BYTES_PER_ELEMENT); + x = new Float64Array(sab); + assertEq(x.length, sab.byteLength / Float64Array.BYTES_PER_ELEMENT); +} + testSharedArrayBuffer(); testSharedTypedArray(); testSharedTypedArrayMethods(); testClone1(); testClone2(); +testApplicable(); reportCompare(0, 0, 'ok'); diff --git a/js/src/vm/CaseFolding.txt b/js/src/vm/CaseFolding.txt new file mode 100644 index 0000000000..42f90efaad --- /dev/null +++ b/js/src/vm/CaseFolding.txt @@ -0,0 +1,1414 @@ +# CaseFolding-8.0.0.txt +# Date: 2015-01-13, 18:16:36 GMT [MD] +# +# Unicode Character Database +# Copyright (c) 1991-2015 Unicode, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Case Folding Properties +# +# This file is a supplement to the UnicodeData file. +# It provides a case folding mapping generated from the Unicode Character Database. +# If all characters are mapped according to the full mapping below, then +# case differences (according to UnicodeData.txt and SpecialCasing.txt) +# are eliminated. +# +# The data supports both implementations that require simple case foldings +# (where string lengths don't change), and implementations that allow full case folding +# (where string lengths may grow). Note that where they can be supported, the +# full case foldings are superior: for example, they allow "MASSE" and "Ma?e" to match. +# +# All code points not listed in this file map to themselves. +# +# NOTE: case folding does not preserve normalization formats! +# +# For information on case folding, including how to have case folding +# preserve normalization formats, see Section 3.13 Default Case Algorithms in +# The Unicode Standard. +# +# ================================================================================ +# Format +# ================================================================================ +# The entries in this file are in the following machine-readable format: +# +# ; ; ; # +# +# The status field is: +# C: common case folding, common mappings shared by both simple and full mappings. +# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces. +# S: simple case folding, mappings to single characters where different from F. +# T: special case for uppercase I and dotted uppercase I +# - For non-Turkic languages, this mapping is normally not used. +# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters. +# Note that the Turkic mappings do not maintain canonical equivalence without additional processing. +# See the discussions of case mapping in the Unicode Standard for more information. +# +# Usage: +# A. To do a simple case folding, use the mappings with status C + S. +# B. To do a full case folding, use the mappings with status C + F. +# +# The mappings with status T can be used or omitted depending on the desired case-folding +# behavior. (The default option is to exclude them.) +# +# ================================================================= + +# Property: Case_Folding + +# All code points not explicitly listed for Case_Folding +# have the value C for the status field, and the code point itself for the mapping field. + +# ================================================================= +0041; C; 0061; # LATIN CAPITAL LETTER A +0042; C; 0062; # LATIN CAPITAL LETTER B +0043; C; 0063; # LATIN CAPITAL LETTER C +0044; C; 0064; # LATIN CAPITAL LETTER D +0045; C; 0065; # LATIN CAPITAL LETTER E +0046; C; 0066; # LATIN CAPITAL LETTER F +0047; C; 0067; # LATIN CAPITAL LETTER G +0048; C; 0068; # LATIN CAPITAL LETTER H +0049; C; 0069; # LATIN CAPITAL LETTER I +0049; T; 0131; # LATIN CAPITAL LETTER I +004A; C; 006A; # LATIN CAPITAL LETTER J +004B; C; 006B; # LATIN CAPITAL LETTER K +004C; C; 006C; # LATIN CAPITAL LETTER L +004D; C; 006D; # LATIN CAPITAL LETTER M +004E; C; 006E; # LATIN CAPITAL LETTER N +004F; C; 006F; # LATIN CAPITAL LETTER O +0050; C; 0070; # LATIN CAPITAL LETTER P +0051; C; 0071; # LATIN CAPITAL LETTER Q +0052; C; 0072; # LATIN CAPITAL LETTER R +0053; C; 0073; # LATIN CAPITAL LETTER S +0054; C; 0074; # LATIN CAPITAL LETTER T +0055; C; 0075; # LATIN CAPITAL LETTER U +0056; C; 0076; # LATIN CAPITAL LETTER V +0057; C; 0077; # LATIN CAPITAL LETTER W +0058; C; 0078; # LATIN CAPITAL LETTER X +0059; C; 0079; # LATIN CAPITAL LETTER Y +005A; C; 007A; # LATIN CAPITAL LETTER Z +00B5; C; 03BC; # MICRO SIGN +00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE +00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE +00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE +00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS +00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE +00C6; C; 00E6; # LATIN CAPITAL LETTER AE +00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA +00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE +00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE +00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS +00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE +00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE +00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS +00D0; C; 00F0; # LATIN CAPITAL LETTER ETH +00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE +00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE +00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE +00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE +00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS +00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE +00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE +00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE +00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS +00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE +00DE; C; 00FE; # LATIN CAPITAL LETTER THORN +00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S +0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON +0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE +0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK +0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE +0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE +010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON +010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON +0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE +0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON +0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE +0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE +0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK +011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON +011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE +0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE +0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA +0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE +0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE +012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON +012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE +012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK +0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0132; C; 0133; # LATIN CAPITAL LIGATURE IJ +0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA +0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE +013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA +013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON +013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT +0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE +0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE +0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA +0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON +0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014A; C; 014B; # LATIN CAPITAL LETTER ENG +014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON +014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE +0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0152; C; 0153; # LATIN CAPITAL LIGATURE OE +0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE +0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA +0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON +015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE +015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA +0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON +0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA +0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON +0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE +0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE +016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON +016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE +016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE +0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK +0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS +0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE +017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE +017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON +017F; C; 0073; # LATIN SMALL LETTER LONG S +0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK +0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR +0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX +0186; C; 0254; # LATIN CAPITAL LETTER OPEN O +0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK +0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D +018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK +018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR +018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E +018F; C; 0259; # LATIN CAPITAL LETTER SCHWA +0190; C; 025B; # LATIN CAPITAL LETTER OPEN E +0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK +0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK +0194; C; 0263; # LATIN CAPITAL LETTER GAMMA +0196; C; 0269; # LATIN CAPITAL LETTER IOTA +0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE +0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK +019C; C; 026F; # LATIN CAPITAL LETTER TURNED M +019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK +019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE +01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN +01A2; C; 01A3; # LATIN CAPITAL LETTER OI +01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK +01A6; C; 0280; # LATIN LETTER YR +01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO +01A9; C; 0283; # LATIN CAPITAL LETTER ESH +01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK +01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN +01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON +01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK +01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK +01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE +01B7; C; 0292; # LATIN CAPITAL LETTER EZH +01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED +01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE +01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON +01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C7; C; 01C9; # LATIN CAPITAL LETTER LJ +01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J +01CA; C; 01CC; # LATIN CAPITAL LETTER NJ +01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON +01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON +01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON +01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON +01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON +01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE +01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON +01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON +01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK +01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON +01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON +01F1; C; 01F3; # LATIN CAPITAL LETTER DZ +01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE +01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR +01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN +01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE +01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE +01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE +0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE +0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE +020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE +0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE +0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE +0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW +021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW +021C; C; 021D; # LATIN CAPITAL LETTER YOGH +021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON +0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +0222; C; 0223; # LATIN CAPITAL LETTER OU +0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK +0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE +0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA +022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE +0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON +023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE +023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE +023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR +023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP +0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE +0244; C; 0289; # LATIN CAPITAL LETTER U BAR +0245; C; 028C; # LATIN CAPITAL LETTER TURNED V +0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE +0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE +024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE +024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE +0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI +0370; C; 0371; # GREEK CAPITAL LETTER HETA +0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI +0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA +037F; C; 03F3; # GREEK CAPITAL LETTER YOT +0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS +0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS +0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS +038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS +038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS +038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS +038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS +0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA +0392; C; 03B2; # GREEK CAPITAL LETTER BETA +0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA +0394; C; 03B4; # GREEK CAPITAL LETTER DELTA +0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON +0396; C; 03B6; # GREEK CAPITAL LETTER ZETA +0397; C; 03B7; # GREEK CAPITAL LETTER ETA +0398; C; 03B8; # GREEK CAPITAL LETTER THETA +0399; C; 03B9; # GREEK CAPITAL LETTER IOTA +039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA +039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA +039C; C; 03BC; # GREEK CAPITAL LETTER MU +039D; C; 03BD; # GREEK CAPITAL LETTER NU +039E; C; 03BE; # GREEK CAPITAL LETTER XI +039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON +03A0; C; 03C0; # GREEK CAPITAL LETTER PI +03A1; C; 03C1; # GREEK CAPITAL LETTER RHO +03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA +03A4; C; 03C4; # GREEK CAPITAL LETTER TAU +03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON +03A6; C; 03C6; # GREEK CAPITAL LETTER PHI +03A7; C; 03C7; # GREEK CAPITAL LETTER CHI +03A8; C; 03C8; # GREEK CAPITAL LETTER PSI +03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA +03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA +03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL +03D0; C; 03B2; # GREEK BETA SYMBOL +03D1; C; 03B8; # GREEK THETA SYMBOL +03D5; C; 03C6; # GREEK PHI SYMBOL +03D6; C; 03C0; # GREEK PI SYMBOL +03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA +03DA; C; 03DB; # GREEK LETTER STIGMA +03DC; C; 03DD; # GREEK LETTER DIGAMMA +03DE; C; 03DF; # GREEK LETTER KOPPA +03E0; C; 03E1; # GREEK LETTER SAMPI +03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI +03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI +03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI +03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI +03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA +03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA +03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI +03F0; C; 03BA; # GREEK KAPPA SYMBOL +03F1; C; 03C1; # GREEK RHO SYMBOL +03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL +03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL +03F7; C; 03F8; # GREEK CAPITAL LETTER SHO +03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL +03FA; C; 03FB; # GREEK CAPITAL LETTER SAN +03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401; C; 0451; # CYRILLIC CAPITAL LETTER IO +0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE +0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE +0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE +0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0407; C; 0457; # CYRILLIC CAPITAL LETTER YI +0408; C; 0458; # CYRILLIC CAPITAL LETTER JE +0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE +040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE +040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE +040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE +040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE +040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U +040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE +0410; C; 0430; # CYRILLIC CAPITAL LETTER A +0411; C; 0431; # CYRILLIC CAPITAL LETTER BE +0412; C; 0432; # CYRILLIC CAPITAL LETTER VE +0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE +0414; C; 0434; # CYRILLIC CAPITAL LETTER DE +0415; C; 0435; # CYRILLIC CAPITAL LETTER IE +0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE +0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE +0418; C; 0438; # CYRILLIC CAPITAL LETTER I +0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I +041A; C; 043A; # CYRILLIC CAPITAL LETTER KA +041B; C; 043B; # CYRILLIC CAPITAL LETTER EL +041C; C; 043C; # CYRILLIC CAPITAL LETTER EM +041D; C; 043D; # CYRILLIC CAPITAL LETTER EN +041E; C; 043E; # CYRILLIC CAPITAL LETTER O +041F; C; 043F; # CYRILLIC CAPITAL LETTER PE +0420; C; 0440; # CYRILLIC CAPITAL LETTER ER +0421; C; 0441; # CYRILLIC CAPITAL LETTER ES +0422; C; 0442; # CYRILLIC CAPITAL LETTER TE +0423; C; 0443; # CYRILLIC CAPITAL LETTER U +0424; C; 0444; # CYRILLIC CAPITAL LETTER EF +0425; C; 0445; # CYRILLIC CAPITAL LETTER HA +0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE +0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE +0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA +0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA +042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN +042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU +042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN +042D; C; 044D; # CYRILLIC CAPITAL LETTER E +042E; C; 044E; # CYRILLIC CAPITAL LETTER YU +042F; C; 044F; # CYRILLIC CAPITAL LETTER YA +0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA +0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT +0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E +0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS +0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS +046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI +0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI +0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA +0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA +0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0478; C; 0479; # CYRILLIC CAPITAL LETTER UK +047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA +047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047E; C; 047F; # CYRILLIC CAPITAL LETTER OT +0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA +048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN +048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK +0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE +0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER +049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE +04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA +04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE +04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA +04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER +04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER +04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U +04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE +04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA +04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA +04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK +04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL +04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK +04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL +04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL +04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE +04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE +04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE +04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA +04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE +04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON +04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O +04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON +04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK +04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE +0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE +0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE +0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE +0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE +0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE +050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE +050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE +050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE +0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE +0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK +0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA +0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA +0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE +051A; C; 051B; # CYRILLIC CAPITAL LETTER QA +051C; C; 051D; # CYRILLIC CAPITAL LETTER WE +051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA +0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK +0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK +0524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER +0526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER +0528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK +052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE +052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE +052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER +0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB +0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN +0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM +0534; C; 0564; # ARMENIAN CAPITAL LETTER DA +0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH +0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA +0537; C; 0567; # ARMENIAN CAPITAL LETTER EH +0538; C; 0568; # ARMENIAN CAPITAL LETTER ET +0539; C; 0569; # ARMENIAN CAPITAL LETTER TO +053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE +053B; C; 056B; # ARMENIAN CAPITAL LETTER INI +053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN +053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH +053E; C; 056E; # ARMENIAN CAPITAL LETTER CA +053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN +0540; C; 0570; # ARMENIAN CAPITAL LETTER HO +0541; C; 0571; # ARMENIAN CAPITAL LETTER JA +0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD +0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH +0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN +0545; C; 0575; # ARMENIAN CAPITAL LETTER YI +0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW +0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA +0548; C; 0578; # ARMENIAN CAPITAL LETTER VO +0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA +054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH +054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH +054C; C; 057C; # ARMENIAN CAPITAL LETTER RA +054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH +054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW +054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN +0550; C; 0580; # ARMENIAN CAPITAL LETTER REH +0551; C; 0581; # ARMENIAN CAPITAL LETTER CO +0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN +0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR +0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH +0555; C; 0585; # ARMENIAN CAPITAL LETTER OH +0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH +0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN +10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN +10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN +10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN +10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON +10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN +10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN +10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN +10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN +10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN +10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN +10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS +10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN +10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR +10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON +10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR +10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR +10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE +10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN +10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR +10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN +10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR +10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR +10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN +10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR +10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN +10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN +10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN +10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL +10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL +10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR +10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN +10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN +10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE +10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE +10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE +10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE +10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR +10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE +10C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN +10CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN +13F8; C; 13F0; # CHEROKEE SMALL LETTER YE +13F9; C; 13F1; # CHEROKEE SMALL LETTER YI +13FA; C; 13F2; # CHEROKEE SMALL LETTER YO +13FB; C; 13F3; # CHEROKEE SMALL LETTER YU +13FC; C; 13F4; # CHEROKEE SMALL LETTER YV +13FD; C; 13F5; # CHEROKEE SMALL LETTER MV +1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW +1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE +1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW +1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW +1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW +1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW +1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA +1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE +1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON +1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE +1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW +1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS +1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA +1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE +1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW +1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW +1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW +1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW +1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE +1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE +1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW +1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE +1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW +1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW +1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE +1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE +1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE +1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW +1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW +1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE +1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW +1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW +1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW +1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW +1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE +1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW +1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE +1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE +1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS +1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE +1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW +1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS +1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW +1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW +1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW +1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS +1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE +1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE +1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE +1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S +1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S +1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW +1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW +1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE +1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE +1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW +1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW +1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW +1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE +1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE +1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL +1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V +1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP +1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI +1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA +1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI +1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI +1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBE; C; 03B9; # GREEK PROSGEGRAMMENI +1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA +1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA +1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA +1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI +1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA +1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +2126; C; 03C9; # OHM SIGN +212A; C; 006B; # KELVIN SIGN +212B; C; 00E5; # ANGSTROM SIGN +2132; C; 214E; # TURNED CAPITAL F +2160; C; 2170; # ROMAN NUMERAL ONE +2161; C; 2171; # ROMAN NUMERAL TWO +2162; C; 2172; # ROMAN NUMERAL THREE +2163; C; 2173; # ROMAN NUMERAL FOUR +2164; C; 2174; # ROMAN NUMERAL FIVE +2165; C; 2175; # ROMAN NUMERAL SIX +2166; C; 2176; # ROMAN NUMERAL SEVEN +2167; C; 2177; # ROMAN NUMERAL EIGHT +2168; C; 2178; # ROMAN NUMERAL NINE +2169; C; 2179; # ROMAN NUMERAL TEN +216A; C; 217A; # ROMAN NUMERAL ELEVEN +216B; C; 217B; # ROMAN NUMERAL TWELVE +216C; C; 217C; # ROMAN NUMERAL FIFTY +216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED +216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED +216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND +2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED +24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A +24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B +24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C +24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D +24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E +24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F +24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G +24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H +24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I +24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J +24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K +24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L +24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M +24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N +24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O +24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P +24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q +24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R +24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S +24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T +24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U +24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V +24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W +24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X +24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y +24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z +2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU +2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY +2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE +2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI +2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO +2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU +2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE +2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO +2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA +2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE +2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I +2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI +2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO +2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE +2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE +2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI +2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU +2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI +2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI +2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO +2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO +2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU +2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU +2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU +2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU +2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE +2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA +2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI +2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI +2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA +2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU +2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI +2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI +2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU +2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS +2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO +2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS +2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA +2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA +2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC +2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR +2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE +2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE +2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL +2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER +2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER +2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER +2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA +2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK +2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A +2C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA +2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK +2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H +2C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL +2C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA +2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA +2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA +2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA +2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE +2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU +2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA +2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE +2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE +2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA +2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA +2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA +2C98; C; 2C99; # COPTIC CAPITAL LETTER MI +2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI +2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI +2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O +2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI +2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO +2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA +2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU +2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA +2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI +2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI +2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI +2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU +2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN +2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA +2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI +2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU +2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI +2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI +2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH +2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI +2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI +2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA +2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA +2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT +2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA +2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA +2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU +2CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI +2CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA +2CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI +A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA +A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO +A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE +A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA +A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV +A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK +A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA +A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER +A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER +A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT +A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU +A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A +A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS +A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS +A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS +A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN +A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE +A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE +A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL +A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM +A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O +A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O +A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O +A680; C; A681; # CYRILLIC CAPITAL LETTER DWE +A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE +A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE +A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE +A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE +A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK +A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE +A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE +A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE +A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE +A694; C; A695; # CYRILLIC CAPITAL LETTER HWE +A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE +A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O +A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O +A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF +A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN +A726; C; A727; # LATIN CAPITAL LETTER HENG +A728; C; A729; # LATIN CAPITAL LETTER TZ +A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO +A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO +A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA +A732; C; A733; # LATIN CAPITAL LETTER AA +A734; C; A735; # LATIN CAPITAL LETTER AO +A736; C; A737; # LATIN CAPITAL LETTER AU +A738; C; A739; # LATIN CAPITAL LETTER AV +A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR +A73C; C; A73D; # LATIN CAPITAL LETTER AY +A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT +A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE +A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE +A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE +A746; C; A747; # LATIN CAPITAL LETTER BROKEN L +A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE +A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY +A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP +A74E; C; A74F; # LATIN CAPITAL LETTER OO +A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER +A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH +A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL +A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER +A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE +A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA +A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA +A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE +A760; C; A761; # LATIN CAPITAL LETTER VY +A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z +A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE +A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER +A768; C; A769; # LATIN CAPITAL LETTER VEND +A76A; C; A76B; # LATIN CAPITAL LETTER ET +A76C; C; A76D; # LATIN CAPITAL LETTER IS +A76E; C; A76F; # LATIN CAPITAL LETTER CON +A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D +A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F +A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G +A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G +A780; C; A781; # LATIN CAPITAL LETTER TURNED L +A782; C; A783; # LATIN CAPITAL LETTER INSULAR R +A784; C; A785; # LATIN CAPITAL LETTER INSULAR S +A786; C; A787; # LATIN CAPITAL LETTER INSULAR T +A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO +A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H +A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER +A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR +A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH +A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE +A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE +A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE +A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE +A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE +A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE +A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE +A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE +A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE +A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK +A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E +A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G +A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT +A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K +A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T +A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL +A7B3; C; AB53; # LATIN CAPITAL LETTER CHI +A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA +A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA +AB70; C; 13A0; # CHEROKEE SMALL LETTER A +AB71; C; 13A1; # CHEROKEE SMALL LETTER E +AB72; C; 13A2; # CHEROKEE SMALL LETTER I +AB73; C; 13A3; # CHEROKEE SMALL LETTER O +AB74; C; 13A4; # CHEROKEE SMALL LETTER U +AB75; C; 13A5; # CHEROKEE SMALL LETTER V +AB76; C; 13A6; # CHEROKEE SMALL LETTER GA +AB77; C; 13A7; # CHEROKEE SMALL LETTER KA +AB78; C; 13A8; # CHEROKEE SMALL LETTER GE +AB79; C; 13A9; # CHEROKEE SMALL LETTER GI +AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO +AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU +AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV +AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA +AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE +AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI +AB80; C; 13B0; # CHEROKEE SMALL LETTER HO +AB81; C; 13B1; # CHEROKEE SMALL LETTER HU +AB82; C; 13B2; # CHEROKEE SMALL LETTER HV +AB83; C; 13B3; # CHEROKEE SMALL LETTER LA +AB84; C; 13B4; # CHEROKEE SMALL LETTER LE +AB85; C; 13B5; # CHEROKEE SMALL LETTER LI +AB86; C; 13B6; # CHEROKEE SMALL LETTER LO +AB87; C; 13B7; # CHEROKEE SMALL LETTER LU +AB88; C; 13B8; # CHEROKEE SMALL LETTER LV +AB89; C; 13B9; # CHEROKEE SMALL LETTER MA +AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME +AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI +AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO +AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU +AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA +AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA +AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH +AB91; C; 13C1; # CHEROKEE SMALL LETTER NE +AB92; C; 13C2; # CHEROKEE SMALL LETTER NI +AB93; C; 13C3; # CHEROKEE SMALL LETTER NO +AB94; C; 13C4; # CHEROKEE SMALL LETTER NU +AB95; C; 13C5; # CHEROKEE SMALL LETTER NV +AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA +AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE +AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI +AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO +AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU +AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV +AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA +AB9D; C; 13CD; # CHEROKEE SMALL LETTER S +AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE +AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI +ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO +ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU +ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV +ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA +ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA +ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE +ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE +ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI +ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI +ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO +ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU +ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV +ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA +ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA +ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE +ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI +ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO +ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU +ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV +ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA +ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE +ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI +ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO +ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU +ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV +ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA +ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE +ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI +ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO +ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU +ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV +ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA +FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF +FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI +FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL +FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI +FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL +FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T +FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST +FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW +FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH +FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI +FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW +FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH +FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A +FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B +FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C +FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D +FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E +FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F +FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G +FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H +FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I +FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J +FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K +FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L +FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M +FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N +FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O +FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P +FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q +FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R +FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S +FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T +FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U +FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V +FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W +FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X +FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y +FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z +10400; C; 10428; # DESERET CAPITAL LETTER LONG I +10401; C; 10429; # DESERET CAPITAL LETTER LONG E +10402; C; 1042A; # DESERET CAPITAL LETTER LONG A +10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH +10404; C; 1042C; # DESERET CAPITAL LETTER LONG O +10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO +10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I +10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E +10408; C; 10430; # DESERET CAPITAL LETTER SHORT A +10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH +1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O +1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO +1040C; C; 10434; # DESERET CAPITAL LETTER AY +1040D; C; 10435; # DESERET CAPITAL LETTER OW +1040E; C; 10436; # DESERET CAPITAL LETTER WU +1040F; C; 10437; # DESERET CAPITAL LETTER YEE +10410; C; 10438; # DESERET CAPITAL LETTER H +10411; C; 10439; # DESERET CAPITAL LETTER PEE +10412; C; 1043A; # DESERET CAPITAL LETTER BEE +10413; C; 1043B; # DESERET CAPITAL LETTER TEE +10414; C; 1043C; # DESERET CAPITAL LETTER DEE +10415; C; 1043D; # DESERET CAPITAL LETTER CHEE +10416; C; 1043E; # DESERET CAPITAL LETTER JEE +10417; C; 1043F; # DESERET CAPITAL LETTER KAY +10418; C; 10440; # DESERET CAPITAL LETTER GAY +10419; C; 10441; # DESERET CAPITAL LETTER EF +1041A; C; 10442; # DESERET CAPITAL LETTER VEE +1041B; C; 10443; # DESERET CAPITAL LETTER ETH +1041C; C; 10444; # DESERET CAPITAL LETTER THEE +1041D; C; 10445; # DESERET CAPITAL LETTER ES +1041E; C; 10446; # DESERET CAPITAL LETTER ZEE +1041F; C; 10447; # DESERET CAPITAL LETTER ESH +10420; C; 10448; # DESERET CAPITAL LETTER ZHEE +10421; C; 10449; # DESERET CAPITAL LETTER ER +10422; C; 1044A; # DESERET CAPITAL LETTER EL +10423; C; 1044B; # DESERET CAPITAL LETTER EM +10424; C; 1044C; # DESERET CAPITAL LETTER EN +10425; C; 1044D; # DESERET CAPITAL LETTER ENG +10426; C; 1044E; # DESERET CAPITAL LETTER OI +10427; C; 1044F; # DESERET CAPITAL LETTER EW +10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A +10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA +10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB +10C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB +10C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC +10C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC +10C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS +10C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED +10C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND +10C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E +10C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E +10C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE +10C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF +10C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG +10C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY +10C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH +10C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I +10C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II +10C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ +10C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK +10C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK +10C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK +10C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL +10C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY +10C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM +10C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN +10C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY +10C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O +10C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO +10C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE +10C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE +10C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE +10CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP +10CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP +10CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER +10CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER +10CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES +10CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ +10CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET +10CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT +10CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY +10CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH +10CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U +10CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU +10CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE +10CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE +10CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV +10CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ +10CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS +10CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN +10CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US +118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA +118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A +118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI +118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU +118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA +118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO +118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II +118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU +118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E +118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O +118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG +118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA +118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO +118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY +118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ +118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC +118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN +118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD +118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE +118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG +118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA +118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT +118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM +118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU +118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU +118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO +118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO +118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR +118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR +118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU +118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII +118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO +# +# EOF diff --git a/js/src/vm/CharacterEncoding.cpp b/js/src/vm/CharacterEncoding.cpp index c33d700065..cb7bb8ad86 100644 --- a/js/src/vm/CharacterEncoding.cpp +++ b/js/src/vm/CharacterEncoding.cpp @@ -203,7 +203,7 @@ static void ReportInvalidCharacter(JSContext* cx, uint32_t offset) { char buffer[10]; - JS_snprintf(buffer, 10, "%d", offset); + JS_snprintf(buffer, 10, "%u", offset); JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr, JSMSG_MALFORMED_UTF8_CHAR, buffer); } diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp index f5d628edf3..70225e3bbd 100644 --- a/js/src/vm/CodeCoverage.cpp +++ b/js/src/vm/CodeCoverage.cpp @@ -535,8 +535,8 @@ LCovRuntime::fillWithFilename(char *name, size_t length) static mozilla::Atomic globalRuntimeId(0); size_t rid = globalRuntimeId++; - size_t len = JS_snprintf(name, length, "%s/%" PRId64 "-%d-%d.info", - outDir, timestamp, size_t(pid_), rid); + size_t len = JS_snprintf(name, length, "%s/%" PRId64 "-%" PRIuSIZE "-%" PRIuSIZE ".info", + outDir, timestamp, pid_, rid); if (length <= len) { fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name."); return false; diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 7ad8977967..1c03b99bf1 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -33,6 +33,7 @@ macro(bytes, bytes, "bytes") \ macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \ macro(call, call, "call") \ + macro(callContentFunction, callContentFunction, "callContentFunction") \ macro(callee, callee, "callee") \ macro(caller, caller, "caller") \ macro(callFunction, callFunction, "callFunction") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index a0494bf535..39bef84cee 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -356,11 +356,12 @@ Breakpoint::nextInSite() Debugger::Debugger(JSContext* cx, NativeObject* dbg) : object(dbg), + debuggees(cx->runtime()), uncaughtExceptionHook(nullptr), enabled(true), allowUnobservedAsmJS(false), collectCoverageInfo(false), - observedGCs(cx), + observedGCs(cx->runtime()), tenurePromotionsLog(cx), trackingTenurePromotions(false), maxTenurePromotionsLogLength(DEFAULT_MAX_LOG_LENGTH), @@ -376,10 +377,10 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg) objects(cx), environments(cx), #ifdef NIGHTLY_BUILD - traceLoggerLastDrainedId(0), + traceLoggerLastDrainedSize(0), traceLoggerLastDrainedIteration(0), #endif - traceLoggerScriptedCallsLastDrainedId(0), + traceLoggerScriptedCallsLastDrainedSize(0), traceLoggerScriptedCallsLastDrainedIteration(0) { assertSameCompartment(cx, dbg); @@ -4401,9 +4402,9 @@ Debugger::drainTraceLogger(JSContext* cx, unsigned argc, Value* vp) size_t num; TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); bool lostEvents = logger->lostEvents(dbg->traceLoggerLastDrainedIteration, - dbg->traceLoggerLastDrainedId); + dbg->traceLoggerLastDrainedSize); EventEntry* events = logger->getEventsStartingAt(&dbg->traceLoggerLastDrainedIteration, - &dbg->traceLoggerLastDrainedId, + &dbg->traceLoggerLastDrainedSize, &num); RootedObject array(cx, NewDenseEmptyArray(cx)); @@ -4496,10 +4497,10 @@ Debugger::drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp) size_t num; TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); bool lostEvents = logger->lostEvents(dbg->traceLoggerScriptedCallsLastDrainedIteration, - dbg->traceLoggerScriptedCallsLastDrainedId); + dbg->traceLoggerScriptedCallsLastDrainedSize); EventEntry* events = logger->getEventsStartingAt( &dbg->traceLoggerScriptedCallsLastDrainedIteration, - &dbg->traceLoggerScriptedCallsLastDrainedId, + &dbg->traceLoggerScriptedCallsLastDrainedSize, &num); RootedObject array(cx, NewDenseEmptyArray(cx)); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 1a78eeab95..a544587385 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -43,7 +43,7 @@ class DebuggerMemory; typedef HashSet, - SystemAllocPolicy> WeakGlobalObjectSet; + RuntimeAllocPolicy> WeakGlobalObjectSet; /* * A weakmap from GC thing keys to JSObject values that supports the keys being @@ -260,6 +260,7 @@ class Debugger : private mozilla::LinkedListElement // Return true if this Debugger observed a debuggee that participated in the // GC identified by the given GC number. Return false otherwise. + // May return false negatives if we have hit OOM. bool observedGC(uint64_t majorGCNumber) const { return observedGCs.has(majorGCNumber); } @@ -340,7 +341,8 @@ class Debugger : private mozilla::LinkedListElement // The set of GC numbers for which one or more of this Debugger's observed // debuggees participated in. - js::HashSet observedGCs; + using GCNumberSet = HashSet, RuntimeAllocPolicy>; + GCNumberSet observedGCs; using TenurePromotionsLog = js::TraceableFifo; TenurePromotionsLog tenurePromotionsLog; @@ -446,10 +448,10 @@ class Debugger : private mozilla::LinkedListElement * lost events. */ #ifdef NIGHTLY_BUILD - uint32_t traceLoggerLastDrainedId; + uint32_t traceLoggerLastDrainedSize; uint32_t traceLoggerLastDrainedIteration; #endif - uint32_t traceLoggerScriptedCallsLastDrainedId; + uint32_t traceLoggerScriptedCallsLastDrainedSize; uint32_t traceLoggerScriptedCallsLastDrainedIteration; class FrameRange; diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 950c7524a4..f763dcc098 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -539,7 +539,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); if (!rootCount) return false; - JS::ubi::CensusHandler handler(census, rootCount); + JS::ubi::CensusHandler handler(census, rootCount, cx->runtime()->debuggerMallocSizeOf); Debugger* dbg = memory->getDebugger(); RootedObject dbgObj(cx, dbg->object); @@ -573,7 +573,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) } } - return handler.report(args.rval()); + return handler.report(cx, args.rval()); } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index d4ed3d45c5..0df19dc349 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -420,7 +420,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle globa InitBareWeakMapCtor(cx, global) && InitStopIterationClass(cx, global) && InitSelfHostingCollectionIteratorFunctions(cx, global) && - JS_DefineFunctions(cx, global, builtins); + DefineFunctions(cx, global, builtins, AsIntrinsic); } /* static */ bool diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 0e1e23bb96..cbf30c2a8d 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -395,18 +395,14 @@ NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue val } static MOZ_ALWAYS_INLINE bool -ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue objval, - HandleValue idval, MutableHandleValue res) +ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval, + MutableHandleValue res) { if (idval.isInt32()) { res.set(idval); return true; } - JSObject* obj = ToObjectFromStack(cx, objval); - if (!obj) - return false; - RootedId id(cx); if (!ToPropertyKey(cx, idval, &id)) return false; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 914cb5befb..14d63acc62 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -175,6 +175,22 @@ js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject scopeChain, MutableHan return true; } +bool +js::Debug_CheckSelfHosted(JSContext* cx, HandleValue fun) +{ +#ifndef DEBUG + MOZ_CRASH("Self hosted checks should only be done in Debug builds"); +#endif + + MOZ_ASSERT(fun.isObject()); + + MOZ_ASSERT(fun.toObject().is()); + MOZ_ASSERT(fun.toObject().as().isSelfHostedOrIntrinsic()); + + // This is purely to police self-hosted code. There is no actual operation. + return true; +} + static inline bool GetPropertyOperation(JSContext* cx, InterpreterFrame* fp, HandleScript script, jsbytecode* pc, MutableHandleValue lval, MutableHandleValue vp) @@ -1775,8 +1791,6 @@ CASE(JSOP_NOP) CASE(JSOP_UNUSED14) CASE(JSOP_UNUSED65) CASE(JSOP_BACKPATCH) -CASE(JSOP_UNUSED163) -CASE(JSOP_UNUSED177) CASE(JSOP_UNUSED178) CASE(JSOP_UNUSED179) CASE(JSOP_UNUSED180) @@ -2457,10 +2471,9 @@ CASE(JSOP_TOID) * but we need to avoid the observable stringification the second time. * There must be an object value below the id, which will not be popped. */ - ReservedRooted objval(&rootValue0, REGS.sp[-2]); ReservedRooted idval(&rootValue1, REGS.sp[-1]); MutableHandleValue res = REGS.stackHandleAt(-1); - if (!ToIdOperation(cx, script, REGS.pc, objval, idval, res)) + if (!ToIdOperation(cx, script, REGS.pc, idval, res)) goto error; } END_CASE(JSOP_TOID) @@ -3927,6 +3940,24 @@ CASE(JSOP_CLASSCONSTRUCTOR) } END_CASE(JSOP_CLASSCONSTRUCTOR) +CASE(JSOP_CHECKOBJCOERCIBLE) +{ + ReservedRooted checkVal(&rootValue0, REGS.sp[-1]); + if (checkVal.isNullOrUndefined() && !ToObjectFromStack(cx, checkVal)) + goto error; +} +END_CASE(JSOP_CHECKOBJCOERCIBLE) + +CASE(JSOP_DEBUGCHECKSELFHOSTED) +{ +#ifdef DEBUG + ReservedRooted checkVal(&rootValue0, REGS.sp[-1]); + if (!Debug_CheckSelfHosted(cx, checkVal)) + goto error; +#endif +} +END_CASE(JSOP_DEBUGCHECKSELFHOSTED) + DEFAULT() { char numBuf[12]; diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 5243f81578..92f68b6744 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -491,6 +491,9 @@ DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp); bool DefaultDerivedClassConstructor(JSContext* cx, unsigned argc, Value* vp); +bool +Debug_CheckSelfHosted(JSContext* cx, HandleValue v); + } /* namespace js */ #endif /* vm_Interpreter_h */ diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index ca4f5bc0eb..12e2944b19 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1668,7 +1668,14 @@ * Stack: => */ \ macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \ - macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 1, JOF_BYTE) \ + /* + * Throw if the value on the stack is not coerscible to an object (is |null| or |undefined|). + * Category: Literals + * Type: Object + * Operands: + * Stack: val => val + */ \ + macro(JSOP_CHECKOBJCOERCIBLE, 163, "checkobjcoercible", NULL, 1, 1, 1, JOF_BYTE) \ /* * Find the function to invoke with |super()| on the scope chain. * @@ -1802,7 +1809,7 @@ * Stack: => val */ \ macro(JSOP_GETIMPORT, 176,"getimport", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \ - macro(JSOP_UNUSED177, 177,"unused177", NULL, 1, 0, 0, JOF_BYTE) \ + macro(JSOP_DEBUGCHECKSELFHOSTED, 177,"debug-checkselfhosted", NULL, 1, 1, 1, JOF_BYTE) \ macro(JSOP_UNUSED178, 178,"unused178", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED179, 179,"unused179", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED180, 180,"unused180", NULL, 1, 0, 0, JOF_BYTE) \ @@ -2122,15 +2129,12 @@ macro(JSOP_REST, 224, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET) \ \ /* - * First, throw a TypeError if baseValue is null or undefined. Then, - * replace the top-of-stack value propertyNameValue with - * ToPropertyKey(propertyNameValue). This opcode implements ES6 12.3.2.1 - * steps 7-10. It is also used to implement computed property names; in - * that case, baseValue is always an object, so the first step is a no-op. + * Replace the top-of-stack value propertyNameValue with + * ToPropertyKey(propertyNameValue). * Category: Literals * Type: Object * Operands: - * Stack: baseValue, propertyNameValue => baseValue, propertyKey + * Stack: propertyNameValue => propertyKey */ \ macro(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \ \ diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 89b3bf6ac3..bdfd02c922 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -39,6 +39,7 @@ JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD); JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB); JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE); JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY); +JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE); RegExpObject* js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */) @@ -216,7 +217,7 @@ RegExpObject::createNoStatics(ExclusiveContext* cx, HandleAtom source, RegExpFla tokenStream = dummyTokenStream.ptr(); } - if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source)) + if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag)) return nullptr; Rooted regexp(cx, RegExpAlloc(cx)); @@ -276,6 +277,7 @@ RegExpObject::init(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags) self->setIgnoreCase(flags & IgnoreCaseFlag); self->setMultiline(flags & MultilineFlag); self->setSticky(flags & StickyFlag); + self->setUnicode(flags & UnicodeFlag); return true; } @@ -458,6 +460,8 @@ RegExpObject::toString(JSContext* cx) const return nullptr; if (multiline() && !sb.append('m')) return nullptr; + if (unicode() && !sb.append('u')) + return nullptr; if (sticky() && !sb.append('y')) return nullptr; @@ -518,7 +522,7 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu /* Parse the pattern. */ irregexp::RegExpCompileData data; if (!irregexp::ParsePattern(dummyTokenStream, cx->tempLifoAlloc(), pattern, - multiline(), mode == MatchOnly, &data)) + multiline(), mode == MatchOnly, unicode(), ignoreCase(), &data)) { return false; } @@ -531,7 +535,7 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu input->hasLatin1Chars(), mode == MatchOnly, force == ForceByteCode, - sticky()); + sticky(), unicode()); if (code.empty()) return false; @@ -957,6 +961,10 @@ ParseRegExpFlags(const CharT* chars, size_t length, RegExpFlag* flagsOut, char16 if (!HandleRegExpFlag(StickyFlag, flagsOut)) return false; break; + case 'u': + if (!HandleRegExpFlag(UnicodeFlag, flagsOut)) + return false; + break; default: return false; } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index ad118914d9..8fd0420845 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -51,9 +51,10 @@ enum RegExpFlag GlobalFlag = 0x02, MultilineFlag = 0x04, StickyFlag = 0x08, + UnicodeFlag = 0x10, NoFlags = 0x00, - AllFlags = 0x0f + AllFlags = 0x1f }; enum RegExpRunStatus @@ -186,6 +187,7 @@ class RegExpShared bool global() const { return flags & GlobalFlag; } bool multiline() const { return flags & MultilineFlag; } bool sticky() const { return flags & StickyFlag; } + bool unicode() const { return flags & UnicodeFlag; } bool isCompiled(CompilationMode mode, bool latin1, ForceByteCodeEnum force = DontForceByteCode) const { @@ -340,9 +342,10 @@ class RegExpObject : public NativeObject static const unsigned IGNORE_CASE_FLAG_SLOT = 3; static const unsigned MULTILINE_FLAG_SLOT = 4; static const unsigned STICKY_FLAG_SLOT = 5; + static const unsigned UNICODE_FLAG_SLOT = 6; public: - static const unsigned RESERVED_SLOTS = 6; + static const unsigned RESERVED_SLOTS = 7; static const unsigned PRIVATE_SLOT = 7; static const Class class_; @@ -404,6 +407,7 @@ class RegExpObject : public NativeObject flags |= ignoreCase() ? IgnoreCaseFlag : 0; flags |= multiline() ? MultilineFlag : 0; flags |= sticky() ? StickyFlag : 0; + flags |= unicode() ? UnicodeFlag : 0; return RegExpFlag(flags); } @@ -429,10 +433,15 @@ class RegExpObject : public NativeObject setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled)); } + void setUnicode(bool enabled) { + setSlot(UNICODE_FLAG_SLOT, BooleanValue(enabled)); + } + bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); } bool global() const { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); } bool multiline() const { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); } bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); } + bool unicode() const { return getFixedSlot(UNICODE_FLAG_SLOT).toBoolean(); } bool getShared(JSContext* cx, RegExpGuard* g); diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp index 67d9ddead0..527ab593f9 100644 --- a/js/src/vm/SPSProfiler.cpp +++ b/js/src/vm/SPSProfiler.cpp @@ -353,9 +353,9 @@ SPSProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun) : JS::CharsToNewUTF8CharsZ(nullptr, atom->twoByteRange(nogc)).c_str()); if (!atomStr) return nullptr; - ret = JS_snprintf(cstr, len + 1, "%s (%s:%llu)", atomStr.get(), filename, lineno); + ret = JS_snprintf(cstr, len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno); } else { - ret = JS_snprintf(cstr, len + 1, "%s:%llu", filename, lineno); + ret = JS_snprintf(cstr, len + 1, "%s:%" PRIu64, filename, lineno); } MOZ_ASSERT(ret == len, "Computed length should match actual length!"); diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h index 62cad44473..6ddda04f65 100644 --- a/js/src/vm/TraceLogging.h +++ b/js/src/vm/TraceLogging.h @@ -208,22 +208,22 @@ class TraceLoggerThread bool fail(JSContext* cx, const char* error); public: - // Given the previous iteration and lastEntryId, return an array of events + // Given the previous iteration and size, return an array of events // (there could be lost events). At the same time update the iteration and - // lastEntry and gives back how many events there are. - EventEntry* getEventsStartingAt(uint32_t* lastIteration, uint32_t* lastEntryId, size_t* num) { + // size and gives back how many events there are. + EventEntry* getEventsStartingAt(uint32_t* lastIteration, uint32_t* lastSize, size_t* num) { EventEntry* start; if (iteration_ == *lastIteration) { - MOZ_ASSERT(*lastEntryId < events.size()); - *num = events.lastEntryId() - *lastEntryId; - start = events.data() + *lastEntryId + 1; + MOZ_ASSERT(*lastSize <= events.size()); + *num = events.size() - *lastSize; + start = events.data() + *lastSize; } else { *num = events.size(); start = events.data(); } *lastIteration = iteration_; - *lastEntryId = events.lastEntryId(); + *lastSize = events.size(); return start; } @@ -233,16 +233,16 @@ class TraceLoggerThread const char** lineno, size_t* lineno_len, const char** colno, size_t* colno_len); - bool lostEvents(uint32_t lastIteration, uint32_t lastEntryId) { + bool lostEvents(uint32_t lastIteration, uint32_t lastSize) { // If still logging in the same iteration, there are no lost events. if (lastIteration == iteration_) { - MOZ_ASSERT(lastEntryId < events.size()); + MOZ_ASSERT(lastSize <= events.size()); return false; } - // When proceeded to the next iteration and lastEntryId points to - // the maximum capacity there are no logs that are lost. - if (lastIteration + 1 == iteration_ && lastEntryId == events.capacity()) + // If we are in a consecutive iteration we are only sure we didn't lose any events, + // when the lastSize equals the maximum size 'events' can get. + if (lastIteration == iteration_ - 1 && lastSize == events.maxSize()) return false; return true; diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index cbf490cee7..a789a5710d 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -1227,7 +1227,9 @@ class RecompileInfo bool shouldSweep(TypeZone& types); }; -typedef Vector RecompileInfoVector; +// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a +// single IonScript doesn't require an allocation. +typedef Vector RecompileInfoVector; struct AutoEnterAnalysis; diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp index 93bb04b649..1f9b293cb7 100644 --- a/js/src/vm/UbiNodeCensus.cpp +++ b/js/src/vm/UbiNodeCensus.cpp @@ -54,18 +54,17 @@ class SimpleCount : public CountType { bool reportBytes : 1; public: - SimpleCount(Census& census, - UniquePtr& label, - bool reportCount=true, - bool reportBytes=true) - : CountType(census), + explicit SimpleCount(UniquePtr& label, + bool reportCount=true, + bool reportBytes=true) + : CountType(), label(Move(label)), reportCount(reportCount), reportBytes(reportBytes) { } - explicit SimpleCount(Census& census) - : CountType(census), + explicit SimpleCount() + : CountType(), label(nullptr), reportCount(true), reportBytes(true) @@ -76,45 +75,45 @@ class SimpleCount : public CountType { count.~Count(); } - CountBasePtr makeCount() override { return CountBasePtr(census.new_(*this)); } + CountBasePtr makeCount() override { return CountBasePtr(js_new(*this)); } void traceCount(CountBase& countBase, JSTracer* trc) override { } - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; bool -SimpleCount::count(CountBase& countBase, const Node& node) +SimpleCount::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; if (reportBytes) - count.totalBytes_ += node.size(census.cx->runtime()->debuggerMallocSizeOf); + count.totalBytes_ += node.size(mallocSizeOf); return true; } bool -SimpleCount::report(CountBase& countBase, MutableHandleValue report) +SimpleCount::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - RootedPlainObject obj(census.cx, NewBuiltinClassInstance(census.cx)); + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); if (!obj) return false; - RootedValue countValue(census.cx, NumberValue(count.total_)); - if (reportCount && !DefineProperty(census.cx, obj, census.cx->names().count, countValue)) + RootedValue countValue(cx, NumberValue(count.total_)); + if (reportCount && !DefineProperty(cx, obj, cx->names().count, countValue)) return false; - RootedValue bytesValue(census.cx, NumberValue(count.totalBytes_)); - if (reportBytes && !DefineProperty(census.cx, obj, census.cx->names().bytes, bytesValue)) + RootedValue bytesValue(cx, NumberValue(count.totalBytes_)); + if (reportBytes && !DefineProperty(cx, obj, cx->names().bytes, bytesValue)) return false; if (label) { - JSString* labelString = JS_NewUCStringCopyZ(census.cx, label.get()); + JSString* labelString = JS_NewUCStringCopyZ(cx, label.get()); if (!labelString) return false; - RootedValue labelValue(census.cx, StringValue(labelString)); - if (!DefineProperty(census.cx, obj, census.cx->names().label, labelValue)) + RootedValue labelValue(cx, StringValue(labelString)); + if (!DefineProperty(cx, obj, cx->names().label, labelValue)) return false; } @@ -155,12 +154,11 @@ class ByCoarseType : public CountType { }; public: - ByCoarseType(Census& census, - CountTypePtr& objects, + ByCoarseType(CountTypePtr& objects, CountTypePtr& scripts, CountTypePtr& strings, CountTypePtr& other) - : CountType(census), + : CountType(), objects(Move(objects)), scripts(Move(scripts)), strings(Move(strings)), @@ -174,8 +172,8 @@ class ByCoarseType : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -189,11 +187,11 @@ ByCoarseType::makeCount() if (!objectsCount || !scriptsCount || !stringsCount || !otherCount) return CountBasePtr(nullptr); - return CountBasePtr(census.new_(*this, - objectsCount, - scriptsCount, - stringsCount, - otherCount)); + return CountBasePtr(js_new(*this, + objectsCount, + scriptsCount, + stringsCount, + otherCount)); } void @@ -207,20 +205,20 @@ ByCoarseType::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByCoarseType::count(CountBase& countBase, const Node& node) +ByCoarseType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; switch (node.coarseType()) { case JS::ubi::CoarseType::Object: - return count.objects->count(node); + return count.objects->count(mallocSizeOf, node); case JS::ubi::CoarseType::Script: - return count.scripts->count(node); + return count.scripts->count(mallocSizeOf, node); case JS::ubi::CoarseType::String: - return count.strings->count(node); + return count.strings->count(mallocSizeOf, node); case JS::ubi::CoarseType::Other: - return count.other->count(node); + return count.other->count(mallocSizeOf, node); default: MOZ_CRASH("bad JS::ubi::CoarseType in JS::ubi::ByCoarseType::count"); return false; @@ -228,32 +226,31 @@ ByCoarseType::count(CountBase& countBase, const Node& node) } bool -ByCoarseType::report(CountBase& countBase, MutableHandleValue report) +ByCoarseType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); if (!obj) return false; RootedValue objectsReport(cx); - if (!count.objects->report(&objectsReport) || + if (!count.objects->report(cx, &objectsReport) || !DefineProperty(cx, obj, cx->names().objects, objectsReport)) return false; RootedValue scriptsReport(cx); - if (!count.scripts->report(&scriptsReport) || + if (!count.scripts->report(cx, &scriptsReport) || !DefineProperty(cx, obj, cx->names().scripts, scriptsReport)) return false; RootedValue stringsReport(cx); - if (!count.strings->report(&stringsReport) || + if (!count.strings->report(cx, &stringsReport) || !DefineProperty(cx, obj, cx->names().strings, stringsReport)) return false; RootedValue otherReport(cx); - if (!count.other->report(&otherReport) || + if (!count.other->report(cx, &otherReport) || !DefineProperty(cx, obj, cx->names().other, otherReport)) return false; @@ -320,7 +317,7 @@ cStringCountMapToObject(JSContext* cx, CStringCountMap& map) { for (auto& entry : entries) { CountBasePtr& thenCount = entry->value(); RootedValue thenReport(cx); - if (!thenCount->report(&thenReport)) + if (!thenCount->report(cx, &thenReport)) return nullptr; const char* name = entry->key(); @@ -365,10 +362,8 @@ class ByObjectClass : public CountType { CountTypePtr otherType; public: - ByObjectClass(Census& census, - CountTypePtr& classesType, - CountTypePtr& otherType) - : CountType(census), + ByObjectClass(CountTypePtr& classesType, CountTypePtr& otherType) + : CountType(), classesType(Move(classesType)), otherType(Move(otherType)) { } @@ -380,8 +375,8 @@ class ByObjectClass : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -391,7 +386,7 @@ ByObjectClass::makeCount() if (!otherCount) return nullptr; - UniquePtr count(census.new_(*this, otherCount)); + UniquePtr count(js_new(*this, otherCount)); if (!count || !count->init()) return nullptr; @@ -408,14 +403,14 @@ ByObjectClass::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByObjectClass::count(CountBase& countBase, const Node& node) +ByObjectClass::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; const char* className = node.jsObjectClassName(); if (!className) - return count.other->count(node); + return count.other->count(mallocSizeOf, node); Table::AddPtr p = count.table.lookupForAdd(className); if (!p) { @@ -423,21 +418,20 @@ ByObjectClass::count(CountBase& countBase, const Node& node) if (!classCount || !count.table.add(p, className, Move(classCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByObjectClass::report(CountBase& countBase, MutableHandleValue report) +ByObjectClass::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table)); if (!obj) return false; RootedValue otherReport(cx); - if (!count.other->report(&otherReport) || + if (!count.other->report(cx, &otherReport) || !DefineProperty(cx, obj, cx->names().other, otherReport)) return false; @@ -466,8 +460,8 @@ class ByUbinodeType : public CountType { CountTypePtr entryType; public: - ByUbinodeType(Census& census, CountTypePtr& entryType) - : CountType(census), + explicit ByUbinodeType(CountTypePtr& entryType) + : CountType(), entryType(Move(entryType)) { } @@ -478,14 +472,14 @@ class ByUbinodeType : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr ByUbinodeType::makeCount() { - UniquePtr count(census.new_(*this)); + UniquePtr count(js_new(*this)); if (!count || !count->init()) return nullptr; @@ -501,7 +495,7 @@ ByUbinodeType::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByUbinodeType::count(CountBase& countBase, const Node& node) +ByUbinodeType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; @@ -514,14 +508,13 @@ ByUbinodeType::count(CountBase& countBase, const Node& node) if (!typesCount || !count.table.add(p, key, Move(typesCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByUbinodeType::report(CountBase& countBase, MutableHandleValue report) +ByUbinodeType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; // Build a vector of pointers to entries; sort by total; and then use // that to build the result object. This makes the ordering of entries @@ -541,7 +534,7 @@ ByUbinodeType::report(CountBase& countBase, MutableHandleValue report) Entry& entry = **entryPtr; CountBasePtr& typeCount = entry.value(); RootedValue typeReport(cx); - if (!typeCount->report(&typeReport)) + if (!typeCount->report(cx, &typeReport)) return false; const char16_t* name = entry.key(); @@ -609,8 +602,8 @@ class ByAllocationStack : public CountType { CountTypePtr noStackType; public: - ByAllocationStack(Census& census, CountTypePtr& entryType, CountTypePtr& noStackType) - : CountType(census), + ByAllocationStack(CountTypePtr& entryType, CountTypePtr& noStackType) + : CountType(), entryType(Move(entryType)), noStackType(Move(noStackType)) { } @@ -622,8 +615,8 @@ class ByAllocationStack : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -633,7 +626,7 @@ ByAllocationStack::makeCount() if (!noStackCount) return nullptr; - UniquePtr count(census.new_(*this, noStackCount)); + UniquePtr count(js_new(*this, noStackCount)); if (!count || !count->init()) return nullptr; return CountBasePtr(count.release()); @@ -657,7 +650,7 @@ ByAllocationStack::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByAllocationStack::count(CountBase& countBase, const Node& node) +ByAllocationStack::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; @@ -673,18 +666,17 @@ ByAllocationStack::count(CountBase& countBase, const Node& node) return false; } MOZ_ASSERT(p); - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } // Otherwise, count it in the "no stack" category. - return count.noStack->count(node); + return count.noStack->count(mallocSizeOf, node); } bool -ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) +ByAllocationStack::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; #ifdef DEBUG // Check that nothing rehashes our table while we hold pointers into it. @@ -719,7 +711,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) CountBasePtr& stackCount = entry.value(); RootedValue stackReport(cx); - if (!stackCount->report(&stackReport)) + if (!stackCount->report(cx, &stackReport)) return false; if (!MapObject::set(cx, map, stackVal, stackReport)) @@ -728,7 +720,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report) if (count.noStack->total_ > 0) { RootedValue noStackReport(cx); - if (!count.noStack->report(&noStackReport)) + if (!count.noStack->report(cx, &noStackReport)) return false; RootedValue noStack(cx, StringValue(cx->names().noStack)); if (!MapObject::set(cx, map, noStack, noStackReport)) @@ -767,10 +759,8 @@ class ByFilename : public CountType { CountTypePtr noFilenameType; public: - ByFilename(Census& census, - CountTypePtr& thenType, - CountTypePtr& noFilenameType) - : CountType(census), + ByFilename(CountTypePtr& thenType, CountTypePtr& noFilenameType) + : CountType(), thenType(Move(thenType)), noFilenameType(Move(noFilenameType)) { } @@ -782,8 +772,8 @@ class ByFilename : public CountType { CountBasePtr makeCount() override; void traceCount(CountBase& countBase, JSTracer* trc) override; - bool count(CountBase& countBase, const Node& node) override; - bool report(CountBase& countBase, MutableHandleValue report) override; + bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override; + bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override; }; CountBasePtr @@ -797,7 +787,7 @@ ByFilename::makeCount() if (!noFilenameCount) return nullptr; - UniquePtr count(census.new_(*this, Move(thenCount), Move(noFilenameCount))); + UniquePtr count(js_new(*this, Move(thenCount), Move(noFilenameCount))); if (!count || !count->init()) return nullptr; @@ -814,14 +804,14 @@ ByFilename::traceCount(CountBase& countBase, JSTracer* trc) } bool -ByFilename::count(CountBase& countBase, const Node& node) +ByFilename::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) { Count& count = static_cast(countBase); count.total_++; const char* filename = node.scriptFilename(); if (!filename) - return count.noFilename->count(node); + return count.noFilename->count(mallocSizeOf, node); Table::AddPtr p = count.table.lookupForAdd(filename); if (!p) { @@ -829,21 +819,20 @@ ByFilename::count(CountBase& countBase, const Node& node) if (!thenCount || !count.table.add(p, filename, Move(thenCount))) return false; } - return p->value()->count(node); + return p->value()->count(mallocSizeOf, node); } bool -ByFilename::report(CountBase& countBase, MutableHandleValue report) +ByFilename::report(JSContext* cx, CountBase& countBase, MutableHandleValue report) { Count& count = static_cast(countBase); - JSContext* cx = census.cx; RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table)); if (!obj) return false; RootedValue noFilenameReport(cx); - if (!count.noFilename->report(&noFilenameReport) || + if (!count.noFilename->report(cx, &noFilenameReport) || !DefineProperty(cx, obj, cx->names().noFilename, noFilenameReport)) { return false; @@ -876,11 +865,11 @@ CensusHandler::operator() (BreadthFirst& traversal, Zone* zone = referent.zone(); if (census.targetZones.count() == 0 || census.targetZones.has(zone)) - return rootCount->count(referent); + return rootCount->count(mallocSizeOf, referent); if (zone == census.atomsZone) { traversal.abandonReferent(); - return rootCount->count(referent); + return rootCount->count(mallocSizeOf, referent); } traversal.abandonReferent(); @@ -890,26 +879,21 @@ CensusHandler::operator() (BreadthFirst& traversal, /*** Parsing Breakdowns ***************************************************************************/ -static CountTypePtr ParseBreakdown(Census& census, HandleValue breakdownValue); - static CountTypePtr -ParseChildBreakdown(Census& census, HandleObject breakdown, PropertyName* prop) +ParseChildBreakdown(JSContext* cx, HandleObject breakdown, PropertyName* prop) { - JSContext* cx = census.cx; RootedValue v(cx); if (!GetProperty(cx, breakdown, breakdown, prop, &v)) return nullptr; - return ParseBreakdown(census, v); + return ParseBreakdown(cx, v); } -static CountTypePtr -ParseBreakdown(Census& census, HandleValue breakdownValue) +CountTypePtr +ParseBreakdown(JSContext* cx, HandleValue breakdownValue) { - JSContext* cx = census.cx; - if (breakdownValue.isUndefined()) { // Construct the default type, { by: 'count' } - CountTypePtr simple(census.new_(census)); + CountTypePtr simple(js_new()); return simple; } @@ -967,75 +951,73 @@ ParseBreakdown(Census& census, HandleValue breakdownValue) return nullptr; } - CountTypePtr simple(census.new_(census, - labelUnique, - ToBoolean(countValue), - ToBoolean(bytesValue))); + CountTypePtr simple(js_new(labelUnique, + ToBoolean(countValue), + ToBoolean(bytesValue))); return simple; } if (StringEqualsAscii(by, "objectClass")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other)); + CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other)); if (!otherType) return nullptr; - return CountTypePtr(census.new_(census, thenType, otherType)); + return CountTypePtr(js_new(thenType, otherType)); } if (StringEqualsAscii(by, "coarseType")) { - CountTypePtr objectsType(ParseChildBreakdown(census, breakdown, cx->names().objects)); + CountTypePtr objectsType(ParseChildBreakdown(cx, breakdown, cx->names().objects)); if (!objectsType) return nullptr; - CountTypePtr scriptsType(ParseChildBreakdown(census, breakdown, cx->names().scripts)); + CountTypePtr scriptsType(ParseChildBreakdown(cx, breakdown, cx->names().scripts)); if (!scriptsType) return nullptr; - CountTypePtr stringsType(ParseChildBreakdown(census, breakdown, cx->names().strings)); + CountTypePtr stringsType(ParseChildBreakdown(cx, breakdown, cx->names().strings)); if (!stringsType) return nullptr; - CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other)); + CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other)); if (!otherType) return nullptr; - return CountTypePtr(census.new_(census, - objectsType, - scriptsType, - stringsType, - otherType)); + return CountTypePtr(js_new(objectsType, + scriptsType, + stringsType, + otherType)); } if (StringEqualsAscii(by, "internalType")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - return CountTypePtr(census.new_(census, thenType)); + return CountTypePtr(js_new(thenType)); } if (StringEqualsAscii(by, "allocationStack")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr noStackType(ParseChildBreakdown(census, breakdown, cx->names().noStack)); + CountTypePtr noStackType(ParseChildBreakdown(cx, breakdown, cx->names().noStack)); if (!noStackType) return nullptr; - return CountTypePtr(census.new_(census, thenType, noStackType)); + return CountTypePtr(js_new(thenType, noStackType)); } if (StringEqualsAscii(by, "filename")) { - CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then)); + CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then)); if (!thenType) return nullptr; - CountTypePtr noFilenameType(ParseChildBreakdown(census, breakdown, cx->names().noFilename)); + CountTypePtr noFilenameType(ParseChildBreakdown(cx, breakdown, cx->names().noFilename)); if (!noFilenameType) return nullptr; - return CountTypePtr(census.new_(census, thenType, noFilenameType)); + return CountTypePtr(js_new(thenType, noFilenameType)); } // We didn't recognize the breakdown type; complain. @@ -1059,25 +1041,22 @@ ParseBreakdown(Census& census, HandleValue breakdownValue) // other: { by: "internalType" } // } static CountTypePtr -GetDefaultBreakdown(Census& census) +GetDefaultBreakdown() { - CountTypePtr byClass(census.new_(census)); - CountTypePtr byClassElse(census.new_(census)); - CountTypePtr objects(census.new_(census, - byClass, - byClassElse)); + CountTypePtr byClass(js_new()); + CountTypePtr byClassElse(js_new()); + CountTypePtr objects(js_new(byClass, byClassElse)); - CountTypePtr scripts(census.new_(census)); - CountTypePtr strings(census.new_(census)); + CountTypePtr scripts(js_new()); + CountTypePtr strings(js_new()); - CountTypePtr byType(census.new_(census)); - CountTypePtr other(census.new_(census, byType)); + CountTypePtr byType(js_new()); + CountTypePtr other(js_new(byType)); - return CountTypePtr(census.new_(census, - objects, - scripts, - strings, - other)); + return CountTypePtr(js_new(objects, + scripts, + strings, + other)); } bool @@ -1088,8 +1067,8 @@ ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTyp return false; outResult = breakdown.isUndefined() - ? GetDefaultBreakdown(census) - : ParseBreakdown(census, breakdown); + ? GetDefaultBreakdown() + : ParseBreakdown(cx, breakdown); return !!outResult; } diff --git a/js/src/vm/Unicode.cpp b/js/src/vm/Unicode.cpp index b110fbc5db..9214450ac2 100644 --- a/js/src/vm/Unicode.cpp +++ b/js/src/vm/Unicode.cpp @@ -772,4 +772,439 @@ const uint8_t unicode::index2[] = { 5, 5, 5, 0, 0, 0, }; +const FoldingInfo unicode::js_foldinfo[] = { + {0, 0, 0, 0}, + {32, 0, 0, 0}, + {32, 8415, 0, 0}, + {32, 300, 0, 0}, + {0, 65504, 0, 0}, + {0, 65504, 8383, 0}, + {0, 65504, 268, 0}, + {775, 743, 0, 0}, + {32, 8294, 0, 0}, + {0, 7615, 0, 0}, + {0, 65504, 8262, 0}, + {0, 121, 0, 0}, + {1, 0, 0, 0}, + {0, 65535, 0, 0}, + {65415, 0, 0, 0}, + {65268, 65236, 0, 0}, + {0, 195, 0, 0}, + {210, 0, 0, 0}, + {206, 0, 0, 0}, + {205, 0, 0, 0}, + {79, 0, 0, 0}, + {202, 0, 0, 0}, + {203, 0, 0, 0}, + {207, 0, 0, 0}, + {0, 97, 0, 0}, + {211, 0, 0, 0}, + {209, 0, 0, 0}, + {0, 163, 0, 0}, + {213, 0, 0, 0}, + {0, 130, 0, 0}, + {214, 0, 0, 0}, + {218, 0, 0, 0}, + {217, 0, 0, 0}, + {219, 0, 0, 0}, + {0, 56, 0, 0}, + {2, 1, 0, 0}, + {1, 65535, 0, 0}, + {0, 65534, 65535, 0}, + {0, 65457, 0, 0}, + {65439, 0, 0, 0}, + {65480, 0, 0, 0}, + {65406, 0, 0, 0}, + {10795, 0, 0, 0}, + {65373, 0, 0, 0}, + {10792, 0, 0, 0}, + {0, 10815, 0, 0}, + {65341, 0, 0, 0}, + {69, 0, 0, 0}, + {71, 0, 0, 0}, + {0, 10783, 0, 0}, + {0, 10780, 0, 0}, + {0, 10782, 0, 0}, + {0, 65326, 0, 0}, + {0, 65330, 0, 0}, + {0, 65331, 0, 0}, + {0, 65334, 0, 0}, + {0, 65333, 0, 0}, + {0, 42319, 0, 0}, + {0, 42315, 0, 0}, + {0, 65329, 0, 0}, + {0, 42280, 0, 0}, + {0, 42308, 0, 0}, + {0, 65327, 0, 0}, + {0, 65325, 0, 0}, + {0, 10743, 0, 0}, + {0, 42305, 0, 0}, + {0, 10749, 0, 0}, + {0, 65323, 0, 0}, + {0, 65322, 0, 0}, + {0, 10727, 0, 0}, + {0, 65318, 0, 0}, + {0, 42282, 0, 0}, + {0, 65467, 0, 0}, + {0, 65319, 0, 0}, + {0, 65465, 0, 0}, + {0, 65317, 0, 0}, + {0, 42261, 0, 0}, + {0, 42258, 0, 0}, + {116, 84, 7289, 0}, + {116, 0, 0, 0}, + {38, 0, 0, 0}, + {37, 0, 0, 0}, + {64, 0, 0, 0}, + {63, 0, 0, 0}, + {32, 62, 0, 0}, + {32, 96, 0, 0}, + {32, 57, 92, 0}, + {32, 65452, 7205, 0}, + {32, 86, 0, 0}, + {32, 64793, 0, 0}, + {32, 54, 0, 0}, + {32, 80, 0, 0}, + {32, 31, 0, 0}, + {32, 47, 0, 0}, + {32, 7549, 0, 0}, + {0, 65498, 0, 0}, + {0, 65499, 0, 0}, + {0, 65504, 30, 0}, + {0, 65504, 64, 0}, + {0, 65504, 25, 60}, + {0, 65420, 65504, 7173}, + {0, 65504, 54, 0}, + {0, 64761, 65504, 0}, + {0, 65504, 22, 0}, + {0, 65504, 48, 0}, + {1, 65505, 0, 0}, + {0, 65504, 65535, 0}, + {0, 65504, 15, 0}, + {0, 65504, 7517, 0}, + {0, 65472, 0, 0}, + {0, 65473, 0, 0}, + {8, 0, 0, 0}, + {65506, 65474, 0, 0}, + {65511, 65479, 35, 0}, + {65521, 65489, 0, 0}, + {65514, 65482, 0, 0}, + {0, 65528, 0, 0}, + {65482, 65450, 0, 0}, + {65488, 65456, 0, 0}, + {0, 7, 0, 0}, + {0, 65420, 0, 0}, + {65476, 65444, 65501, 0}, + {65472, 65440, 0, 0}, + {65529, 0, 0, 0}, + {80, 0, 0, 0}, + {0, 65456, 0, 0}, + {15, 0, 0, 0}, + {0, 65521, 0, 0}, + {48, 0, 0, 0}, + {0, 65488, 0, 0}, + {7264, 0, 0, 0}, + {0, 38864, 0, 0}, + {0, 8, 0, 0}, + {65528, 0, 0, 0}, + {0, 35332, 0, 0}, + {0, 3814, 0, 0}, + {1, 59, 0, 0}, + {0, 65535, 58, 0}, + {65478, 65477, 0, 0}, + {57921, 0, 0, 0}, + {0, 74, 0, 0}, + {0, 86, 0, 0}, + {0, 100, 0, 0}, + {0, 128, 0, 0}, + {0, 112, 0, 0}, + {0, 126, 0, 0}, + {0, 9, 0, 0}, + {65462, 0, 0, 0}, + {65527, 0, 0, 0}, + {58363, 58247, 58331, 0}, + {65450, 0, 0, 0}, + {65436, 0, 0, 0}, + {65424, 0, 0, 0}, + {65408, 0, 0, 0}, + {65410, 0, 0, 0}, + {58019, 57987, 0, 0}, + {57153, 57121, 0, 0}, + {57274, 57242, 0, 0}, + {28, 0, 0, 0}, + {0, 65508, 0, 0}, + {16, 0, 0, 0}, + {0, 65520, 0, 0}, + {26, 0, 0, 0}, + {0, 65510, 0, 0}, + {54793, 0, 0, 0}, + {61722, 0, 0, 0}, + {54809, 0, 0, 0}, + {0, 54741, 0, 0}, + {0, 54744, 0, 0}, + {54756, 0, 0, 0}, + {54787, 0, 0, 0}, + {54753, 0, 0, 0}, + {54754, 0, 0, 0}, + {54721, 0, 0, 0}, + {0, 58272, 0, 0}, + {30204, 0, 0, 0}, + {23256, 0, 0, 0}, + {23228, 0, 0, 0}, + {23217, 0, 0, 0}, + {23221, 0, 0, 0}, + {23231, 0, 0, 0}, + {23278, 0, 0, 0}, + {23254, 0, 0, 0}, + {23275, 0, 0, 0}, + {928, 0, 0, 0}, + {0, 64608, 0, 0}, + {26672, 0, 0, 0}, +}; + +const uint8_t unicode::folding_index1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 26, 27, 28, 26, 29, 30, + 31, 32, 0, 0, 0, 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 26, 40, + 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, + 43, 0, 44, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, +}; + +const uint8_t unicode::folding_index2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 8, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 9, 4, 4, 4, 4, 4, 10, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, + 4, 4, 4, 11, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, + 12, 13, 12, 13, 12, 13, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, + 13, 12, 13, 12, 13, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 14, 12, + 13, 12, 13, 12, 13, 15, 16, 17, 12, 13, 12, 13, 18, 12, 13, 19, 19, 12, + 13, 0, 20, 21, 22, 12, 13, 19, 23, 24, 25, 26, 12, 13, 27, 0, 25, 28, + 29, 30, 12, 13, 12, 13, 12, 13, 31, 12, 13, 31, 0, 0, 12, 13, 31, 12, + 13, 32, 32, 12, 13, 12, 13, 33, 12, 13, 0, 0, 12, 13, 0, 34, 0, 0, + 0, 0, 35, 36, 37, 35, 36, 37, 35, 36, 37, 12, 13, 12, 13, 12, 13, 12, + 13, 12, 13, 12, 13, 12, 13, 12, 13, 38, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 35, 36, 37, 12, 13, 39, 40, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 41, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 0, 0, 0, 0, 0, 0, 42, 12, 13, 43, 44, 45, + 45, 12, 13, 46, 47, 48, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 49, 50, + 51, 52, 53, 0, 54, 54, 0, 55, 0, 56, 57, 0, 0, 0, 54, 58, 0, 59, + 0, 60, 61, 0, 62, 63, 0, 64, 65, 0, 0, 63, 0, 66, 67, 0, 0, 68, + 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 70, 0, 0, 70, 0, 0, 0, 71, + 70, 72, 73, 73, 74, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 76, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 12, 13, + 0, 0, 12, 13, 0, 0, 0, 29, 29, 29, 0, 79, 0, 0, 0, 0, 0, 0, + 80, 0, 81, 81, 81, 0, 82, 0, 83, 83, 0, 1, 84, 1, 1, 85, 1, 1, + 86, 87, 88, 1, 89, 1, 1, 1, 90, 91, 0, 92, 1, 1, 93, 1, 1, 94, + 1, 1, 95, 96, 96, 96, 0, 4, 97, 4, 4, 98, 4, 4, 99, 100, 101, 4, + 102, 4, 4, 4, 103, 104, 105, 106, 4, 4, 107, 4, 4, 108, 4, 4, 109, 110, + 110, 111, 112, 113, 0, 0, 0, 114, 115, 116, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 117, 118, + 119, 120, 121, 122, 0, 12, 13, 123, 12, 13, 0, 41, 41, 41, 124, 124, 124, 124, + 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 126, 12, 13, 12, 13, 12, 13, 12, 13, 12, + 13, 12, 13, 12, 13, 127, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 0, 130, 0, 0, 0, 0, 0, 130, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 132, 132, 132, 132, 132, 132, 0, 0, 133, 133, 133, 133, 133, 133, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 134, 0, 0, 0, 135, 0, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 136, 137, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, 0, 0, + 0, 138, 0, 0, 139, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, + 132, 132, 132, 132, 132, 132, 0, 0, 133, 133, 133, 133, 133, 133, 0, 0, 132, 132, + 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 132, 132, 132, 132, + 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 132, 132, 132, 132, 132, 132, + 0, 0, 133, 133, 133, 133, 133, 133, 0, 0, 0, 132, 0, 132, 0, 132, 0, 132, + 0, 133, 0, 133, 0, 133, 0, 133, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, + 133, 133, 133, 133, 133, 133, 140, 140, 141, 141, 141, 141, 142, 142, 143, 143, 144, 144, + 145, 145, 0, 0, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, + 133, 133, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, + 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 132, 132, + 0, 146, 0, 0, 0, 0, 133, 133, 147, 147, 148, 0, 149, 0, 0, 0, 0, 146, + 0, 0, 0, 0, 150, 150, 150, 150, 148, 0, 0, 0, 132, 132, 0, 0, 0, 0, + 0, 0, 133, 133, 151, 151, 0, 0, 0, 0, 132, 132, 0, 0, 0, 119, 0, 0, + 133, 133, 152, 152, 123, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 153, 153, + 154, 154, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 156, 157, 0, 0, 0, 0, + 0, 0, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 0, 12, 13, 164, 165, 166, 167, 168, 12, 13, 12, + 13, 12, 13, 169, 170, 171, 172, 0, 12, 13, 0, 12, 13, 0, 0, 0, 0, 0, + 0, 0, 173, 173, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 0, 0, 0, 0, 0, 0, 0, 12, 13, 12, 13, 0, 0, 0, + 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 174, 174, 174, + 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, + 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 0, 174, + 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 0, 0, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 13, 12, 13, 175, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, + 0, 0, 0, 12, 13, 176, 0, 0, 12, 13, 12, 13, 0, 0, 12, 13, 12, 13, + 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 177, 178, + 179, 180, 0, 0, 181, 182, 183, 184, 12, 13, 12, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, + 186, 186, 186, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; + diff --git a/js/src/vm/Unicode.h b/js/src/vm/Unicode.h index ea853442c7..16ae398918 100644 --- a/js/src/vm/Unicode.h +++ b/js/src/vm/Unicode.h @@ -234,7 +234,102 @@ CanLowerCase(char16_t ch) return CharInfo(ch).lowerCase != 0; } +class FoldingInfo { + public: + uint16_t folding; + uint16_t reverse1; + uint16_t reverse2; + uint16_t reverse3; +}; + +extern const uint8_t folding_index1[]; +extern const uint8_t folding_index2[]; +extern const FoldingInfo js_foldinfo[]; + +inline const FoldingInfo& +CaseFoldInfo(char16_t code) +{ + const size_t shift = 6; + size_t index = folding_index1[code >> shift]; + index = folding_index2[(index << shift) + (code & ((1 << shift) - 1))]; + return js_foldinfo[index]; +} + +inline char16_t +FoldCase(char16_t ch) +{ + const FoldingInfo& info = CaseFoldInfo(ch); + return uint16_t(ch) + info.folding; +} + +inline char16_t +ReverseFoldCase1(char16_t ch) +{ + const FoldingInfo& info = CaseFoldInfo(ch); + return uint16_t(ch) + info.reverse1; +} + +inline char16_t +ReverseFoldCase2(char16_t ch) +{ + const FoldingInfo& info = CaseFoldInfo(ch); + return uint16_t(ch) + info.reverse2; +} + +inline char16_t +ReverseFoldCase3(char16_t ch) +{ + const FoldingInfo& info = CaseFoldInfo(ch); + return uint16_t(ch) + info.reverse3; +} + +const size_t LeadSurrogateMin = 0xD800; +const size_t LeadSurrogateMax = 0xDBFF; +const size_t TrailSurrogateMin = 0xDC00; +const size_t TrailSurrogateMax = 0xDFFF; +const size_t UTF16Max = 0xFFFF; +const size_t NonBMPMin = 0x10000; +const size_t NonBMPMax = 0x10FFFF; + +inline bool +IsLeadSurrogate(size_t value) +{ + return value >= LeadSurrogateMin && value <= LeadSurrogateMax; +} + +inline bool +IsTrailSurrogate(size_t value) +{ + return value >= TrailSurrogateMin && value <= TrailSurrogateMax; +} + +inline void +UTF16Encode(size_t cp, size_t* lead, size_t* trail) +{ + MOZ_ASSERT(cp >= NonBMPMin && cp <= NonBMPMax); + + *lead = (cp - NonBMPMin) / 1024 + LeadSurrogateMin; + *trail = ((cp - NonBMPMin) % 1024) + TrailSurrogateMin; +} + +inline size_t +UTF16Decode(size_t lead, size_t trail) +{ + MOZ_ASSERT(IsLeadSurrogate(lead)); + MOZ_ASSERT(IsTrailSurrogate(trail)); + + return (lead - LeadSurrogateMin) * 1024 + (trail - TrailSurrogateMin) + NonBMPMin; +} + } /* namespace unicode */ } /* namespace js */ +#define FOR_EACH_NON_BMP_CASE_FOLDING(macro) \ + macro(0x10400, 0x10427, 0xD801, 0xDC00, 0xDC27, 0x28) \ + macro(0x10428, 0x1044F, 0xD801, 0xDC28, 0xDC4F, -0x28) \ + macro(0x10C80, 0x10CB2, 0xD803, 0xDC80, 0xDCB2, 0x40) \ + macro(0x10CC0, 0x10CF2, 0xD803, 0xDCC0, 0xDCF2, -0x40) \ + macro(0x118A0, 0x118bf, 0xD806, 0xDCA0, 0xDCBF, 0x20) \ + macro(0x118C0, 0x118df, 0xD806, 0xDCC0, 0xDCDF, -0x20) + #endif /* vm_Unicode_h */ diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index c78919904b..eb70d76d31 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 318; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 324; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 423, +static_assert(JSErr_Limit == 433, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " diff --git a/js/src/vm/make_opcode_doc.py b/js/src/vm/make_opcode_doc.py index 8e3be00b3f..321c4527eb 100755 --- a/js/src/vm/make_opcode_doc.py +++ b/js/src/vm/make_opcode_doc.py @@ -333,8 +333,27 @@ def print_opcode(opcode): stack_defs=escape(opcode.stack_defs) or " ", desc=opcode.desc)) # desc is already escaped -def make_element_id(name): - return name.replace(' ', '-') +id_cache = dict() +id_count = dict() + +def make_element_id(category, type=''): + key = '{}:{}'.format(category, type) + if key in id_cache: + return id_cache[key] + + if type == '': + id = category.replace(' ', '_') + else: + id = type.replace(' ', '_') + + if id in id_count: + id_count[id] += 1 + id = '{}_{}'.format(id, id_count[id]) + else: + id_count[id] = 1 + + id_cache[key] = id + return id def print_doc(version, index): print("""
{{{{SpiderMonkeySidebar("Internals")}}}}
@@ -358,7 +377,7 @@ def print_doc(version, index): for (type_name, opcodes) in types: if type_name: print('

{name}

'.format(name=type_name, - id=make_element_id(type_name))) + id=make_element_id(category_name, type_name))) print('
') for opcode in sorted(opcodes, key=lambda opcode: opcode.sort_key): diff --git a/js/src/vm/make_unicode.py b/js/src/vm/make_unicode.py index 16e521da93..63d9f0654f 100644 --- a/js/src/vm/make_unicode.py +++ b/js/src/vm/make_unicode.py @@ -84,13 +84,33 @@ def read_unicode_data(unicode_file): row[0] = int(row[0], 16) yield row -def generate_unicode_stuff(unicode_data, data_file, test_mapping, test_space): +def read_case_folding(case_folding): + for line in case_folding: + if line == '\n' or line.startswith('#'): + continue + row = line.split('; ') + if row[1] in ['F', 'T']: + continue + row[0] = int(row[0], 16) + row[2] = int(row[2], 16) + yield row + +def generate_unicode_stuff(unicode_data, case_folding, + data_file, test_mapping, test_space, test_icase): dummy = (0, 0, 0) table = [dummy] cache = {dummy: 0} index = [0] * (MAX + 1) + folding_map = {} + rev_folding_map = {} + folding_dummy = (0, 0, 0, 0) + folding_table = [folding_dummy] + folding_cache = {folding_dummy: 0} + folding_index = [0] * (MAX + 1) test_table = {} test_space_table = [] + folding_tests = [] + folding_codes = set() for row in read_unicode_data(unicode_data): code = row[0] @@ -143,6 +163,64 @@ def generate_unicode_stuff(unicode_data, data_file, test_mapping, test_space): table.append(item) index[code] = i + for row in read_case_folding(case_folding): + code = row[0] + mapping = row[2] + folding_map[code] = mapping + + if mapping not in rev_folding_map: + rev_folding_map[mapping] = [code] + else: + rev_folding_map[mapping].append(code) + + folding_codes.add(code) + folding_codes.add(mapping) + + for code in sorted(folding_codes): + if code in folding_map: + folding = folding_map[code] + else: + folding = code + + if code in rev_folding_map: + rev_folding = rev_folding_map[code] + elif folding in rev_folding_map: + rev_folding = [c for c in rev_folding_map[folding] if c != code] + else: + rev_folding = [] + + assert len(rev_folding) <= 3 + + if folding != code or len(rev_folding): + item = [code] + if folding != code: + item.append(folding) + folding_tests.append(item + rev_folding) + + if code > MAX: + continue + + folding_d = folding - code + rev_folding_ds = [v - code for v in rev_folding] + + assert folding_d > -65535 and folding_d < 65535 + assert all([v > -65535 and v < 65535 for v in rev_folding]) + + folding = folding_d & 0xffff + rev_folding = [v & 0xffff for v in rev_folding_ds] + rev_folding_0 = rev_folding[0] if len(rev_folding) >= 1 else 0 + rev_folding_1 = rev_folding[1] if len(rev_folding) >= 2 else 0 + rev_folding_2 = rev_folding[2] if len(rev_folding) >= 3 else 0 + + item = (folding, rev_folding_0, rev_folding_1, rev_folding_2) + + i = folding_cache.get(item) + if i is None: + assert item not in folding_table + folding_cache[item] = i = len(folding_table) + folding_table.append(item) + folding_index[code] = i + test_mapping.write('/* Generated by make_unicode.py DO NOT MODIFY */\n') test_mapping.write(public_domain) test_mapping.write('var mapping = [\n') @@ -180,6 +258,29 @@ assertEq((onlySpace + 'aaaa').trim(), 'aaaa'); assertEq(('aaaa' + onlySpace).trim(), 'aaaa'); assertEq((onlySpace + 'aaaa' + onlySpace).trim(), 'aaaa'); +if (typeof reportCompare === "function") + reportCompare(true, true); +""") + + test_icase.write('/* Generated by make_unicode.py DO NOT MODIFY */\n') + test_icase.write(public_domain) + test_icase.write(""" +var BUGNUMBER = 1135377; +var summary = "Implement RegExp unicode flag -- ignoreCase flag."; + +print(BUGNUMBER + ": " + summary); + +function test(code, ...equivs) { + var codeRe = new RegExp(String.fromCodePoint(code) + "+", "iu"); + var ans = String.fromCodePoint(code) + equivs.map(c => String.fromCodePoint(c)).join(""); + assertEqArray(codeRe.exec("<" + ans + ">"), [ans]); + codeRe = new RegExp("[" + String.fromCodePoint(code) + "]+", "iu"); + assertEqArray(codeRe.exec("<" + ans + ">"), [ans]); +} +""") + for args in folding_tests: + test_icase.write('test(' + ','.join([hex(c) for c in args]) + ');\n') + test_icase.write(""" if (typeof reportCompare === "function") reportCompare(true, true); """) @@ -189,6 +290,11 @@ if (typeof reportCompare === "function") # Don't forget to update CharInfo in Unicode.cpp if you need to change this assert shift == 5 + folding_index1, folding_index2, folding_shift = splitbins(folding_index) + + # Don't forget to update CharInfo in Unicode.cpp if you need to change this + assert folding_shift == 6 + # verify correctness for char in index: test = table[index[char]] @@ -198,6 +304,14 @@ if (typeof reportCompare === "function") assert test == table[idx] + # verify correctness + for char in folding_index: + test = folding_table[folding_index[char]] + + idx = folding_index1[char >> folding_shift] + idx = folding_index2[(idx << folding_shift) + (char & ((1 << folding_shift) - 1))] + + assert test == folding_table[idx] comment = """ /* @@ -284,6 +398,19 @@ if (typeof reportCompare === "function") dump(index2, 'index2', data_file) data_file.write('\n') + data_file.write('const FoldingInfo unicode::js_foldinfo[] = {\n') + for d in folding_table: + data_file.write(' {') + data_file.write(', '.join((str(e) for e in d))) + data_file.write('},\n') + data_file.write('};\n') + data_file.write('\n') + + dump(folding_index1, 'folding_index1', data_file) + data_file.write('\n') + dump(folding_index2, 'folding_index2', data_file) + data_file.write('\n') + data_file.write('\n') def getsize(data): @@ -362,7 +489,7 @@ if __name__ == '__main__': print('Always make sure you have the newest UnicodeData.txt!') unicode_data = open(sys.argv[1], 'r') else: - print('Downloading...') + print('Downloading UnicodeData.txt...') reader = urllib2.urlopen('http://unicode.org/Public/UNIDATA/UnicodeData.txt') data = reader.read() reader.close() @@ -370,8 +497,21 @@ if __name__ == '__main__': unicode_data.write(data) unicode_data.seek(0) + if len(sys.argv) > 2: + print('Always make sure you have the newest CaseFolding.txt!') + case_folding = open(sys.argv[2], 'r') + else: + print('Downloading CaseFolding.txt...') + reader = urllib2.urlopen('http://unicode.org/Public/UNIDATA/CaseFolding.txt') + data = reader.read() + reader.close() + case_folding = open('CaseFolding.txt', 'w+') + case_folding.write(data) + case_folding.seek(0) + print('Generating...') - generate_unicode_stuff(unicode_data, + generate_unicode_stuff(unicode_data, case_folding, open('Unicode.cpp', 'w'), open('../tests/ecma_5/String/string-upper-lower-mapping.js', 'w'), - open('../tests/ecma_5/String/string-space-trim.js', 'w')) + open('../tests/ecma_5/String/string-space-trim.js', 'w'), + open('../tests/ecma_6/RegExp/unicode-ignoreCase.js', 'w')) diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 64dc2534e9..169ac1dd3e 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -198,7 +198,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 gPrototypeProperties['RegExp'] = ["constructor", "toSource", "toString", "compile", "exec", "test", - "flags", "global", "ignoreCase", "multiline", "source", "sticky", + "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode", "lastIndex"]; // Sort an array that may contain symbols as well as strings. @@ -612,7 +612,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 // Test with modified flags accessors iwin.eval(` -var props = ["global", "ignoreCase", "multiline", "sticky", "source"]; +var props = ["global", "ignoreCase", "multiline", "sticky", "source", "unicode"]; var origDescs = {}; for (var prop of props) { origDescs[prop] = Object.getOwnPropertyDescriptor(RegExp.prototype, prop); diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 138a888e5e..511e5bce0a 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -950,7 +950,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, void nsCSSRendering::PaintFocus(nsPresContext* aPresContext, - nsRenderingContext& aRenderingContext, + DrawTarget* aDrawTarget, const nsRect& aFocusRect, nscolor aColor) { @@ -975,8 +975,6 @@ nsCSSRendering::PaintFocus(nsPresContext* aPresContext, NS_STYLE_BORDER_STYLE_DOTTED }; nscolor focusColors[4] = { aColor, aColor, aColor, aColor }; - gfxContext *ctx = aRenderingContext.ThebesContext(); - // Because this renders a dotted border, the background color // should not be used. Therefore, we provide a value that will // be blatantly wrong if it ever does get used. (If this becomes @@ -984,7 +982,7 @@ nsCSSRendering::PaintFocus(nsPresContext* aPresContext, // to a style context and can use the same logic that PaintBorder // and PaintOutline do.) nsCSSBorderRenderer br(aPresContext->Type(), - ctx->GetDrawTarget(), + aDrawTarget, focusRect, focusStyles, focusWidths, @@ -3844,7 +3842,7 @@ static void SetPoly(const Rect& aRect, Point* poly) } static void -DrawDashedSegment(nsRenderingContext& aContext, +DrawDashedSegment(DrawTarget& aDrawTarget, nsRect aRect, nscoord aDashLength, nscolor aColor, @@ -3852,8 +3850,6 @@ DrawDashedSegment(nsRenderingContext& aContext, nscoord aTwipsPerPixel, bool aHorizontal) { - DrawTarget* drawTarget = aContext.GetDrawTarget(); - ColorPattern color(ToDeviceColor(aColor)); DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE); StrokeOptions strokeOptions; @@ -3870,20 +3866,20 @@ DrawDashedSegment(nsRenderingContext& aContext, nsPoint right = (aRect.TopRight() + aRect.BottomRight()) / 2; strokeOptions.mLineWidth = Float(aRect.height) / aAppUnitsPerDevPixel; StrokeLineWithSnapping(left, right, - aAppUnitsPerDevPixel, *drawTarget, + aAppUnitsPerDevPixel, aDrawTarget, color, strokeOptions, drawOptions); } else { nsPoint top = (aRect.TopLeft() + aRect.TopRight()) / 2; nsPoint bottom = (aRect.BottomLeft() + aRect.BottomRight()) / 2; strokeOptions.mLineWidth = Float(aRect.width) / aAppUnitsPerDevPixel; StrokeLineWithSnapping(top, bottom, - aAppUnitsPerDevPixel, *drawTarget, + aAppUnitsPerDevPixel, aDrawTarget, color, strokeOptions, drawOptions); } } static void -DrawSolidBorderSegment(nsRenderingContext& aContext, +DrawSolidBorderSegment(DrawTarget& aDrawTarget, nsRect aRect, nscolor aColor, int32_t aAppUnitsPerDevPixel, @@ -3893,8 +3889,6 @@ DrawSolidBorderSegment(nsRenderingContext& aContext, uint8_t aEndBevelSide = 0, nscoord aEndBevelOffset = 0) { - DrawTarget* drawTarget = aContext.GetDrawTarget(); - ColorPattern color(ToDeviceColor(aColor)); DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE); @@ -3902,14 +3896,14 @@ DrawSolidBorderSegment(nsRenderingContext& aContext, if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) || ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) { // simple rectangle - drawTarget->FillRect(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, - *drawTarget), + aDrawTarget.FillRect(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, + aDrawTarget), color, drawOptions); } else { // polygon with beveling Point poly[4]; - SetPoly(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, *drawTarget), + SetPoly(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, aDrawTarget), poly); Float startBevelOffset = @@ -3944,14 +3938,14 @@ DrawSolidBorderSegment(nsRenderingContext& aContext, poly[3].y -= endBevelOffset; } - RefPtr builder = drawTarget->CreatePathBuilder(); + RefPtr builder = aDrawTarget.CreatePathBuilder(); builder->MoveTo(poly[0]); builder->LineTo(poly[1]); builder->LineTo(poly[2]); builder->LineTo(poly[3]); builder->Close(); RefPtr path = builder->Finish(); - drawTarget->Fill(path, color, drawOptions); + aDrawTarget.Fill(path, color, drawOptions); } } @@ -4009,6 +4003,8 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, ctx->SetColor(Color::FromABGR(aBorderColor)); + DrawTarget& drawTarget = *aContext.GetDrawTarget(); + switch (aBorderStyle) { case NS_STYLE_BORDER_STYLE_NONE: case NS_STYLE_BORDER_STYLE_HIDDEN: @@ -4031,36 +4027,36 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength); nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height); - DrawSolidBorderSegment(aContext, rect, aBorderColor, + DrawSolidBorderSegment(drawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); rect.x += startDashLength + dashLength; rect.width = aBorder.width - (startDashLength + endDashLength + dashLength); - DrawDashedSegment(aContext, rect, dashLength, aBorderColor, + DrawDashedSegment(drawTarget, rect, dashLength, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, horizontal); rect.x += rect.width; rect.width = endDashLength; - DrawSolidBorderSegment(aContext, rect, aBorderColor, + DrawSolidBorderSegment(drawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); } else { GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength); nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength); - DrawSolidBorderSegment(aContext, rect, aBorderColor, + DrawSolidBorderSegment(drawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); rect.y += rect.height + dashLength; rect.height = aBorder.height - (startDashLength + endDashLength + dashLength); - DrawDashedSegment(aContext, rect, dashLength, aBorderColor, + DrawDashedSegment(drawTarget, rect, dashLength, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, horizontal); rect.y += rect.height; rect.height = endDashLength; - DrawSolidBorderSegment(aContext, rect, aBorderColor, + DrawSolidBorderSegment(drawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); } } @@ -4071,7 +4067,8 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if ((horizontal && (twipsPerPixel >= aBorder.height)) || (!horizontal && (twipsPerPixel >= aBorder.width))) { // a one pixel border - DrawSolidBorderSegment(aContext, aBorder, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, + DrawSolidBorderSegment(drawTarget, aBorder, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, aStartBevelOffset, aEndBevelSide, aEndBevelOffset); } @@ -4100,8 +4097,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_TOP == aEndBevelSide) { rect.width -= endBevel; } - DrawSolidBorderSegment(aContext, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, rect, bevelColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } else { // left, right half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel); @@ -4113,8 +4112,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_LEFT == aEndBevelSide) { rect.height -= endBevel; } - DrawSolidBorderSegment(aContext, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, rect, bevelColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } rect = aBorder; @@ -4135,8 +4136,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_BOTTOM == aEndBevelSide) { rect.width -= endBevel; } - DrawSolidBorderSegment(aContext, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, rect, bevelColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } else { rect.x = rect.x + half; @@ -4148,8 +4151,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_RIGHT == aEndBevelSide) { rect.height -= endBevel; } - DrawSolidBorderSegment(aContext, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, rect, bevelColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } } break; @@ -4175,8 +4180,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_TOP == aEndBevelSide) { topRect.width -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(aContext, topRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, topRect, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); // draw the botom line or rect nscoord heightOffset = aBorder.height - thirdHeight; @@ -4188,8 +4195,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_BOTTOM == aEndBevelSide) { bottomRect.width -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(aContext, bottomRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, bottomRect, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } else { // left, right nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel); @@ -4202,8 +4211,10 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_LEFT == aEndBevelSide) { leftRect.height -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(aContext, leftRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, leftRect, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); nscoord widthOffset = aBorder.width - thirdWidth; nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height); @@ -4214,14 +4225,17 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_RIGHT == aEndBevelSide) { rightRect.height -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(aContext, rightRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, - startBevel, aEndBevelSide, endBevel); + DrawSolidBorderSegment(drawTarget, rightRect, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, + aStartBevelSide, startBevel, aEndBevelSide, + endBevel); } break; } // else fall through to solid case NS_STYLE_BORDER_STYLE_SOLID: - DrawSolidBorderSegment(aContext, aBorder, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, + DrawSolidBorderSegment(drawTarget, aBorder, aBorderColor, + aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, aStartBevelOffset, aEndBevelSide, aEndBevelOffset); break; case NS_STYLE_BORDER_STYLE_OUTSET: diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index ee15620a31..7af936758e 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -437,7 +437,7 @@ struct nsCSSRendering { * Not used for controls, because the native theme may differ. */ static void PaintFocus(nsPresContext* aPresContext, - nsRenderingContext& aRenderingContext, + DrawTarget* aDrawTarget, const nsRect& aFocusRect, nscolor aColor); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 7c06aef31f..faf362b4de 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5406,7 +5406,7 @@ nsLayoutUtils::MinISizeFromInline(nsIFrame* aFrame, nsIFrame::InlineMinISizeData data; DISPLAY_MIN_WIDTH(aFrame, data.prevLines); aFrame->AddInlineMinISize(aRenderingContext, &data); - data.ForceBreak(aRenderingContext); + data.ForceBreak(); return data.prevLines; } @@ -5420,7 +5420,7 @@ nsLayoutUtils::PrefISizeFromInline(nsIFrame* aFrame, nsIFrame::InlinePrefISizeData data; DISPLAY_PREF_WIDTH(aFrame, data.prevLines); aFrame->AddInlinePrefISize(aRenderingContext, &data); - data.ForceBreak(aRenderingContext); + data.ForceBreak(); return data.prevLines; } diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index 4271338e2d..09bf6c5eed 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -1554,8 +1554,7 @@ nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, DisplaySelectionOverlay(aBuilder, aLists.Content()); } -void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget, - nsPoint aPt) +void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt) { /* Do we need to do anything? */ EventStates eventStates = mContent->AsElement()->State(); diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 57a4fdc500..b1928988ce 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -182,7 +182,7 @@ nsListControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, * @param aPt the offset of this frame, relative to the rendering reference * frame */ -void nsListControlFrame::PaintFocus(nsRenderingContext& aRC, nsPoint aPt) +void nsListControlFrame::PaintFocus(DrawTarget* aDrawTarget, nsPoint aPt) { if (mFocused != this) return; @@ -232,7 +232,7 @@ void nsListControlFrame::PaintFocus(nsRenderingContext& aRC, nsPoint aPt) LookAndFeel::eColorID_WidgetSelectForeground : LookAndFeel::eColorID_WidgetSelectBackground); - nsCSSRendering::PaintFocus(presContext, aRC, fRect, color); + nsCSSRendering::PaintFocus(presContext, aDrawTarget, fRect, color); } void diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h index c2afcb0c43..bfd6a8d915 100644 --- a/layout/forms/nsListControlFrame.h +++ b/layout/forms/nsListControlFrame.h @@ -193,7 +193,8 @@ public: * @param aPt the offset of this frame, relative to the rendering reference * frame */ - void PaintFocus(nsRenderingContext& aRC, nsPoint aPt); + void PaintFocus(mozilla::gfx::DrawTarget* aDrawTarget, nsPoint aPt); + /** * If this frame IsFocused(), invalidates an area that includes anything * that PaintFocus will or could have painted --- basically the whole diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index c1bd774c43..d9800b5086 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -118,7 +118,8 @@ public: nsRenderingContext* aCtx) override { nsListControlFrame* listFrame = GetEnclosingListFrame(Frame()); // listFrame must be non-null or we wouldn't get called. - listFrame->PaintFocus(*aCtx, aBuilder->ToReferenceFrame(listFrame)); + listFrame->PaintFocus(aCtx->GetDrawTarget(), + aBuilder->ToReferenceFrame(listFrame)); } NS_DISPLAY_DECL_NAME("ListFocus", TYPE_LIST_FOCUS) }; diff --git a/layout/generic/nsBRFrame.cpp b/layout/generic/nsBRFrame.cpp index 875de0fc6f..505e5ba531 100644 --- a/layout/generic/nsBRFrame.cpp +++ b/layout/generic/nsBRFrame.cpp @@ -170,7 +170,7 @@ BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext, nsIFrame::InlineMinISizeData *aData) { if (!GetParent()->StyleContext()->ShouldSuppressLineBreak()) { - aData->ForceBreak(aRenderingContext); + aData->ForceBreak(); } } @@ -179,7 +179,7 @@ BRFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefISizeData *aData) { if (!GetParent()->StyleContext()->ShouldSuppressLineBreak()) { - aData->ForceBreak(aRenderingContext); + aData->ForceBreak(); } } diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 3a3769e532..2c9d79da5f 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -720,10 +720,10 @@ nsBlockFrame::GetMinISize(nsRenderingContext *aRenderingContext) AutoNoisyIndenter lineindent(gNoisyIntrinsic); #endif if (line->IsBlock()) { - data.ForceBreak(aRenderingContext); + data.ForceBreak(); data.currentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, line->mFirstChild, nsLayoutUtils::MIN_ISIZE); - data.ForceBreak(aRenderingContext); + data.ForceBreak(); } else { if (!curFrame->GetPrevContinuation() && line == curFrame->begin_lines()) { @@ -753,7 +753,7 @@ nsBlockFrame::GetMinISize(nsRenderingContext *aRenderingContext) #endif } } - data.ForceBreak(aRenderingContext); + data.ForceBreak(); mMinWidth = data.prevLines; return mMinWidth; @@ -805,10 +805,10 @@ nsBlockFrame::GetPrefISize(nsRenderingContext *aRenderingContext) AutoNoisyIndenter lineindent(gNoisyIntrinsic); #endif if (line->IsBlock()) { - data.ForceBreak(aRenderingContext); + data.ForceBreak(); data.currentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, line->mFirstChild, nsLayoutUtils::PREF_ISIZE); - data.ForceBreak(aRenderingContext); + data.ForceBreak(); } else { if (!curFrame->GetPrevContinuation() && line == curFrame->begin_lines()) { @@ -838,7 +838,7 @@ nsBlockFrame::GetPrefISize(nsRenderingContext *aRenderingContext) #endif } } - data.ForceBreak(aRenderingContext); + data.ForceBreak(); mPrefWidth = data.prevLines; return mPrefWidth; @@ -876,7 +876,7 @@ nsBlockFrame::GetPrefWidthTightBounds(nsRenderingContext* aRenderingContext, { nscoord childX, childXMost; if (line->IsBlock()) { - data.ForceBreak(aRenderingContext); + data.ForceBreak(); rv = line->mFirstChild->GetPrefWidthTightBounds(aRenderingContext, &childX, &childXMost); NS_ENSURE_SUCCESS(rv, rv); @@ -910,7 +910,7 @@ nsBlockFrame::GetPrefWidthTightBounds(nsRenderingContext* aRenderingContext, } } } - data.ForceBreak(aRenderingContext); + data.ForceBreak(); return NS_OK; } diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 999ff5b5bb..0fce76ad44 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -455,7 +455,7 @@ public: nsRenderingContext* aCtx) override { nsCanvasFrame* frame = static_cast(mFrame); - frame->PaintFocus(*aCtx, ToReferenceFrame()); + frame->PaintFocus(aCtx->GetDrawTarget(), ToReferenceFrame()); } NS_DISPLAY_DECL_NAME("CanvasFocus", TYPE_CANVAS_FOCUS) @@ -558,7 +558,7 @@ nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } void -nsCanvasFrame::PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt) +nsCanvasFrame::PaintFocus(DrawTarget* aDrawTarget, nsPoint aPt) { nsRect focusRect(aPt, GetSize()); @@ -579,7 +579,7 @@ nsCanvasFrame::PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt) return; } - nsCSSRendering::PaintFocus(PresContext(), aRenderingContext, + nsCSSRendering::PaintFocus(PresContext(), aDrawTarget, focusRect, color->mColor); } diff --git a/layout/generic/nsCanvasFrame.h b/layout/generic/nsCanvasFrame.h index 5890ea0606..4381755a56 100644 --- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -126,7 +126,7 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - void PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt); + void PaintFocus(mozilla::gfx::DrawTarget* aRenderingContext, nsPoint aPt); // nsIScrollPositionListener virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index f93e2a320c..6ffd1c4dab 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4077,17 +4077,19 @@ nsFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext, bool canBreak = !CanContinueTextRun() && !parent->StyleContext()->ShouldSuppressLineBreak() && parent->StyleText()->WhiteSpaceCanWrap(parent); - - if (canBreak) - aData->OptionallyBreak(aRenderingContext); + + if (canBreak) { + aData->OptionallyBreak(); + } aData->trailingWhitespace = 0; aData->skipWhitespace = false; aData->trailingTextFrame = nullptr; aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, this, nsLayoutUtils::MIN_ISIZE); aData->atStartOfLine = false; - if (canBreak) - aData->OptionallyBreak(aRenderingContext); + if (canBreak) { + aData->OptionallyBreak(); + } } /* virtual */ void @@ -4102,7 +4104,7 @@ nsFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext, } void -nsIFrame::InlineMinISizeData::ForceBreak(nsRenderingContext *aRenderingContext) +nsIFrame::InlineMinISizeData::ForceBreak() { currentLine -= trailingWhitespace; prevLines = std::max(prevLines, currentLine); @@ -4119,8 +4121,7 @@ nsIFrame::InlineMinISizeData::ForceBreak(nsRenderingContext *aRenderingContext) } void -nsIFrame::InlineMinISizeData::OptionallyBreak(nsRenderingContext *aRenderingContext, - nscoord aHyphenWidth) +nsIFrame::InlineMinISizeData::OptionallyBreak(nscoord aHyphenWidth) { trailingTextFrame = nullptr; @@ -4132,11 +4133,11 @@ nsIFrame::InlineMinISizeData::OptionallyBreak(nsRenderingContext *aRenderingCont if (currentLine + aHyphenWidth < 0 || atStartOfLine) return; currentLine += aHyphenWidth; - ForceBreak(aRenderingContext); + ForceBreak(); } void -nsIFrame::InlinePrefISizeData::ForceBreak(nsRenderingContext *aRenderingContext) +nsIFrame::InlinePrefISizeData::ForceBreak() { if (floats.Length() != 0) { // preferred widths accumulated for floats that have already diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 9c6a4053ef..532820e564 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1645,12 +1645,11 @@ public: // current line total is negative. When it is, we need to ignore // optional breaks to prevent min-width from ending up bigger than // pref-width. - void ForceBreak(nsRenderingContext *aRenderingContext); + void ForceBreak(); // If the break here is actually taken, aHyphenWidth must be added to the // width of the current line. - void OptionallyBreak(nsRenderingContext *aRenderingContext, - nscoord aHyphenWidth = 0); + void OptionallyBreak(nscoord aHyphenWidth = 0); // The last text frame processed so far in the current line, when // the last characters in that text frame are relevant for line @@ -1664,7 +1663,7 @@ public: }; struct InlinePrefISizeData : public InlineIntrinsicISizeData { - void ForceBreak(nsRenderingContext *aRenderingContext); + void ForceBreak(); }; /** diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index c22b39cb10..d6de6d015f 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -2465,9 +2465,9 @@ nsImageFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext, parent->StyleText()->WhiteSpaceCanWrap(parent) && !IsInAutoWidthTableCellForQuirk(this); - if (canBreak) - aData->OptionallyBreak(aRenderingContext); - + if (canBreak) { + aData->OptionallyBreak(); + } aData->trailingWhitespace = 0; aData->skipWhitespace = false; aData->trailingTextFrame = nullptr; @@ -2475,7 +2475,7 @@ nsImageFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext, this, nsLayoutUtils::MIN_ISIZE); aData->atStartOfLine = false; - if (canBreak) - aData->OptionallyBreak(aRenderingContext); - + if (canBreak) { + aData->OptionallyBreak(); + } } diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index 1187eaae68..9eba5669ec 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -210,7 +210,7 @@ nsRubyBaseContainerFrame::AddInlineMinISize( gfxBreakPriority breakPriority = LineBreakBefore(baseFrame, aRenderingContext, nullptr, nullptr); if (breakPriority != gfxBreakPriority::eNoBreak) { - aData->OptionallyBreak(aRenderingContext); + aData->OptionallyBreak(); } } } diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index f0579d09fb..ec10f01130 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -7945,14 +7945,12 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, (i == textRun->GetLength() && (textRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK))) { if (preformattedNewline) { - aData->ForceBreak(aRenderingContext); + aData->ForceBreak(); } else if (i < flowEndInTextRun && hyphBreakBefore && - hyphBreakBefore[i - start]) - { - aData->OptionallyBreak(aRenderingContext, - NSToCoordRound(provider.GetHyphenWidth())); + hyphBreakBefore[i - start]) { + aData->OptionallyBreak(NSToCoordRound(provider.GetHyphenWidth())); } else { - aData->OptionallyBreak(aRenderingContext); + aData->OptionallyBreak(); } wordStart = i; } @@ -8095,7 +8093,7 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, aData->currentLine = nscoord(afterTab + spacing.mAfter); lineStart = i + 1; } else if (preformattedNewline) { - aData->ForceBreak(aRenderingContext); + aData->ForceBreak(); lineStart = i; } } diff --git a/toolkit/devtools/server/DominatorTree.cpp b/toolkit/devtools/server/DominatorTree.cpp index 1bc9e23ce0..9e4df041b9 100644 --- a/toolkit/devtools/server/DominatorTree.cpp +++ b/toolkit/devtools/server/DominatorTree.cpp @@ -4,25 +4,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/devtools/DominatorTree.h" -#include "js/Debug.h" -#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/dom/DominatorTreeBinding.h" namespace mozilla { namespace devtools { -static MallocSizeOf -getCurrentThreadDebuggerMallocSizeOf() -{ - auto ccrt = CycleCollectedJSRuntime::Get(); - MOZ_ASSERT(ccrt); - auto rt = ccrt->Runtime(); - MOZ_ASSERT(rt); - auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt); - MOZ_ASSERT(mallocSizeOf); - return mallocSizeOf; -} - dom::Nullable DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv) { @@ -31,7 +17,7 @@ DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv) if (node.isNothing()) return dom::Nullable(); - auto mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf(); + auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); JS::ubi::Node::Size size = 0; if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); @@ -83,7 +69,7 @@ DominatorTree::GetImmediatelyDominated(uint64_t aNodeId, return; // Get all immediately dominated nodes and their retained sizes. - MallocSizeOf mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf(); + MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); Maybe range = mDominatorTree.getDominatedSet(*node); MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot."); size_t length = range->length(); diff --git a/toolkit/devtools/server/HeapSnapshot.cpp b/toolkit/devtools/server/HeapSnapshot.cpp index a3f4197951..b7167dcfe0 100644 --- a/toolkit/devtools/server/HeapSnapshot.cpp +++ b/toolkit/devtools/server/HeapSnapshot.cpp @@ -55,22 +55,21 @@ using ::google::protobuf::io::ZeroCopyInputStream; using JS::ubi::AtomOrTwoByteChars; +MallocSizeOf +GetCurrentThreadDebuggerMallocSizeOf() +{ + auto ccrt = CycleCollectedJSRuntime::Get(); + MOZ_ASSERT(ccrt); + auto rt = ccrt->Runtime(); + MOZ_ASSERT(rt); + auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt); + MOZ_ASSERT(mallocSizeOf); + return mallocSizeOf; +} + /*** Cycle Collection Boilerplate *****************************************************************/ -NS_IMPL_CYCLE_COLLECTION_CLASS(HeapSnapshot) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HeapSnapshot) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HeapSnapshot) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HeapSnapshot) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER -NS_IMPL_CYCLE_COLLECTION_TRACE_END +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HeapSnapshot, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(HeapSnapshot) NS_IMPL_CYCLE_COLLECTING_RELEASE(HeapSnapshot) @@ -495,7 +494,7 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, return; } - JS::ubi::CensusHandler handler(census, rootCount); + JS::ubi::CensusHandler handler(census, rootCount, GetCurrentThreadDebuggerMallocSizeOf()); { JS::AutoCheckCannotGC nogc; @@ -517,12 +516,49 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, } } - if (NS_WARN_IF(!handler.report(rval))) { + if (NS_WARN_IF(!handler.report(cx, rval))) { rv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } } +void +HeapSnapshot::DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId, + JS::MutableHandleValue rval, ErrorResult& rv) { + MOZ_ASSERT(breakdown); + JS::RootedValue breakdownVal(cx, JS::ObjectValue(*breakdown)); + JS::ubi::CountTypePtr rootType = JS::ubi::ParseBreakdown(cx, breakdownVal); + if (NS_WARN_IF(!rootType)) { + rv.Throw(NS_ERROR_UNEXPECTED); + return; + } + + JS::ubi::RootedCount rootCount(cx, rootType->makeCount()); + if (NS_WARN_IF(!rootCount)) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + JS::ubi::Node::Id id(nodeId); + Maybe node = getNodeById(id); + if (NS_WARN_IF(node.isNothing())) { + rv.Throw(NS_ERROR_INVALID_ARG); + return; + } + + MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); + if (NS_WARN_IF(!rootCount->count(mallocSizeOf, *node))) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + if (NS_WARN_IF(!rootCount->report(cx, rval))) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } +} + + already_AddRefed HeapSnapshot::ComputeDominatorTree(ErrorResult& rv) { diff --git a/toolkit/devtools/server/HeapSnapshot.h b/toolkit/devtools/server/HeapSnapshot.h index c869c74ae5..efc80c25cc 100644 --- a/toolkit/devtools/server/HeapSnapshot.h +++ b/toolkit/devtools/server/HeapSnapshot.h @@ -159,6 +159,9 @@ public: void TakeCensus(JSContext* cx, JS::HandleObject options, JS::MutableHandleValue rval, ErrorResult& rv); + void DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId, + JS::MutableHandleValue rval, ErrorResult& rv); + already_AddRefed ComputeDominatorTree(ErrorResult& rv); dom::Nullable GetCreationTime() { @@ -221,6 +224,9 @@ WriteHeapGraph(JSContext* cx, ignoreNodeCount, ignoreEdgeCount); } +// Get the mozilla::MallocSizeOf for the current thread's JSRuntime. +MallocSizeOf GetCurrentThreadDebuggerMallocSizeOf(); + } // namespace devtools } // namespace mozilla diff --git a/toolkit/devtools/server/tests/unit/test_HeapSnapshot_describeNode_01.js b/toolkit/devtools/server/tests/unit/test_HeapSnapshot_describeNode_01.js new file mode 100644 index 0000000000..d79cb5a7b4 --- /dev/null +++ b/toolkit/devtools/server/tests/unit/test_HeapSnapshot_describeNode_01.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that we can describe nodes with a breakdown. + +function run_test() { + const path = saveNewHeapSnapshot(); + const snapshot = ChromeUtils.readHeapSnapshot(path); + ok(snapshot.describeNode); + equal(typeof snapshot.describeNode, "function"); + + const dt = snapshot.computeDominatorTree(); + + let threw = false; + try { + snapshot.describeNode(undefined, dt.root); + } catch (_) { + threw = true; + } + ok(threw, "Should require a breakdown"); + + const breakdown = { + by: "coarseType", + objects: { by: "objectClass" }, + scripts: { by: "internalType" }, + strings: { by: "internalType" }, + other: { by: "internalType" } + }; + + threw = false; + try { + snapshot.describeNode(breakdown, 0); + } catch (_) { + threw = true; + } + ok(threw, "Should throw when given an invalid node id"); + + const description = snapshot.describeNode(breakdown, dt.root); + ok(description); + ok(description.other); + ok(description.other["JS::ubi::RootList"]); +} diff --git a/toolkit/devtools/server/tests/unit/xpcshell.ini b/toolkit/devtools/server/tests/unit/xpcshell.ini index 727656e3eb..50c7a60403 100644 --- a/toolkit/devtools/server/tests/unit/xpcshell.ini +++ b/toolkit/devtools/server/tests/unit/xpcshell.ini @@ -44,6 +44,7 @@ support-files = [test_getyoungestframe.js] [test_nsjsinspector.js] [test_SaveHeapSnapshot.js] +[test_HeapSnapshot_describeNode_01.js] [test_HeapSnapshot_takeCensus_01.js] [test_HeapSnapshot_takeCensus_02.js] [test_HeapSnapshot_takeCensus_03.js] diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 7ade73e997..ffc4b40868 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -71,6 +71,7 @@ #include "nsArrayEnumerator.h" #include "nsStringEnumerator.h" #include "mozilla/FileUtils.h" +#include "mozilla/UniquePtr.h" #include "nsDataHashtable.h" #include // for placement new @@ -393,6 +394,7 @@ nsComponentManagerImpl::Init() #if defined(MOZILLA_XPCOMRT_API) RegisterModule(&kXPCOMRTModule, nullptr); RegisterModule(&kNeckoStandaloneModule, nullptr); + RegisterModule(&kStunUDPSocketFilterHandlerModule, nullptr); #else RegisterModule(&kXPCOMModule, nullptr); #endif // defined(MOZILLA_XPCOMRT_API) @@ -619,18 +621,22 @@ DoRegisterManifest(NSLocationType aType, MOZ_ASSERT(!aXPTOnly || !nsComponentManagerImpl::gComponentManager); uint32_t len; FileLocation::Data data; - nsAutoArrayPtr buf; + UniquePtr buf; nsresult rv = aFile.GetData(data); if (NS_SUCCEEDED(rv)) { rv = data.GetSize(&len); } if (NS_SUCCEEDED(rv)) { - buf = new char[len + 1]; - rv = data.Copy(buf, len); + buf = MakeUnique(len + 1); + rv = data.Copy(buf.get(), len); } if (NS_SUCCEEDED(rv)) { buf[len] = '\0'; - ParseManifest(aType, aFile, buf, aChromeOnly, aXPTOnly); + ParseManifest(aType, aFile, buf.get(), aChromeOnly, aXPTOnly); + } else if (NS_BOOTSTRAPPED_LOCATION != aType) { + nsCString uri; + aFile.GetURIString(uri); + LogMessage("Could not read chrome manifest '%s'.", uri.get()); } } @@ -694,17 +700,17 @@ DoRegisterXPT(FileLocation& aFile) uint32_t len; FileLocation::Data data; - nsAutoArrayPtr buf; + UniquePtr buf; nsresult rv = aFile.GetData(data); if (NS_SUCCEEDED(rv)) { rv = data.GetSize(&len); } if (NS_SUCCEEDED(rv)) { - buf = new char[len]; - rv = data.Copy(buf, len); + buf = MakeUnique(len); + rv = data.Copy(buf.get(), len); } if (NS_SUCCEEDED(rv)) { - XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len); + XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf.get(), len); #ifdef MOZ_B2G_LOADER MarkRegisteredXPTIInfo(aFile); #endif @@ -1743,7 +1749,12 @@ nsComponentManagerImpl::IsContractIDRegistered(const char* aClass, nsFactoryEntry* entry = GetFactoryEntry(aClass, strlen(aClass)); if (entry) { - *aResult = true; + // UnregisterFactory might have left a stale nsFactoryEntry in + // mContractIDs, so we should check to see whether this entry has + // anything useful. + *aResult = (bool(entry->mModule) || + bool(entry->mFactory) || + bool(entry->mServiceObject)); } else { *aResult = false; } diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h index 259da7e3dd..2698ef0356 100644 --- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -72,6 +72,7 @@ extern const char staticComponentType[]; #if defined(MOZILLA_XPCOMRT_API) extern const mozilla::Module kXPCOMRTModule; extern const mozilla::Module kNeckoStandaloneModule; +extern const mozilla::Module kStunUDPSocketFilterHandlerModule; #else extern const mozilla::Module kXPCOMModule; #endif diff --git a/xpcom/glue/FileUtils.cpp b/xpcom/glue/FileUtils.cpp index 6e86af7685..ad52446299 100644 --- a/xpcom/glue/FileUtils.cpp +++ b/xpcom/glue/FileUtils.cpp @@ -394,7 +394,11 @@ mozilla::ReadAheadLib(mozilla::pathstr_t aFilePath) if ((read(fd, elf.buf, bufsize) <= 0) || (memcmp(elf.buf, ELFMAG, 4)) || (elf.ehdr.e_ident[EI_CLASS] != ELFCLASS) || - (elf.ehdr.e_phoff + elf.ehdr.e_phentsize * elf.ehdr.e_phnum >= bufsize)) { + // Upcast e_phentsize so the multiplication is done in the same precision + // as the subsequent addition, to satisfy static analyzers and avoid + // issues with abnormally large program header tables. + (elf.ehdr.e_phoff + (static_cast(elf.ehdr.e_phentsize) * + elf.ehdr.e_phnum) >= bufsize)) { close(fd); return; } diff --git a/xpcom/glue/nsINIParser.cpp b/xpcom/glue/nsINIParser.cpp index 56197ed9f6..53eae72929 100644 --- a/xpcom/glue/nsINIParser.cpp +++ b/xpcom/glue/nsINIParser.cpp @@ -24,6 +24,8 @@ #define READ_BINARYMODE "r" #endif +using namespace mozilla; + #ifdef XP_WIN inline FILE* TS_tfopen(const char* aPath, const wchar_t* aMode) @@ -117,12 +119,13 @@ nsINIParser::InitFromFILE(FILE* aFd) } long flen = ftell(aFd); - if (flen == 0) { + /* zero-sized file, or an error */ + if (flen <= 0) { return NS_ERROR_FAILURE; } /* malloc an internal buf the size of the file */ - mFileContents = new char[flen + 2]; + mFileContents = MakeUnique(flen + 2); if (!mFileContents) { return NS_ERROR_OUT_OF_MEMORY; } @@ -132,7 +135,7 @@ nsINIParser::InitFromFILE(FILE* aFd) return NS_BASE_STREAM_OSERROR; } - int rd = fread(mFileContents, sizeof(char), flen, aFd); + int rd = fread(mFileContents.get(), sizeof(char), flen, aFd); if (rd != flen) { return NS_BASE_STREAM_OSERROR; } @@ -171,13 +174,13 @@ nsINIParser::InitFromFILE(FILE* aFd) return NS_ERROR_FAILURE; } - nsAutoArrayPtr utf8Buffer(new char[flen]); + UniquePtr utf8Buffer(new char[flen]); if (WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(buffer), -1, - utf8Buffer, flen, nullptr, nullptr) == 0) { + utf8Buffer.get(), flen, nullptr, nullptr) == 0) { return NS_ERROR_FAILURE; } - mFileContents = utf8Buffer.forget(); - buffer = mFileContents; + mFileContents = Move(utf8Buffer); + buffer = mFileContents.get(); } #endif @@ -241,13 +244,13 @@ nsINIParser::InitFromFILE(FILE* aFd) break; } if (!v->next) { - v->next = new INIValue(key, token); + v->next = MakeUnique(key, token); if (!v->next) { return NS_ERROR_OUT_OF_MEMORY; } break; } - v = v->next; + v = v->next.get(); } NS_ASSERTION(v, "v should never be null coming out of this loop"); } @@ -268,7 +271,7 @@ nsINIParser::GetString(const char* aSection, const char* aKey, return NS_OK; } - val = val->next; + val = val->next.get(); } return NS_ERROR_FAILURE; @@ -292,7 +295,7 @@ nsINIParser::GetString(const char* aSection, const char* aKey, return NS_OK; } - val = val->next; + val = val->next.get(); } return NS_ERROR_FAILURE; @@ -317,7 +320,7 @@ nsINIParser::GetStrings(const char* aSection, for (mSections.Get(aSection, &val); val; - val = val->next) { + val = val->next.get()) { if (!aCB(val->key, val->value, aClosure)) { return NS_OK; diff --git a/xpcom/glue/nsINIParser.h b/xpcom/glue/nsINIParser.h index 65fbf8576c..d0f553d49d 100644 --- a/xpcom/glue/nsINIParser.h +++ b/xpcom/glue/nsINIParser.h @@ -15,7 +15,7 @@ #include "nscore.h" #include "nsClassHashtable.h" -#include "nsAutoPtr.h" +#include "mozilla/UniquePtr.h" #include @@ -106,11 +106,11 @@ private: const char* key; const char* value; - nsAutoPtr next; + mozilla::UniquePtr next; }; nsClassHashtable mSections; - nsAutoArrayPtr mFileContents; + mozilla::UniquePtr mFileContents; nsresult InitFromFILE(FILE* aFd); }; diff --git a/xpcom/idl-parser/xpidl/header.py b/xpcom/idl-parser/xpidl/header.py index 15eba9dd7e..467a60f5ef 100644 --- a/xpcom/idl-parser/xpidl/header.py +++ b/xpcom/idl-parser/xpidl/header.py @@ -111,6 +111,19 @@ def paramlistAsNative(m, empty='void'): location=None, realtype=m.realtype))) + # Set any optional out params to default to nullptr. Skip if we just added + # extra non-optional args to l. + if len(l) == len(m.params): + paramIter = len(m.params) - 1 + while (paramIter >= 0 and m.params[paramIter].optional and + m.params[paramIter].paramtype == "out"): + t = m.params[paramIter].type + # Strings can't be optional, so this shouldn't happen, but let's make sure: + if t == "AString" or t == "ACString" or t == "DOMString" or t == "AUTF8String": + break + l[paramIter] += " = nullptr" + paramIter -= 1 + if len(l) == 0: return empty diff --git a/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp index c72ff0de9b..ed96295e8d 100644 --- a/xpcom/io/nsMultiplexInputStream.cpp +++ b/xpcom/io/nsMultiplexInputStream.cpp @@ -141,25 +141,10 @@ nsMultiplexInputStream::GetCount(uint32_t* aCount) return NS_OK; } -#ifdef DEBUG -static bool -SeekableStreamAtBeginning(nsIInputStream* aStream) -{ - int64_t streamPos; - nsCOMPtr stream = do_QueryInterface(aStream); - if (stream && NS_SUCCEEDED(stream->Tell(&streamPos)) && streamPos != 0) { - return false; - } - return true; -} -#endif - NS_IMETHODIMP nsMultiplexInputStream::AppendStream(nsIInputStream* aStream) { MutexAutoLock lock(mLock); - NS_ASSERTION(SeekableStreamAtBeginning(aStream), - "Appended stream not at beginning."); return mStreams.AppendElement(aStream) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } @@ -167,8 +152,6 @@ NS_IMETHODIMP nsMultiplexInputStream::InsertStream(nsIInputStream* aStream, uint32_t aIndex) { MutexAutoLock lock(mLock); - NS_ASSERTION(SeekableStreamAtBeginning(aStream), - "Inserted stream not at beginning."); mStreams.InsertElementAt(aIndex, aStream); if (mCurrentStream > aIndex || (mCurrentStream == aIndex && mStartedReadingCurrent)) { @@ -231,15 +214,14 @@ nsMultiplexInputStream::Available(uint64_t* aResult) return mStatus; } - nsresult rv; uint64_t avail = 0; uint32_t len = mStreams.Length(); for (uint32_t i = mCurrentStream; i < len; i++) { uint64_t streamAvail; - rv = AvailableMaybeSeek(mStreams[i], &streamAvail); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + mStatus = AvailableMaybeSeek(mStreams[i], &streamAvail); + if (NS_WARN_IF(NS_FAILED(mStatus))) { + return mStatus; } avail += streamAvail; } diff --git a/xpcom/reflect/xptcall/moz.build b/xpcom/reflect/xptcall/moz.build index 9788c9b81c..3e8d0ed430 100644 --- a/xpcom/reflect/xptcall/moz.build +++ b/xpcom/reflect/xptcall/moz.build @@ -21,3 +21,6 @@ LOCAL_INCLUDES += [ ] FINAL_LIBRARY = 'xul' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wshadow'] diff --git a/xpcom/reflect/xptinfo/moz.build b/xpcom/reflect/xptinfo/moz.build index 8391818219..594fa18dc5 100644 --- a/xpcom/reflect/xptinfo/moz.build +++ b/xpcom/reflect/xptinfo/moz.build @@ -32,3 +32,6 @@ LOCAL_INCLUDES += [ ] FINAL_LIBRARY = 'xul' + +if CONFIG['CLANG_CXX']: + CXXFLAGS += ['-Wshadow'] diff --git a/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl b/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl index 38e44be0fc..cc74a06176 100644 --- a/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl +++ b/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl @@ -24,7 +24,7 @@ class nsXPTType; %} /* this is NOT intended to be scriptable */ -[uuid(4e698ffe-e9b5-42f3-9129-78a6c5fe0e9e)] +[uuid(3820e663-8e22-4789-b470-56bcf7083f2b)] interface nsIInterfaceInfo : nsISupports { readonly attribute string name; @@ -32,7 +32,6 @@ interface nsIInterfaceInfo : nsISupports boolean isScriptable(); boolean isBuiltinClass(); - boolean isMainProcessScriptableOnly(); readonly attribute nsIInterfaceInfo parent; @@ -98,5 +97,7 @@ interface nsIInterfaceInfo : nsISupports [notxpcom] nsresult getIIDForParamNoAlloc(in uint16_t methodIndex, [const] in nsXPTParamInfoPtr param, out nsIID iid); + + boolean isMainProcessScriptableOnly(); }; diff --git a/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp b/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp index dda87b21f8..2661912ad1 100644 --- a/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp +++ b/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp @@ -10,6 +10,13 @@ using namespace mozilla; +// Ensure through static analysis that xptiTypelibGuts won't have a vtable. +template +class MOZ_NEEDS_NO_VTABLE_TYPE CheckNoVTable +{ +}; +CheckNoVTable gChecker; + // static xptiTypelibGuts* xptiTypelibGuts::Create(XPTHeader* aHeader) diff --git a/xpcom/tests/gtest/TestExpirationTracker.cpp b/xpcom/tests/gtest/TestExpirationTracker.cpp index 67385d1cf2..a6a0e146cf 100644 --- a/xpcom/tests/gtest/TestExpirationTracker.cpp +++ b/xpcom/tests/gtest/TestExpirationTracker.cpp @@ -18,6 +18,7 @@ #include "nsIFile.h" #include "prinrval.h" #include "nsThreadUtils.h" +#include "mozilla/UniquePtr.h" #include "gtest/gtest.h" namespace TestExpirationTracker { @@ -49,7 +50,7 @@ public: LogAction(obj, "Created"); } - nsTArray > mUniverse; + nsTArray> mUniverse; void LogAction(Object* aObj, const char* aAction) { if (logging) { @@ -79,28 +80,28 @@ public: break; } case 1: { - obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; - if (obj->mExpiration.IsTracked()) { - nsExpirationTracker::RemoveObject(obj); - LogAction(obj, "Removed"); + UniquePtr& objref = mUniverse[uint32_t(rand())%mUniverse.Length()]; + if (objref->mExpiration.IsTracked()) { + nsExpirationTracker::RemoveObject(objref.get()); + LogAction(objref.get(), "Removed"); } break; } case 2: { - obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; - if (!obj->mExpiration.IsTracked()) { - obj->Touch(); - nsExpirationTracker::AddObject(obj); - LogAction(obj, "Added"); + UniquePtr& objref = mUniverse[uint32_t(rand())%mUniverse.Length()]; + if (!objref->mExpiration.IsTracked()) { + objref->Touch(); + nsExpirationTracker::AddObject(objref.get()); + LogAction(objref.get(), "Added"); } break; } case 3: { - obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; - if (obj->mExpiration.IsTracked()) { - obj->Touch(); - nsExpirationTracker::MarkUsed(obj); - LogAction(obj, "Marked used"); + UniquePtr& objref = mUniverse[uint32_t(rand())%mUniverse.Length()]; + if (objref->mExpiration.IsTracked()) { + objref->Touch(); + nsExpirationTracker::MarkUsed(objref.get()); + LogAction(objref.get(), "Marked used"); } break; } diff --git a/xulrunner/stub/nsXULStub.cpp b/xulrunner/stub/nsXULStub.cpp index 7042c922b4..8638ae43e1 100644 --- a/xulrunner/stub/nsXULStub.cpp +++ b/xulrunner/stub/nsXULStub.cpp @@ -335,48 +335,30 @@ main(int argc, char **argv) if (!greFound) { #ifdef XP_MACOSX - // Check for /Contents/Frameworks/XUL.framework/Versions/Current/libmozglue.dylib - CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle); - CFURLRef absfwurl = nullptr; - if (fwurl) { - absfwurl = CFURLCopyAbsoluteURL(fwurl); - CFRelease(fwurl); + // The bundle can be found next to the executable, in the MacOS dir. + CFURLRef exurl = CFBundleCopyExecutableURL(appBundle); + CFURLRef absexurl = nullptr; + if (exurl) { + absexurl = CFURLCopyAbsoluteURL(exurl); + CFRelease(exurl); } - if (absfwurl) { - CFURLRef xulurl = - CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl, - CFSTR("XUL.framework/Versions/Current"), - true); + if (absexurl) { + char tbuffer[MAXPATHLEN]; - if (xulurl) { - CFURLRef xpcomurl = - CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, - CFSTR("libmozglue.dylib"), - false); - - if (xpcomurl) { - char tbuffer[MAXPATHLEN]; - - if (CFURLGetFileSystemRepresentation(xpcomurl, true, - (UInt8*) tbuffer, - sizeof(tbuffer)) && - access(tbuffer, R_OK | X_OK) == 0) { - if (realpath(tbuffer, greDir)) { - greFound = true; - } - else { - greDir[0] = '\0'; - } - } - - CFRelease(xpcomurl); + if (CFURLGetFileSystemRepresentation(absexurl, true, + (UInt8*) tbuffer, + sizeof(tbuffer)) && + access(tbuffer, R_OK | X_OK) == 0) { + if (realpath(tbuffer, greDir)) { + greFound = true; + } + else { + greDir[0] = '\0'; } - - CFRelease(xulurl); } - CFRelease(absfwurl); + CFRelease(absexurl); } #endif if (!greFound) {