summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/vm
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/ArgumentsObject-inl.h67
-rw-r--r--js/src/vm/ArgumentsObject.cpp848
-rw-r--r--js/src/vm/ArgumentsObject.h436
-rw-r--r--js/src/vm/ArrayBufferObject-inl.h64
-rw-r--r--js/src/vm/ArrayBufferObject.cpp1950
-rw-r--r--js/src/vm/ArrayBufferObject.h641
-rw-r--r--js/src/vm/ArrayObject-inl.h121
-rw-r--r--js/src/vm/ArrayObject.h77
-rw-r--r--js/src/vm/AsyncFunction.cpp240
-rw-r--r--js/src/vm/AsyncFunction.h40
-rw-r--r--js/src/vm/BooleanObject-inl.h28
-rw-r--r--js/src/vm/BooleanObject.h49
-rw-r--r--js/src/vm/Caches-inl.h82
-rw-r--r--js/src/vm/Caches.cpp52
-rw-r--r--js/src/vm/Caches.h306
-rw-r--r--js/src/vm/CallNonGenericMethod.cpp37
-rw-r--r--js/src/vm/CaseFolding.txt1495
-rw-r--r--js/src/vm/CharacterEncoding.cpp531
-rw-r--r--js/src/vm/CodeCoverage.cpp636
-rw-r--r--js/src/vm/CodeCoverage.h177
-rw-r--r--js/src/vm/CommonPropertyNames.h357
-rw-r--r--js/src/vm/Compression.cpp265
-rw-r--r--js/src/vm/Compression.h104
-rw-r--r--js/src/vm/DateObject.h95
-rw-r--r--js/src/vm/DateTime.cpp354
-rw-r--r--js/src/vm/DateTime.h215
-rw-r--r--js/src/vm/Debugger-inl.h118
-rw-r--r--js/src/vm/Debugger.cpp11183
-rw-r--r--js/src/vm/Debugger.h1584
-rw-r--r--js/src/vm/DebuggerMemory.cpp460
-rw-r--r--js/src/vm/DebuggerMemory.h59
-rw-r--r--js/src/vm/DerivedCoreProperties.txt11309
-rw-r--r--js/src/vm/EnvironmentObject-inl.h86
-rw-r--r--js/src/vm/EnvironmentObject.cpp3594
-rw-r--r--js/src/vm/EnvironmentObject.h1126
-rw-r--r--js/src/vm/ErrorObject-inl.h41
-rw-r--r--js/src/vm/ErrorObject.cpp274
-rw-r--r--js/src/vm/ErrorObject.h123
-rw-r--r--js/src/vm/ForOfIterator.cpp172
-rw-r--r--js/src/vm/GeneratorObject.cpp367
-rw-r--r--js/src/vm/GeneratorObject.h231
-rw-r--r--js/src/vm/GlobalObject.cpp874
-rw-r--r--js/src/vm/GlobalObject.h1024
-rw-r--r--js/src/vm/HelperThreads.cpp1896
-rw-r--r--js/src/vm/HelperThreads.h655
-rw-r--r--js/src/vm/Id.cpp17
-rw-r--r--js/src/vm/Initialization.cpp198
-rw-r--r--js/src/vm/Interpreter-inl.h880
-rw-r--r--js/src/vm/Interpreter.cpp5087
-rw-r--r--js/src/vm/Interpreter.h582
-rw-r--r--js/src/vm/JSONParser.cpp801
-rw-r--r--js/src/vm/JSONParser.h268
-rw-r--r--js/src/vm/Keywords.h66
-rw-r--r--js/src/vm/MallocProvider.h199
-rw-r--r--js/src/vm/MatchPairs.h153
-rw-r--r--js/src/vm/MemoryMetrics.cpp959
-rw-r--r--js/src/vm/Monitor.h102
-rw-r--r--js/src/vm/MutexIDs.h55
-rw-r--r--js/src/vm/NativeObject-inl.h612
-rw-r--r--js/src/vm/NativeObject.cpp2564
-rw-r--r--js/src/vm/NativeObject.h1552
-rw-r--r--js/src/vm/NumberObject-inl.h28
-rw-r--r--js/src/vm/NumberObject.h47
-rw-r--r--js/src/vm/ObjectGroup-inl.h127
-rw-r--r--js/src/vm/ObjectGroup.cpp1862
-rw-r--r--js/src/vm/ObjectGroup.h655
-rw-r--r--js/src/vm/Opcodes.h2314
-rw-r--r--js/src/vm/PIC.cpp330
-rw-r--r--js/src/vm/PIC.h276
-rw-r--r--js/src/vm/PosixNSPR.cpp59
-rw-r--r--js/src/vm/PosixNSPR.h70
-rw-r--r--js/src/vm/Printer.cpp618
-rw-r--r--js/src/vm/Printer.h233
-rw-r--r--js/src/vm/Probes-inl.h93
-rw-r--r--js/src/vm/Probes.cpp67
-rw-r--r--js/src/vm/Probes.h143
-rw-r--r--js/src/vm/PropDesc.h0
-rw-r--r--js/src/vm/ProxyObject.cpp150
-rw-r--r--js/src/vm/ProxyObject.h145
-rw-r--r--js/src/vm/Realm.cpp49
-rw-r--r--js/src/vm/ReceiverGuard.cpp66
-rw-r--r--js/src/vm/ReceiverGuard.h137
-rw-r--r--js/src/vm/RegExpObject.cpp1555
-rw-r--r--js/src/vm/RegExpObject.h561
-rw-r--r--js/src/vm/RegExpStatics.cpp111
-rw-r--r--js/src/vm/RegExpStatics.h415
-rw-r--r--js/src/vm/RegExpStaticsObject.h28
-rw-r--r--js/src/vm/Runtime.cpp968
-rw-r--r--js/src/vm/Runtime.h1777
-rw-r--r--js/src/vm/SPSProfiler.cpp586
-rw-r--r--js/src/vm/SPSProfiler.h341
-rw-r--r--js/src/vm/SavedFrame.h323
-rw-r--r--js/src/vm/SavedStacks-inl.h29
-rw-r--r--js/src/vm/SavedStacks.cpp1758
-rw-r--r--js/src/vm/SavedStacks.h332
-rw-r--r--js/src/vm/Scope.cpp1460
-rw-r--r--js/src/vm/Scope.h1451
-rw-r--r--js/src/vm/SelfHosting.cpp3109
-rw-r--r--js/src/vm/SelfHosting.h52
-rw-r--r--js/src/vm/Shape-inl.h210
-rw-r--r--js/src/vm/Shape.cpp1782
-rw-r--r--js/src/vm/Shape.h1636
-rw-r--r--js/src/vm/ShapedObject-inl.h23
-rw-r--r--js/src/vm/ShapedObject.h57
-rw-r--r--js/src/vm/SharedArrayObject.cpp488
-rw-r--r--js/src/vm/SharedArrayObject.h189
-rw-r--r--js/src/vm/SharedImmutableStringsCache-inl.h76
-rw-r--r--js/src/vm/SharedImmutableStringsCache.cpp123
-rw-r--r--js/src/vm/SharedImmutableStringsCache.h468
-rw-r--r--js/src/vm/SharedMem.h226
-rw-r--r--js/src/vm/Stack-inl.h998
-rw-r--r--js/src/vm/Stack.cpp1959
-rw-r--r--js/src/vm/Stack.h2077
-rw-r--r--js/src/vm/StopIterationObject.h22
-rw-r--r--js/src/vm/Stopwatch.cpp655
-rw-r--r--js/src/vm/Stopwatch.h406
-rw-r--r--js/src/vm/String-inl.h422
-rw-r--r--js/src/vm/String.cpp1442
-rw-r--r--js/src/vm/String.h1509
-rw-r--r--js/src/vm/StringBuffer.cpp170
-rw-r--r--js/src/vm/StringBuffer.h343
-rw-r--r--js/src/vm/StringObject-inl.h49
-rw-r--r--js/src/vm/StringObject.h74
-rw-r--r--js/src/vm/StructuredClone.cpp2785
-rw-r--r--js/src/vm/Symbol.cpp152
-rw-r--r--js/src/vm/Symbol.h149
-rw-r--r--js/src/vm/TaggedProto.cpp77
-rw-r--r--js/src/vm/TaggedProto.h138
-rw-r--r--js/src/vm/Time.cpp382
-rw-r--r--js/src/vm/Time.h163
-rw-r--r--js/src/vm/TraceLogging.cpp1085
-rw-r--r--js/src/vm/TraceLogging.h564
-rw-r--r--js/src/vm/TraceLoggingGraph.cpp649
-rw-r--r--js/src/vm/TraceLoggingGraph.h272
-rw-r--r--js/src/vm/TraceLoggingTypes.cpp20
-rw-r--r--js/src/vm/TraceLoggingTypes.h269
-rw-r--r--js/src/vm/TypeInference-inl.h1130
-rw-r--r--js/src/vm/TypeInference.cpp4600
-rw-r--r--js/src/vm/TypeInference.h1345
-rw-r--r--js/src/vm/TypedArrayCommon.h887
-rw-r--r--js/src/vm/TypedArrayObject.cpp3315
-rw-r--r--js/src/vm/TypedArrayObject.h607
-rw-r--r--js/src/vm/UbiNode.cpp519
-rw-r--r--js/src/vm/UbiNodeCensus.cpp1167
-rw-r--r--js/src/vm/UbiNodeShortestPaths.cpp93
-rw-r--r--js/src/vm/UnboxedObject-inl.h840
-rw-r--r--js/src/vm/UnboxedObject.cpp2152
-rw-r--r--js/src/vm/UnboxedObject.h531
-rw-r--r--js/src/vm/Unicode.cpp1750
-rw-r--r--js/src/vm/Unicode.h498
-rw-r--r--js/src/vm/UnicodeData.txt30592
-rw-r--r--js/src/vm/UnicodeNonBMP.h41
-rw-r--r--js/src/vm/Value.cpp21
-rw-r--r--js/src/vm/WeakMapPtr.cpp110
-rw-r--r--js/src/vm/WrapperObject.h45
-rw-r--r--js/src/vm/Xdr.cpp170
-rw-r--r--js/src/vm/Xdr.h216
-rwxr-xr-xjs/src/vm/make_opcode_doc.py369
-rwxr-xr-xjs/src/vm/make_unicode.py836
159 files changed, 154806 insertions, 0 deletions
diff --git a/js/src/vm/ArgumentsObject-inl.h b/js/src/vm/ArgumentsObject-inl.h
new file mode 100644
index 000000000..fdd3d3e13
--- /dev/null
+++ b/js/src/vm/ArgumentsObject-inl.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArgumentsObject_inl_h
+#define vm_ArgumentsObject_inl_h
+
+#include "vm/ArgumentsObject.h"
+
+#include "vm/EnvironmentObject.h"
+
+#include "jsscriptinlines.h"
+
+#include "vm/EnvironmentObject-inl.h"
+
+namespace js {
+
+inline const Value&
+ArgumentsObject::element(uint32_t i) const
+{
+ MOZ_ASSERT(!isElementDeleted(i));
+ const Value& v = data()->args[i];
+ if (IsMagicScopeSlotValue(v)) {
+ CallObject& callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
+ return callobj.aliasedFormalFromArguments(v);
+ }
+ return v;
+}
+
+inline void
+ArgumentsObject::setElement(JSContext* cx, uint32_t i, const Value& v)
+{
+ MOZ_ASSERT(!isElementDeleted(i));
+ GCPtrValue& lhs = data()->args[i];
+ if (IsMagicScopeSlotValue(lhs)) {
+ uint32_t slot = SlotFromMagicScopeSlotValue(lhs);
+ CallObject& callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
+ for (Shape::Range<NoGC> r(callobj.lastProperty()); !r.empty(); r.popFront()) {
+ if (r.front().slot() == slot) {
+ callobj.setAliasedFormalFromArguments(cx, lhs, r.front().propid(), v);
+ return;
+ }
+ }
+ MOZ_CRASH("Bad Arguments::setElement");
+ }
+ lhs = v;
+}
+
+inline bool
+ArgumentsObject::maybeGetElements(uint32_t start, uint32_t count, Value* vp)
+{
+ MOZ_ASSERT(start + count >= start);
+
+ uint32_t length = initialLength();
+ if (start > length || start + count > length || isAnyElementDeleted())
+ return false;
+
+ for (uint32_t i = start, end = start + count; i < end; ++i, ++vp)
+ *vp = element(i);
+ return true;
+}
+
+} /* namespace js */
+
+#endif /* vm_ArgumentsObject_inl_h */
diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp
new file mode 100644
index 000000000..d01121ef0
--- /dev/null
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -0,0 +1,848 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ArgumentsObject-inl.h"
+
+#include "mozilla/PodOperations.h"
+
+#include "jit/JitFrames.h"
+#include "vm/AsyncFunction.h"
+#include "vm/GlobalObject.h"
+#include "vm/Stack.h"
+
+#include "jsobjinlines.h"
+
+#include "gc/Nursery-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+/* static */ size_t
+RareArgumentsData::bytesRequired(size_t numActuals)
+{
+ size_t extraBytes = NumWordsForBitArrayOfLength(numActuals) * sizeof(size_t);
+ return offsetof(RareArgumentsData, deletedBits_) + extraBytes;
+}
+
+/* static */ RareArgumentsData*
+RareArgumentsData::create(JSContext* cx, ArgumentsObject* obj)
+{
+ size_t bytes = RareArgumentsData::bytesRequired(obj->initialLength());
+
+ uint8_t* data = AllocateObjectBuffer<uint8_t>(cx, obj, bytes);
+ if (!data)
+ return nullptr;
+
+ mozilla::PodZero(data, bytes);
+
+ return new(data) RareArgumentsData();
+}
+
+bool
+ArgumentsObject::createRareData(JSContext* cx)
+{
+ MOZ_ASSERT(!data()->rareData);
+
+ RareArgumentsData* rareData = RareArgumentsData::create(cx, this);
+ if (!rareData)
+ return false;
+
+ data()->rareData = rareData;
+ return true;
+}
+
+bool
+ArgumentsObject::markElementDeleted(JSContext* cx, uint32_t i)
+{
+ RareArgumentsData* data = getOrCreateRareData(cx);
+ if (!data)
+ return false;
+
+ data->markElementDeleted(initialLength(), i);
+ return true;
+}
+
+static void
+CopyStackFrameArguments(const AbstractFramePtr frame, GCPtrValue* dst, unsigned totalArgs)
+{
+ MOZ_ASSERT_IF(frame.isInterpreterFrame(), !frame.asInterpreterFrame()->runningInJit());
+
+ MOZ_ASSERT(Max(frame.numActualArgs(), frame.numFormalArgs()) == totalArgs);
+
+ /* Copy arguments. */
+ Value* src = frame.argv();
+ Value* end = src + totalArgs;
+ while (src != end)
+ (dst++)->init(*src++);
+}
+
+/* static */ void
+ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObject* obj,
+ ArgumentsData* data)
+{
+ JSScript* script = frame.script();
+ if (frame.callee()->needsCallObject() && script->argumentsAliasesFormals()) {
+ obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(frame.callObj()));
+ for (PositionalFormalParameterIter fi(script); fi; fi++) {
+ if (fi.closedOver())
+ data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
+ }
+ }
+}
+
+/* static */ void
+ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
+ ArgumentsObject* obj, ArgumentsData* data)
+{
+ JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
+ JSScript* script = callee->nonLazyScript();
+ if (callee->needsCallObject() && script->argumentsAliasesFormals()) {
+ MOZ_ASSERT(callObj && callObj->is<CallObject>());
+ obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
+ for (PositionalFormalParameterIter fi(script); fi; fi++) {
+ if (fi.closedOver())
+ data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot());
+ }
+ }
+}
+
+struct CopyFrameArgs
+{
+ AbstractFramePtr frame_;
+
+ explicit CopyFrameArgs(AbstractFramePtr frame)
+ : frame_(frame)
+ { }
+
+ void copyArgs(JSContext*, GCPtrValue* dst, unsigned totalArgs) const {
+ CopyStackFrameArguments(frame_, dst, totalArgs);
+ }
+
+ /*
+ * If a call object exists and the arguments object aliases formals, the
+ * call object is the canonical location for formals.
+ */
+ void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
+ ArgumentsObject::MaybeForwardToCallObject(frame_, obj, data);
+ }
+};
+
+struct CopyJitFrameArgs
+{
+ jit::JitFrameLayout* frame_;
+ HandleObject callObj_;
+
+ CopyJitFrameArgs(jit::JitFrameLayout* frame, HandleObject callObj)
+ : frame_(frame), callObj_(callObj)
+ { }
+
+ void copyArgs(JSContext*, GCPtrValue* dstBase, unsigned totalArgs) const {
+ unsigned numActuals = frame_->numActualArgs();
+ unsigned numFormals = jit::CalleeTokenToFunction(frame_->calleeToken())->nargs();
+ MOZ_ASSERT(numActuals <= totalArgs);
+ MOZ_ASSERT(numFormals <= totalArgs);
+ MOZ_ASSERT(Max(numActuals, numFormals) == totalArgs);
+
+ /* Copy all arguments. */
+ Value* src = frame_->argv() + 1; /* +1 to skip this. */
+ Value* end = src + numActuals;
+ GCPtrValue* dst = dstBase;
+ while (src != end)
+ (dst++)->init(*src++);
+
+ if (numActuals < numFormals) {
+ GCPtrValue* dstEnd = dstBase + totalArgs;
+ while (dst != dstEnd)
+ (dst++)->init(UndefinedValue());
+ }
+ }
+
+ /*
+ * If a call object exists and the arguments object aliases formals, the
+ * call object is the canonical location for formals.
+ */
+ void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
+ ArgumentsObject::MaybeForwardToCallObject(frame_, callObj_, obj, data);
+ }
+};
+
+struct CopyScriptFrameIterArgs
+{
+ ScriptFrameIter& iter_;
+
+ explicit CopyScriptFrameIterArgs(ScriptFrameIter& iter)
+ : iter_(iter)
+ { }
+
+ void copyArgs(JSContext* cx, GCPtrValue* dstBase, unsigned totalArgs) const {
+ /* Copy actual arguments. */
+ iter_.unaliasedForEachActual(cx, CopyToHeap(dstBase));
+
+ /* Define formals which are not part of the actuals. */
+ unsigned numActuals = iter_.numActualArgs();
+ unsigned numFormals = iter_.calleeTemplate()->nargs();
+ MOZ_ASSERT(numActuals <= totalArgs);
+ MOZ_ASSERT(numFormals <= totalArgs);
+ MOZ_ASSERT(Max(numActuals, numFormals) == totalArgs);
+
+ if (numActuals < numFormals) {
+ GCPtrValue* dst = dstBase + numActuals;
+ GCPtrValue* dstEnd = dstBase + totalArgs;
+ while (dst != dstEnd)
+ (dst++)->init(UndefinedValue());
+ }
+ }
+
+ /*
+ * Ion frames are copying every argument onto the stack, other locations are
+ * invalid.
+ */
+ void maybeForwardToCallObject(ArgumentsObject* obj, ArgumentsData* data) {
+ if (!iter_.isIon())
+ ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj, data);
+ }
+};
+
+ArgumentsObject*
+ArgumentsObject::createTemplateObject(JSContext* cx, bool mapped)
+{
+ const Class* clasp = mapped
+ ? &MappedArgumentsObject::class_
+ : &UnmappedArgumentsObject::class_;
+
+ RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx));
+ if (!proto)
+ return nullptr;
+
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto.get())));
+ if (!group)
+ return nullptr;
+
+ RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto),
+ FINALIZE_KIND, BaseShape::INDEXED));
+ if (!shape)
+ return nullptr;
+
+ AutoSetNewObjectMetadata metadata(cx);
+ JSObject* base = JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, shape, group);
+ if (!base)
+ return nullptr;
+
+ ArgumentsObject* obj = &base->as<js::ArgumentsObject>();
+ obj->initFixedSlot(ArgumentsObject::DATA_SLOT, PrivateValue(nullptr));
+ return obj;
+}
+
+ArgumentsObject*
+JSCompartment::maybeArgumentsTemplateObject(bool mapped) const
+{
+ return mapped ? mappedArgumentsTemplate_ : unmappedArgumentsTemplate_;
+}
+
+ArgumentsObject*
+JSCompartment::getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped)
+{
+ ReadBarriered<ArgumentsObject*>& obj =
+ mapped ? mappedArgumentsTemplate_ : unmappedArgumentsTemplate_;
+
+ ArgumentsObject* templateObj = obj;
+ if (templateObj)
+ return templateObj;
+
+ templateObj = ArgumentsObject::createTemplateObject(cx, mapped);
+ if (!templateObj)
+ return nullptr;
+
+ obj.set(templateObj);
+ return templateObj;
+}
+
+template <typename CopyArgs>
+/* static */ ArgumentsObject*
+ArgumentsObject::create(JSContext* cx, HandleFunction callee, unsigned numActuals, CopyArgs& copy)
+{
+ bool mapped = callee->nonLazyScript()->hasMappedArgsObj();
+ ArgumentsObject* templateObj = cx->compartment()->getOrCreateArgumentsTemplateObject(cx, mapped);
+ if (!templateObj)
+ return nullptr;
+
+ RootedShape shape(cx, templateObj->lastProperty());
+ RootedObjectGroup group(cx, templateObj->group());
+
+ unsigned numFormals = callee->nargs();
+ unsigned numArgs = Max(numActuals, numFormals);
+ unsigned numBytes = ArgumentsData::bytesRequired(numArgs);
+
+ Rooted<ArgumentsObject*> obj(cx);
+ ArgumentsData* data = nullptr;
+ {
+ // The copyArgs call below can allocate objects, so add this block scope
+ // to make sure we set the metadata for this arguments object first.
+ AutoSetNewObjectMetadata metadata(cx);
+
+ JSObject* base = JSObject::create(cx, FINALIZE_KIND, gc::DefaultHeap, shape, group);
+ if (!base)
+ return nullptr;
+ obj = &base->as<ArgumentsObject>();
+
+ data =
+ reinterpret_cast<ArgumentsData*>(AllocateObjectBuffer<uint8_t>(cx, obj, numBytes));
+ if (!data) {
+ // Make the object safe for GC.
+ obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr));
+ return nullptr;
+ }
+
+ data->numArgs = numArgs;
+ data->rareData = nullptr;
+
+ // Zero the argument Values. This sets each value to DoubleValue(0), which
+ // is safe for GC tracing.
+ memset(data->args, 0, numArgs * sizeof(Value));
+ MOZ_ASSERT(DoubleValue(0).asRawBits() == 0x0);
+ MOZ_ASSERT_IF(numArgs > 0, data->args[0].asRawBits() == 0x0);
+
+ obj->initFixedSlot(DATA_SLOT, PrivateValue(data));
+ obj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
+ }
+ MOZ_ASSERT(data != nullptr);
+
+ /* Copy [0, numArgs) into data->slots. */
+ copy.copyArgs(cx, data->args, numArgs);
+
+ obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT));
+
+ copy.maybeForwardToCallObject(obj, data);
+
+ MOZ_ASSERT(obj->initialLength() == numActuals);
+ MOZ_ASSERT(!obj->hasOverriddenLength());
+ return obj;
+}
+
+ArgumentsObject*
+ArgumentsObject::createExpected(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT(frame.script()->needsArgsObj());
+ RootedFunction callee(cx, frame.callee());
+ CopyFrameArgs copy(frame);
+ ArgumentsObject* argsobj = create(cx, callee, frame.numActualArgs(), copy);
+ if (!argsobj)
+ return nullptr;
+
+ frame.initArgsObj(*argsobj);
+ return argsobj;
+}
+
+ArgumentsObject*
+ArgumentsObject::createUnexpected(JSContext* cx, ScriptFrameIter& iter)
+{
+ RootedFunction callee(cx, iter.callee(cx));
+ CopyScriptFrameIterArgs copy(iter);
+ return create(cx, callee, iter.numActualArgs(), copy);
+}
+
+ArgumentsObject*
+ArgumentsObject::createUnexpected(JSContext* cx, AbstractFramePtr frame)
+{
+ RootedFunction callee(cx, frame.callee());
+ CopyFrameArgs copy(frame);
+ return create(cx, callee, frame.numActualArgs(), copy);
+}
+
+ArgumentsObject*
+ArgumentsObject::createForIon(JSContext* cx, jit::JitFrameLayout* frame, HandleObject scopeChain)
+{
+ jit::CalleeToken token = frame->calleeToken();
+ MOZ_ASSERT(jit::CalleeTokenIsFunction(token));
+ RootedFunction callee(cx, jit::CalleeTokenToFunction(token));
+ RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain.get() : nullptr);
+ CopyJitFrameArgs copy(frame, callObj);
+ return create(cx, callee, frame->numActualArgs(), copy);
+}
+
+/* static */ ArgumentsObject*
+ArgumentsObject::finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
+ JSObject* scopeChain, ArgumentsObject* obj)
+{
+ // JIT code calls this directly (no callVM), because it's faster, so we're
+ // not allowed to GC in here.
+ JS::AutoCheckCannotGC nogc;
+
+ JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
+ RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain : nullptr);
+ CopyJitFrameArgs copy(frame, callObj);
+
+ unsigned numActuals = frame->numActualArgs();
+ unsigned numFormals = callee->nargs();
+ unsigned numArgs = Max(numActuals, numFormals);
+ unsigned numBytes = ArgumentsData::bytesRequired(numArgs);
+
+ ArgumentsData* data =
+ reinterpret_cast<ArgumentsData*>(AllocateObjectBuffer<uint8_t>(cx, obj, numBytes));
+ if (!data) {
+ // Make the object safe for GC. Don't report OOM, the slow path will
+ // retry the allocation.
+ cx->recoverFromOutOfMemory();
+ obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr));
+ return nullptr;
+ }
+
+ data->numArgs = numArgs;
+ data->rareData = nullptr;
+
+ obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT));
+ obj->initFixedSlot(DATA_SLOT, PrivateValue(data));
+ obj->initFixedSlot(MAYBE_CALL_SLOT, UndefinedValue());
+ obj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
+
+ copy.copyArgs(cx, data->args, numArgs);
+
+ if (callObj && callee->needsCallObject())
+ copy.maybeForwardToCallObject(obj, data);
+
+ MOZ_ASSERT(obj->initialLength() == numActuals);
+ MOZ_ASSERT(!obj->hasOverriddenLength());
+ return obj;
+}
+
+/* static */ bool
+ArgumentsObject::obj_delProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result)
+{
+ ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
+ if (JSID_IS_INT(id)) {
+ unsigned arg = unsigned(JSID_TO_INT(id));
+ if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
+ if (!argsobj.markElementDeleted(cx, arg))
+ return false;
+ }
+ } else if (JSID_IS_ATOM(id, cx->names().length)) {
+ argsobj.markLengthOverridden();
+ } else if (JSID_IS_ATOM(id, cx->names().callee)) {
+ argsobj.as<MappedArgumentsObject>().markCalleeOverridden();
+ } else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
+ argsobj.markIteratorOverridden();
+ }
+ return result.succeed();
+}
+
+static bool
+MappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
+ MappedArgumentsObject& argsobj = obj->as<MappedArgumentsObject>();
+ if (JSID_IS_INT(id)) {
+ /*
+ * arg can exceed the number of arguments if a script changed the
+ * prototype to point to another Arguments object with a bigger argc.
+ */
+ unsigned arg = unsigned(JSID_TO_INT(id));
+ if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
+ vp.set(argsobj.element(arg));
+ } else if (JSID_IS_ATOM(id, cx->names().length)) {
+ if (!argsobj.hasOverriddenLength())
+ vp.setInt32(argsobj.initialLength());
+ } else {
+ MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().callee));
+ if (!argsobj.hasOverriddenCallee()) {
+ RootedFunction callee(cx, &argsobj.callee());
+ if (callee->isAsync())
+ vp.setObject(*GetWrappedAsyncFunction(callee));
+ else
+ vp.setObject(*callee);
+ }
+ }
+ return true;
+}
+
+static bool
+MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+ ObjectOpResult& result)
+{
+ if (!obj->is<MappedArgumentsObject>())
+ return result.succeed();
+ Handle<MappedArgumentsObject*> argsobj = obj.as<MappedArgumentsObject>();
+
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
+ return false;
+ MOZ_ASSERT(desc.object());
+ unsigned attrs = desc.attributes();
+ MOZ_ASSERT(!(attrs & JSPROP_READONLY));
+ attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
+
+ RootedFunction callee(cx, &argsobj->callee());
+ RootedScript script(cx, callee->getOrCreateScript(cx));
+ if (!script)
+ return false;
+
+ if (JSID_IS_INT(id)) {
+ unsigned arg = unsigned(JSID_TO_INT(id));
+ if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) {
+ argsobj->setElement(cx, arg, vp);
+ if (arg < script->functionNonDelazifying()->nargs())
+ TypeScript::SetArgument(cx, script, arg, vp);
+ return result.succeed();
+ }
+ } else {
+ MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee));
+ }
+
+ /*
+ * For simplicity we use delete/define to replace the property with a
+ * simple data property. Note that we rely on ArgumentsObject::obj_delProperty
+ * to clear the corresponding reserved slot so the GC can collect its value.
+ * Note also that we must define the property instead of setting it in case
+ * the user has changed the prototype to an object that has a setter for
+ * this id.
+ */
+ ObjectOpResult ignored;
+ return NativeDeleteProperty(cx, argsobj, id, ignored) &&
+ NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
+}
+
+static bool
+DefineArgumentsIterator(JSContext* cx, Handle<ArgumentsObject*> argsobj)
+{
+ RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+ HandlePropertyName shName = cx->names().ArrayValues;
+ RootedAtom name(cx, cx->names().values);
+ RootedValue val(cx);
+ if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 0, &val))
+ return false;
+
+ return NativeDefineProperty(cx, argsobj, iteratorId, val, nullptr, nullptr, JSPROP_RESOLVING);
+}
+
+/* static */ bool
+MappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
+{
+ Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>());
+
+ if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
+ if (argsobj->hasOverriddenIterator())
+ return true;
+
+ if (!DefineArgumentsIterator(cx, argsobj))
+ return false;
+ *resolvedp = true;
+ return true;
+ }
+
+ unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE | JSPROP_RESOLVING;
+ if (JSID_IS_INT(id)) {
+ uint32_t arg = uint32_t(JSID_TO_INT(id));
+ if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
+ return true;
+
+ attrs |= JSPROP_ENUMERATE;
+ } else if (JSID_IS_ATOM(id, cx->names().length)) {
+ if (argsobj->hasOverriddenLength())
+ return true;
+ } else {
+ if (!JSID_IS_ATOM(id, cx->names().callee))
+ return true;
+
+ if (argsobj->hasOverriddenCallee())
+ return true;
+ }
+
+ if (!NativeDefineProperty(cx, argsobj, id, UndefinedHandleValue,
+ MappedArgGetter, MappedArgSetter, attrs))
+ {
+ return false;
+ }
+
+ *resolvedp = true;
+ return true;
+}
+
+/* static */ bool
+MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
+{
+ Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>());
+
+ RootedId id(cx);
+ bool found;
+
+ // Trigger reflection.
+ id = NameToId(cx->names().length);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ id = NameToId(cx->names().callee);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ for (unsigned i = 0; i < argsobj->initialLength(); i++) {
+ id = INT_TO_JSID(i);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+UnmappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
+ UnmappedArgumentsObject& argsobj = obj->as<UnmappedArgumentsObject>();
+
+ if (JSID_IS_INT(id)) {
+ /*
+ * arg can exceed the number of arguments if a script changed the
+ * prototype to point to another Arguments object with a bigger argc.
+ */
+ unsigned arg = unsigned(JSID_TO_INT(id));
+ if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
+ vp.set(argsobj.element(arg));
+ } else {
+ MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length));
+ if (!argsobj.hasOverriddenLength())
+ vp.setInt32(argsobj.initialLength());
+ }
+ return true;
+}
+
+static bool
+UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
+ ObjectOpResult& result)
+{
+ if (!obj->is<UnmappedArgumentsObject>())
+ return result.succeed();
+ Handle<UnmappedArgumentsObject*> argsobj = obj.as<UnmappedArgumentsObject>();
+
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
+ return false;
+ MOZ_ASSERT(desc.object());
+ unsigned attrs = desc.attributes();
+ MOZ_ASSERT(!(attrs & JSPROP_READONLY));
+ attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
+
+ if (JSID_IS_INT(id)) {
+ unsigned arg = unsigned(JSID_TO_INT(id));
+ if (arg < argsobj->initialLength()) {
+ argsobj->setElement(cx, arg, vp);
+ return result.succeed();
+ }
+ } else {
+ MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().length));
+ }
+
+ /*
+ * For simplicity we use delete/define to replace the property with a
+ * simple data property. Note that we rely on ArgumentsObject::obj_delProperty
+ * to clear the corresponding reserved slot so the GC can collect its value.
+ */
+ ObjectOpResult ignored;
+ return NativeDeleteProperty(cx, argsobj, id, ignored) &&
+ NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
+}
+
+/* static */ bool
+UnmappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
+{
+ Rooted<UnmappedArgumentsObject*> argsobj(cx, &obj->as<UnmappedArgumentsObject>());
+
+ if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
+ if (argsobj->hasOverriddenIterator())
+ return true;
+
+ if (!DefineArgumentsIterator(cx, argsobj))
+ return false;
+ *resolvedp = true;
+ return true;
+ }
+
+ unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
+ GetterOp getter = UnmappedArgGetter;
+ SetterOp setter = UnmappedArgSetter;
+
+ if (JSID_IS_INT(id)) {
+ uint32_t arg = uint32_t(JSID_TO_INT(id));
+ if (arg >= argsobj->initialLength() || argsobj->isElementDeleted(arg))
+ return true;
+
+ attrs |= JSPROP_ENUMERATE;
+ } else if (JSID_IS_ATOM(id, cx->names().length)) {
+ if (argsobj->hasOverriddenLength())
+ return true;
+ } else {
+ if (!JSID_IS_ATOM(id, cx->names().callee) && !JSID_IS_ATOM(id, cx->names().caller))
+ return true;
+
+ attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
+ getter = CastAsGetterOp(argsobj->global().getThrowTypeError());
+ setter = CastAsSetterOp(argsobj->global().getThrowTypeError());
+ }
+
+ attrs |= JSPROP_RESOLVING;
+ if (!NativeDefineProperty(cx, argsobj, id, UndefinedHandleValue, getter, setter, attrs))
+ return false;
+
+ *resolvedp = true;
+ return true;
+}
+
+/* static */ bool
+UnmappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
+{
+ Rooted<UnmappedArgumentsObject*> argsobj(cx, &obj->as<UnmappedArgumentsObject>());
+
+ RootedId id(cx);
+ bool found;
+
+ // Trigger reflection.
+ id = NameToId(cx->names().length);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ id = NameToId(cx->names().callee);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ id = NameToId(cx->names().caller);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+
+ for (unsigned i = 0; i < argsobj->initialLength(); i++) {
+ id = INT_TO_JSID(i);
+ if (!HasProperty(cx, argsobj, id, &found))
+ return false;
+ }
+
+ return true;
+}
+
+void
+ArgumentsObject::finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(!IsInsideNursery(obj));
+ if (obj->as<ArgumentsObject>().data()) {
+ fop->free_(obj->as<ArgumentsObject>().maybeRareData());
+ fop->free_(obj->as<ArgumentsObject>().data());
+ }
+}
+
+void
+ArgumentsObject::trace(JSTracer* trc, JSObject* obj)
+{
+ ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
+ if (ArgumentsData* data = argsobj.data()) // Template objects have no ArgumentsData.
+ TraceRange(trc, data->numArgs, data->begin(), js_arguments_str);
+}
+
+/* static */ size_t
+ArgumentsObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src)
+{
+ ArgumentsObject* ndst = &dst->as<ArgumentsObject>();
+ ArgumentsObject* nsrc = &src->as<ArgumentsObject>();
+ MOZ_ASSERT(ndst->data() == nsrc->data());
+
+ Nursery& nursery = trc->runtime()->gc.nursery;
+
+ size_t nbytesTotal = 0;
+ if (!nursery.isInside(nsrc->data())) {
+ nursery.removeMallocedBuffer(nsrc->data());
+ } else {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ uint32_t nbytes = ArgumentsData::bytesRequired(nsrc->data()->numArgs);
+ uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes);
+ if (!data)
+ oomUnsafe.crash("Failed to allocate ArgumentsObject data while tenuring.");
+ ndst->initFixedSlot(DATA_SLOT, PrivateValue(data));
+
+ mozilla::PodCopy(data, reinterpret_cast<uint8_t*>(nsrc->data()), nbytes);
+ nbytesTotal += nbytes;
+ }
+
+ if (RareArgumentsData* srcRareData = nsrc->maybeRareData()) {
+ if (!nursery.isInside(srcRareData)) {
+ nursery.removeMallocedBuffer(srcRareData);
+ } else {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ uint32_t nbytes = RareArgumentsData::bytesRequired(nsrc->initialLength());
+ uint8_t* dstRareData = nsrc->zone()->pod_malloc<uint8_t>(nbytes);
+ if (!dstRareData)
+ oomUnsafe.crash("Failed to allocate RareArgumentsData data while tenuring.");
+ ndst->data()->rareData = (RareArgumentsData*)dstRareData;
+
+ mozilla::PodCopy(dstRareData, reinterpret_cast<uint8_t*>(srcRareData), nbytes);
+ nbytesTotal += nbytes;
+ }
+ }
+
+ return nbytesTotal;
+}
+
+/*
+ * The classes below collaborate to lazily reflect and synchronize actual
+ * argument values, argument count, and callee function object stored in a
+ * stack frame with their corresponding property values in the frame's
+ * arguments object.
+ */
+const ClassOps MappedArgumentsObject::classOps_ = {
+ nullptr, /* addProperty */
+ ArgumentsObject::obj_delProperty,
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ MappedArgumentsObject::obj_enumerate,
+ MappedArgumentsObject::obj_resolve,
+ nullptr, /* mayResolve */
+ ArgumentsObject::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ArgumentsObject::trace
+};
+
+const Class MappedArgumentsObject::class_ = {
+ "Arguments",
+ JSCLASS_DELAY_METADATA_BUILDER |
+ JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
+ JSCLASS_SKIP_NURSERY_FINALIZE |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &MappedArgumentsObject::classOps_
+};
+
+/*
+ * Unmapped arguments is significantly less magical than mapped arguments, so
+ * it is represented by a different class while sharing some functionality.
+ */
+const ClassOps UnmappedArgumentsObject::classOps_ = {
+ nullptr, /* addProperty */
+ ArgumentsObject::obj_delProperty,
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ UnmappedArgumentsObject::obj_enumerate,
+ UnmappedArgumentsObject::obj_resolve,
+ nullptr, /* mayResolve */
+ ArgumentsObject::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ArgumentsObject::trace
+};
+
+const Class UnmappedArgumentsObject::class_ = {
+ "Arguments",
+ JSCLASS_DELAY_METADATA_BUILDER |
+ JSCLASS_HAS_RESERVED_SLOTS(UnmappedArgumentsObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
+ JSCLASS_SKIP_NURSERY_FINALIZE |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &UnmappedArgumentsObject::classOps_
+};
diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h
new file mode 100644
index 000000000..247c7cd94
--- /dev/null
+++ b/js/src/vm/ArgumentsObject.h
@@ -0,0 +1,436 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArgumentsObject_h
+#define vm_ArgumentsObject_h
+
+#include "mozilla/MemoryReporting.h"
+
+#include "gc/Barrier.h"
+#include "vm/NativeObject.h"
+
+namespace js {
+
+class AbstractFramePtr;
+class ScriptFrameIter;
+
+namespace jit {
+class JitFrameLayout;
+} // namespace jit
+
+// RareArgumentsData stores the deleted-elements bits for an arguments object.
+// Because |delete arguments[i]| is uncommon, we allocate this data the first
+// time an element is deleted.
+class RareArgumentsData
+{
+ // Pointer to an array of bits indicating, for every argument in
+ // [0, initialLength) whether the element has been deleted. See
+ // ArgumentsObject::isElementDeleted comment.
+ size_t deletedBits_[1];
+
+ RareArgumentsData() = default;
+ RareArgumentsData(const RareArgumentsData&) = delete;
+ void operator=(const RareArgumentsData&) = delete;
+
+ public:
+ static RareArgumentsData* create(JSContext* cx, ArgumentsObject* obj);
+ static size_t bytesRequired(size_t numActuals);
+
+ bool isAnyElementDeleted(size_t len) const {
+ return IsAnyBitArrayElementSet(deletedBits_, len);
+ }
+ bool isElementDeleted(size_t len, size_t i) const {
+ MOZ_ASSERT(i < len);
+ return IsBitArrayElementSet(deletedBits_, len, i);
+ }
+ void markElementDeleted(size_t len, size_t i) {
+ MOZ_ASSERT(i < len);
+ SetBitArrayElement(deletedBits_, len, i);
+ }
+};
+
+/*
+ * ArgumentsData stores the initial indexed arguments provided to the
+ * corresponding and that function itself. It is used to store arguments[i]
+ * and arguments.callee -- up until the corresponding property is modified,
+ * when the relevant value is flagged to memorialize the modification.
+ */
+struct ArgumentsData
+{
+ /*
+ * numArgs = Max(numFormalArgs, numActualArgs)
+ * The array 'args' has numArgs elements.
+ */
+ uint32_t numArgs;
+
+ RareArgumentsData* rareData;
+
+ /*
+ * This array holds either the current argument value or the magic
+ * forwarding value. The latter means that the function has both a
+ * CallObject and an ArgumentsObject AND the particular formal variable is
+ * aliased by the CallObject. In such cases, the CallObject holds the
+ * canonical value so any element access to the arguments object should load
+ * the value out of the CallObject (which is pointed to by MAYBE_CALL_SLOT).
+ */
+ GCPtrValue args[1];
+
+ /* For jit use: */
+ static ptrdiff_t offsetOfArgs() { return offsetof(ArgumentsData, args); }
+
+ /* Iterate args. */
+ GCPtrValue* begin() { return args; }
+ const GCPtrValue* begin() const { return args; }
+ GCPtrValue* end() { return args + numArgs; }
+ const GCPtrValue* end() const { return args + numArgs; }
+
+ static size_t bytesRequired(size_t numArgs) {
+ return offsetof(ArgumentsData, args) + numArgs * sizeof(Value);
+ }
+};
+
+// Maximum supported value of arguments.length. This bounds the maximum
+// number of arguments that can be supplied to Function.prototype.apply.
+// This value also bounds the number of elements parsed in an array
+// initializer.
+// NB: keep this in sync with the copy in builtin/SelfHostingDefines.h.
+static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
+
+/*
+ * ArgumentsObject instances represent |arguments| objects created to store
+ * function arguments when a function is called. It's expensive to create such
+ * objects if they're never used, so they're only created when they are
+ * potentially used.
+ *
+ * Arguments objects are complicated because, for non-strict mode code, they
+ * must alias any named arguments which were provided to the function. Gnarly
+ * example:
+ *
+ * function f(a, b, c, d)
+ * {
+ * arguments[0] = "seta";
+ * assertEq(a, "seta");
+ * b = "setb";
+ * assertEq(arguments[1], "setb");
+ * c = "setc";
+ * assertEq(arguments[2], undefined);
+ * arguments[3] = "setd";
+ * assertEq(d, undefined);
+ * }
+ * f("arga", "argb");
+ *
+ * ES5's strict mode behaves more sanely, and named arguments don't alias
+ * elements of an arguments object.
+ *
+ * ArgumentsObject instances use the following reserved slots:
+ *
+ * INITIAL_LENGTH_SLOT
+ * Stores the initial value of arguments.length, plus a bit indicating
+ * whether arguments.length and/or arguments[@@iterator] have been
+ * modified. Use initialLength(), hasOverriddenLength(), and
+ * hasOverriddenIterator() to access these values. If arguments.length has
+ * been modified, then the current value of arguments.length is stored in
+ * another slot associated with a new property.
+ * DATA_SLOT
+ * Stores an ArgumentsData*, described above.
+ * MAYBE_CALL_SLOT
+ * Stores the CallObject, if the callee has aliased bindings. See
+ * the ArgumentsData::args comment.
+ * CALLEE_SLOT
+ * Stores the initial arguments.callee. This value can be overridden on
+ * mapped arguments objects, see hasOverriddenCallee.
+ */
+class ArgumentsObject : public NativeObject
+{
+ protected:
+ static const uint32_t INITIAL_LENGTH_SLOT = 0;
+ static const uint32_t DATA_SLOT = 1;
+ static const uint32_t MAYBE_CALL_SLOT = 2;
+ static const uint32_t CALLEE_SLOT = 3;
+
+ public:
+ static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
+ static const uint32_t ITERATOR_OVERRIDDEN_BIT = 0x2;
+ static const uint32_t ELEMENT_OVERRIDDEN_BIT = 0x4;
+ static const uint32_t CALLEE_OVERRIDDEN_BIT = 0x8;
+ static const uint32_t PACKED_BITS_COUNT = 4;
+
+ static_assert(ARGS_LENGTH_MAX <= (UINT32_MAX >> PACKED_BITS_COUNT),
+ "Max arguments length must fit in available bits");
+
+ protected:
+ template <typename CopyArgs>
+ static ArgumentsObject* create(JSContext* cx, HandleFunction callee, unsigned numActuals,
+ CopyArgs& copy);
+
+ ArgumentsData* data() const {
+ return reinterpret_cast<ArgumentsData*>(getFixedSlot(DATA_SLOT).toPrivate());
+ }
+
+ RareArgumentsData* maybeRareData() const {
+ return data()->rareData;
+ }
+
+ MOZ_MUST_USE bool createRareData(JSContext* cx);
+
+ RareArgumentsData* getOrCreateRareData(JSContext* cx) {
+ if (!data()->rareData && !createRareData(cx))
+ return nullptr;
+ return data()->rareData;
+ }
+
+ static bool obj_delProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result);
+
+ public:
+ static const uint32_t RESERVED_SLOTS = 4;
+ static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT4_BACKGROUND;
+
+ /* Create an arguments object for a frame that is expecting them. */
+ static ArgumentsObject* createExpected(JSContext* cx, AbstractFramePtr frame);
+
+ /*
+ * Purposefully disconnect the returned arguments object from the frame
+ * by always creating a new copy that does not alias formal parameters.
+ * This allows function-local analysis to determine that formals are
+ * not aliased and generally simplifies arguments objects.
+ */
+ static ArgumentsObject* createUnexpected(JSContext* cx, ScriptFrameIter& iter);
+ static ArgumentsObject* createUnexpected(JSContext* cx, AbstractFramePtr frame);
+ static ArgumentsObject* createForIon(JSContext* cx, jit::JitFrameLayout* frame,
+ HandleObject scopeChain);
+
+ /*
+ * Allocate ArgumentsData and fill reserved slots after allocating an
+ * ArgumentsObject in Ion code.
+ */
+ static ArgumentsObject* finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
+ JSObject* scopeChain, ArgumentsObject* obj);
+
+ static ArgumentsObject* createTemplateObject(JSContext* cx, bool mapped);
+
+ /*
+ * Return the initial length of the arguments. This may differ from the
+ * current value of arguments.length!
+ */
+ uint32_t initialLength() const {
+ uint32_t argc = uint32_t(getFixedSlot(INITIAL_LENGTH_SLOT).toInt32()) >> PACKED_BITS_COUNT;
+ MOZ_ASSERT(argc <= ARGS_LENGTH_MAX);
+ return argc;
+ }
+
+ /* True iff arguments.length has been assigned or its attributes changed. */
+ bool hasOverriddenLength() const {
+ const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
+ return v.toInt32() & LENGTH_OVERRIDDEN_BIT;
+ }
+
+ void markLengthOverridden() {
+ uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | LENGTH_OVERRIDDEN_BIT;
+ setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
+ }
+
+ /* True iff arguments[@@iterator] has been assigned or its attributes
+ * changed. */
+ bool hasOverriddenIterator() const {
+ const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
+ return v.toInt32() & ITERATOR_OVERRIDDEN_BIT;
+ }
+
+ void markIteratorOverridden() {
+ uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | ITERATOR_OVERRIDDEN_BIT;
+ setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
+ }
+
+ /* True iff any element has been assigned or its attributes
+ * changed. */
+ bool hasOverriddenElement() const {
+ const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
+ return v.toInt32() & ELEMENT_OVERRIDDEN_BIT;
+ }
+
+ void markElementOverridden() {
+ uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | ELEMENT_OVERRIDDEN_BIT;
+ setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
+ }
+
+ /*
+ * Because the arguments object is a real object, its elements may be
+ * deleted. This is implemented by setting a 'deleted' flag for the arg
+ * which is read by argument object resolve and getter/setter hooks.
+ *
+ * NB: an element, once deleted, stays deleted. Thus:
+ *
+ * function f(x) { delete arguments[0]; arguments[0] = 42; return x }
+ * assertEq(f(1), 1);
+ *
+ * This works because, once a property is deleted from an arguments object,
+ * it gets regular properties with regular getters/setters that don't alias
+ * ArgumentsData::slots.
+ */
+ bool isElementDeleted(uint32_t i) const {
+ MOZ_ASSERT(i < data()->numArgs);
+ if (i >= initialLength())
+ return false;
+ return maybeRareData() && maybeRareData()->isElementDeleted(initialLength(), i);
+ }
+
+ bool isAnyElementDeleted() const {
+ return maybeRareData() && maybeRareData()->isAnyElementDeleted(initialLength());
+ }
+
+ bool markElementDeleted(JSContext* cx, uint32_t i);
+
+ /*
+ * An ArgumentsObject serves two roles:
+ * - a real object, accessed through regular object operations, e.g..,
+ * GetElement corresponding to 'arguments[i]';
+ * - a VM-internal data structure, storing the value of arguments (formal
+ * and actual) that are accessed directly by the VM when a reading the
+ * value of a formal parameter.
+ * There are two ways to access the ArgumentsData::args corresponding to
+ * these two use cases:
+ * - object access should use elements(i) which will take care of
+ * forwarding when the value is the magic forwarding value;
+ * - VM argument access should use arg(i) which will assert that the
+ * value is not the magic forwarding value (since, if such forwarding was
+ * needed, the frontend should have emitted JSOP_GETALIASEDVAR).
+ */
+ const Value& element(uint32_t i) const;
+
+ inline void setElement(JSContext* cx, uint32_t i, const Value& v);
+
+ const Value& arg(unsigned i) const {
+ MOZ_ASSERT(i < data()->numArgs);
+ const Value& v = data()->args[i];
+ MOZ_ASSERT(!v.isMagic());
+ return v;
+ }
+
+ void setArg(unsigned i, const Value& v) {
+ MOZ_ASSERT(i < data()->numArgs);
+ GCPtrValue& lhs = data()->args[i];
+ MOZ_ASSERT(!lhs.isMagic());
+ lhs = v;
+ }
+
+ /*
+ * Attempt to speedily and efficiently access the i-th element of this
+ * arguments object. Return true if the element was speedily returned.
+ * Return false if the element must be looked up more slowly using
+ * getProperty or some similar method. The second overload copies the
+ * elements [start, start + count) into the locations starting at 'vp'.
+ *
+ * NB: Returning false does not indicate error!
+ */
+ bool maybeGetElement(uint32_t i, MutableHandleValue vp) {
+ if (i >= initialLength() || isElementDeleted(i))
+ return false;
+ vp.set(element(i));
+ return true;
+ }
+
+ inline bool maybeGetElements(uint32_t start, uint32_t count, js::Value* vp);
+
+ /*
+ * Measures things hanging off this ArgumentsObject that are counted by the
+ * |miscSize| argument in JSObject::sizeOfExcludingThis().
+ */
+ size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const {
+ if (!data()) // Template arguments objects have no data.
+ return 0;
+ return mallocSizeOf(data()) + mallocSizeOf(maybeRareData());
+ }
+ size_t sizeOfData() const {
+ return ArgumentsData::bytesRequired(data()->numArgs) +
+ (maybeRareData() ? RareArgumentsData::bytesRequired(initialLength()) : 0);
+ }
+
+ static void finalize(FreeOp* fop, JSObject* obj);
+ static void trace(JSTracer* trc, JSObject* obj);
+ static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src);
+
+ /* For jit use: */
+ static size_t getDataSlotOffset() {
+ return getFixedSlotOffset(DATA_SLOT);
+ }
+ static size_t getInitialLengthSlotOffset() {
+ return getFixedSlotOffset(INITIAL_LENGTH_SLOT);
+ }
+
+ static Value MagicEnvSlotValue(uint32_t slot) {
+ // When forwarding slots to a backing CallObject, the slot numbers are
+ // stored as uint32 magic values. This raises an ambiguity if we have
+ // also copied JS_OPTIMIZED_OUT magic from a JIT frame or
+ // JS_UNINITIALIZED_LEXICAL magic on the CallObject. To distinguish
+ // normal magic values (those with a JSWhyMagic) and uint32 magic
+ // values, we add the maximum JSWhyMagic value to the slot
+ // number. This is safe as ARGS_LENGTH_MAX is well below UINT32_MAX.
+ JS_STATIC_ASSERT(UINT32_MAX - JS_WHY_MAGIC_COUNT > ARGS_LENGTH_MAX);
+ return JS::MagicValueUint32(slot + JS_WHY_MAGIC_COUNT);
+ }
+ static uint32_t SlotFromMagicScopeSlotValue(const Value& v) {
+ JS_STATIC_ASSERT(UINT32_MAX - JS_WHY_MAGIC_COUNT > ARGS_LENGTH_MAX);
+ return v.magicUint32() - JS_WHY_MAGIC_COUNT;
+ }
+ static bool IsMagicScopeSlotValue(const Value& v) {
+ return v.isMagic() && v.magicUint32() > JS_WHY_MAGIC_COUNT;
+ }
+
+ static void MaybeForwardToCallObject(AbstractFramePtr frame, ArgumentsObject* obj,
+ ArgumentsData* data);
+ static void MaybeForwardToCallObject(jit::JitFrameLayout* frame, HandleObject callObj,
+ ArgumentsObject* obj, ArgumentsData* data);
+};
+
+class MappedArgumentsObject : public ArgumentsObject
+{
+ static const ClassOps classOps_;
+
+ public:
+ static const Class class_;
+
+ JSFunction& callee() const {
+ return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
+ }
+
+ bool hasOverriddenCallee() const {
+ const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
+ return v.toInt32() & CALLEE_OVERRIDDEN_BIT;
+ }
+
+ void markCalleeOverridden() {
+ uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | CALLEE_OVERRIDDEN_BIT;
+ setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
+ }
+
+ private:
+ static bool obj_enumerate(JSContext* cx, HandleObject obj);
+ static bool obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp);
+};
+
+class UnmappedArgumentsObject : public ArgumentsObject
+{
+ static const ClassOps classOps_;
+
+ public:
+ static const Class class_;
+
+ private:
+ static bool obj_enumerate(JSContext* cx, HandleObject obj);
+ static bool obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp);
+};
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::ArgumentsObject>() const
+{
+ return is<js::MappedArgumentsObject>() || is<js::UnmappedArgumentsObject>();
+}
+
+#endif /* vm_ArgumentsObject_h */
diff --git a/js/src/vm/ArrayBufferObject-inl.h b/js/src/vm/ArrayBufferObject-inl.h
new file mode 100644
index 000000000..af50d4393
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject-inl.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArrayBufferObject_inl_h
+#define vm_ArrayBufferObject_inl_h
+
+/* Utilities and common inline code for ArrayBufferObject and SharedArrayBufferObject */
+
+#include "vm/ArrayBufferObject.h"
+
+#include "js/Value.h"
+
+#include "vm/SharedArrayObject.h"
+#include "vm/SharedMem.h"
+
+namespace js {
+
+inline SharedMem<uint8_t*>
+ArrayBufferObjectMaybeShared::dataPointerEither()
+{
+ ArrayBufferObjectMaybeShared* buf = this;
+ if (buf->is<ArrayBufferObject>())
+ return buf->as<ArrayBufferObject>().dataPointerShared();
+ return buf->as<SharedArrayBufferObject>().dataPointerShared();
+}
+
+inline bool
+ArrayBufferObjectMaybeShared::isDetached() const
+{
+ if (this->is<ArrayBufferObject>())
+ return this->as<ArrayBufferObject>().isDetached();
+ return false;
+}
+
+inline uint32_t
+AnyArrayBufferByteLength(const ArrayBufferObjectMaybeShared* buf)
+{
+ if (buf->is<ArrayBufferObject>())
+ return buf->as<ArrayBufferObject>().byteLength();
+ return buf->as<SharedArrayBufferObject>().byteLength();
+}
+
+inline bool
+AnyArrayBufferIsPreparedForAsmJS(const ArrayBufferObjectMaybeShared* buf)
+{
+ if (buf->is<ArrayBufferObject>())
+ return buf->as<ArrayBufferObject>().isPreparedForAsmJS();
+ return buf->as<SharedArrayBufferObject>().isPreparedForAsmJS();
+}
+
+inline ArrayBufferObjectMaybeShared&
+AsAnyArrayBuffer(HandleValue val)
+{
+ if (val.toObject().is<ArrayBufferObject>())
+ return val.toObject().as<ArrayBufferObject>();
+ return val.toObject().as<SharedArrayBufferObject>();
+}
+
+} // namespace js
+
+#endif // vm_ArrayBufferObject_inl_h
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
new file mode 100644
index 000000000..1053fa99d
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -0,0 +1,1950 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ArrayBufferObject-inl.h"
+#include "vm/ArrayBufferObject.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/TaggedAnonymousMemory.h"
+
+#include <string.h>
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+
+#ifdef MOZ_VALGRIND
+# include <valgrind/memcheck.h>
+#endif
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jscpucfg.h"
+#include "jsfriendapi.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jstypes.h"
+#include "jsutil.h"
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+#include "jswrapper.h"
+
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "gc/Memory.h"
+#include "js/Conversions.h"
+#include "js/MemoryMetrics.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
+#include "vm/SharedArrayObject.h"
+#include "vm/WrapperObject.h"
+#include "wasm/WasmSignalHandlers.h"
+#include "wasm/WasmTypes.h"
+
+#include "jsatominlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Shape-inl.h"
+
+using JS::ToInt32;
+
+using mozilla::DebugOnly;
+using mozilla::CheckedInt;
+using mozilla::Some;
+using mozilla::Maybe;
+using mozilla::Nothing;
+
+using namespace js;
+using namespace js::gc;
+
+/*
+ * Convert |v| to an array index for an array of length |length| per
+ * the Typed Array Specification section 7.0, |subarray|. If successful,
+ * the output value is in the range [0, length].
+ */
+bool
+js::ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out)
+{
+ int32_t result;
+ if (!ToInt32(cx, v, &result))
+ return false;
+ if (result < 0) {
+ result += length;
+ if (result < 0)
+ result = 0;
+ } else if (uint32_t(result) > length) {
+ result = length;
+ }
+ *out = uint32_t(result);
+ return true;
+}
+
+static bool
+arraybuffer_static_slice(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (args.length() < 1) {
+ ReportMissingArg(cx, args.calleev(), 1);
+ return false;
+ }
+
+ if (!GlobalObject::warnOnceAboutArrayBufferSlice(cx, cx->global()))
+ return false;
+
+ FixedInvokeArgs<2> args2(cx);
+ args2[0].set(args.get(1));
+ args2[1].set(args.get(2));
+ return CallSelfHostedFunction(cx, "ArrayBufferSlice", args[0], args2, args.rval());
+}
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the TypedArrayObject classes
+ * access. It can be created explicitly and passed to a TypedArrayObject, or
+ * can be created implicitly by constructing a TypedArrayObject with a size.
+ */
+
+/*
+ * ArrayBufferObject (base)
+ */
+
+static const ClassSpec ArrayBufferObjectProtoClassSpec = {
+ DELEGATED_CLASSSPEC(ArrayBufferObject::class_.spec),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ ClassSpec::IsDelegated
+};
+
+static const Class ArrayBufferObjectProtoClass = {
+ "ArrayBufferPrototype",
+ JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+ JS_NULL_CLASS_OPS,
+ &ArrayBufferObjectProtoClassSpec
+};
+
+static JSObject*
+CreateArrayBufferPrototype(JSContext* cx, JSProtoKey key)
+{
+ return cx->global()->createBlankPrototype(cx, &ArrayBufferObjectProtoClass);
+}
+
+static const ClassOps ArrayBufferObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ ArrayBufferObject::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ArrayBufferObject::trace,
+};
+
+static const JSFunctionSpec static_functions[] = {
+ JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
+ JS_FN("slice", arraybuffer_static_slice, 3, 0),
+ JS_FS_END
+};
+
+static const JSPropertySpec static_properties[] = {
+ JS_SELF_HOSTED_SYM_GET(species, "ArrayBufferSpecies", 0),
+ JS_PS_END
+};
+
+
+static const JSFunctionSpec prototype_functions[] = {
+ JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
+ JS_FS_END
+};
+
+static const JSPropertySpec prototype_properties[] = {
+ JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
+ JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
+ JS_PS_END
+};
+
+static const ClassSpec ArrayBufferObjectClassSpec = {
+ GenericCreateConstructor<ArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
+ CreateArrayBufferPrototype,
+ static_functions,
+ static_properties,
+ prototype_functions,
+ prototype_properties
+};
+
+static const ClassExtension ArrayBufferObjectClassExtension = {
+ nullptr, /* weakmapKeyDelegateOp */
+ ArrayBufferObject::objectMoved
+};
+
+const Class ArrayBufferObject::class_ = {
+ "ArrayBuffer",
+ JSCLASS_DELAY_METADATA_BUILDER |
+ JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &ArrayBufferObjectClassOps,
+ &ArrayBufferObjectClassSpec,
+ &ArrayBufferObjectClassExtension
+};
+
+bool
+js::IsArrayBuffer(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<ArrayBufferObject>();
+}
+
+bool
+js::IsArrayBuffer(HandleObject obj)
+{
+ return obj->is<ArrayBufferObject>();
+}
+
+bool
+js::IsArrayBuffer(JSObject* obj)
+{
+ return obj->is<ArrayBufferObject>();
+}
+
+ArrayBufferObject&
+js::AsArrayBuffer(HandleObject obj)
+{
+ MOZ_ASSERT(IsArrayBuffer(obj));
+ return obj->as<ArrayBufferObject>();
+}
+
+ArrayBufferObject&
+js::AsArrayBuffer(JSObject* obj)
+{
+ MOZ_ASSERT(IsArrayBuffer(obj));
+ return obj->as<ArrayBufferObject>();
+}
+
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+ args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
+ return true;
+}
+
+bool
+ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
+}
+
+/*
+ * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
+ */
+bool
+ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ args.rval().setBoolean(args.get(0).isObject() &&
+ JS_IsArrayBufferViewObject(&args.get(0).toObject()));
+ return true;
+}
+
+/*
+ * new ArrayBuffer(byteLength)
+ */
+bool
+ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "ArrayBuffer"))
+ return false;
+
+ int32_t nbytes = 0;
+ if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
+ return false;
+
+ if (nbytes < 0) {
+ /*
+ * We're just not going to support arrays that are bigger than what will fit
+ * as an integer value; if someone actually ever complains (validly), then we
+ * can fix.
+ */
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+ return false;
+ }
+
+ RootedObject proto(cx);
+ RootedObject newTarget(cx, &args.newTarget().toObject());
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ JSObject* bufobj = create(cx, uint32_t(nbytes), proto);
+ if (!bufobj)
+ return false;
+ args.rval().setObject(*bufobj);
+ return true;
+}
+
+static ArrayBufferObject::BufferContents
+AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
+{
+ uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
+ if (!p)
+ ReportOutOfMemory(cx);
+
+ return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
+}
+
+static void
+NoteViewBufferWasDetached(ArrayBufferViewObject* view,
+ ArrayBufferObject::BufferContents newContents,
+ JSContext* cx)
+{
+ view->notifyBufferDetached(cx, newContents.data());
+
+ // Notify compiled jit code that the base pointer has moved.
+ MarkObjectStateChange(cx, view);
+}
+
+/* static */ void
+ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer,
+ BufferContents newContents)
+{
+ assertSameCompartment(cx, buffer);
+ MOZ_ASSERT(!buffer->isPreparedForAsmJS());
+
+ // When detaching buffers where we don't know all views, the new data must
+ // match the old data. All missing views are typed objects, which do not
+ // expect their data to ever change.
+ MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
+ newContents.data() == buffer->dataPointer());
+
+ // When detaching a buffer with typed object views, any jitcode accessing
+ // such views must be deoptimized so that detachment checks are performed.
+ // This is done by setting a compartment-wide flag indicating that buffers
+ // with typed object views have been detached.
+ if (buffer->hasTypedObjectViews()) {
+ // Make sure the global object's group has been instantiated, so the
+ // flag change will be observed.
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!cx->global()->getGroup(cx))
+ oomUnsafe.crash("ArrayBufferObject::detach");
+ MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER);
+ cx->compartment()->detachedTypedObjects = 1;
+ }
+
+ // Update all views of the buffer to account for the buffer having been
+ // detached, and clear the buffer's data and list of views.
+
+ auto& innerViews = cx->compartment()->innerViews;
+ if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
+ for (size_t i = 0; i < views->length(); i++)
+ NoteViewBufferWasDetached((*views)[i], newContents, cx);
+ innerViews.removeViews(buffer);
+ }
+ if (buffer->firstView()) {
+ if (buffer->forInlineTypedObject()) {
+ // The buffer points to inline data in its first view, so to keep
+ // this pointer alive we don't clear out the first view.
+ MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
+ } else {
+ NoteViewBufferWasDetached(buffer->firstView(), newContents, cx);
+ buffer->setFirstView(nullptr);
+ }
+ }
+
+ if (newContents.data() != buffer->dataPointer())
+ buffer->setNewData(cx->runtime()->defaultFreeOp(), newContents, OwnsData);
+
+ buffer->setByteLength(0);
+ buffer->setIsDetached();
+}
+
+void
+ArrayBufferObject::setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState)
+{
+ if (ownsData()) {
+ MOZ_ASSERT(newContents.data() != dataPointer());
+ releaseData(fop);
+ }
+
+ setDataPointer(newContents, ownsState);
+}
+
+// This is called *only* from changeContents(), below.
+// By construction, every view parameter will be mapping unshared memory (an ArrayBuffer).
+// Hence no reason to worry about shared memory here.
+
+void
+ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
+ uint8_t* oldDataPointer, BufferContents newContents)
+{
+ MOZ_ASSERT(!view->isSharedMemory());
+
+ // Watch out for NULL data pointers in views. This means that the view
+ // is not fully initialized (in which case it'll be initialized later
+ // with the correct pointer).
+ JS::AutoCheckCannotGC nogc(cx);
+ uint8_t* viewDataPointer = view->dataPointerUnshared(nogc);
+ if (viewDataPointer) {
+ MOZ_ASSERT(newContents);
+ ptrdiff_t offset = viewDataPointer - oldDataPointer;
+ viewDataPointer = static_cast<uint8_t*>(newContents.data()) + offset;
+ view->setDataPointerUnshared(viewDataPointer);
+ }
+
+ // Notify compiled jit code that the base pointer has moved.
+ MarkObjectStateChange(cx, view);
+}
+
+// BufferContents is specific to ArrayBuffer, hence it will not represent shared memory.
+
+void
+ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
+ OwnsState ownsState)
+{
+ MOZ_RELEASE_ASSERT(!isWasm());
+ MOZ_ASSERT(!forInlineTypedObject());
+
+ // Change buffer contents.
+ uint8_t* oldDataPointer = dataPointer();
+ setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
+
+ // Update all views.
+ auto& innerViews = cx->compartment()->innerViews;
+ if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
+ for (size_t i = 0; i < views->length(); i++)
+ changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
+ }
+ if (firstView())
+ changeViewContents(cx, firstView(), oldDataPointer, newContents);
+}
+
+/*
+ * Wasm Raw Buf Linear Memory Structure
+ *
+ * The linear heap in Wasm is an mmaped array buffer. Several
+ * constants manage its lifetime:
+ *
+ * - length - the wasm-visible current length of the buffer. Acesses in the
+ * range [0, length] succeed. May only increase
+ *
+ * - boundsCheckLimit - when !WASM_HUGE_MEMORY, the size against which we
+ * perform bounds checks. It is always a constant offset smaller than
+ * mappedSize. Currently that constant offset is 0.
+ *
+ * - max - the optional declared limit on how much length can grow.
+ *
+ * - mappedSize - the actual mmaped size. Access in the range
+ * [0, mappedSize] will either succeed, or be handled by the wasm signal
+ * handlers.
+ *
+ * The below diagram shows the layout of the wams heap. The wasm-visible
+ * portion of the heap starts at 0. There is one extra page prior to the
+ * start of the wasm heap which contains the WasmArrayRawBuffer struct at
+ * its end. (i.e. right before the start of the WASM heap).
+ *
+ * WasmArrayRawBuffer
+ * \ ArrayBufferObject::dataPointer()
+ * \ /
+ * \ |
+ * ______|_|____________________________________________________________
+ * |______|_|______________|___________________|____________|____________|
+ * 0 length maxSize boundsCheckLimit mappedSize
+ *
+ * \_______________________/
+ * COMMITED
+ * \____________________________________________/
+ * SLOP
+ * \_____________________________________________________________________/
+ * MAPPED
+ *
+ * Invariants:
+ * - length only increases
+ * - 0 <= length <= maxSize (if present) <= boundsCheckLimit <= mappedSize
+ * - on ARM boundsCheckLimit must be a valid ARM immediate.
+ * - if maxSize is not specified, boundsCheckLimit/mappedSize may grow. They are
+ * otherwise constant.
+ *
+ * NOTE: For asm.js on non-x64 we guarantee that
+ *
+ * length == maxSize == boundsCheckLimit == mappedSize
+ *
+ * That is, signal handlers will not be invoked, since they cannot emulate
+ * asm.js accesses on non-x64 architectures.
+ *
+ * The region between length and mappedSize is the SLOP - an area where we use
+ * signal handlers to catch things that slip by bounds checks. Logically it has
+ * two parts:
+ *
+ * - from length to boundsCheckLimit - this part of the SLOP serves to catch
+ * accesses to memory we have reserved but not yet grown into. This allows us
+ * to grow memory up to max (when present) without having to patch/update the
+ * bounds checks.
+ *
+ * - from boundsCheckLimit to mappedSize - (Note: In current patch 0) - this
+ * part of the SLOP allows us to bounds check against base pointers and fold
+ * some constant offsets inside loads. This enables better Bounds
+ * Check Elimination.
+ *
+ */
+
+class js::WasmArrayRawBuffer
+{
+ Maybe<uint32_t> maxSize_;
+ size_t mappedSize_;
+
+ protected:
+ WasmArrayRawBuffer(uint8_t* buffer, uint32_t length, Maybe<uint32_t> maxSize, size_t mappedSize)
+ : maxSize_(maxSize), mappedSize_(mappedSize)
+ {
+ MOZ_ASSERT(buffer == dataPointer());
+ }
+
+ public:
+ static WasmArrayRawBuffer* Allocate(uint32_t numBytes, Maybe<uint32_t> maxSize);
+ static void Release(void* mem);
+
+ uint8_t* dataPointer() {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(this);
+ return ptr + sizeof(WasmArrayRawBuffer);
+ }
+
+ uint8_t* basePointer() {
+ return dataPointer() - gc::SystemPageSize();
+ }
+
+ size_t mappedSize() const {
+ return mappedSize_;
+ }
+
+ Maybe<uint32_t> maxSize() const {
+ return maxSize_;
+ }
+
+ size_t allocatedBytes() const {
+ return mappedSize_ + gc::SystemPageSize();
+ }
+
+#ifndef WASM_HUGE_MEMORY
+ uint32_t boundsCheckLimit() const {
+ MOZ_ASSERT(mappedSize_ <= UINT32_MAX);
+ MOZ_ASSERT(mappedSize_ >= wasm::GuardSize);
+ MOZ_ASSERT(wasm::IsValidBoundsCheckImmediate(mappedSize_ - wasm::GuardSize));
+ return mappedSize_ - wasm::GuardSize;
+ }
+#endif
+
+ MOZ_MUST_USE bool growToSizeInPlace(uint32_t oldSize, uint32_t newSize) {
+ MOZ_ASSERT(newSize >= oldSize);
+ MOZ_ASSERT_IF(maxSize(), newSize <= maxSize().value());
+ MOZ_ASSERT(newSize <= mappedSize());
+
+ uint32_t delta = newSize - oldSize;
+ MOZ_ASSERT(delta % wasm::PageSize == 0);
+
+ uint8_t* dataEnd = dataPointer() + oldSize;
+ MOZ_ASSERT(uintptr_t(dataEnd) % gc::SystemPageSize() == 0);
+# ifdef XP_WIN
+ if (delta && !VirtualAlloc(dataEnd, delta, MEM_COMMIT, PAGE_READWRITE))
+ return false;
+# else // XP_WIN
+ if (delta && mprotect(dataEnd, delta, PROT_READ | PROT_WRITE))
+ return false;
+# endif // !XP_WIN
+
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+ VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)dataEnd, delta);
+# endif
+
+ MemProfiler::SampleNative(dataEnd, delta);
+ return true;
+ }
+
+#ifndef WASM_HUGE_MEMORY
+ bool extendMappedSize(uint32_t maxSize) {
+ size_t newMappedSize = wasm::ComputeMappedSize(maxSize);
+ MOZ_ASSERT(mappedSize_ <= newMappedSize);
+ if (mappedSize_ == newMappedSize)
+ return true;
+
+# ifdef XP_WIN
+ uint8_t* mappedEnd = dataPointer() + mappedSize_;
+ uint32_t delta = newMappedSize - mappedSize_;
+ if (!VirtualAlloc(mappedEnd, delta, MEM_RESERVE, PAGE_NOACCESS))
+ return false;
+# elif defined(XP_LINUX)
+ // Note this will not move memory (no MREMAP_MAYMOVE specified)
+ if (MAP_FAILED == mremap(dataPointer(), mappedSize_, newMappedSize, 0))
+ return false;
+# else
+ // No mechanism for remapping on MacOS and other Unices. Luckily
+ // shouldn't need it here as most of these are 64-bit.
+ return false;
+# endif
+
+ mappedSize_ = newMappedSize;
+ return true;
+ }
+
+ // Try and grow the mapped region of memory. Does not changes current size.
+ // Does not move memory if no space to grow.
+ void tryGrowMaxSizeInPlace(uint32_t deltaMaxSize) {
+ CheckedInt<uint32_t> newMaxSize = maxSize_.value();
+ newMaxSize += deltaMaxSize;
+ MOZ_ASSERT(newMaxSize.isValid());
+ MOZ_ASSERT(newMaxSize.value() % wasm::PageSize == 0);
+
+ if (!extendMappedSize(newMaxSize.value()))
+ return;
+
+ maxSize_ = Some(newMaxSize.value());
+ }
+#endif // WASM_HUGE_MEMORY
+};
+
+/* static */ WasmArrayRawBuffer*
+WasmArrayRawBuffer::Allocate(uint32_t numBytes, Maybe<uint32_t> maxSize)
+{
+ size_t mappedSize;
+#ifdef WASM_HUGE_MEMORY
+ mappedSize = wasm::HugeMappedSize;
+#else
+ mappedSize = wasm::ComputeMappedSize(maxSize.valueOr(numBytes));
+#endif
+
+ MOZ_RELEASE_ASSERT(mappedSize <= SIZE_MAX - gc::SystemPageSize());
+ MOZ_RELEASE_ASSERT(numBytes <= maxSize.valueOr(UINT32_MAX));
+ MOZ_ASSERT(numBytes % gc::SystemPageSize() == 0);
+ MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);
+
+ uint64_t mappedSizeWithHeader = mappedSize + gc::SystemPageSize();
+ uint64_t numBytesWithHeader = numBytes + gc::SystemPageSize();
+
+# ifdef XP_WIN
+ void* data = VirtualAlloc(nullptr, (size_t) mappedSizeWithHeader, MEM_RESERVE, PAGE_NOACCESS);
+ if (!data)
+ return nullptr;
+
+ if (!VirtualAlloc(data, numBytesWithHeader, MEM_COMMIT, PAGE_READWRITE)) {
+ VirtualFree(data, 0, MEM_RELEASE);
+ return nullptr;
+ }
+# else // XP_WIN
+ void* data = MozTaggedAnonymousMmap(nullptr, (size_t) mappedSizeWithHeader, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON, -1, 0, "wasm-reserved");
+ if (data == MAP_FAILED)
+ return nullptr;
+
+ // Note we will waste a page on zero-sized memories here
+ if (mprotect(data, numBytesWithHeader, PROT_READ | PROT_WRITE)) {
+ munmap(data, mappedSizeWithHeader);
+ return nullptr;
+ }
+# endif // !XP_WIN
+ MemProfiler::SampleNative(data, numBytesWithHeader);
+
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+ VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)data + numBytesWithHeader,
+ mappedSizeWithHeader - numBytesWithHeader);
+# endif
+
+ uint8_t* base = reinterpret_cast<uint8_t*>(data) + gc::SystemPageSize();
+ uint8_t* header = base - sizeof(WasmArrayRawBuffer);
+
+ auto rawBuf = new (header) WasmArrayRawBuffer(base, numBytes, maxSize, mappedSize);
+ return rawBuf;
+}
+
+/* static */ void
+WasmArrayRawBuffer::Release(void* mem)
+{
+ WasmArrayRawBuffer* header = (WasmArrayRawBuffer*)((uint8_t*)mem - sizeof(WasmArrayRawBuffer));
+ uint8_t* base = header->basePointer();
+ MOZ_RELEASE_ASSERT(header->mappedSize() <= SIZE_MAX - gc::SystemPageSize());
+ size_t mappedSizeWithHeader = header->mappedSize() + gc::SystemPageSize();
+
+ MemProfiler::RemoveNative(base);
+# ifdef XP_WIN
+ VirtualFree(base, 0, MEM_RELEASE);
+# else // XP_WIN
+ munmap(base, mappedSizeWithHeader);
+# endif // !XP_WIN
+
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+ VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(base, mappedSizeWithHeader);
+# endif
+}
+
+WasmArrayRawBuffer*
+ArrayBufferObject::BufferContents::wasmBuffer() const
+{
+ MOZ_RELEASE_ASSERT(kind_ == WASM);
+ return (WasmArrayRawBuffer*)(data_ - sizeof(WasmArrayRawBuffer));
+}
+
+#define ROUND_UP(v, a) ((v) % (a) == 0 ? (v) : v + a - ((v) % (a)))
+
+/* static */ ArrayBufferObject*
+ArrayBufferObject::createForWasm(JSContext* cx, uint32_t initialSize, Maybe<uint32_t> maxSize)
+{
+ MOZ_ASSERT(initialSize % wasm::PageSize == 0);
+ MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+
+ // Prevent applications specifying a large max (like UINT32_MAX) from
+ // unintentially OOMing the browser on 32-bit: they just want "a lot of
+ // memory". Maintain the invariant that initialSize <= maxSize.
+ if (sizeof(void*) == 4 && maxSize) {
+ static const uint32_t OneGiB = 1 << 30;
+ uint32_t clamp = Max(OneGiB, initialSize);
+ maxSize = Some(Min(clamp, maxSize.value()));
+ }
+
+ RootedArrayBufferObject buffer(cx, ArrayBufferObject::createEmpty(cx));
+ if (!buffer)
+ return nullptr;
+
+ // Try to reserve the maximum requested memory
+ WasmArrayRawBuffer* wasmBuf = WasmArrayRawBuffer::Allocate(initialSize, maxSize);
+ if (!wasmBuf) {
+#ifdef WASM_HUGE_MEMORY
+ ReportOutOfMemory(cx);
+ return nullptr;
+#else
+ // If we fail, and have a maxSize, try to reserve the biggest chunk in
+ // the range [initialSize, maxSize) using log backoff.
+ if (!maxSize) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ uint32_t cur = maxSize.value() / 2;
+
+ for (; cur > initialSize; cur /= 2) {
+ wasmBuf = WasmArrayRawBuffer::Allocate(initialSize, Some(ROUND_UP(cur, wasm::PageSize)));
+ if (wasmBuf)
+ break;
+ }
+
+ if (!wasmBuf) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ // Try to grow our chunk as much as possible.
+ for (size_t d = cur / 2; d >= wasm::PageSize; d /= 2)
+ wasmBuf->tryGrowMaxSizeInPlace(ROUND_UP(d, wasm::PageSize));
+#endif
+ }
+
+ auto contents = BufferContents::create<WASM>(wasmBuf->dataPointer());
+ buffer->initialize(initialSize, contents, OwnsData);
+ cx->zone()->updateMallocCounter(wasmBuf->mappedSize());
+ return buffer;
+}
+
+// Note this function can return false with or without an exception pending. The
+// asm.js caller checks cx->isExceptionPending before propagating failure.
+// Returning false without throwing means that asm.js linking will fail which
+// will recompile as non-asm.js.
+/* static */ bool
+ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer, bool needGuard)
+{
+#ifdef WASM_HUGE_MEMORY
+ MOZ_ASSERT(needGuard);
+#endif
+ MOZ_ASSERT(buffer->byteLength() % wasm::PageSize == 0);
+ MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+
+ if (buffer->forInlineTypedObject())
+ return false;
+
+ if (needGuard) {
+ if (buffer->isWasm() && buffer->isPreparedForAsmJS())
+ return true;
+
+ // Non-prepared-for-asm.js wasm buffers can be detached at any time.
+ // This error can only be triggered for SIMD.js (which isn't shipping)
+ // on !WASM_HUGE_MEMORY so this error is only visible in testing.
+ if (buffer->isWasm() || buffer->isPreparedForAsmJS())
+ return false;
+
+ uint32_t length = buffer->byteLength();
+ WasmArrayRawBuffer* wasmBuf = WasmArrayRawBuffer::Allocate(length, Some(length));
+ if (!wasmBuf) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ void* data = wasmBuf->dataPointer();
+ memcpy(data, buffer->dataPointer(), length);
+
+ // Swap the new elements into the ArrayBufferObject. Mark the
+ // ArrayBufferObject so we don't do this again.
+ buffer->changeContents(cx, BufferContents::create<WASM>(data), OwnsData);
+ buffer->setIsPreparedForAsmJS();
+ MOZ_ASSERT(data == buffer->dataPointer());
+ cx->zone()->updateMallocCounter(wasmBuf->mappedSize());
+ return true;
+ }
+
+ if (!buffer->isWasm() && buffer->isPreparedForAsmJS())
+ return true;
+
+ // Non-prepared-for-asm.js wasm buffers can be detached at any time.
+ if (buffer->isWasm())
+ return false;
+
+ if (!buffer->ownsData()) {
+ BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
+ if (!contents)
+ return false;
+ memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
+ buffer->changeContents(cx, contents, OwnsData);
+ }
+
+ buffer->setIsPreparedForAsmJS();
+ return true;
+}
+
+ArrayBufferObject::BufferContents
+ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
+{
+ void* data = AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
+ MemProfiler::SampleNative(data, length);
+ return BufferContents::create<MAPPED>(data);
+}
+
+uint8_t*
+ArrayBufferObject::inlineDataPointer() const
+{
+ return static_cast<uint8_t*>(fixedData(JSCLASS_RESERVED_SLOTS(&class_)));
+}
+
+uint8_t*
+ArrayBufferObject::dataPointer() const
+{
+ return static_cast<uint8_t*>(getSlot(DATA_SLOT).toPrivate());
+}
+
+SharedMem<uint8_t*>
+ArrayBufferObject::dataPointerShared() const
+{
+ return SharedMem<uint8_t*>::unshared(getSlot(DATA_SLOT).toPrivate());
+}
+
+void
+ArrayBufferObject::releaseData(FreeOp* fop)
+{
+ MOZ_ASSERT(ownsData());
+
+ switch (bufferKind()) {
+ case PLAIN:
+ fop->free_(dataPointer());
+ break;
+ case MAPPED:
+ MemProfiler::RemoveNative(dataPointer());
+ DeallocateMappedContent(dataPointer(), byteLength());
+ break;
+ case WASM:
+ WasmArrayRawBuffer::Release(dataPointer());
+ break;
+ case KIND_MASK:
+ MOZ_CRASH("bad bufferKind()");
+ }
+}
+
+void
+ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
+{
+ setSlot(DATA_SLOT, PrivateValue(contents.data()));
+ setOwnsData(ownsData);
+ setFlags((flags() & ~KIND_MASK) | contents.kind());
+}
+
+uint32_t
+ArrayBufferObject::byteLength() const
+{
+ return getSlot(BYTE_LENGTH_SLOT).toInt32();
+}
+
+void
+ArrayBufferObject::setByteLength(uint32_t length)
+{
+ MOZ_ASSERT(length <= INT32_MAX);
+ setSlot(BYTE_LENGTH_SLOT, Int32Value(length));
+}
+
+size_t
+ArrayBufferObject::wasmMappedSize() const
+{
+ if (isWasm())
+ return contents().wasmBuffer()->mappedSize();
+ return byteLength();
+}
+
+size_t
+js::WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf)
+{
+ if (buf->is<ArrayBufferObject>())
+ return buf->as<ArrayBufferObject>().wasmMappedSize();
+#ifdef WASM_HUGE_MEMORY
+ return wasm::HugeMappedSize;
+#else
+ return buf->as<SharedArrayBufferObject>().byteLength();
+#endif
+}
+
+Maybe<uint32_t>
+ArrayBufferObject::wasmMaxSize() const
+{
+ if (isWasm())
+ return contents().wasmBuffer()->maxSize();
+ else
+ return Some<uint32_t>(byteLength());
+}
+
+Maybe<uint32_t>
+js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf)
+{
+ if (buf->is<ArrayBufferObject>())
+ return buf->as<ArrayBufferObject>().wasmMaxSize();
+
+ return Some(buf->as<SharedArrayBufferObject>().byteLength());
+}
+
+/* static */ bool
+ArrayBufferObject::wasmGrowToSizeInPlace(uint32_t newSize,
+ HandleArrayBufferObject oldBuf,
+ MutableHandleArrayBufferObject newBuf,
+ JSContext* cx)
+{
+ // On failure, do not throw and ensure that the original buffer is
+ // unmodified and valid. After WasmArrayRawBuffer::growToSizeInPlace(), the
+ // wasm-visible length of the buffer has been increased so it must be the
+ // last fallible operation.
+
+ // byteLength can be at most INT32_MAX.
+ if (newSize > INT32_MAX)
+ return false;
+
+ newBuf.set(ArrayBufferObject::createEmpty(cx));
+ if (!newBuf) {
+ cx->clearPendingException();
+ return false;
+ }
+
+ if (!oldBuf->contents().wasmBuffer()->growToSizeInPlace(oldBuf->byteLength(), newSize))
+ return false;
+
+ bool hasStealableContents = true;
+ BufferContents contents = ArrayBufferObject::stealContents(cx, oldBuf, hasStealableContents);
+ MOZ_ASSERT(contents);
+ newBuf->initialize(newSize, contents, OwnsData);
+ return true;
+}
+
+#ifndef WASM_HUGE_MEMORY
+/* static */ bool
+ArrayBufferObject::wasmMovingGrowToSize(uint32_t newSize,
+ HandleArrayBufferObject oldBuf,
+ MutableHandleArrayBufferObject newBuf,
+ JSContext* cx)
+{
+ // On failure, do not throw and ensure that the original buffer is
+ // unmodified and valid.
+
+ // byteLength can be at most INT32_MAX.
+ if (newSize > INT32_MAX)
+ return false;
+
+ if (newSize <= oldBuf->wasmBoundsCheckLimit() ||
+ oldBuf->contents().wasmBuffer()->extendMappedSize(newSize))
+ {
+ return wasmGrowToSizeInPlace(newSize, oldBuf, newBuf, cx);
+ }
+
+ newBuf.set(ArrayBufferObject::createEmpty(cx));
+ if (!newBuf) {
+ cx->clearPendingException();
+ return false;
+ }
+
+ WasmArrayRawBuffer* newRawBuf = WasmArrayRawBuffer::Allocate(newSize, Nothing());
+ if (!newRawBuf)
+ return false;
+ BufferContents contents = BufferContents::create<WASM>(newRawBuf->dataPointer());
+ newBuf->initialize(newSize, contents, OwnsData);
+
+ memcpy(newBuf->dataPointer(), oldBuf->dataPointer(), oldBuf->byteLength());
+ ArrayBufferObject::detach(cx, oldBuf, BufferContents::createPlain(nullptr));
+ return true;
+}
+
+uint32_t
+ArrayBufferObject::wasmBoundsCheckLimit() const
+{
+ if (isWasm())
+ return contents().wasmBuffer()->boundsCheckLimit();
+ else
+ return byteLength();
+}
+
+uint32_t
+ArrayBufferObjectMaybeShared::wasmBoundsCheckLimit() const
+{
+ if (is<ArrayBufferObject>())
+ return as<ArrayBufferObject>().wasmBoundsCheckLimit();
+
+ return as<SharedArrayBufferObject>().byteLength();
+}
+#endif
+
+uint32_t
+ArrayBufferObject::flags() const
+{
+ return uint32_t(getSlot(FLAGS_SLOT).toInt32());
+}
+
+void
+ArrayBufferObject::setFlags(uint32_t flags)
+{
+ setSlot(FLAGS_SLOT, Int32Value(flags));
+}
+
+ArrayBufferObject*
+ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
+ OwnsState ownsState /* = OwnsData */,
+ HandleObject proto /* = nullptr */,
+ NewObjectKind newKind /* = GenericObject */)
+{
+ MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
+
+ // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
+ // Refuse to allocate too large buffers, currently limited to ~2 GiB.
+ if (nbytes > INT32_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+ return nullptr;
+ }
+
+ // If we need to allocate data, try to use a larger object size class so
+ // that the array buffer's data can be allocated inline with the object.
+ // The extra space will be left unused by the object's fixed slots and
+ // available for the buffer's data, see NewObject().
+ size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
+
+ size_t nslots = reservedSlots;
+ bool allocated = false;
+ if (contents) {
+ if (ownsState == OwnsData) {
+ // The ABO is taking ownership, so account the bytes against the zone.
+ size_t nAllocated = nbytes;
+ if (contents.kind() == MAPPED)
+ nAllocated = JS_ROUNDUP(nbytes, js::gc::SystemPageSize());
+ else if (contents.kind() == WASM)
+ nAllocated = contents.wasmBuffer()->allocatedBytes();
+ cx->zone()->updateMallocCounter(nAllocated);
+ }
+ } else {
+ MOZ_ASSERT(ownsState == OwnsData);
+ size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
+ if (nbytes <= usableSlots * sizeof(Value)) {
+ int newSlots = (nbytes - 1) / sizeof(Value) + 1;
+ MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
+ nslots = reservedSlots + newSlots;
+ contents = BufferContents::createPlain(nullptr);
+ } else {
+ contents = AllocateArrayBufferContents(cx, nbytes);
+ if (!contents)
+ return nullptr;
+ allocated = true;
+ }
+ }
+
+ MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
+ gc::AllocKind allocKind = GetGCObjectKind(nslots);
+
+ AutoSetNewObjectMetadata metadata(cx);
+ Rooted<ArrayBufferObject*> obj(cx,
+ NewObjectWithClassProto<ArrayBufferObject>(cx, proto, allocKind, newKind));
+ if (!obj) {
+ if (allocated)
+ js_free(contents.data());
+ return nullptr;
+ }
+
+ MOZ_ASSERT(obj->getClass() == &class_);
+ MOZ_ASSERT(!gc::IsInsideNursery(obj));
+
+ if (!contents) {
+ void* data = obj->inlineDataPointer();
+ memset(data, 0, nbytes);
+ obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData);
+ } else {
+ obj->initialize(nbytes, contents, ownsState);
+ }
+
+ return obj;
+}
+
+ArrayBufferObject*
+ArrayBufferObject::create(JSContext* cx, uint32_t nbytes,
+ HandleObject proto /* = nullptr */,
+ NewObjectKind newKind /* = GenericObject */)
+{
+ return create(cx, nbytes, BufferContents::createPlain(nullptr),
+ OwnsState::OwnsData, proto);
+}
+
+ArrayBufferObject*
+ArrayBufferObject::createEmpty(JSContext* cx)
+{
+ AutoSetNewObjectMetadata metadata(cx);
+ ArrayBufferObject* obj = NewObjectWithClassProto<ArrayBufferObject>(cx, nullptr);
+ if (!obj)
+ return nullptr;
+
+ obj->initEmpty();
+ return obj;
+}
+
+bool
+ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(IsArrayBuffer(args.thisv()));
+
+ /*
+ * This method is only called for |DataView(alienBuf, ...)| which calls
+ * this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength,
+ * DataView.prototype)|,
+ * ergo there must be exactly 3 arguments.
+ */
+ MOZ_ASSERT(args.length() == 3);
+
+ uint32_t byteOffset = args[0].toPrivateUint32();
+ uint32_t byteLength = args[1].toPrivateUint32();
+ Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
+
+ /*
+ * Pop off the passed-along prototype and delegate to normal DataViewObject
+ * construction.
+ */
+ JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject());
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+}
+
+bool
+ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
+}
+
+/* static */ ArrayBufferObject::BufferContents
+ArrayBufferObject::externalizeContents(JSContext* cx, Handle<ArrayBufferObject*> buffer,
+ bool hasStealableContents)
+{
+ MOZ_ASSERT(buffer->isPlain(), "Only support doing this on plain ABOs");
+ MOZ_ASSERT(!buffer->isDetached(), "must have contents to externalize");
+ MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
+
+ BufferContents contents(buffer->dataPointer(), buffer->bufferKind());
+
+ if (hasStealableContents) {
+ buffer->setOwnsData(DoesntOwnData);
+ return contents;
+ }
+
+ // Create a new chunk of memory to return since we cannot steal the
+ // existing contents away from the buffer.
+ BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
+ if (!newContents)
+ return BufferContents::createPlain(nullptr);
+ memcpy(newContents.data(), contents.data(), buffer->byteLength());
+ buffer->changeContents(cx, newContents, DoesntOwnData);
+
+ return newContents;
+}
+
+/* static */ ArrayBufferObject::BufferContents
+ArrayBufferObject::stealContents(JSContext* cx, Handle<ArrayBufferObject*> buffer,
+ bool hasStealableContents)
+{
+ // While wasm buffers cannot generally be transferred by content, the
+ // stealContents() is used internally by the impl of memory growth.
+ MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents() ||
+ (buffer->isWasm() && !buffer->isPreparedForAsmJS()));
+ assertSameCompartment(cx, buffer);
+
+ BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind());
+
+ if (hasStealableContents) {
+ // Return the old contents and reset the detached buffer's data
+ // pointer. This pointer should never be accessed.
+ auto newContents = BufferContents::createPlain(nullptr);
+ buffer->setOwnsData(DoesntOwnData); // Do not free the stolen data.
+ ArrayBufferObject::detach(cx, buffer, newContents);
+ buffer->setOwnsData(DoesntOwnData); // Do not free the nullptr.
+ return oldContents;
+ }
+
+ // Create a new chunk of memory to return since we cannot steal the
+ // existing contents away from the buffer.
+ BufferContents contentsCopy = AllocateArrayBufferContents(cx, buffer->byteLength());
+ if (!contentsCopy)
+ return BufferContents::createPlain(nullptr);
+
+ if (buffer->byteLength() > 0)
+ memcpy(contentsCopy.data(), oldContents.data(), buffer->byteLength());
+ ArrayBufferObject::detach(cx, buffer, oldContents);
+ return contentsCopy;
+}
+
+/* static */ void
+ArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
+ JS::ClassInfo* info)
+{
+ ArrayBufferObject& buffer = AsArrayBuffer(obj);
+
+ if (!buffer.ownsData())
+ return;
+
+ switch (buffer.bufferKind()) {
+ case PLAIN:
+ if (buffer.isPreparedForAsmJS())
+ info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
+ else
+ info->objectsMallocHeapElementsNormal += mallocSizeOf(buffer.dataPointer());
+ break;
+ case MAPPED:
+ info->objectsNonHeapElementsNormal += buffer.byteLength();
+ break;
+ case WASM:
+ info->objectsNonHeapElementsWasm += buffer.byteLength();
+ MOZ_ASSERT(buffer.wasmMappedSize() >= buffer.byteLength());
+ info->wasmGuardPages += buffer.wasmMappedSize() - buffer.byteLength();
+ break;
+ case KIND_MASK:
+ MOZ_CRASH("bad bufferKind()");
+ }
+}
+
+/* static */ void
+ArrayBufferObject::finalize(FreeOp* fop, JSObject* obj)
+{
+ ArrayBufferObject& buffer = obj->as<ArrayBufferObject>();
+
+ if (buffer.ownsData())
+ buffer.releaseData(fop);
+}
+
+/* static */ void
+ArrayBufferObject::copyData(Handle<ArrayBufferObject*> toBuffer,
+ Handle<ArrayBufferObject*> fromBuffer,
+ uint32_t fromIndex, uint32_t count)
+{
+ MOZ_ASSERT(toBuffer->byteLength() >= count);
+ MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
+ MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex + count);
+
+ memcpy(toBuffer->dataPointer(), fromBuffer->dataPointer() + fromIndex, count);
+}
+
+/* static */ void
+ArrayBufferObject::trace(JSTracer* trc, JSObject* obj)
+{
+ // If this buffer is associated with an inline typed object,
+ // fix up the data pointer if the typed object was moved.
+ ArrayBufferObject& buf = obj->as<ArrayBufferObject>();
+
+ if (!buf.forInlineTypedObject())
+ return;
+
+ JSObject* view = MaybeForwarded(buf.firstView());
+ MOZ_ASSERT(view && view->is<InlineTransparentTypedObject>());
+
+ TraceManuallyBarrieredEdge(trc, &view, "array buffer inline typed object owner");
+ buf.setSlot(DATA_SLOT, PrivateValue(view->as<InlineTransparentTypedObject>().inlineTypedMem()));
+}
+
+/* static */ void
+ArrayBufferObject::objectMoved(JSObject* obj, const JSObject* old)
+{
+ ArrayBufferObject& dst = obj->as<ArrayBufferObject>();
+ const ArrayBufferObject& src = old->as<ArrayBufferObject>();
+
+ // Fix up possible inline data pointer.
+ if (src.hasInlineData())
+ dst.setSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
+}
+
+ArrayBufferViewObject*
+ArrayBufferObject::firstView()
+{
+ return getSlot(FIRST_VIEW_SLOT).isObject()
+ ? static_cast<ArrayBufferViewObject*>(&getSlot(FIRST_VIEW_SLOT).toObject())
+ : nullptr;
+}
+
+void
+ArrayBufferObject::setFirstView(ArrayBufferViewObject* view)
+{
+ setSlot(FIRST_VIEW_SLOT, ObjectOrNullValue(view));
+}
+
+bool
+ArrayBufferObject::addView(JSContext* cx, JSObject* viewArg)
+{
+ // Note: we don't pass in an ArrayBufferViewObject as the argument due to
+ // tricky inheritance in the various view classes. View classes do not
+ // inherit from ArrayBufferViewObject so won't be upcast automatically.
+ MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
+ ArrayBufferViewObject* view = static_cast<ArrayBufferViewObject*>(viewArg);
+
+ if (!firstView()) {
+ setFirstView(view);
+ return true;
+ }
+ return cx->compartment()->innerViews.get().addView(cx, this, view);
+}
+
+/*
+ * InnerViewTable
+ */
+
+static size_t VIEW_LIST_MAX_LENGTH = 500;
+
+bool
+InnerViewTable::addView(JSContext* cx, ArrayBufferObject* buffer, ArrayBufferViewObject* view)
+{
+ // ArrayBufferObject entries are only added when there are multiple views.
+ MOZ_ASSERT(buffer->firstView());
+
+ if (!map.initialized() && !map.init()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ Map::AddPtr p = map.lookupForAdd(buffer);
+
+ MOZ_ASSERT(!gc::IsInsideNursery(buffer));
+ bool addToNursery = nurseryKeysValid && gc::IsInsideNursery(view);
+
+ if (p) {
+ ViewVector& views = p->value();
+ MOZ_ASSERT(!views.empty());
+
+ if (addToNursery) {
+ // Only add the entry to |nurseryKeys| if it isn't already there.
+ if (views.length() >= VIEW_LIST_MAX_LENGTH) {
+ // To avoid quadratic blowup, skip the loop below if we end up
+ // adding enormous numbers of views for the same object.
+ nurseryKeysValid = false;
+ } else {
+ for (size_t i = 0; i < views.length(); i++) {
+ if (gc::IsInsideNursery(views[i])) {
+ addToNursery = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!views.append(view)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ } else {
+ if (!map.add(p, buffer, ViewVector())) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ // ViewVector has one inline element, so the first insertion is
+ // guaranteed to succeed.
+ MOZ_ALWAYS_TRUE(p->value().append(view));
+ }
+
+ if (addToNursery && !nurseryKeys.append(buffer))
+ nurseryKeysValid = false;
+
+ return true;
+}
+
+InnerViewTable::ViewVector*
+InnerViewTable::maybeViewsUnbarriered(ArrayBufferObject* buffer)
+{
+ if (!map.initialized())
+ return nullptr;
+
+ Map::Ptr p = map.lookup(buffer);
+ if (p)
+ return &p->value();
+ return nullptr;
+}
+
+void
+InnerViewTable::removeViews(ArrayBufferObject* buffer)
+{
+ Map::Ptr p = map.lookup(buffer);
+ MOZ_ASSERT(p);
+
+ map.remove(p);
+}
+
+/* static */ bool
+InnerViewTable::sweepEntry(JSObject** pkey, ViewVector& views)
+{
+ if (IsAboutToBeFinalizedUnbarriered(pkey))
+ return true;
+
+ MOZ_ASSERT(!views.empty());
+ for (size_t i = 0; i < views.length(); i++) {
+ if (IsAboutToBeFinalizedUnbarriered(&views[i])) {
+ views[i--] = views.back();
+ views.popBack();
+ }
+ }
+
+ return views.empty();
+}
+
+void
+InnerViewTable::sweep()
+{
+ MOZ_ASSERT(nurseryKeys.empty());
+ map.sweep();
+}
+
+void
+InnerViewTable::sweepAfterMinorGC()
+{
+ MOZ_ASSERT(needsSweepAfterMinorGC());
+
+ if (nurseryKeysValid) {
+ for (size_t i = 0; i < nurseryKeys.length(); i++) {
+ JSObject* buffer = MaybeForwarded(nurseryKeys[i]);
+ Map::Ptr p = map.lookup(buffer);
+ if (!p)
+ continue;
+
+ if (sweepEntry(&p->mutableKey(), p->value()))
+ map.remove(buffer);
+ }
+ nurseryKeys.clear();
+ } else {
+ // Do the required sweeping by looking at every map entry.
+ nurseryKeys.clear();
+ sweep();
+
+ nurseryKeysValid = true;
+ }
+}
+
+size_t
+InnerViewTable::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ if (!map.initialized())
+ return 0;
+
+ size_t vectorSize = 0;
+ for (Map::Enum e(map); !e.empty(); e.popFront())
+ vectorSize += e.front().value().sizeOfExcludingThis(mallocSizeOf);
+
+ return vectorSize
+ + map.sizeOfExcludingThis(mallocSizeOf)
+ + nurseryKeys.sizeOfExcludingThis(mallocSizeOf);
+}
+
+/*
+ * ArrayBufferViewObject
+ */
+
+/*
+ * This method is used to trace TypedArrayObjects and DataViewObjects. We need
+ * a custom tracer to move the object's data pointer if its owner was moved and
+ * stores its data inline.
+ */
+/* static */ void
+ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg)
+{
+ NativeObject* obj = &objArg->as<NativeObject>();
+ HeapSlot& bufSlot = obj->getFixedSlotRef(TypedArrayObject::BUFFER_SLOT);
+ TraceEdge(trc, &bufSlot, "typedarray.buffer");
+
+ // Update obj's data pointer if it moved.
+ if (bufSlot.isObject()) {
+ if (IsArrayBuffer(&bufSlot.toObject())) {
+ ArrayBufferObject& buf = AsArrayBuffer(MaybeForwarded(&bufSlot.toObject()));
+ uint32_t offset = uint32_t(obj->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT).toInt32());
+ MOZ_ASSERT(offset <= INT32_MAX);
+
+ if (buf.forInlineTypedObject()) {
+ MOZ_ASSERT(buf.dataPointer() != nullptr);
+
+ // The data is inline with an InlineTypedObject associated with the
+ // buffer. Get a new address for the typed object if it moved.
+ JSObject* view = buf.firstView();
+
+ // Mark the object to move it into the tenured space.
+ TraceManuallyBarrieredEdge(trc, &view, "typed array nursery owner");
+ MOZ_ASSERT(view->is<InlineTypedObject>());
+ MOZ_ASSERT(view != obj);
+
+ void* srcData = obj->getPrivate();
+ void* dstData = view->as<InlineTypedObject>().inlineTypedMemForGC() + offset;
+ obj->setPrivateUnbarriered(dstData);
+
+ // We can't use a direct forwarding pointer here, as there might
+ // not be enough bytes available, and other views might have data
+ // pointers whose forwarding pointers would overlap this one.
+ trc->runtime()->gc.nursery.maybeSetForwardingPointer(trc, srcData, dstData,
+ /* direct = */ false);
+ } else {
+ MOZ_ASSERT_IF(buf.dataPointer() == nullptr, offset == 0);
+
+ // The data may or may not be inline with the buffer. The buffer
+ // can only move during a compacting GC, in which case its
+ // objectMoved hook has already updated the buffer's data pointer.
+ obj->initPrivate(buf.dataPointer() + offset);
+ }
+ }
+ }
+}
+
+template <>
+bool
+JSObject::is<js::ArrayBufferViewObject>() const
+{
+ return is<DataViewObject>() || is<TypedArrayObject>();
+}
+
+template <>
+bool
+JSObject::is<js::ArrayBufferObjectMaybeShared>() const
+{
+ return is<ArrayBufferObject>() || is<SharedArrayBufferObject>();
+}
+
+void
+ArrayBufferViewObject::notifyBufferDetached(JSContext* cx, void* newData)
+{
+ if (is<DataViewObject>()) {
+ as<DataViewObject>().notifyBufferDetached(newData);
+ } else if (is<TypedArrayObject>()) {
+ if (as<TypedArrayObject>().isSharedMemory())
+ return;
+ as<TypedArrayObject>().notifyBufferDetached(cx, newData);
+ } else {
+ as<OutlineTypedObject>().notifyBufferDetached(newData);
+ }
+}
+
+uint8_t*
+ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc)
+{
+ if (is<DataViewObject>())
+ return static_cast<uint8_t*>(as<DataViewObject>().dataPointer());
+ if (is<TypedArrayObject>()) {
+ MOZ_ASSERT(!as<TypedArrayObject>().isSharedMemory());
+ return static_cast<uint8_t*>(as<TypedArrayObject>().viewDataUnshared());
+ }
+ return as<TypedObject>().typedMem(nogc);
+}
+
+#ifdef DEBUG
+bool
+ArrayBufferViewObject::isSharedMemory()
+{
+ if (is<TypedArrayObject>())
+ return as<TypedArrayObject>().isSharedMemory();
+ return false;
+}
+#endif
+
+void
+ArrayBufferViewObject::setDataPointerUnshared(uint8_t* data)
+{
+ if (is<DataViewObject>()) {
+ as<DataViewObject>().setPrivate(data);
+ } else if (is<TypedArrayObject>()) {
+ MOZ_ASSERT(!as<TypedArrayObject>().isSharedMemory());
+ as<TypedArrayObject>().setPrivate(data);
+ } else if (is<OutlineTypedObject>()) {
+ as<OutlineTypedObject>().setData(data);
+ } else {
+ MOZ_CRASH();
+ }
+}
+
+/* static */ ArrayBufferObjectMaybeShared*
+ArrayBufferViewObject::bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> thisObject)
+{
+ if (thisObject->is<TypedArrayObject>()) {
+ Rooted<TypedArrayObject*> typedArray(cx, &thisObject->as<TypedArrayObject>());
+ if (!TypedArrayObject::ensureHasBuffer(cx, typedArray))
+ return nullptr;
+ return thisObject->as<TypedArrayObject>().bufferEither();
+ }
+ MOZ_ASSERT(thisObject->is<DataViewObject>());
+ return &thisObject->as<DataViewObject>().arrayBuffer();
+}
+
+/* JS Friend API */
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferViewObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj && obj->is<ArrayBufferViewObject>();
+}
+
+JS_FRIEND_API(JSObject*)
+js::UnwrapArrayBufferView(JSObject* obj)
+{
+ if (JSObject* unwrapped = CheckedUnwrap(obj))
+ return unwrapped->is<ArrayBufferViewObject>() ? unwrapped : nullptr;
+ return nullptr;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferByteLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? AsArrayBuffer(obj).byteLength() : 0;
+}
+
+JS_FRIEND_API(uint8_t*)
+JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ if (!IsArrayBuffer(obj))
+ return nullptr;
+ *isSharedMemory = false;
+ return AsArrayBuffer(obj).dataPointer();
+}
+
+JS_FRIEND_API(bool)
+JS_DetachArrayBuffer(JSContext* cx, HandleObject obj)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ assertSameCompartment(cx, obj);
+
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportErrorASCII(cx, "ArrayBuffer object required");
+ return false;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+
+ if (buffer->isWasm() || buffer->isPreparedForAsmJS()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
+ return false;
+ }
+
+ ArrayBufferObject::BufferContents newContents =
+ buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr)
+ : buffer->contents();
+
+ ArrayBufferObject::detach(cx, buffer, newContents);
+
+ return true;
+}
+
+JS_FRIEND_API(bool)
+JS_IsDetachedArrayBufferObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return false;
+
+ return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isDetached();
+}
+
+JS_FRIEND_API(JSObject*)
+JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_ASSERT(nbytes <= INT32_MAX);
+ return ArrayBufferObject::create(cx, nbytes);
+}
+
+JS_PUBLIC_API(JSObject*)
+JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_ASSERT_IF(!data, nbytes == 0);
+ ArrayBufferObject::BufferContents contents =
+ ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
+ return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
+ /* proto = */ nullptr, TenuredObject);
+}
+
+JS_PUBLIC_API(JSObject*)
+JS_NewArrayBufferWithExternalContents(JSContext* cx, size_t nbytes, void* data)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_ASSERT_IF(!data, nbytes == 0);
+ ArrayBufferObject::BufferContents contents =
+ ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
+ return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::DoesntOwnData,
+ /* proto = */ nullptr, TenuredObject);
+}
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj && obj->is<ArrayBufferObject>();
+}
+
+JS_FRIEND_API(bool)
+JS_ArrayBufferHasData(JSObject* obj)
+{
+ return CheckedUnwrap(obj)->as<ArrayBufferObject>().hasData();
+}
+
+JS_FRIEND_API(JSObject*)
+js::UnwrapArrayBuffer(JSObject* obj)
+{
+ if (JSObject* unwrapped = CheckedUnwrap(obj))
+ return unwrapped->is<ArrayBufferObject>() ? unwrapped : nullptr;
+ return nullptr;
+}
+
+JS_FRIEND_API(JSObject*)
+js::UnwrapSharedArrayBuffer(JSObject* obj)
+{
+ if (JSObject* unwrapped = CheckedUnwrap(obj))
+ return unwrapped->is<SharedArrayBufferObject>() ? unwrapped : nullptr;
+ return nullptr;
+}
+
+JS_PUBLIC_API(void*)
+JS_ExternalizeArrayBufferContents(JSContext* cx, HandleObject obj)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ assertSameCompartment(cx, obj);
+
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr;
+ }
+
+ Handle<ArrayBufferObject*> buffer = obj.as<ArrayBufferObject>();
+ if (!buffer->isPlain()) {
+ // This operation isn't supported on mapped or wsm ArrayBufferObjects.
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr;
+ }
+ if (buffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+
+ // The caller assumes that a plain malloc'd buffer is returned.
+ // hasStealableContents is true for mapped buffers, so we must additionally
+ // require that the buffer is plain. In the future, we could consider
+ // returning something that handles releasing the memory.
+ bool hasStealableContents = buffer->hasStealableContents();
+
+ return ArrayBufferObject::externalizeContents(cx, buffer, hasStealableContents).data();
+}
+
+JS_PUBLIC_API(void*)
+JS_StealArrayBufferContents(JSContext* cx, HandleObject objArg)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ assertSameCompartment(cx, objArg);
+
+ JSObject* obj = CheckedUnwrap(objArg);
+ if (!obj)
+ return nullptr;
+
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+ if (buffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+
+ if (buffer->isWasm() || buffer->isPreparedForAsmJS()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
+ return nullptr;
+ }
+
+ // The caller assumes that a plain malloc'd buffer is returned.
+ // hasStealableContents is true for mapped buffers, so we must additionally
+ // require that the buffer is plain. In the future, we could consider
+ // returning something that handles releasing the memory.
+ bool hasStealableContents = buffer->hasStealableContents() && buffer->isPlain();
+
+ AutoCompartment ac(cx, buffer);
+ return ArrayBufferObject::stealContents(cx, buffer, hasStealableContents).data();
+}
+
+JS_PUBLIC_API(JSObject*)
+JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+
+ MOZ_ASSERT(data);
+ ArrayBufferObject::BufferContents contents =
+ ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED>(data);
+ return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
+ /* proto = */ nullptr, TenuredObject);
+}
+
+JS_PUBLIC_API(void*)
+JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
+{
+ return ArrayBufferObject::createMappedContents(fd, offset, length).data();
+}
+
+JS_PUBLIC_API(void)
+JS_ReleaseMappedArrayBufferContents(void* contents, size_t length)
+{
+ MemProfiler::RemoveNative(contents);
+ DeallocateMappedContent(contents, length);
+}
+
+JS_FRIEND_API(bool)
+JS_IsMappedArrayBufferObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return false;
+
+ return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isMapped();
+}
+
+JS_FRIEND_API(void*)
+JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ if (obj->is<DataViewObject>()) {
+ *isSharedMemory = false;
+ return obj->as<DataViewObject>().dataPointer();
+ }
+ TypedArrayObject& ta = obj->as<TypedArrayObject>();
+ *isSharedMemory = ta.isSharedMemory();
+ return ta.viewDataEither().unwrap(/*safe - caller sees isShared flag*/);
+}
+
+JS_FRIEND_API(JSObject*)
+JS_GetArrayBufferViewBuffer(JSContext* cx, HandleObject objArg, bool* isSharedMemory)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ assertSameCompartment(cx, objArg);
+
+ JSObject* obj = CheckedUnwrap(objArg);
+ if (!obj)
+ return nullptr;
+ MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
+
+ Rooted<ArrayBufferViewObject*> viewObject(cx, static_cast<ArrayBufferViewObject*>(obj));
+ ArrayBufferObjectMaybeShared* buffer = ArrayBufferViewObject::bufferObject(cx, viewObject);
+ *isSharedMemory = buffer->is<SharedArrayBufferObject>();
+ return buffer;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferViewByteLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().byteLength()
+ : obj->as<TypedArrayObject>().byteLength();
+}
+
+JS_FRIEND_API(JSObject*)
+JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
+{
+ if (!(obj = CheckedUnwrap(obj)))
+ return nullptr;
+ if (!(obj->is<ArrayBufferViewObject>()))
+ return nullptr;
+
+ js::GetArrayBufferViewLengthAndData(obj, length, isSharedMemory, data);
+ return obj;
+}
+
+JS_FRIEND_API(void)
+js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
+{
+ MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
+
+ *length = obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().byteLength()
+ : obj->as<TypedArrayObject>().byteLength();
+
+ if (obj->is<DataViewObject>()) {
+ *isSharedMemory = false;
+ *data = static_cast<uint8_t*>(obj->as<DataViewObject>().dataPointer());
+ }
+ else {
+ TypedArrayObject& ta = obj->as<TypedArrayObject>();
+ *isSharedMemory = ta.isSharedMemory();
+ *data = static_cast<uint8_t*>(ta.viewDataEither().unwrap(/*safe - caller sees isShared flag*/));
+ }
+}
+
+JS_FRIEND_API(JSObject*)
+JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data)
+{
+ if (!(obj = CheckedUnwrap(obj)))
+ return nullptr;
+ if (!IsArrayBuffer(obj))
+ return nullptr;
+
+ *length = AsArrayBuffer(obj).byteLength();
+ *data = AsArrayBuffer(obj).dataPointer();
+
+ return obj;
+}
+
+JS_FRIEND_API(void)
+js::GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
+{
+ MOZ_ASSERT(IsArrayBuffer(obj));
+ *length = AsArrayBuffer(obj).byteLength();
+ *data = AsArrayBuffer(obj).dataPointer();
+ *isSharedMemory = false;
+}
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
new file mode 100644
index 000000000..6614f5220
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.h
@@ -0,0 +1,641 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArrayBufferObject_h
+#define vm_ArrayBufferObject_h
+
+#include "mozilla/Maybe.h"
+
+#include "jsobj.h"
+
+#include "builtin/TypedObjectConstants.h"
+#include "js/GCHashTable.h"
+#include "vm/Runtime.h"
+#include "vm/SharedMem.h"
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+class ArrayBufferViewObject;
+class WasmArrayRawBuffer;
+
+// The inheritance hierarchy for the various classes relating to typed arrays
+// is as follows.
+//
+// - NativeObject
+// - ArrayBufferObjectMaybeShared
+// - ArrayBufferObject
+// - SharedArrayBufferObject
+// - DataViewObject
+// - TypedArrayObject (declared in vm/TypedArrayObject.h)
+// - TypedArrayObjectTemplate
+// - Int8ArrayObject
+// - Uint8ArrayObject
+// - ...
+// - JSObject
+// - ArrayBufferViewObject
+// - TypedObject (declared in builtin/TypedObject.h)
+//
+// Note that |TypedArrayObjectTemplate| is just an implementation
+// detail that makes implementing its various subclasses easier.
+//
+// ArrayBufferObject and SharedArrayBufferObject are unrelated data types:
+// the racy memory of the latter cannot substitute for the non-racy memory of
+// the former; the non-racy memory of the former cannot be used with the atomics;
+// the former can be detached and the latter not. Hence they have been
+// separated completely.
+//
+// Most APIs will only accept ArrayBufferObject. ArrayBufferObjectMaybeShared
+// exists as a join point to allow APIs that can take or use either, notably AsmJS.
+//
+// In contrast with the separation of ArrayBufferObject and
+// SharedArrayBufferObject, the TypedArray types can map either.
+//
+// The possible data ownership and reference relationships with ArrayBuffers
+// and related classes are enumerated below. These are the possible locations
+// for typed data:
+//
+// (1) malloc'ed or mmap'ed data owned by an ArrayBufferObject.
+// (2) Data allocated inline with an ArrayBufferObject.
+// (3) Data allocated inline with a TypedArrayObject.
+// (4) Data allocated inline with an InlineTypedObject.
+//
+// An ArrayBufferObject may point to any of these sources of data, except (3).
+// All array buffer views may point to any of these sources of data, except
+// that (3) may only be pointed to by the typed array the data is inline with.
+//
+// During a minor GC, (3) and (4) may move. During a compacting GC, (2), (3),
+// and (4) may move.
+
+class ArrayBufferObjectMaybeShared;
+
+uint32_t AnyArrayBufferByteLength(const ArrayBufferObjectMaybeShared* buf);
+mozilla::Maybe<uint32_t> WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf);
+size_t WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf);
+bool WasmArrayBufferGrowForWasm(ArrayBufferObjectMaybeShared* buf, uint32_t delta);
+bool AnyArrayBufferIsPreparedForAsmJS(const ArrayBufferObjectMaybeShared* buf);
+ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val);
+
+class ArrayBufferObjectMaybeShared : public NativeObject
+{
+ public:
+ uint32_t byteLength() {
+ return AnyArrayBufferByteLength(this);
+ }
+
+ inline bool isDetached() const;
+
+ inline SharedMem<uint8_t*> dataPointerEither();
+
+ // WebAssembly support:
+ // Note: the eventual goal is to remove this from ArrayBuffer and have
+ // (Shared)ArrayBuffers alias memory owned by some wasm::Memory object.
+
+ mozilla::Maybe<uint32_t> wasmMaxSize() const {
+ return WasmArrayBufferMaxSize(this);
+ }
+ size_t wasmMappedSize() const {
+ return WasmArrayBufferMappedSize(this);
+ }
+#ifndef WASM_HUGE_MEMORY
+ uint32_t wasmBoundsCheckLimit() const;
+#endif
+
+ bool isPreparedForAsmJS() const {
+ return AnyArrayBufferIsPreparedForAsmJS(this);
+ }
+};
+
+typedef Rooted<ArrayBufferObjectMaybeShared*> RootedArrayBufferObjectMaybeShared;
+typedef Handle<ArrayBufferObjectMaybeShared*> HandleArrayBufferObjectMaybeShared;
+typedef MutableHandle<ArrayBufferObjectMaybeShared*> MutableHandleArrayBufferObjectMaybeShared;
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the various ArrayBufferViews
+ * (eg DataViewObject, the TypedArrays, TypedObjects) access. It can be created
+ * explicitly and used to construct an ArrayBufferView, or can be created
+ * lazily when it is first accessed for a TypedArrayObject or TypedObject that
+ * doesn't have an explicit buffer.
+ *
+ * ArrayBufferObject (or really the underlying memory) /is not racy/: the
+ * memory is private to a single worker.
+ */
+class ArrayBufferObject : public ArrayBufferObjectMaybeShared
+{
+ static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+ static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
+
+ public:
+ static const uint8_t DATA_SLOT = 0;
+ static const uint8_t BYTE_LENGTH_SLOT = 1;
+ static const uint8_t FIRST_VIEW_SLOT = 2;
+ static const uint8_t FLAGS_SLOT = 3;
+
+ static const uint8_t RESERVED_SLOTS = 4;
+
+ static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
+
+ static_assert(FLAGS_SLOT == JS_ARRAYBUFFER_FLAGS_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right flags slot");
+
+ public:
+
+ enum OwnsState {
+ DoesntOwnData = 0,
+ OwnsData = 1,
+ };
+
+ enum BufferKind {
+ PLAIN = 0, // malloced or inline data
+ WASM = 1,
+ MAPPED = 2,
+
+ KIND_MASK = 0x3
+ };
+
+ protected:
+
+ enum ArrayBufferFlags {
+ // The flags also store the BufferKind
+ BUFFER_KIND_MASK = BufferKind::KIND_MASK,
+
+ DETACHED = 0x4,
+
+ // The dataPointer() is owned by this buffer and should be released
+ // when no longer in use. Releasing the pointer may be done by either
+ // freeing or unmapping it, and how to do this is determined by the
+ // buffer's other flags.
+ //
+ // Array buffers which do not own their data include buffers that
+ // allocate their data inline, and buffers that are created lazily for
+ // typed objects with inline storage, in which case the buffer points
+ // directly to the typed object's storage.
+ OWNS_DATA = 0x8,
+
+ // This array buffer was created lazily for a typed object with inline
+ // data. This implies both that the typed object owns the buffer's data
+ // and that the list of views sharing this buffer's data might be
+ // incomplete. Any missing views will be typed objects.
+ FOR_INLINE_TYPED_OBJECT = 0x10,
+
+ // Views of this buffer might include typed objects.
+ TYPED_OBJECT_VIEWS = 0x20,
+
+ // This PLAIN or WASM buffer has been prepared for asm.js and cannot
+ // henceforth be transferred/detached.
+ FOR_ASMJS = 0x40
+ };
+
+ static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
+ "self-hosted code with burned-in constants must use the "
+ "correct DETACHED bit value");
+ public:
+
+ class BufferContents {
+ uint8_t* data_;
+ BufferKind kind_;
+
+ friend class ArrayBufferObject;
+
+ BufferContents(uint8_t* data, BufferKind kind) : data_(data), kind_(kind) {
+ MOZ_ASSERT((kind_ & ~KIND_MASK) == 0);
+ }
+
+ public:
+
+ template<BufferKind Kind>
+ static BufferContents create(void* data)
+ {
+ return BufferContents(static_cast<uint8_t*>(data), Kind);
+ }
+
+ static BufferContents createPlain(void* data)
+ {
+ return BufferContents(static_cast<uint8_t*>(data), PLAIN);
+ }
+
+ uint8_t* data() const { return data_; }
+ BufferKind kind() const { return kind_; }
+
+ explicit operator bool() const { return data_ != nullptr; }
+ WasmArrayRawBuffer* wasmBuffer() const;
+ };
+
+ static const Class class_;
+
+ static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool fun_species(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
+
+ static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
+ BufferContents contents,
+ OwnsState ownsState = OwnsData,
+ HandleObject proto = nullptr,
+ NewObjectKind newKind = GenericObject);
+ static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
+ HandleObject proto = nullptr,
+ NewObjectKind newKind = GenericObject);
+
+ // Create an ArrayBufferObject that is safely finalizable and can later be
+ // initialize()d to become a real, content-visible ArrayBufferObject.
+ static ArrayBufferObject* createEmpty(JSContext* cx);
+
+ static bool createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
+ static bool createDataViewForThis(JSContext* cx, unsigned argc, Value* vp);
+
+ template<typename T>
+ static bool createTypedArrayFromBufferImpl(JSContext* cx, const CallArgs& args);
+
+ template<typename T>
+ static bool createTypedArrayFromBuffer(JSContext* cx, unsigned argc, Value* vp);
+
+ static void copyData(Handle<ArrayBufferObject*> toBuffer,
+ Handle<ArrayBufferObject*> fromBuffer,
+ uint32_t fromIndex, uint32_t count);
+
+ static void trace(JSTracer* trc, JSObject* obj);
+ static void objectMoved(JSObject* obj, const JSObject* old);
+
+ static BufferContents externalizeContents(JSContext* cx,
+ Handle<ArrayBufferObject*> buffer,
+ bool hasStealableContents);
+ static BufferContents stealContents(JSContext* cx,
+ Handle<ArrayBufferObject*> buffer,
+ bool hasStealableContents);
+
+ bool hasStealableContents() const {
+ // Inline elements strictly adhere to the corresponding buffer.
+ return ownsData() && !isPreparedForAsmJS() && !isWasm();
+ }
+
+ static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
+ JS::ClassInfo* info);
+
+ // ArrayBufferObjects (strongly) store the first view added to them, while
+ // later views are (weakly) stored in the compartment's InnerViewTable
+ // below. Buffers usually only have one view, so this slot optimizes for
+ // the common case. Avoiding entries in the InnerViewTable saves memory and
+ // non-incrementalized sweep time.
+ ArrayBufferViewObject* firstView();
+
+ bool addView(JSContext* cx, JSObject* view);
+
+ void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
+ void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
+
+ // Detach this buffer from its original memory. (This necessarily makes
+ // views of this buffer unusable for modifying that original memory.)
+ static void
+ detach(JSContext* cx, Handle<ArrayBufferObject*> buffer, BufferContents newContents);
+
+ private:
+ void changeViewContents(JSContext* cx, ArrayBufferViewObject* view,
+ uint8_t* oldDataPointer, BufferContents newContents);
+ void setFirstView(ArrayBufferViewObject* view);
+
+ uint8_t* inlineDataPointer() const;
+
+ public:
+ uint8_t* dataPointer() const;
+ SharedMem<uint8_t*> dataPointerShared() const;
+ uint32_t byteLength() const;
+
+ BufferContents contents() const {
+ return BufferContents(dataPointer(), bufferKind());
+ }
+ bool hasInlineData() const {
+ return dataPointer() == inlineDataPointer();
+ }
+
+ void releaseData(FreeOp* fop);
+
+ /*
+ * Check if the arrayBuffer contains any data. This will return false for
+ * ArrayBuffer.prototype and detached ArrayBuffers.
+ */
+ bool hasData() const {
+ return getClass() == &class_;
+ }
+
+ BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
+ bool isPlain() const { return bufferKind() == PLAIN; }
+ bool isWasm() const { return bufferKind() == WASM; }
+ bool isMapped() const { return bufferKind() == MAPPED; }
+ bool isDetached() const { return flags() & DETACHED; }
+ bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
+
+ // WebAssembly support:
+ static ArrayBufferObject* createForWasm(JSContext* cx, uint32_t initialSize,
+ mozilla::Maybe<uint32_t> maxSize);
+ static MOZ_MUST_USE bool prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer,
+ bool needGuard);
+ size_t wasmMappedSize() const;
+ mozilla::Maybe<uint32_t> wasmMaxSize() const;
+ static MOZ_MUST_USE bool wasmGrowToSizeInPlace(uint32_t newSize,
+ Handle<ArrayBufferObject*> oldBuf,
+ MutableHandle<ArrayBufferObject*> newBuf,
+ JSContext* cx);
+#ifndef WASM_HUGE_MEMORY
+ static MOZ_MUST_USE bool wasmMovingGrowToSize(uint32_t newSize,
+ Handle<ArrayBufferObject*> oldBuf,
+ MutableHandle<ArrayBufferObject*> newBuf,
+ JSContext* cx);
+ uint32_t wasmBoundsCheckLimit() const;
+#endif
+
+ static void finalize(FreeOp* fop, JSObject* obj);
+
+ static BufferContents createMappedContents(int fd, size_t offset, size_t length);
+
+ static size_t offsetOfFlagsSlot() {
+ return getFixedSlotOffset(FLAGS_SLOT);
+ }
+ static size_t offsetOfDataSlot() {
+ return getFixedSlotOffset(DATA_SLOT);
+ }
+
+ void setForInlineTypedObject() {
+ setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
+ }
+ void setHasTypedObjectViews() {
+ setFlags(flags() | TYPED_OBJECT_VIEWS);
+ }
+
+ bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
+
+ protected:
+ void setDataPointer(BufferContents contents, OwnsState ownsState);
+ void setByteLength(uint32_t length);
+
+ uint32_t flags() const;
+ void setFlags(uint32_t flags);
+
+ bool ownsData() const { return flags() & OWNS_DATA; }
+ void setOwnsData(OwnsState owns) {
+ setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
+ }
+
+ bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
+
+ void setIsDetached() { setFlags(flags() | DETACHED); }
+ void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
+
+ void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
+ setByteLength(byteLength);
+ setFlags(0);
+ setFirstView(nullptr);
+ setDataPointer(contents, ownsState);
+ }
+
+ // Note: initialize() may be called after initEmpty(); initEmpty() must
+ // only initialize the ArrayBufferObject to a safe, finalizable state.
+ void initEmpty() {
+ setByteLength(0);
+ setFlags(0);
+ setFirstView(nullptr);
+ setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
+ }
+};
+
+typedef Rooted<ArrayBufferObject*> RootedArrayBufferObject;
+typedef Handle<ArrayBufferObject*> HandleArrayBufferObject;
+typedef MutableHandle<ArrayBufferObject*> MutableHandleArrayBufferObject;
+
+/*
+ * ArrayBufferViewObject
+ *
+ * Common definitions shared by all array buffer views.
+ */
+
+class ArrayBufferViewObject : public JSObject
+{
+ public:
+ static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);
+
+ void notifyBufferDetached(JSContext* cx, void* newData);
+
+#ifdef DEBUG
+ bool isSharedMemory();
+#endif
+
+ // By construction we only need unshared variants here. See
+ // comments in ArrayBufferObject.cpp.
+ uint8_t* dataPointerUnshared(const JS::AutoRequireNoGC&);
+ void setDataPointerUnshared(uint8_t* data);
+
+ static void trace(JSTracer* trc, JSObject* obj);
+};
+
+bool
+ToClampedIndex(JSContext* cx, HandleValue v, uint32_t length, uint32_t* out);
+
+/*
+ * Tests for ArrayBufferObject, like obj->is<ArrayBufferObject>().
+ */
+bool IsArrayBuffer(HandleValue v);
+bool IsArrayBuffer(HandleObject obj);
+bool IsArrayBuffer(JSObject* obj);
+ArrayBufferObject& AsArrayBuffer(HandleObject obj);
+ArrayBufferObject& AsArrayBuffer(JSObject* obj);
+
+extern uint32_t JS_FASTCALL
+ClampDoubleToUint8(const double x);
+
+struct uint8_clamped {
+ uint8_t val;
+
+ uint8_clamped() { }
+ uint8_clamped(const uint8_clamped& other) : val(other.val) { }
+
+ // invoke our assignment helpers for constructor conversion
+ explicit uint8_clamped(uint8_t x) { *this = x; }
+ explicit uint8_clamped(uint16_t x) { *this = x; }
+ explicit uint8_clamped(uint32_t x) { *this = x; }
+ explicit uint8_clamped(int8_t x) { *this = x; }
+ explicit uint8_clamped(int16_t x) { *this = x; }
+ explicit uint8_clamped(int32_t x) { *this = x; }
+ explicit uint8_clamped(double x) { *this = x; }
+
+ uint8_clamped& operator=(const uint8_clamped& x) {
+ val = x.val;
+ return *this;
+ }
+
+ uint8_clamped& operator=(uint8_t x) {
+ val = x;
+ return *this;
+ }
+
+ uint8_clamped& operator=(uint16_t x) {
+ val = (x > 255) ? 255 : uint8_t(x);
+ return *this;
+ }
+
+ uint8_clamped& operator=(uint32_t x) {
+ val = (x > 255) ? 255 : uint8_t(x);
+ return *this;
+ }
+
+ uint8_clamped& operator=(int8_t x) {
+ val = (x >= 0) ? uint8_t(x) : 0;
+ return *this;
+ }
+
+ uint8_clamped& operator=(int16_t x) {
+ val = (x >= 0)
+ ? ((x < 255)
+ ? uint8_t(x)
+ : 255)
+ : 0;
+ return *this;
+ }
+
+ uint8_clamped& operator=(int32_t x) {
+ val = (x >= 0)
+ ? ((x < 255)
+ ? uint8_t(x)
+ : 255)
+ : 0;
+ return *this;
+ }
+
+ uint8_clamped& operator=(const double x) {
+ val = uint8_t(ClampDoubleToUint8(x));
+ return *this;
+ }
+
+ operator uint8_t() const {
+ return val;
+ }
+
+ void staticAsserts() {
+ static_assert(sizeof(uint8_clamped) == 1,
+ "uint8_clamped must be layout-compatible with uint8_t");
+ }
+};
+
+/* Note that we can't use std::numeric_limits here due to uint8_clamped. */
+template<typename T> inline bool TypeIsFloatingPoint() { return false; }
+template<> inline bool TypeIsFloatingPoint<float>() { return true; }
+template<> inline bool TypeIsFloatingPoint<double>() { return true; }
+
+template<typename T> inline bool TypeIsUnsigned() { return false; }
+template<> inline bool TypeIsUnsigned<uint8_t>() { return true; }
+template<> inline bool TypeIsUnsigned<uint16_t>() { return true; }
+template<> inline bool TypeIsUnsigned<uint32_t>() { return true; }
+
+// Per-compartment table that manages the relationship between array buffers
+// and the views that use their storage.
+class InnerViewTable
+{
+ public:
+ typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
+
+ friend class ArrayBufferObject;
+ friend class WeakCacheBase<InnerViewTable>;
+
+ private:
+ struct MapGCPolicy {
+ static bool needsSweep(JSObject** key, ViewVector* value) {
+ return InnerViewTable::sweepEntry(key, *value);
+ }
+ };
+
+ // This key is a raw pointer and not a ReadBarriered because the post-
+ // barrier would hold nursery-allocated entries live unconditionally. It is
+ // a very common pattern in low-level and performance-oriented JavaScript
+ // to create hundreds or thousands of very short lived temporary views on a
+ // larger buffer; having to tenured all of these would be a catastrophic
+ // performance regression. Thus, it is vital that nursery pointers in this
+ // map not be held live. Special support is required in the minor GC,
+ // implemented in sweepAfterMinorGC.
+ typedef GCHashMap<JSObject*,
+ ViewVector,
+ MovableCellHasher<JSObject*>,
+ SystemAllocPolicy,
+ MapGCPolicy> Map;
+
+ // For all objects sharing their storage with some other view, this maps
+ // the object to the list of such views. All entries in this map are weak.
+ Map map;
+
+ // List of keys from innerViews where either the source or at least one
+ // target is in the nursery. The raw pointer to a JSObject is allowed here
+ // because this vector is cleared after every minor collection. Users in
+ // sweepAfterMinorCollection must be careful to use MaybeForwarded before
+ // touching these pointers.
+ Vector<JSObject*, 0, SystemAllocPolicy> nurseryKeys;
+
+ // Whether nurseryKeys is a complete list.
+ bool nurseryKeysValid;
+
+ // Sweep an entry during GC, returning whether the entry should be removed.
+ static bool sweepEntry(JSObject** pkey, ViewVector& views);
+
+ bool addView(JSContext* cx, ArrayBufferObject* obj, ArrayBufferViewObject* view);
+ ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj);
+ void removeViews(ArrayBufferObject* obj);
+
+ public:
+ InnerViewTable()
+ : nurseryKeysValid(true)
+ {}
+
+ // Remove references to dead objects in the table and update table entries
+ // to reflect moved objects.
+ void sweep();
+ void sweepAfterMinorGC();
+
+ bool needsSweepAfterMinorGC() const {
+ return !nurseryKeys.empty() || !nurseryKeysValid;
+ }
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+};
+
+template <>
+class WeakCacheBase<InnerViewTable>
+{
+ InnerViewTable& table() {
+ return static_cast<JS::WeakCache<InnerViewTable>*>(this)->get();
+ }
+ const InnerViewTable& table() const {
+ return static_cast<const JS::WeakCache<InnerViewTable>*>(this)->get();
+ }
+
+ public:
+ InnerViewTable::ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj) {
+ return table().maybeViewsUnbarriered(obj);
+ }
+ void removeViews(ArrayBufferObject* obj) { table().removeViews(obj); }
+ void sweepAfterMinorGC() { table().sweepAfterMinorGC(); }
+ bool needsSweepAfterMinorGC() const { return table().needsSweepAfterMinorGC(); }
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+ return table().sizeOfExcludingThis(mallocSizeOf);
+ }
+};
+
+} // namespace js
+
+template <>
+bool
+JSObject::is<js::ArrayBufferViewObject>() const;
+
+template <>
+bool
+JSObject::is<js::ArrayBufferObjectMaybeShared>() const;
+
+#endif // vm_ArrayBufferObject_h
diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h
new file mode 100644
index 000000000..d5f8b82ea
--- /dev/null
+++ b/js/src/vm/ArrayObject-inl.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArrayObject_inl_h
+#define vm_ArrayObject_inl_h
+
+#include "vm/ArrayObject.h"
+
+#include "gc/GCTrace.h"
+#include "vm/String.h"
+
+#include "jsgcinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/TypeInference-inl.h"
+
+namespace js {
+
+inline void
+ArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
+{
+ MOZ_ASSERT(lengthIsWritable());
+ MOZ_ASSERT_IF(length != getElementsHeader()->length, !denseElementsAreFrozen());
+
+ if (length > INT32_MAX) {
+ /* Track objects with overflowing lengths in type information. */
+ MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
+ }
+
+ getElementsHeader()->length = length;
+}
+
+/* static */ inline ArrayObject*
+ArrayObject::createArrayInternal(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
+ HandleShape shape, HandleObjectGroup group,
+ AutoSetNewObjectMetadata&)
+{
+ // Create a new array and initialize everything except for its elements.
+ MOZ_ASSERT(shape && group);
+ MOZ_ASSERT(group->clasp() == shape->getObjectClass());
+ MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
+ MOZ_ASSERT_IF(group->clasp()->hasFinalize(), heap == gc::TenuredHeap);
+ MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
+ heap == js::gc::TenuredHeap);
+ MOZ_ASSERT(group->clasp()->shouldDelayMetadataBuilder());
+
+ // Arrays can use their fixed slots to store elements, so can't have shapes
+ // which allow named properties to be stored in the fixed slots.
+ MOZ_ASSERT(shape->numFixedSlots() == 0);
+
+ size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), group->clasp());
+ JSObject* obj = Allocate<JSObject>(cx, kind, nDynamicSlots, heap, group->clasp());
+ if (!obj)
+ return nullptr;
+
+ static_cast<ArrayObject*>(obj)->shape_.init(shape);
+ static_cast<ArrayObject*>(obj)->group_.init(group);
+
+ cx->compartment()->setObjectPendingMetadata(cx, obj);
+ return &obj->as<ArrayObject>();
+}
+
+/* static */ inline ArrayObject*
+ArrayObject::finishCreateArray(ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata)
+{
+ size_t span = shape->slotSpan();
+ if (span)
+ obj->initializeSlotRange(0, span);
+
+ gc::TraceCreateObject(obj);
+
+ return obj;
+}
+
+/* static */ inline ArrayObject*
+ArrayObject::createArray(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
+ HandleShape shape, HandleObjectGroup group,
+ uint32_t length, AutoSetNewObjectMetadata& metadata)
+{
+ ArrayObject* obj = createArrayInternal(cx, kind, heap, shape, group, metadata);
+ if (!obj)
+ return nullptr;
+
+ uint32_t capacity = gc::GetGCKindSlots(kind) - ObjectElements::VALUES_PER_HEADER;
+
+ obj->setFixedElements();
+ new (obj->getElementsHeader()) ObjectElements(capacity, length);
+
+ return finishCreateArray(obj, shape, metadata);
+}
+
+/* static */ inline ArrayObject*
+ArrayObject::createCopyOnWriteArray(ExclusiveContext* cx, gc::InitialHeap heap,
+ HandleArrayObject sharedElementsOwner)
+{
+ MOZ_ASSERT(sharedElementsOwner->getElementsHeader()->isCopyOnWrite());
+ MOZ_ASSERT(sharedElementsOwner->getElementsHeader()->ownerObject() == sharedElementsOwner);
+
+ // Use the smallest allocation kind for the array, as it can't have any
+ // fixed slots (see the assert in createArrayInternal) and will not be using
+ // its fixed elements.
+ gc::AllocKind kind = gc::AllocKind::OBJECT0_BACKGROUND;
+
+ AutoSetNewObjectMetadata metadata(cx);
+ RootedShape shape(cx, sharedElementsOwner->lastProperty());
+ RootedObjectGroup group(cx, sharedElementsOwner->group());
+ ArrayObject* obj = createArrayInternal(cx, kind, heap, shape, group, metadata);
+ if (!obj)
+ return nullptr;
+
+ obj->elements_ = sharedElementsOwner->getDenseElementsAllowCopyOnWrite();
+
+ return finishCreateArray(obj, shape, metadata);
+}
+
+} // namespace js
+
+#endif // vm_ArrayObject_inl_h
diff --git a/js/src/vm/ArrayObject.h b/js/src/vm/ArrayObject.h
new file mode 100644
index 000000000..8cfef0d56
--- /dev/null
+++ b/js/src/vm/ArrayObject.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ArrayObject_h
+#define vm_ArrayObject_h
+
+#include "vm/NativeObject.h"
+
+namespace js {
+
+class AutoSetNewObjectMetadata;
+
+class ArrayObject : public NativeObject
+{
+ public:
+ // Array(x) eagerly allocates dense elements if x <= this value. Without
+ // the subtraction the max would roll over to the next power-of-two (4096)
+ // due to the way that growElements() and goodAllocated() work.
+ static const uint32_t EagerAllocationMaxLength = 2048 - ObjectElements::VALUES_PER_HEADER;
+
+ static const Class class_;
+
+ bool lengthIsWritable() const {
+ return !getElementsHeader()->hasNonwritableArrayLength();
+ }
+
+ uint32_t length() const {
+ return getElementsHeader()->length;
+ }
+
+ inline void setLength(ExclusiveContext* cx, uint32_t length);
+
+ // Variant of setLength for use on arrays where the length cannot overflow int32_t.
+ void setLengthInt32(uint32_t length) {
+ MOZ_ASSERT(lengthIsWritable());
+ MOZ_ASSERT(length <= INT32_MAX);
+ getElementsHeader()->length = length;
+ }
+
+ // Make an array object with the specified initial state.
+ static inline ArrayObject*
+ createArray(ExclusiveContext* cx,
+ gc::AllocKind kind,
+ gc::InitialHeap heap,
+ HandleShape shape,
+ HandleObjectGroup group,
+ uint32_t length,
+ AutoSetNewObjectMetadata& metadata);
+
+ // Make a copy-on-write array object which shares the elements of an
+ // existing object.
+ static inline ArrayObject*
+ createCopyOnWriteArray(ExclusiveContext* cx,
+ gc::InitialHeap heap,
+ HandleArrayObject sharedElementsOwner);
+
+ private:
+ // Helper for the above methods.
+ static inline ArrayObject*
+ createArrayInternal(ExclusiveContext* cx,
+ gc::AllocKind kind,
+ gc::InitialHeap heap,
+ HandleShape shape,
+ HandleObjectGroup group,
+ AutoSetNewObjectMetadata&);
+
+ static inline ArrayObject*
+ finishCreateArray(ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata);
+};
+
+} // namespace js
+
+#endif // vm_ArrayObject_h
+
diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp
new file mode 100644
index 000000000..bd0b4f32a
--- /dev/null
+++ b/js/src/vm/AsyncFunction.cpp
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/AsyncFunction.h"
+
+#include "jscompartment.h"
+
+#include "builtin/Promise.h"
+#include "vm/GeneratorObject.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+using namespace js::gc;
+
+/* static */ bool
+GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(ASYNC_FUNCTION_PROTO).isObject())
+ return true;
+
+ RootedObject asyncFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!asyncFunctionProto)
+ return false;
+
+ if (!DefineToStringTag(cx, asyncFunctionProto, cx->names().AsyncFunction))
+ return false;
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ return false;
+ RootedObject proto(cx, &function.toObject());
+ RootedAtom name(cx, cx->names().AsyncFunction);
+ RootedObject asyncFunction(cx, NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
+ JSFunction::NATIVE_CTOR, nullptr, name,
+ proto));
+ if (!asyncFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
+ return false;
+
+ global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
+ global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
+ return true;
+}
+
+static MOZ_MUST_USE bool AsyncFunctionStart(JSContext* cx, Handle<PromiseObject*> resultPromise,
+ HandleValue generatorVal);
+
+#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
+#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
+
+// Async Functions proposal 1.1.8 and 1.2.14.
+static bool
+WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
+ RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
+ RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
+ RootedValue thisValue(cx, args.thisv());
+
+ // Step 2.
+ // Also does a part of 2.2 steps 1-2.
+ RootedValue generatorVal(cx);
+ InvokeArgs args2(cx);
+ if (!args2.init(cx, argc))
+ return false;
+ for (size_t i = 0, len = argc; i < len; i++)
+ args2[i].set(args[i]);
+ if (Call(cx, unwrappedVal, thisValue, args2, &generatorVal)) {
+ // Step 1.
+ Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx, generatorVal));
+ if (!resultPromise)
+ return false;
+
+ // Step 3.
+ if (!AsyncFunctionStart(cx, resultPromise, generatorVal))
+ return false;
+
+ // Step 5.
+ args.rval().setObject(*resultPromise);
+ return true;
+ }
+
+ // Steps 1, 4.
+ RootedValue exc(cx);
+ if (!GetAndClearException(cx, &exc))
+ return false;
+ RootedObject rejectPromise(cx, PromiseObject::unforgeableReject(cx, exc));
+ if (!rejectPromise)
+ return false;
+
+ // Step 5.
+ args.rval().setObject(*rejectPromise);
+ return true;
+}
+
+// Async Functions proposal 2.1 steps 1, 3 (partially).
+// In the spec it creates a function, but we create 2 functions `unwrapped` and
+// `wrapped`. `unwrapped` is a generator that corresponds to
+// the async function's body, replacing `await` with `yield`. `wrapped` is a
+// function that is visible to the outside, and handles yielded values.
+JSObject*
+js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
+{
+ MOZ_ASSERT(unwrapped->isStarGenerator());
+
+ // Create a new function with AsyncFunctionPrototype, reusing the name and
+ // the length of `unwrapped`.
+
+ // Step 1.
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
+ if (!proto)
+ return nullptr;
+
+ RootedAtom funName(cx, unwrapped->name());
+ uint16_t length;
+ if (!unwrapped->getLength(cx, &length))
+ return nullptr;
+
+ // Steps 3 (partially).
+ RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncFunction, length,
+ JSFunction::NATIVE_FUN, nullptr,
+ funName, proto,
+ AllocKind::FUNCTION_EXTENDED,
+ TenuredObject));
+ if (!wrapped)
+ return nullptr;
+
+ // Link them to each other to make GetWrappedAsyncFunction and
+ // GetUnwrappedAsyncFunction work.
+ unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
+ wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
+
+ return wrapped;
+}
+
+enum class ResumeKind {
+ Normal,
+ Throw
+};
+
+// Async Functions proposal 2.2 steps 3.f, 3.g.
+// Async Functions proposal 2.2 steps 3.d-e, 3.g.
+// Implemented in js/src/builtin/Promise.cpp
+
+// Async Functions proposal 2.2 steps 3-8, 2.4 steps 2-7, 2.5 steps 2-7.
+static bool
+AsyncFunctionResume(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue generatorVal,
+ ResumeKind kind, HandleValue valueOrReason)
+{
+ // Execution context switching is handled in generator.
+ HandlePropertyName funName = kind == ResumeKind::Normal
+ ? cx->names().StarGeneratorNext
+ : cx->names().StarGeneratorThrow;
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(valueOrReason);
+ RootedValue result(cx);
+ if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result))
+ return AsyncFunctionThrown(cx, resultPromise);
+
+ RootedObject resultObj(cx, &result.toObject());
+ RootedValue doneVal(cx);
+ RootedValue value(cx);
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
+ return false;
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
+ return false;
+
+ if (doneVal.toBoolean())
+ return AsyncFunctionReturned(cx, resultPromise, value);
+
+ return AsyncFunctionAwait(cx, resultPromise, value);
+}
+
+// Async Functions proposal 2.2 steps 3-8.
+static MOZ_MUST_USE bool
+AsyncFunctionStart(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue generatorVal)
+{
+ return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Normal, UndefinedHandleValue);
+}
+
+// Async Functions proposal 2.3 steps 1-8.
+// Implemented in js/src/builtin/Promise.cpp
+
+// Async Functions proposal 2.4.
+MOZ_MUST_USE bool
+js::AsyncFunctionAwaitedFulfilled(JSContext* cx, Handle<PromiseObject*> resultPromise,
+ HandleValue generatorVal, HandleValue value)
+{
+ // Step 1 (implicit).
+
+ // Steps 2-7.
+ return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Normal, value);
+}
+
+// Async Functions proposal 2.5.
+MOZ_MUST_USE bool
+js::AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
+ HandleValue generatorVal, HandleValue reason)
+{
+ // Step 1 (implicit).
+
+ // Step 2-7.
+ return AsyncFunctionResume(cx, resultPromise, generatorVal, ResumeKind::Throw, reason);
+}
+
+JSFunction*
+js::GetWrappedAsyncFunction(JSFunction* unwrapped)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
+}
+
+JSFunction*
+js::GetUnwrappedAsyncFunction(JSFunction* wrapped)
+{
+ MOZ_ASSERT(IsWrappedAsyncFunction(wrapped));
+ JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT).toObject().as<JSFunction>();
+ MOZ_ASSERT(unwrapped->isAsync());
+ return unwrapped;
+}
+
+bool
+js::IsWrappedAsyncFunction(JSFunction* fun)
+{
+ return fun->maybeNative() == WrappedAsyncFunction;
+}
+
+MOZ_MUST_USE bool
+js::CheckAsyncResumptionValue(JSContext* cx, HandleValue v)
+{
+ return CheckStarGeneratorResumptionValue(cx, v);
+}
diff --git a/js/src/vm/AsyncFunction.h b/js/src/vm/AsyncFunction.h
new file mode 100644
index 000000000..ddf81a177
--- /dev/null
+++ b/js/src/vm/AsyncFunction.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_AsyncFunction_h
+#define vm_AsyncFunction_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+namespace js {
+
+JSFunction*
+GetWrappedAsyncFunction(JSFunction* unwrapped);
+
+JSFunction*
+GetUnwrappedAsyncFunction(JSFunction* wrapped);
+
+bool
+IsWrappedAsyncFunction(JSFunction* fun);
+
+JSObject*
+WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped);
+
+MOZ_MUST_USE bool
+AsyncFunctionAwaitedFulfilled(JSContext* cx, Handle<PromiseObject*> resultPromise,
+ HandleValue generatorVal, HandleValue value);
+
+MOZ_MUST_USE bool
+AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
+ HandleValue generatorVal, HandleValue reason);
+
+MOZ_MUST_USE bool
+CheckAsyncResumptionValue(JSContext* cx, HandleValue v);
+
+} // namespace js
+
+#endif /* vm_AsyncFunction_h */
diff --git a/js/src/vm/BooleanObject-inl.h b/js/src/vm/BooleanObject-inl.h
new file mode 100644
index 000000000..c5e0f7538
--- /dev/null
+++ b/js/src/vm/BooleanObject-inl.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BooleanObject_inl_h
+#define vm_BooleanObject_inl_h
+
+#include "vm/BooleanObject.h"
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+inline BooleanObject*
+BooleanObject::create(JSContext* cx, bool b, HandleObject proto /* = nullptr */)
+{
+ BooleanObject* obj = NewObjectWithClassProto<BooleanObject>(cx, proto);
+ if (!obj)
+ return nullptr;
+ obj->setPrimitiveValue(b);
+ return obj;
+}
+
+} // namespace js
+
+#endif /* vm_BooleanObject_inl_h */
diff --git a/js/src/vm/BooleanObject.h b/js/src/vm/BooleanObject.h
new file mode 100644
index 000000000..c3c74fb19
--- /dev/null
+++ b/js/src/vm/BooleanObject.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BooleanObject_h
+#define vm_BooleanObject_h
+
+#include "jsbool.h"
+
+#include "vm/NativeObject.h"
+
+namespace js {
+
+class BooleanObject : public NativeObject
+{
+ /* Stores this Boolean object's [[PrimitiveValue]]. */
+ static const unsigned PRIMITIVE_VALUE_SLOT = 0;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 1;
+
+ static const Class class_;
+
+ /*
+ * Creates a new Boolean object boxing the given primitive bool.
+ * If proto is nullptr, the [[Prototype]] will default to Boolean.prototype.
+ */
+ static inline BooleanObject* create(JSContext* cx, bool b,
+ HandleObject proto = nullptr);
+
+ bool unbox() const {
+ return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBoolean();
+ }
+
+ private:
+ inline void setPrimitiveValue(bool b) {
+ setFixedSlot(PRIMITIVE_VALUE_SLOT, BooleanValue(b));
+ }
+
+ /* For access to init, as Boolean.prototype is special. */
+ friend JSObject*
+ js::InitBooleanClass(JSContext* cx, js::HandleObject global);
+};
+
+} // namespace js
+
+#endif /* vm_BooleanObject_h */
diff --git a/js/src/vm/Caches-inl.h b/js/src/vm/Caches-inl.h
new file mode 100644
index 000000000..4eb8ecaa6
--- /dev/null
+++ b/js/src/vm/Caches-inl.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Caches_inl_h
+#define vm_Caches_inl_h
+
+#include "vm/Caches.h"
+
+#include "jscompartment.h"
+
+#include "gc/Allocator.h"
+#include "gc/GCTrace.h"
+#include "vm/Probes.h"
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+inline bool
+NewObjectCache::lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry)
+{
+ MOZ_ASSERT(!proto->is<GlobalObject>());
+ return lookup(clasp, proto, kind, pentry);
+}
+
+inline bool
+NewObjectCache::lookupGlobal(const Class* clasp, GlobalObject* global, gc::AllocKind kind, EntryIndex* pentry)
+{
+ return lookup(clasp, global, kind, pentry);
+}
+
+inline void
+NewObjectCache::fillGlobal(EntryIndex entry, const Class* clasp, GlobalObject* global,
+ gc::AllocKind kind, NativeObject* obj)
+{
+ //MOZ_ASSERT(global == obj->getGlobal());
+ return fill(entry, clasp, global, kind, obj);
+}
+
+inline NativeObject*
+NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::InitialHeap heap)
+{
+ MOZ_ASSERT(unsigned(entryIndex) < mozilla::ArrayLength(entries));
+ Entry* entry = &entries[entryIndex];
+
+ NativeObject* templateObj = reinterpret_cast<NativeObject*>(&entry->templateObject);
+
+ // Do an end run around JSObject::group() to avoid doing AutoUnprotectCell
+ // on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
+ ObjectGroup* group = templateObj->group_;
+
+ MOZ_ASSERT(!group->hasUnanalyzedPreliminaryObjects());
+
+ if (group->shouldPreTenure())
+ heap = gc::TenuredHeap;
+
+ if (cx->runtime()->gc.upcomingZealousGC())
+ return nullptr;
+
+ NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind, 0,
+ heap, group->clasp()));
+ if (!obj)
+ return nullptr;
+
+ copyCachedToObject(obj, templateObj, entry->kind);
+
+ if (group->clasp()->shouldDelayMetadataBuilder())
+ cx->compartment()->setObjectPendingMetadata(cx, obj);
+ else
+ obj = static_cast<NativeObject*>(SetNewObjectMetadata(cx, obj));
+
+ probes::CreateObject(cx, obj);
+ gc::TraceCreateObject(obj);
+ return obj;
+}
+
+} /* namespace js */
+
+#endif /* vm_Caches_inl_h */
diff --git a/js/src/vm/Caches.cpp b/js/src/vm/Caches.cpp
new file mode 100644
index 000000000..667ea6ed3
--- /dev/null
+++ b/js/src/vm/Caches.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Caches-inl.h"
+
+#include "mozilla/PodOperations.h"
+
+using namespace js;
+
+using mozilla::PodZero;
+
+MathCache*
+ContextCaches::createMathCache(JSContext* cx)
+{
+ MOZ_ASSERT(!mathCache_);
+
+ UniquePtr<MathCache> newMathCache(js_new<MathCache>());
+ if (!newMathCache) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ mathCache_ = Move(newMathCache);
+ return mathCache_.get();
+}
+
+bool
+ContextCaches::init()
+{
+ if (!evalCache.init())
+ return false;
+
+ return true;
+}
+
+void
+NewObjectCache::clearNurseryObjects(JSRuntime* rt)
+{
+ for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
+ Entry& e = entries[i];
+ NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject);
+ if (IsInsideNursery(e.key) ||
+ rt->gc.nursery.isInside(obj->slots_) ||
+ rt->gc.nursery.isInside(obj->elements_))
+ {
+ PodZero(&e);
+ }
+ }
+}
diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
new file mode 100644
index 000000000..91a78bdc8
--- /dev/null
+++ b/js/src/vm/Caches.h
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Caches_h
+#define vm_Caches_h
+
+#include "jsatom.h"
+#include "jsbytecode.h"
+#include "jsobj.h"
+#include "jsscript.h"
+
+#include "ds/FixedSizeHash.h"
+#include "frontend/SourceNotes.h"
+#include "gc/Tracer.h"
+#include "js/RootingAPI.h"
+#include "js/UniquePtr.h"
+#include "vm/NativeObject.h"
+
+namespace js {
+
+/*
+ * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
+ * given pc in a script. We use the script->code pointer to tag the cache,
+ * instead of the script address itself, so that source notes are always found
+ * by offset from the bytecode with which they were generated.
+ */
+struct GSNCache {
+ typedef HashMap<jsbytecode*,
+ jssrcnote*,
+ PointerHasher<jsbytecode*, 0>,
+ SystemAllocPolicy> Map;
+
+ jsbytecode* code;
+ Map map;
+
+ GSNCache() : code(nullptr) { }
+
+ void purge();
+};
+
+/*
+ * EnvironmentCoordinateName cache to avoid O(n^2) growth in finding the name
+ * associated with a given aliasedvar operation.
+ */
+struct EnvironmentCoordinateNameCache {
+ typedef HashMap<uint32_t,
+ jsid,
+ DefaultHasher<uint32_t>,
+ SystemAllocPolicy> Map;
+
+ Shape* shape;
+ Map map;
+
+ EnvironmentCoordinateNameCache() : shape(nullptr) {}
+ void purge();
+};
+
+struct EvalCacheEntry
+{
+ JSLinearString* str;
+ JSScript* script;
+ JSScript* callerScript;
+ jsbytecode* pc;
+};
+
+struct EvalCacheLookup
+{
+ explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
+ RootedLinearString str;
+ RootedScript callerScript;
+ JSVersion version;
+ jsbytecode* pc;
+};
+
+struct EvalCacheHashPolicy
+{
+ typedef EvalCacheLookup Lookup;
+
+ static HashNumber hash(const Lookup& l);
+ static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
+};
+
+typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
+
+struct LazyScriptHashPolicy
+{
+ struct Lookup {
+ JSContext* cx;
+ LazyScript* lazy;
+
+ Lookup(JSContext* cx, LazyScript* lazy)
+ : cx(cx), lazy(lazy)
+ {}
+ };
+
+ static const size_t NumHashes = 3;
+
+ static void hash(const Lookup& lookup, HashNumber hashes[NumHashes]);
+ static bool match(JSScript* script, const Lookup& lookup);
+
+ // Alternate methods for use when removing scripts from the hash without an
+ // explicit LazyScript lookup.
+ static void hash(JSScript* script, HashNumber hashes[NumHashes]);
+ static bool match(JSScript* script, JSScript* lookup) { return script == lookup; }
+
+ static void clear(JSScript** pscript) { *pscript = nullptr; }
+ static bool isCleared(JSScript* script) { return !script; }
+};
+
+typedef FixedSizeHashSet<JSScript*, LazyScriptHashPolicy, 769> LazyScriptCache;
+
+class PropertyIteratorObject;
+
+class NativeIterCache
+{
+ static const size_t SIZE = size_t(1) << 8;
+
+ /* Cached native iterators. */
+ PropertyIteratorObject* data[SIZE];
+
+ static size_t getIndex(uint32_t key) {
+ return size_t(key) % SIZE;
+ }
+
+ public:
+ NativeIterCache() {
+ mozilla::PodArrayZero(data);
+ }
+
+ void purge() {
+ mozilla::PodArrayZero(data);
+ }
+
+ PropertyIteratorObject* get(uint32_t key) const {
+ return data[getIndex(key)];
+ }
+
+ void set(uint32_t key, PropertyIteratorObject* iterobj) {
+ data[getIndex(key)] = iterobj;
+ }
+};
+
+/*
+ * Cache for speeding up repetitive creation of objects in the VM.
+ * When an object is created which matches the criteria in the 'key' section
+ * below, an entry is filled with the resulting object.
+ */
+class NewObjectCache
+{
+ /* Statically asserted to be equal to sizeof(JSObject_Slots16) */
+ static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
+
+ static void staticAsserts() {
+ JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
+ JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
+ }
+
+ struct Entry
+ {
+ /* Class of the constructed object. */
+ const Class* clasp;
+
+ /*
+ * Key with one of three possible values:
+ *
+ * - Global for the object. The object must have a standard class for
+ * which the global's prototype can be determined, and the object's
+ * parent will be the global.
+ *
+ * - Prototype for the object (cannot be global). The object's parent
+ * will be the prototype's parent.
+ *
+ * - Type for the object. The object's parent will be the type's
+ * prototype's parent.
+ */
+ gc::Cell* key;
+
+ /* Allocation kind for the constructed object. */
+ gc::AllocKind kind;
+
+ /* Number of bytes to copy from the template object. */
+ uint32_t nbytes;
+
+ /*
+ * Template object to copy from, with the initial values of fields,
+ * fixed slots (undefined) and private data (nullptr).
+ */
+ char templateObject[MAX_OBJ_SIZE];
+ };
+
+ Entry entries[41]; // TODO: reconsider size
+
+ public:
+
+ typedef int EntryIndex;
+
+ NewObjectCache() { mozilla::PodZero(this); }
+ void purge() { mozilla::PodZero(this); }
+
+ /* Remove any cached items keyed on moved objects. */
+ void clearNurseryObjects(JSRuntime* rt);
+
+ /*
+ * Get the entry index for the given lookup, return whether there was a hit
+ * on an existing entry.
+ */
+ inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
+ inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
+ EntryIndex* pentry);
+
+ bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
+ return lookup(group->clasp(), group, kind, pentry);
+ }
+
+ /*
+ * Return a new object from a cache hit produced by a lookup method, or
+ * nullptr if returning the object could possibly trigger GC (does not
+ * indicate failure).
+ */
+ inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
+
+ /* Fill an entry after a cache miss. */
+ void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
+ gc::AllocKind kind, NativeObject* obj);
+
+ inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
+ gc::AllocKind kind, NativeObject* obj);
+
+ void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
+ NativeObject* obj)
+ {
+ MOZ_ASSERT(obj->group() == group);
+ return fill(entry, group->clasp(), group, kind, obj);
+ }
+
+ /* Invalidate any entries which might produce an object with shape/proto. */
+ void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
+
+ private:
+ EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
+ uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
+ return hash % mozilla::ArrayLength(entries);
+ }
+
+ bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
+ *pentry = makeIndex(clasp, key, kind);
+ Entry* entry = &entries[*pentry];
+
+ /* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
+ return entry->clasp == clasp && entry->key == key;
+ }
+
+ void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
+ NativeObject* obj) {
+ MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
+ MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
+ Entry* entry = &entries[entry_];
+
+ entry->clasp = clasp;
+ entry->key = key;
+ entry->kind = kind;
+
+ entry->nbytes = gc::Arena::thingSize(kind);
+ js_memcpy(&entry->templateObject, obj, entry->nbytes);
+ }
+
+ static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
+ js_memcpy(dst, src, gc::Arena::thingSize(kind));
+ Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
+ ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
+ }
+};
+
+class MathCache;
+
+class ContextCaches
+{
+ UniquePtr<js::MathCache> mathCache_;
+
+ js::MathCache* createMathCache(JSContext* cx);
+
+ public:
+ js::GSNCache gsnCache;
+ js::EnvironmentCoordinateNameCache envCoordinateNameCache;
+ js::NewObjectCache newObjectCache;
+ js::NativeIterCache nativeIterCache;
+ js::UncompressedSourceCache uncompressedSourceCache;
+ js::EvalCache evalCache;
+ js::LazyScriptCache lazyScriptCache;
+
+ bool init();
+
+ js::MathCache* getMathCache(JSContext* cx) {
+ return mathCache_ ? mathCache_.get() : createMathCache(cx);
+ }
+ js::MathCache* maybeGetMathCache() {
+ return mathCache_.get();
+ }
+};
+
+} // namespace js
+
+#endif /* vm_Caches_h */
diff --git a/js/src/vm/CallNonGenericMethod.cpp b/js/src/vm/CallNonGenericMethod.cpp
new file mode 100644
index 000000000..131c44742
--- /dev/null
+++ b/js/src/vm/CallNonGenericMethod.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/CallNonGenericMethod.h"
+
+#include "jsfun.h"
+#include "jsobj.h"
+
+#include "proxy/Proxy.h"
+#include "vm/ProxyObject.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+
+bool
+JS::detail::CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args)
+{
+ HandleValue thisv = args.thisv();
+ MOZ_ASSERT(!test(thisv));
+
+ if (thisv.isObject()) {
+ JSObject& thisObj = args.thisv().toObject();
+ if (thisObj.is<ProxyObject>())
+ return Proxy::nativeCall(cx, test, impl, args);
+ }
+
+ if (IsCallSelfHostedNonGenericMethod(impl))
+ return ReportIncompatibleSelfHostedMethod(cx, args);
+
+ ReportIncompatible(cx, args);
+ return false;
+}
+
diff --git a/js/src/vm/CaseFolding.txt b/js/src/vm/CaseFolding.txt
new file mode 100644
index 000000000..372ee68bd
--- /dev/null
+++ b/js/src/vm/CaseFolding.txt
@@ -0,0 +1,1495 @@
+# CaseFolding-9.0.0.txt
+# Date: 2016-03-02, 18:54:54 GMT
+# © 2016 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Unicode Character Database
+# 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:
+#
+# <code>; <status>; <mapping>; # <name>
+#
+# 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
+1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE
+1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE
+1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O
+1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES
+1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE
+1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE
+1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN
+1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT
+1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK
+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
+A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I
+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
+104B0; C; 104D8; # OSAGE CAPITAL LETTER A
+104B1; C; 104D9; # OSAGE CAPITAL LETTER AI
+104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN
+104B3; C; 104DB; # OSAGE CAPITAL LETTER AH
+104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA
+104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA
+104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA
+104B7; C; 104DF; # OSAGE CAPITAL LETTER E
+104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN
+104B9; C; 104E1; # OSAGE CAPITAL LETTER HA
+104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA
+104BB; C; 104E3; # OSAGE CAPITAL LETTER I
+104BC; C; 104E4; # OSAGE CAPITAL LETTER KA
+104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA
+104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA
+104BF; C; 104E7; # OSAGE CAPITAL LETTER LA
+104C0; C; 104E8; # OSAGE CAPITAL LETTER MA
+104C1; C; 104E9; # OSAGE CAPITAL LETTER NA
+104C2; C; 104EA; # OSAGE CAPITAL LETTER O
+104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN
+104C4; C; 104EC; # OSAGE CAPITAL LETTER PA
+104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA
+104C6; C; 104EE; # OSAGE CAPITAL LETTER SA
+104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA
+104C8; C; 104F0; # OSAGE CAPITAL LETTER TA
+104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA
+104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA
+104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA
+104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA
+104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA
+104CE; C; 104F6; # OSAGE CAPITAL LETTER U
+104CF; C; 104F7; # OSAGE CAPITAL LETTER WA
+104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA
+104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA
+104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA
+104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA
+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
+1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF
+1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI
+1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM
+1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM
+1E904; C; 1E926; # ADLAM CAPITAL LETTER BA
+1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE
+1E906; C; 1E928; # ADLAM CAPITAL LETTER PE
+1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE
+1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA
+1E909; C; 1E92B; # ADLAM CAPITAL LETTER E
+1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA
+1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I
+1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O
+1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA
+1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE
+1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW
+1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN
+1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF
+1E912; C; 1E934; # ADLAM CAPITAL LETTER YA
+1E913; C; 1E935; # ADLAM CAPITAL LETTER U
+1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM
+1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI
+1E916; C; 1E938; # ADLAM CAPITAL LETTER HA
+1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF
+1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA
+1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA
+1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU
+1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA
+1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA
+1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA
+1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE
+1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL
+1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO
+1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA
+#
+# EOF
diff --git a/js/src/vm/CharacterEncoding.cpp b/js/src/vm/CharacterEncoding.cpp
new file mode 100644
index 000000000..4644b0a36
--- /dev/null
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/CharacterEncoding.h"
+
+#include "mozilla/Range.h"
+#include "mozilla/Sprintf.h"
+
+#include <algorithm>
+#include <type_traits>
+
+#include "jscntxt.h"
+#include "jsprf.h"
+
+using namespace js;
+
+Latin1CharsZ
+JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx,
+ const mozilla::Range<const char16_t> tbchars)
+{
+ MOZ_ASSERT(cx);
+ size_t len = tbchars.length();
+ unsigned char* latin1 = cx->pod_malloc<unsigned char>(len + 1);
+ if (!latin1)
+ return Latin1CharsZ();
+ for (size_t i = 0; i < len; ++i)
+ latin1[i] = static_cast<unsigned char>(tbchars[i]);
+ latin1[len] = '\0';
+ return Latin1CharsZ(latin1, len);
+}
+
+template <typename CharT>
+static size_t
+GetDeflatedUTF8StringLength(const CharT* chars, size_t nchars)
+{
+ size_t nbytes = nchars;
+ for (const CharT* end = chars + nchars; chars < end; chars++) {
+ char16_t c = *chars;
+ if (c < 0x80)
+ continue;
+ uint32_t v;
+ if (0xD800 <= c && c <= 0xDFFF) {
+ /* nbytes sets 1 length since this is surrogate pair. */
+ if (c >= 0xDC00 || (chars + 1) == end) {
+ nbytes += 2; /* Bad Surrogate */
+ continue;
+ }
+ char16_t c2 = chars[1];
+ if (c2 < 0xDC00 || c2 > 0xDFFF) {
+ nbytes += 2; /* Bad Surrogate */
+ continue;
+ }
+ v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
+ nbytes--;
+ chars++;
+ } else {
+ v = c;
+ }
+ v >>= 11;
+ nbytes++;
+ while (v) {
+ v >>= 5;
+ nbytes++;
+ }
+ }
+ return nbytes;
+}
+
+JS_PUBLIC_API(size_t)
+JS::GetDeflatedUTF8StringLength(JSFlatString* s)
+{
+ JS::AutoCheckCannotGC nogc;
+ return s->hasLatin1Chars()
+ ? ::GetDeflatedUTF8StringLength(s->latin1Chars(nogc), s->length())
+ : ::GetDeflatedUTF8StringLength(s->twoByteChars(nogc), s->length());
+}
+
+static const char16_t UTF8_REPLACEMENT_CHAR = 0xFFFD;
+
+template <typename CharT>
+static void
+DeflateStringToUTF8Buffer(const CharT* src, size_t srclen, mozilla::RangedPtr<char> dst,
+ size_t* dstlenp = nullptr, size_t* numcharsp = nullptr)
+{
+ size_t capacity = 0;
+ if (dstlenp) {
+ capacity = *dstlenp;
+ *dstlenp = 0;
+ }
+ if (numcharsp)
+ *numcharsp = 0;
+
+ while (srclen) {
+ uint32_t v;
+ char16_t c = *src++;
+ srclen--;
+ if (c >= 0xDC00 && c <= 0xDFFF) {
+ v = UTF8_REPLACEMENT_CHAR;
+ } else if (c < 0xD800 || c > 0xDBFF) {
+ v = c;
+ } else {
+ if (srclen < 1) {
+ v = UTF8_REPLACEMENT_CHAR;
+ } else {
+ char16_t c2 = *src;
+ if (c2 < 0xDC00 || c2 > 0xDFFF) {
+ v = UTF8_REPLACEMENT_CHAR;
+ } else {
+ src++;
+ srclen--;
+ v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
+ }
+ }
+ }
+
+ size_t utf8Len;
+ if (v < 0x0080) {
+ /* no encoding necessary - performance hack */
+ if (dstlenp && *dstlenp + 1 > capacity)
+ return;
+ *dst++ = char(v);
+ utf8Len = 1;
+ } else {
+ uint8_t utf8buf[4];
+ utf8Len = OneUcs4ToUtf8Char(utf8buf, v);
+ if (dstlenp && *dstlenp + utf8Len > capacity)
+ return;
+ for (size_t i = 0; i < utf8Len; i++)
+ *dst++ = char(utf8buf[i]);
+ }
+
+ if (dstlenp)
+ *dstlenp += utf8Len;
+ if (numcharsp)
+ (*numcharsp)++;
+ }
+}
+
+JS_PUBLIC_API(void)
+JS::DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr<char> dst,
+ size_t* dstlenp, size_t* numcharsp)
+{
+ JS::AutoCheckCannotGC nogc;
+ return src->hasLatin1Chars()
+ ? ::DeflateStringToUTF8Buffer(src->latin1Chars(nogc), src->length(), dst,
+ dstlenp, numcharsp)
+ : ::DeflateStringToUTF8Buffer(src->twoByteChars(nogc), src->length(), dst,
+ dstlenp, numcharsp);
+}
+
+template <typename CharT>
+UTF8CharsZ
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range<CharT> chars)
+{
+ /* Get required buffer size. */
+ const CharT* str = chars.begin().get();
+ size_t len = ::GetDeflatedUTF8StringLength(str, chars.length());
+
+ /* Allocate buffer. */
+ char* utf8;
+ if (maybeCx)
+ utf8 = maybeCx->pod_malloc<char>(len + 1);
+ else
+ utf8 = js_pod_malloc<char>(len + 1);
+ if (!utf8)
+ return UTF8CharsZ();
+
+ /* Encode to UTF8. */
+ ::DeflateStringToUTF8Buffer(str, chars.length(), mozilla::RangedPtr<char>(utf8, len));
+ utf8[len] = '\0';
+
+ return UTF8CharsZ(utf8, len);
+}
+
+template UTF8CharsZ
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx,
+ const mozilla::Range<Latin1Char> chars);
+
+template UTF8CharsZ
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx,
+ const mozilla::Range<char16_t> chars);
+
+template UTF8CharsZ
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx,
+ const mozilla::Range<const Latin1Char> chars);
+
+template UTF8CharsZ
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx,
+ const mozilla::Range<const char16_t> chars);
+
+static const uint32_t INVALID_UTF8 = UINT32_MAX;
+
+/*
+ * Convert a utf8 character sequence into a UCS-4 character and return that
+ * character. It is assumed that the caller already checked that the sequence
+ * is valid.
+ */
+uint32_t
+JS::Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length)
+{
+ MOZ_ASSERT(1 <= utf8Length && utf8Length <= 4);
+
+ if (utf8Length == 1) {
+ MOZ_ASSERT(!(*utf8Buffer & 0x80));
+ return *utf8Buffer;
+ }
+
+ /* from Unicode 3.1, non-shortest form is illegal */
+ static const uint32_t minucs4Table[] = { 0x80, 0x800, 0x10000 };
+
+ MOZ_ASSERT((*utf8Buffer & (0x100 - (1 << (7 - utf8Length)))) ==
+ (0x100 - (1 << (8 - utf8Length))));
+ uint32_t ucs4Char = *utf8Buffer++ & ((1 << (7 - utf8Length)) - 1);
+ uint32_t minucs4Char = minucs4Table[utf8Length - 2];
+ while (--utf8Length) {
+ MOZ_ASSERT((*utf8Buffer & 0xC0) == 0x80);
+ ucs4Char = (ucs4Char << 6) | (*utf8Buffer++ & 0x3F);
+ }
+
+ if (MOZ_UNLIKELY(ucs4Char < minucs4Char || (ucs4Char >= 0xD800 && ucs4Char <= 0xDFFF)))
+ return INVALID_UTF8;
+
+ return ucs4Char;
+}
+
+static void
+ReportInvalidCharacter(JSContext* cx, uint32_t offset)
+{
+ char buffer[10];
+ SprintfLiteral(buffer, "%u", offset);
+ JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
+ JSMSG_MALFORMED_UTF8_CHAR, buffer);
+}
+
+static void
+ReportInvalidCharacter(js::ExclusiveContext* cx, uint32_t offset)
+{
+}
+
+static void
+ReportBufferTooSmall(JSContext* cx, uint32_t dummy)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
+}
+
+static void
+ReportBufferTooSmall(js::ExclusiveContext* cx, uint32_t dummy)
+{
+}
+
+static void
+ReportTooBigCharacter(JSContext* cx, uint32_t v)
+{
+ char buffer[10];
+ SprintfLiteral(buffer, "0x%x", v + 0x10000);
+ JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
+ JSMSG_UTF8_CHAR_TOO_LARGE, buffer);
+}
+
+static void
+ReportTooBigCharacter(js::ExclusiveContext* cx, uint32_t v)
+{
+}
+
+enum InflateUTF8Action {
+ CountAndReportInvalids,
+ CountAndIgnoreInvalids,
+ AssertNoInvalids,
+ Copy,
+ FindEncoding
+};
+
+static const char16_t REPLACE_UTF8 = 0xFFFD;
+static const Latin1Char REPLACE_UTF8_LATIN1 = '?';
+
+// If making changes to this algorithm, make sure to also update
+// LossyConvertUTF8toUTF16() in dom/wifi/WifiUtils.cpp
+template <InflateUTF8Action Action, typename CharT, class ContextT>
+static bool
+InflateUTF8StringToBuffer(ContextT* cx, const UTF8Chars src, CharT* dst, size_t* dstlenp,
+ JS::SmallestEncoding *smallestEncoding)
+{
+ if (Action != AssertNoInvalids)
+ *smallestEncoding = JS::SmallestEncoding::ASCII;
+ auto RequireLatin1 = [&smallestEncoding]{
+ *smallestEncoding = std::max(JS::SmallestEncoding::Latin1, *smallestEncoding);
+ };
+ auto RequireUTF16 = [&smallestEncoding]{
+ *smallestEncoding = JS::SmallestEncoding::UTF16;
+ };
+
+ // Count how many code units need to be in the inflated string.
+ // |i| is the index into |src|, and |j| is the the index into |dst|.
+ size_t srclen = src.length();
+ uint32_t j = 0;
+ for (uint32_t i = 0; i < srclen; i++, j++) {
+ uint32_t v = uint32_t(src[i]);
+ if (!(v & 0x80)) {
+ // ASCII code unit. Simple copy.
+ if (Action == Copy)
+ dst[j] = CharT(v);
+
+ } else {
+ // Non-ASCII code unit. Determine its length in bytes (n).
+ uint32_t n = 1;
+ while (v & (0x80 >> n))
+ n++;
+
+ #define INVALID(report, arg, n2) \
+ do { \
+ if (Action == CountAndReportInvalids) { \
+ report(cx, arg); \
+ return false; \
+ } else if (Action == AssertNoInvalids) { \
+ MOZ_CRASH("invalid UTF-8 string: " # report); \
+ } else { \
+ if (Action == Copy) { \
+ if (std::is_same<decltype(dst[0]), Latin1Char>::value) \
+ dst[j] = CharT(REPLACE_UTF8_LATIN1); \
+ else \
+ dst[j] = CharT(REPLACE_UTF8); \
+ } else { \
+ MOZ_ASSERT(Action == CountAndIgnoreInvalids || \
+ Action == FindEncoding); \
+ } \
+ n = n2; \
+ goto invalidMultiByteCodeUnit; \
+ } \
+ } while (0)
+
+ // Check the leading byte.
+ if (n < 2 || n > 4)
+ INVALID(ReportInvalidCharacter, i, 1);
+
+ // Check that |src| is large enough to hold an n-byte code unit.
+ if (i + n > srclen)
+ INVALID(ReportBufferTooSmall, /* dummy = */ 0, 1);
+
+ // Check the second byte. From Unicode Standard v6.2, Table 3-7
+ // Well-Formed UTF-8 Byte Sequences.
+ if ((v == 0xE0 && ((uint8_t)src[i + 1] & 0xE0) != 0xA0) || // E0 A0~BF
+ (v == 0xED && ((uint8_t)src[i + 1] & 0xE0) != 0x80) || // ED 80~9F
+ (v == 0xF0 && ((uint8_t)src[i + 1] & 0xF0) == 0x80) || // F0 90~BF
+ (v == 0xF4 && ((uint8_t)src[i + 1] & 0xF0) != 0x80)) // F4 80~8F
+ {
+ INVALID(ReportInvalidCharacter, i, 1);
+ }
+
+ // Check the continuation bytes.
+ for (uint32_t m = 1; m < n; m++) {
+ if ((src[i + m] & 0xC0) != 0x80)
+ INVALID(ReportInvalidCharacter, i, m);
+ }
+
+ // Determine the code unit's length in CharT and act accordingly.
+ v = JS::Utf8ToOneUcs4Char((uint8_t*)&src[i], n);
+ if (Action != AssertNoInvalids) {
+ if (v > 0xff) {
+ RequireUTF16();
+ if (Action == FindEncoding) {
+ MOZ_ASSERT(dst == nullptr);
+ return true;
+ }
+ } else {
+ RequireLatin1();
+ }
+ }
+ if (v < 0x10000) {
+ // The n-byte UTF8 code unit will fit in a single CharT.
+ if (Action == Copy)
+ dst[j] = CharT(v);
+ } else {
+ v -= 0x10000;
+ if (v <= 0xFFFFF) {
+ // The n-byte UTF8 code unit will fit in two CharT units.
+ if (Action == Copy)
+ dst[j] = CharT((v >> 10) + 0xD800);
+ j++;
+ if (Action == Copy)
+ dst[j] = CharT((v & 0x3FF) + 0xDC00);
+
+ } else {
+ // The n-byte UTF8 code unit won't fit in two CharT units.
+ INVALID(ReportTooBigCharacter, v, 1);
+ }
+ }
+
+ invalidMultiByteCodeUnit:
+ // Move i to the last byte of the multi-byte code unit; the loop
+ // header will do the final i++ to move to the start of the next
+ // code unit.
+ i += n - 1;
+ if (Action != AssertNoInvalids)
+ RequireUTF16();
+ }
+ }
+
+ if (Action != AssertNoInvalids && Action != FindEncoding)
+ *dstlenp = j;
+
+ return true;
+}
+
+template <InflateUTF8Action Action, typename CharsT, class ContextT>
+static CharsT
+InflateUTF8StringHelper(ContextT* cx, const UTF8Chars src, size_t* outlen)
+{
+ using CharT = typename CharsT::CharT;
+ *outlen = 0;
+
+ JS::SmallestEncoding encoding;
+ if (!InflateUTF8StringToBuffer<Action, CharT>(cx, src, /* dst = */ nullptr, outlen, &encoding))
+ return CharsT();
+
+ CharT* dst = cx->template pod_malloc<CharT>(*outlen + 1); // +1 for NUL
+ if (!dst) {
+ ReportOutOfMemory(cx);
+ return CharsT();
+ }
+
+ if (encoding == JS::SmallestEncoding::ASCII) {
+ size_t srclen = src.length();
+ MOZ_ASSERT(*outlen == srclen);
+ for (uint32_t i = 0; i < srclen; i++)
+ dst[i] = CharT(src[i]);
+ } else {
+ MOZ_ALWAYS_TRUE((InflateUTF8StringToBuffer<Copy, CharT>(cx, src, dst, outlen, &encoding)));
+ }
+
+ dst[*outlen] = 0; // NUL char
+
+ return CharsT(dst, *outlen);
+}
+
+TwoByteCharsZ
+JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
+{
+ return InflateUTF8StringHelper<CountAndReportInvalids, TwoByteCharsZ>(cx, utf8, outlen);
+}
+
+TwoByteCharsZ
+JS::UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen)
+{
+ UTF8Chars chars(utf8.c_str(), strlen(utf8.c_str()));
+ return InflateUTF8StringHelper<CountAndReportInvalids, TwoByteCharsZ>(cx, chars, outlen);
+}
+
+TwoByteCharsZ
+js::LossyUTF8CharsToNewTwoByteCharsZ(js::ExclusiveContext* cx, const JS::UTF8Chars utf8, size_t* outlen)
+{
+ return InflateUTF8StringHelper<CountAndIgnoreInvalids, TwoByteCharsZ>(cx, utf8, outlen);
+}
+
+TwoByteCharsZ
+JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
+{
+ return js::LossyUTF8CharsToNewTwoByteCharsZ(cx, utf8, outlen);
+}
+
+TwoByteCharsZ
+js::LossyUTF8CharsToNewTwoByteCharsZ(js::ExclusiveContext* cx, const JS::ConstUTF8CharsZ& utf8, size_t* outlen)
+{
+ UTF8Chars chars(utf8.c_str(), strlen(utf8.c_str()));
+ return InflateUTF8StringHelper<CountAndIgnoreInvalids, TwoByteCharsZ>(cx, chars, outlen);
+}
+
+TwoByteCharsZ
+JS::LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen)
+{
+ return js::LossyUTF8CharsToNewTwoByteCharsZ(cx, utf8, outlen);
+}
+
+JS::SmallestEncoding
+JS::FindSmallestEncoding(UTF8Chars utf8)
+{
+ JS::SmallestEncoding encoding;
+ MOZ_ALWAYS_TRUE((InflateUTF8StringToBuffer<FindEncoding, char16_t, JSContext>(
+ /* cx = */ nullptr,
+ utf8,
+ /* dst = */ nullptr,
+ /* dstlen = */ nullptr,
+ &encoding)));
+ return encoding;
+}
+
+Latin1CharsZ
+JS::UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
+{
+ return InflateUTF8StringHelper<CountAndReportInvalids, Latin1CharsZ>(cx, utf8, outlen);
+}
+
+Latin1CharsZ
+js::LossyUTF8CharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const JS::UTF8Chars utf8, size_t* outlen)
+{
+ return InflateUTF8StringHelper<CountAndIgnoreInvalids, Latin1CharsZ>(cx, utf8, outlen);
+}
+
+Latin1CharsZ
+JS::LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen)
+{
+ return js::LossyUTF8CharsToNewLatin1CharsZ(cx, utf8, outlen);
+}
+
+#ifdef DEBUG
+void
+JS::ConstUTF8CharsZ::validate(size_t aLength)
+{
+ MOZ_ASSERT(data_);
+ UTF8Chars chars(data_, aLength);
+ InflateUTF8StringToBuffer<AssertNoInvalids, char16_t, JSContext>(
+ /* cx = */ nullptr,
+ chars,
+ /* dst = */ nullptr,
+ /* dstlen = */ nullptr,
+ /* smallestEncoding = */ nullptr);
+}
+#endif
+
+bool
+JS::StringIsASCII(const char* s)
+{
+ while (*s) {
+ if (*s & 0x80)
+ return false;
+ s++;
+ }
+ return true;
+}
diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp
new file mode 100644
index 000000000..e7146a32a
--- /dev/null
+++ b/js/src/vm/CodeCoverage.cpp
@@ -0,0 +1,636 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/CodeCoverage.h"
+
+#include "mozilla/Atomics.h"
+#include "mozilla/IntegerPrintfMacros.h"
+
+#include <stdio.h>
+#if defined(XP_WIN)
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include "jscompartment.h"
+#include "jsopcode.h"
+#include "jsprf.h"
+#include "jsscript.h"
+
+#include "vm/Runtime.h"
+#include "vm/Time.h"
+
+// This file contains a few functions which are used to produce files understood
+// by lcov tools. A detailed description of the format is available in the man
+// page for "geninfo" [1]. To make it short, the following paraphrases what is
+// commented in the man page by using curly braces prefixed by for-each to
+// express repeated patterns.
+//
+// TN:<compartment name>
+// for-each <source file> {
+// SN:<filename>
+// for-each <script> {
+// FN:<line>,<name>
+// }
+// for-each <script> {
+// FNDA:<hits>,<name>
+// }
+// FNF:<number of scripts>
+// FNH:<sum of scripts hits>
+// for-each <script> {
+// for-each <branch> {
+// BRDA:<line>,<block id>,<target id>,<taken>
+// }
+// }
+// BRF:<number of branches>
+// BRH:<sum of branches hits>
+// for-each <script> {
+// for-each <line> {
+// DA:<line>,<hits>
+// }
+// }
+// LF:<number of lines>
+// LH:<sum of lines hits>
+// }
+//
+// [1] http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
+//
+namespace js {
+namespace coverage {
+
+LCovSource::LCovSource(LifoAlloc* alloc, JSObject* sso)
+ : source_(sso),
+ outSF_(alloc),
+ outFN_(alloc),
+ outFNDA_(alloc),
+ numFunctionsFound_(0),
+ numFunctionsHit_(0),
+ outBRDA_(alloc),
+ numBranchesFound_(0),
+ numBranchesHit_(0),
+ outDA_(alloc),
+ numLinesInstrumented_(0),
+ numLinesHit_(0),
+ hasFilename_(false),
+ hasTopLevelScript_(false)
+{
+}
+
+void
+LCovSource::exportInto(GenericPrinter& out) const
+{
+ // Only write if everything got recorded.
+ if (!hasFilename_ || !hasTopLevelScript_)
+ return;
+
+ outSF_.exportInto(out);
+
+ outFN_.exportInto(out);
+ outFNDA_.exportInto(out);
+ out.printf("FNF:%" PRIuSIZE "\n", numFunctionsFound_);
+ out.printf("FNH:%" PRIuSIZE "\n", numFunctionsHit_);
+
+ outBRDA_.exportInto(out);
+ out.printf("BRF:%" PRIuSIZE "\n", numBranchesFound_);
+ out.printf("BRH:%" PRIuSIZE "\n", numBranchesHit_);
+
+ outDA_.exportInto(out);
+ out.printf("LF:%" PRIuSIZE "\n", numLinesInstrumented_);
+ out.printf("LH:%" PRIuSIZE "\n", numLinesHit_);
+
+ out.put("end_of_record\n");
+}
+
+bool
+LCovSource::writeSourceFilename(ScriptSourceObject* sso)
+{
+ outSF_.printf("SF:%s\n", sso->source()->filename());
+ if (outSF_.hadOutOfMemory())
+ return false;
+
+ hasFilename_ = true;
+ return true;
+}
+
+bool
+LCovSource::writeScriptName(LSprinter& out, JSScript* script)
+{
+ JSFunction* fun = script->functionNonDelazifying();
+ if (fun && fun->displayAtom())
+ return EscapedStringPrinter(out, fun->displayAtom(), 0);
+ out.printf("top-level");
+ return true;
+}
+
+bool
+LCovSource::writeScript(JSScript* script)
+{
+ numFunctionsFound_++;
+ outFN_.printf("FN:%" PRIuSIZE ",", script->lineno());
+ if (!writeScriptName(outFN_, script))
+ return false;
+ outFN_.put("\n", 1);
+
+ uint64_t hits = 0;
+ ScriptCounts* sc = nullptr;
+ if (script->hasScriptCounts()) {
+ sc = &script->getScriptCounts();
+ numFunctionsHit_++;
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(script->main()));
+ outFNDA_.printf("FNDA:%" PRIu64 ",", counts->numExec());
+ if (!writeScriptName(outFNDA_, script))
+ return false;
+ outFNDA_.put("\n", 1);
+
+ // Set the hit count of the pre-main code to 1, if the function ever got
+ // visited.
+ hits = 1;
+ }
+
+ jsbytecode* snpc = script->code();
+ jssrcnote* sn = script->notes();
+ if (!SN_IS_TERMINATOR(sn))
+ snpc += SN_DELTA(sn);
+
+ size_t lineno = script->lineno();
+ jsbytecode* end = script->codeEnd();
+ size_t branchId = 0;
+ size_t tableswitchExitOffset = 0;
+ for (jsbytecode* pc = script->code(); pc != end; pc = GetNextPc(pc)) {
+ JSOp op = JSOp(*pc);
+ bool jump = IsJumpOpcode(op) || op == JSOP_TABLESWITCH;
+ bool fallsthrough = BytecodeFallsThrough(op) && op != JSOP_GOSUB;
+
+ // If the current script & pc has a hit-count report, then update the
+ // current number of hits.
+ if (sc) {
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(pc));
+ if (counts)
+ hits = counts->numExec();
+ }
+
+ // If we have additional source notes, walk all the source notes of the
+ // current pc.
+ if (snpc <= pc) {
+ size_t oldLine = lineno;
+ while (!SN_IS_TERMINATOR(sn) && snpc <= pc) {
+ SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
+ if (type == SRC_SETLINE)
+ lineno = size_t(GetSrcNoteOffset(sn, 0));
+ else if (type == SRC_NEWLINE)
+ lineno++;
+ else if (type == SRC_TABLESWITCH)
+ tableswitchExitOffset = GetSrcNoteOffset(sn, 0);
+
+ sn = SN_NEXT(sn);
+ snpc += SN_DELTA(sn);
+ }
+
+ if (oldLine != lineno && fallsthrough) {
+ outDA_.printf("DA:%" PRIuSIZE ",%" PRIu64 "\n", lineno, hits);
+
+ // Count the number of lines instrumented & hit.
+ numLinesInstrumented_++;
+ if (hits)
+ numLinesHit_++;
+ }
+ }
+
+ // If the current instruction has thrown, then decrement the hit counts
+ // with the number of throws.
+ if (sc) {
+ const PCCounts* counts = sc->maybeGetThrowCounts(script->pcToOffset(pc));
+ if (counts)
+ hits -= counts->numExec();
+ }
+
+ // If the current pc corresponds to a conditional jump instruction, then reports
+ // branch hits.
+ if (jump && fallsthrough) {
+ jsbytecode* fallthroughTarget = GetNextPc(pc);
+ uint64_t fallthroughHits = 0;
+ if (sc) {
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(fallthroughTarget));
+ if (counts)
+ fallthroughHits = counts->numExec();
+ }
+
+ uint64_t taken = hits - fallthroughHits;
+ outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",0,", lineno, branchId);
+ if (taken)
+ outBRDA_.printf("%" PRIu64 "\n", taken);
+ else
+ outBRDA_.put("-\n", 2);
+
+ outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",1,", lineno, branchId);
+ if (fallthroughHits)
+ outBRDA_.printf("%" PRIu64 "\n", fallthroughHits);
+ else
+ outBRDA_.put("-\n", 2);
+
+ // Count the number of branches, and the number of branches hit.
+ numBranchesFound_ += 2;
+ if (hits)
+ numBranchesHit_ += !!taken + !!fallthroughHits;
+ branchId++;
+ }
+
+ // If the current pc corresponds to a pre-computed switch case, then
+ // reports branch hits for each case statement.
+ if (jump && op == JSOP_TABLESWITCH) {
+ MOZ_ASSERT(tableswitchExitOffset != 0);
+
+ // Get the default and exit pc
+ jsbytecode* exitpc = pc + tableswitchExitOffset;
+ jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc);
+ MOZ_ASSERT(defaultpc > pc && defaultpc <= exitpc);
+
+ // Get the low and high from the tableswitch
+ int32_t low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 1);
+ int32_t high = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 2);
+ MOZ_ASSERT(high - low + 1 >= 0);
+ size_t numCases = high - low + 1;
+ jsbytecode* jumpTable = pc + JUMP_OFFSET_LEN * 3;
+
+ jsbytecode* firstcasepc = exitpc;
+ for (size_t j = 0; j < numCases; j++) {
+ jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
+ if (testpc < firstcasepc)
+ firstcasepc = testpc;
+ }
+
+ // Count the number of hits of the default branch, by subtracting
+ // the number of hits of each cases.
+ uint64_t defaultHits = hits;
+
+ // Count the number of hits of the previous case entry.
+ uint64_t fallsThroughHits = 0;
+
+ // Record branches for each cases.
+ size_t caseId = 0;
+ for (size_t i = 0; i < numCases; i++) {
+ jsbytecode* casepc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * i);
+ // The case is not present, and jumps to the default pc if used.
+ if (casepc == pc)
+ continue;
+
+ // PCs might not be in increasing order of case indexes.
+ jsbytecode* lastcasepc = firstcasepc - 1;
+ for (size_t j = 0; j < numCases; j++) {
+ jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
+ if (lastcasepc < testpc && (testpc < casepc || (j < i && testpc == casepc)))
+ lastcasepc = testpc;
+ }
+
+ if (casepc != lastcasepc) {
+ // Case (i + low)
+ uint64_t caseHits = 0;
+ if (sc) {
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(casepc));
+ if (counts)
+ caseHits = counts->numExec();
+
+ // Remove fallthrough.
+ fallsThroughHits = 0;
+ if (casepc != firstcasepc) {
+ jsbytecode* endpc = lastcasepc;
+ while (GetNextPc(endpc) < casepc)
+ endpc = GetNextPc(endpc);
+
+ if (BytecodeFallsThrough(JSOp(*endpc)))
+ fallsThroughHits = script->getHitCount(endpc);
+ }
+
+ caseHits -= fallsThroughHits;
+ }
+
+ outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",%" PRIuSIZE ",",
+ lineno, branchId, caseId);
+ if (caseHits)
+ outBRDA_.printf("%" PRIu64 "\n", caseHits);
+ else
+ outBRDA_.put("-\n", 2);
+
+ numBranchesFound_++;
+ numBranchesHit_ += !!caseHits;
+ defaultHits -= caseHits;
+ caseId++;
+ }
+ }
+
+ // Compute the number of hits of the default branch, if it has its
+ // own case clause.
+ bool defaultHasOwnClause = true;
+ if (defaultpc != exitpc) {
+ defaultHits = 0;
+
+ // Look for the last case entry before the default pc.
+ jsbytecode* lastcasepc = firstcasepc - 1;
+ for (size_t j = 0; j < numCases; j++) {
+ jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
+ if (lastcasepc < testpc && testpc <= defaultpc)
+ lastcasepc = testpc;
+ }
+
+ if (lastcasepc == defaultpc)
+ defaultHasOwnClause = false;
+
+ // Look if the last case entry fallthrough to the default case,
+ // in which case we have to remove the number of fallthrough
+ // hits out of the default case hits.
+ if (sc && lastcasepc != pc) {
+ jsbytecode* endpc = lastcasepc;
+ while (GetNextPc(endpc) < defaultpc)
+ endpc = GetNextPc(endpc);
+
+ if (BytecodeFallsThrough(JSOp(*endpc)))
+ fallsThroughHits = script->getHitCount(endpc);
+ }
+
+ if (sc) {
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(defaultpc));
+ if (counts)
+ defaultHits = counts->numExec();
+ }
+ defaultHits -= fallsThroughHits;
+ }
+
+ if (defaultHasOwnClause) {
+ outBRDA_.printf("BRDA:%" PRIuSIZE ",%" PRIuSIZE ",%" PRIuSIZE ",",
+ lineno, branchId, caseId);
+ if (defaultHits)
+ outBRDA_.printf("%" PRIu64 "\n", defaultHits);
+ else
+ outBRDA_.put("-\n", 2);
+ numBranchesFound_++;
+ numBranchesHit_ += !!defaultHits;
+ }
+
+ // Increment the branch identifier, and go to the next instruction.
+ branchId++;
+ tableswitchExitOffset = 0;
+ }
+ }
+
+ // Report any new OOM.
+ if (outFN_.hadOutOfMemory() ||
+ outFNDA_.hadOutOfMemory() ||
+ outBRDA_.hadOutOfMemory() ||
+ outDA_.hadOutOfMemory())
+ {
+ return false;
+ }
+
+ // If this script is the top-level script, then record it such that we can
+ // assume that the code coverage report is complete, as this script has
+ // references on all inner scripts.
+ if (script->isTopLevel())
+ hasTopLevelScript_ = true;
+
+ return true;
+}
+
+LCovCompartment::LCovCompartment()
+ : alloc_(4096),
+ outTN_(&alloc_),
+ sources_(nullptr)
+{
+ MOZ_ASSERT(alloc_.isEmpty());
+}
+
+void
+LCovCompartment::collectCodeCoverageInfo(JSCompartment* comp, JSObject* sso,
+ JSScript* script)
+{
+ // Skip any operation if we already some out-of memory issues.
+ if (outTN_.hadOutOfMemory())
+ return;
+
+ if (!script->code())
+ return;
+
+ // Get the existing source LCov summary, or create a new one.
+ LCovSource* source = lookupOrAdd(comp, sso);
+ if (!source)
+ return;
+
+ // Write code coverage data into the LCovSource.
+ if (!source->writeScript(script)) {
+ outTN_.reportOutOfMemory();
+ return;
+ }
+}
+
+void
+LCovCompartment::collectSourceFile(JSCompartment* comp, ScriptSourceObject* sso)
+{
+ // Do not add sources if there is no file name associated to it.
+ if (!sso->source()->filename())
+ return;
+
+ // Skip any operation if we already some out-of memory issues.
+ if (outTN_.hadOutOfMemory())
+ return;
+
+ // Get the existing source LCov summary, or create a new one.
+ LCovSource* source = lookupOrAdd(comp, sso);
+ if (!source)
+ return;
+
+ // Write source filename into the LCovSource.
+ if (!source->writeSourceFilename(sso)) {
+ outTN_.reportOutOfMemory();
+ return;
+ }
+}
+
+LCovSource*
+LCovCompartment::lookupOrAdd(JSCompartment* comp, JSObject* sso)
+{
+ // On the first call, write the compartment name, and allocate a LCovSource
+ // vector in the LifoAlloc.
+ if (!sources_) {
+ if (!writeCompartmentName(comp))
+ return nullptr;
+
+ LCovSourceVector* raw = alloc_.pod_malloc<LCovSourceVector>();
+ if (!raw) {
+ outTN_.reportOutOfMemory();
+ return nullptr;
+ }
+
+ sources_ = new(raw) LCovSourceVector(alloc_);
+ } else {
+ // Find the first matching source.
+ for (LCovSource& source : *sources_) {
+ if (source.match(sso))
+ return &source;
+ }
+ }
+
+ // Allocate a new LCovSource for the current top-level.
+ if (!sources_->append(Move(LCovSource(&alloc_, sso)))) {
+ outTN_.reportOutOfMemory();
+ return nullptr;
+ }
+
+ return &sources_->back();
+}
+
+void
+LCovCompartment::exportInto(GenericPrinter& out, bool* isEmpty) const
+{
+ if (!sources_ || outTN_.hadOutOfMemory())
+ return;
+
+ // If we only have cloned function, then do not serialize anything.
+ bool someComplete = false;
+ for (const LCovSource& sc : *sources_) {
+ if (sc.isComplete()) {
+ someComplete = true;
+ break;
+ };
+ }
+
+ if (!someComplete)
+ return;
+
+ *isEmpty = false;
+ outTN_.exportInto(out);
+ for (const LCovSource& sc : *sources_) {
+ if (sc.isComplete())
+ sc.exportInto(out);
+ }
+}
+
+bool
+LCovCompartment::writeCompartmentName(JSCompartment* comp)
+{
+ JSContext* cx = comp->contextFromMainThread();
+
+ // lcov trace files are starting with an optional test case name, that we
+ // recycle to be a compartment name.
+ //
+ // Note: The test case name has some constraint in terms of valid character,
+ // thus we escape invalid chracters with a "_" symbol in front of its
+ // hexadecimal code.
+ outTN_.put("TN:");
+ if (cx->compartmentNameCallback) {
+ char name[1024];
+ {
+ // Hazard analysis cannot tell that the callback does not GC.
+ JS::AutoSuppressGCAnalysis nogc;
+ (*cx->compartmentNameCallback)(cx, comp, name, sizeof(name));
+ }
+ for (char *s = name; s < name + sizeof(name) && *s; s++) {
+ if (('a' <= *s && *s <= 'z') ||
+ ('A' <= *s && *s <= 'Z') ||
+ ('0' <= *s && *s <= '9'))
+ {
+ outTN_.put(s, 1);
+ continue;
+ }
+ outTN_.printf("_%p", (void*) size_t(*s));
+ }
+ outTN_.put("\n", 1);
+ } else {
+ outTN_.printf("Compartment_%p%p\n", (void*) size_t('_'), comp);
+ }
+
+ return !outTN_.hadOutOfMemory();
+}
+
+LCovRuntime::LCovRuntime()
+ : out_(),
+#if defined(XP_WIN)
+ pid_(GetCurrentProcessId()),
+#else
+ pid_(getpid()),
+#endif
+ isEmpty_(false)
+{
+}
+
+LCovRuntime::~LCovRuntime()
+{
+ if (out_.isInitialized())
+ finishFile();
+}
+
+bool
+LCovRuntime::fillWithFilename(char *name, size_t length)
+{
+ const char* outDir = getenv("JS_CODE_COVERAGE_OUTPUT_DIR");
+ if (!outDir || *outDir == 0)
+ return false;
+
+ int64_t timestamp = static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_SEC;
+ static mozilla::Atomic<size_t> globalRuntimeId(0);
+ size_t rid = globalRuntimeId++;
+
+ int len = snprintf(name, length, "%s/%" PRId64 "-%" PRIuSIZE "-%" PRIuSIZE ".info",
+ outDir, timestamp, pid_, rid);
+ if (length != size_t(len)) {
+ fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name.");
+ return false;
+ }
+
+ return true;
+}
+
+void
+LCovRuntime::init()
+{
+ char name[1024];
+ if (!fillWithFilename(name, sizeof(name)))
+ return;
+
+ // If we cannot open the file, report a warning.
+ if (!out_.init(name))
+ fprintf(stderr, "Warning: LCovRuntime::init: Cannot open file named '%s'.", name);
+ isEmpty_ = true;
+}
+
+void
+LCovRuntime::finishFile()
+{
+ MOZ_ASSERT(out_.isInitialized());
+ out_.finish();
+
+ if (isEmpty_) {
+ char name[1024];
+ if (!fillWithFilename(name, sizeof(name)))
+ return;
+ remove(name);
+ }
+}
+
+void
+LCovRuntime::writeLCovResult(LCovCompartment& comp)
+{
+ if (!out_.isInitialized())
+ return;
+
+#if defined(XP_WIN)
+ size_t p = GetCurrentProcessId();
+#else
+ size_t p = getpid();
+#endif
+ if (pid_ != p) {
+ pid_ = p;
+ finishFile();
+ init();
+ if (!out_.isInitialized())
+ return;
+ }
+
+ comp.exportInto(out_, &isEmpty_);
+ out_.flush();
+}
+
+} // namespace coverage
+} // namespace js
diff --git a/js/src/vm/CodeCoverage.h b/js/src/vm/CodeCoverage.h
new file mode 100644
index 000000000..8ab6272d1
--- /dev/null
+++ b/js/src/vm/CodeCoverage.h
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_CodeCoverage_h
+#define vm_CodeCoverage_h
+
+#include "mozilla/Vector.h"
+
+#include "ds/LifoAlloc.h"
+
+#include "vm/Printer.h"
+
+struct JSCompartment;
+class JSScript;
+class JSObject;
+
+namespace js {
+
+class ScriptSourceObject;
+
+namespace coverage {
+
+class LCovCompartment;
+
+class LCovSource
+{
+ public:
+ explicit LCovSource(LifoAlloc* alloc, JSObject* sso);
+
+ // Whether the given script source object matches this LCovSource.
+ bool match(JSObject* sso) const {
+ return sso == source_;
+ }
+
+ // Whether the current source is complete and if it can be flushed.
+ bool isComplete() const {
+ return hasFilename_ && hasTopLevelScript_;
+ }
+
+ // Iterate over the bytecode and collect the lcov output based on the
+ // ScriptCounts counters.
+ bool writeScript(JSScript* script);
+
+ // Write the Lcov output in a buffer, such as the one associated with
+ // the runtime code coverage trace file.
+ void exportInto(GenericPrinter& out) const;
+
+ // Write the script name in out.
+ bool writeSourceFilename(ScriptSourceObject* sso);
+
+ private:
+ // Write the script name in out.
+ bool writeScriptName(LSprinter& out, JSScript* script);
+
+ private:
+ // Weak pointer of the Script Source Object used by the current source.
+ JSObject *source_;
+
+ // LifoAlloc string which hold the filename of the source.
+ LSprinter outSF_;
+
+ // LifoAlloc strings which hold the filename of each function as
+ // well as the number of hits for each function.
+ LSprinter outFN_;
+ LSprinter outFNDA_;
+ size_t numFunctionsFound_;
+ size_t numFunctionsHit_;
+
+ // LifoAlloc string which hold branches statistics.
+ LSprinter outBRDA_;
+ size_t numBranchesFound_;
+ size_t numBranchesHit_;
+
+ // LifoAlloc string which hold lines statistics.
+ LSprinter outDA_;
+ size_t numLinesInstrumented_;
+ size_t numLinesHit_;
+
+ // Status flags.
+ bool hasFilename_ : 1;
+ bool hasTopLevelScript_ : 1;
+};
+
+class LCovCompartment
+{
+ public:
+ LCovCompartment();
+
+ // Collect code coverage information for the given source.
+ void collectCodeCoverageInfo(JSCompartment* comp, JSObject* sso, JSScript* topLevel);
+
+ // Create an ebtry for the current ScriptSourceObject.
+ void collectSourceFile(JSCompartment* comp, ScriptSourceObject* sso);
+
+ // Write the Lcov output in a buffer, such as the one associated with
+ // the runtime code coverage trace file.
+ void exportInto(GenericPrinter& out, bool* isEmpty) const;
+
+ private:
+ // Write the script name in out.
+ bool writeCompartmentName(JSCompartment* comp);
+
+ // Return the LCovSource entry which matches the given ScriptSourceObject.
+ LCovSource* lookupOrAdd(JSCompartment* comp, JSObject* sso);
+
+ private:
+ typedef mozilla::Vector<LCovSource, 16, LifoAllocPolicy<Fallible>> LCovSourceVector;
+
+ // LifoAlloc backend for all temporary allocations needed to stash the
+ // strings to be written in the file.
+ LifoAlloc alloc_;
+
+ // LifoAlloc string which hold the name of the compartment.
+ LSprinter outTN_;
+
+ // Vector of all sources which are used in this compartment.
+ LCovSourceVector* sources_;
+};
+
+class LCovRuntime
+{
+ public:
+ LCovRuntime();
+ ~LCovRuntime();
+
+ // If the environment variable JS_CODE_COVERAGE_OUTPUT_DIR is set to a
+ // directory, create a file inside this directory which uses the process
+ // ID, the thread ID and a timestamp to ensure the uniqueness of the
+ // file.
+ //
+ // At the end of the execution, this file should contains the LCOV output of
+ // all the scripts executed in the current JSRuntime.
+ void init();
+
+ // Check if we should collect code coverage information.
+ bool isEnabled() const { return out_.isInitialized(); }
+
+ // Write the aggregated result of the code coverage of a compartment
+ // into a file.
+ void writeLCovResult(LCovCompartment& comp);
+
+ private:
+ // When a process forks, the file will remain open, but 2 processes will
+ // have the same file. To avoid conflicting writes, we open a new file for
+ // the child process.
+ void maybeReopenAfterFork();
+
+ // Fill an array with the name of the file. Return false if we are unable to
+ // serialize the filename in this array.
+ bool fillWithFilename(char *name, size_t length);
+
+ // Finish the current opened file, and remove if it does not have any
+ // content.
+ void finishFile();
+
+ private:
+ // Output file which is created if code coverage is enabled.
+ Fprinter out_;
+
+ // The process' PID is used to watch for fork. When the process fork,
+ // we want to close the current file and open a new one.
+ size_t pid_;
+
+ // Flag used to report if the generated file is empty or not. If it is empty
+ // when the runtime is destroyed, then the file would be removed as an empty
+ // file is not a valid LCov file.
+ bool isEmpty_;
+};
+
+} // namespace coverage
+} // namespace js
+
+#endif // vm_Printer_h
+
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
new file mode 100644
index 000000000..bd0705446
--- /dev/null
+++ b/js/src/vm/CommonPropertyNames.h
@@ -0,0 +1,357 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A higher-order macro for enumerating all cached property names. */
+
+#ifndef vm_CommonPropertyNames_h
+#define vm_CommonPropertyNames_h
+
+#include "jsprototypes.h"
+
+#define FOR_EACH_COMMON_PROPERTYNAME(macro) \
+ macro(add, add, "add") \
+ macro(allowContentSpread, allowContentSpread, "allowContentSpread") \
+ macro(anonymous, anonymous, "anonymous") \
+ macro(Any, Any, "Any") \
+ macro(apply, apply, "apply") \
+ macro(arguments, arguments, "arguments") \
+ macro(ArrayBufferSpecies, ArrayBufferSpecies, "ArrayBufferSpecies") \
+ macro(ArrayIterator, ArrayIterator, "Array Iterator") \
+ macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
+ macro(ArraySpecies, ArraySpecies, "ArraySpecies") \
+ macro(ArraySpeciesCreate, ArraySpeciesCreate, "ArraySpeciesCreate") \
+ macro(ArrayToLocaleString, ArrayToLocaleString, "ArrayToLocaleString") \
+ macro(ArrayType, ArrayType, "ArrayType") \
+ macro(ArrayValues, ArrayValues, "ArrayValues") \
+ macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
+ macro(as, as, "as") \
+ macro(Async, Async, "Async") \
+ macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
+ macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
+ macro(async, async, "async") \
+ macro(await, await, "await") \
+ macro(Bool8x16, Bool8x16, "Bool8x16") \
+ macro(Bool16x8, Bool16x8, "Bool16x8") \
+ macro(Bool32x4, Bool32x4, "Bool32x4") \
+ macro(Bool64x2, Bool64x2, "Bool64x2") \
+ macro(boundWithSpace, boundWithSpace, "bound ") \
+ macro(breakdown, breakdown, "breakdown") \
+ macro(buffer, buffer, "buffer") \
+ macro(builder, builder, "builder") \
+ macro(by, by, "by") \
+ macro(byteAlignment, byteAlignment, "byteAlignment") \
+ macro(byteLength, byteLength, "byteLength") \
+ macro(byteOffset, byteOffset, "byteOffset") \
+ 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") \
+ macro(caseFirst, caseFirst, "caseFirst") \
+ macro(class_, class_, "class") \
+ macro(close, close, "close") \
+ macro(Collator, Collator, "Collator") \
+ macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
+ macro(collections, collections, "collections") \
+ macro(columnNumber, columnNumber, "columnNumber") \
+ macro(comma, comma, ",") \
+ macro(compare, compare, "compare") \
+ macro(configurable, configurable, "configurable") \
+ macro(construct, construct, "construct") \
+ macro(constructContentFunction, constructContentFunction, "constructContentFunction") \
+ macro(constructor, constructor, "constructor") \
+ macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
+ macro(copyWithin, copyWithin, "copyWithin") \
+ macro(count, count, "count") \
+ macro(CreateResolvingFunctions, CreateResolvingFunctions, "CreateResolvingFunctions") \
+ macro(currency, currency, "currency") \
+ macro(currencyDisplay, currencyDisplay, "currencyDisplay") \
+ macro(DateTimeFormat, DateTimeFormat, "DateTimeFormat") \
+ macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
+ macro(DateTimeFormatFormatToParts, DateTimeFormatFormatToParts, "Intl_DateTimeFormat_formatToParts") \
+ macro(day, day, "day") \
+ macro(dayPeriod, dayPeriod, "dayPeriod") \
+ macro(decodeURI, decodeURI, "decodeURI") \
+ macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
+ macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \
+ macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \
+ macro(default_, default_, "default") \
+ macro(defineGetter, defineGetter, "__defineGetter__") \
+ macro(defineProperty, defineProperty, "defineProperty") \
+ macro(defineSetter, defineSetter, "__defineSetter__") \
+ macro(delete, delete_, "delete") \
+ macro(deleteProperty, deleteProperty, "deleteProperty") \
+ macro(displayURL, displayURL, "displayURL") \
+ macro(done, done, "done") \
+ macro(dotGenerator, dotGenerator, ".generator") \
+ macro(dotThis, dotThis, ".this") \
+ macro(each, each, "each") \
+ macro(elementType, elementType, "elementType") \
+ macro(empty, empty, "") \
+ macro(emptyRegExp, emptyRegExp, "(?:)") \
+ macro(encodeURI, encodeURI, "encodeURI") \
+ macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \
+ macro(endTimestamp, endTimestamp, "endTimestamp") \
+ macro(entries, entries, "entries") \
+ macro(enumerable, enumerable, "enumerable") \
+ macro(enumerate, enumerate, "enumerate") \
+ macro(era, era, "era") \
+ macro(ErrorToStringWithTrailingNewline, ErrorToStringWithTrailingNewline, "ErrorToStringWithTrailingNewline") \
+ macro(escape, escape, "escape") \
+ macro(eval, eval, "eval") \
+ macro(exec, exec, "exec") \
+ macro(false, false_, "false") \
+ macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
+ macro(fieldTypes, fieldTypes, "fieldTypes") \
+ macro(fileName, fileName, "fileName") \
+ macro(fill, fill, "fill") \
+ macro(find, find, "find") \
+ macro(findIndex, findIndex, "findIndex") \
+ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \
+ macro(fix, fix, "fix") \
+ macro(flags, flags, "flags") \
+ macro(float32, float32, "float32") \
+ macro(Float32x4, Float32x4, "Float32x4") \
+ macro(float64, float64, "float64") \
+ macro(Float64x2, Float64x2, "Float64x2") \
+ macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
+ macro(forEach, forEach, "forEach") \
+ macro(format, format, "format") \
+ macro(frame, frame, "frame") \
+ macro(from, from, "from") \
+ macro(fulfilled, fulfilled, "fulfilled") \
+ macro(futexNotEqual, futexNotEqual, "not-equal") \
+ macro(futexOK, futexOK, "ok") \
+ macro(futexTimedOut, futexTimedOut, "timed-out") \
+ macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
+ macro(Generator, Generator, "Generator") \
+ macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
+ macro(get, get, "get") \
+ macro(getInternals, getInternals, "getInternals") \
+ macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
+ macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
+ macro(getPrefix, getPrefix, "get ") \
+ macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
+ macro(getPrototypeOf, getPrototypeOf, "getPrototypeOf") \
+ macro(global, global, "global") \
+ macro(Handle, Handle, "Handle") \
+ macro(has, has, "has") \
+ macro(hasOwn, hasOwn, "hasOwn") \
+ macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
+ macro(hour, hour, "hour") \
+ macro(ignoreCase, ignoreCase, "ignoreCase") \
+ macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \
+ macro(includes, includes, "includes") \
+ macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \
+ macro(index, index, "index") \
+ macro(Infinity, Infinity, "Infinity") \
+ macro(InitializeCollator, InitializeCollator, "InitializeCollator") \
+ macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "InitializeDateTimeFormat") \
+ macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \
+ macro(innermost, innermost, "innermost") \
+ macro(inNursery, inNursery, "inNursery") \
+ macro(input, input, "input") \
+ macro(int8, int8, "int8") \
+ macro(int16, int16, "int16") \
+ macro(int32, int32, "int32") \
+ macro(Int8x16, Int8x16, "Int8x16") \
+ macro(Int16x8, Int16x8, "Int16x8") \
+ macro(Int32x4, Int32x4, "Int32x4") \
+ macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \
+ macro(isEntryPoint, isEntryPoint, "isEntryPoint") \
+ macro(isExtensible, isExtensible, "isExtensible") \
+ macro(isFinite, isFinite, "isFinite") \
+ macro(isNaN, isNaN, "isNaN") \
+ macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
+ macro(IterableToList, IterableToList, "IterableToList") \
+ macro(iterate, iterate, "iterate") \
+ macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
+ macro(join, join, "join") \
+ macro(js, js, "js") \
+ macro(keys, keys, "keys") \
+ macro(label, label, "label") \
+ macro(lastIndex, lastIndex, "lastIndex") \
+ macro(LegacyGeneratorCloseInternal, LegacyGeneratorCloseInternal, "LegacyGeneratorCloseInternal") \
+ macro(length, length, "length") \
+ macro(let, let, "let") \
+ macro(line, line, "line") \
+ macro(lineNumber, lineNumber, "lineNumber") \
+ macro(literal, literal, "literal") \
+ macro(loc, loc, "loc") \
+ macro(locale, locale, "locale") \
+ macro(lookupGetter, lookupGetter, "__lookupGetter__") \
+ macro(lookupSetter, lookupSetter, "__lookupSetter__") \
+ macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
+ macro(MapIterator, MapIterator, "Map Iterator") \
+ macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
+ macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
+ macro(message, message, "message") \
+ macro(minDays, minDays, "minDays") \
+ macro(minimumFractionDigits, minimumFractionDigits, "minimumFractionDigits") \
+ macro(minimumIntegerDigits, minimumIntegerDigits, "minimumIntegerDigits") \
+ macro(minimumSignificantDigits, minimumSignificantDigits, "minimumSignificantDigits") \
+ macro(minute, minute, "minute") \
+ macro(missingArguments, missingArguments, "missingArguments") \
+ macro(module, module, "module") \
+ macro(Module, Module, "Module") \
+ macro(ModuleDeclarationInstantiation, ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation") \
+ macro(ModuleEvaluation, ModuleEvaluation, "ModuleEvaluation") \
+ macro(month, month, "month") \
+ macro(multiline, multiline, "multiline") \
+ macro(name, name, "name") \
+ macro(NaN, NaN, "NaN") \
+ macro(NegativeInfinity, NegativeInfinity, "-Infinity") \
+ macro(new, new_, "new") \
+ macro(next, next, "next") \
+ macro(NFC, NFC, "NFC") \
+ macro(NFD, NFD, "NFD") \
+ macro(NFKC, NFKC, "NFKC") \
+ macro(NFKD, NFKD, "NFKD") \
+ macro(noFilename, noFilename, "noFilename") \
+ macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \
+ macro(noStack, noStack, "noStack") \
+ macro(NumberFormat, NumberFormat, "NumberFormat") \
+ macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \
+ macro(numeric, numeric, "numeric") \
+ macro(objectArguments, objectArguments, "[object Arguments]") \
+ macro(objectArray, objectArray, "[object Array]") \
+ macro(objectBoolean, objectBoolean, "[object Boolean]") \
+ macro(objectDate, objectDate, "[object Date]") \
+ macro(objectError, objectError, "[object Error]") \
+ macro(objectFunction, objectFunction, "[object Function]") \
+ macro(objectNull, objectNull, "[object Null]") \
+ macro(objectNumber, objectNumber, "[object Number]") \
+ macro(objectRegExp, objectRegExp, "[object RegExp]") \
+ macro(objects, objects, "objects") \
+ macro(objectString, objectString, "[object String]") \
+ macro(objectUndefined, objectUndefined, "[object Undefined]") \
+ macro(of, of, "of") \
+ macro(offset, offset, "offset") \
+ macro(optimizedOut, optimizedOut, "optimizedOut") \
+ macro(other, other, "other") \
+ macro(outOfMemory, outOfMemory, "out of memory") \
+ macro(ownKeys, ownKeys, "ownKeys") \
+ macro(parseFloat, parseFloat, "parseFloat") \
+ macro(parseInt, parseInt, "parseInt") \
+ macro(pattern, pattern, "pattern") \
+ macro(pending, pending, "pending") \
+ macro(preventExtensions, preventExtensions, "preventExtensions") \
+ macro(promise, promise, "promise") \
+ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
+ macro(proto, proto, "__proto__") \
+ macro(prototype, prototype, "prototype") \
+ macro(proxy, proxy, "proxy") \
+ macro(raw, raw, "raw") \
+ macro(reason, reason, "reason") \
+ macro(RegExpBuiltinExec, RegExpBuiltinExec, "RegExpBuiltinExec") \
+ macro(RegExpFlagsGetter, RegExpFlagsGetter, "RegExpFlagsGetter") \
+ macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \
+ macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \
+ macro(RegExpTester, RegExpTester, "RegExpTester") \
+ macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \
+ macro(Reify, Reify, "Reify") \
+ macro(reject, reject, "reject") \
+ macro(rejected, rejected, "rejected") \
+ macro(RequireObjectCoercible, RequireObjectCoercible, "RequireObjectCoercible") \
+ macro(resolve, resolve, "resolve") \
+ macro(resumeGenerator, resumeGenerator, "resumeGenerator") \
+ macro(return, return_, "return") \
+ macro(revoke, revoke, "revoke") \
+ macro(script, script, "script") \
+ macro(scripts, scripts, "scripts") \
+ macro(second, second, "second") \
+ macro(selfHosted, selfHosted, "self-hosted") \
+ macro(sensitivity, sensitivity, "sensitivity") \
+ macro(set, set, "set") \
+ macro(SetConstructorInit, SetConstructorInit, "SetConstructorInit") \
+ macro(SetIterator, SetIterator, "Set Iterator") \
+ macro(setPrefix, setPrefix, "set ") \
+ macro(setPrototypeOf, setPrototypeOf, "setPrototypeOf") \
+ macro(shape, shape, "shape") \
+ macro(size, size, "size") \
+ macro(source, source, "source") \
+ macro(SpeciesConstructor, SpeciesConstructor, "SpeciesConstructor") \
+ macro(stack, stack, "stack") \
+ macro(star, star, "*") \
+ macro(starDefaultStar, starDefaultStar, "*default*") \
+ macro(StarGeneratorNext, StarGeneratorNext, "StarGeneratorNext") \
+ macro(StarGeneratorThrow, StarGeneratorThrow, "StarGeneratorThrow") \
+ macro(startTimestamp, startTimestamp, "startTimestamp") \
+ macro(state, state, "state") \
+ macro(static, static_, "static") \
+ macro(std_Function_apply, std_Function_apply, "std_Function_apply") \
+ macro(sticky, sticky, "sticky") \
+ macro(StringIterator, StringIterator, "String Iterator") \
+ macro(strings, strings, "strings") \
+ macro(StructType, StructType, "StructType") \
+ macro(style, style, "style") \
+ macro(super, super, "super") \
+ macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \
+ macro(target, target, "target") \
+ macro(test, test, "test") \
+ macro(then, then, "then") \
+ macro(throw, throw_, "throw") \
+ macro(timestamp, timestamp, "timestamp") \
+ macro(timeZone, timeZone, "timeZone") \
+ macro(timeZoneName, timeZoneName, "timeZoneName") \
+ macro(toGMTString, toGMTString, "toGMTString") \
+ macro(toISOString, toISOString, "toISOString") \
+ macro(toJSON, toJSON, "toJSON") \
+ macro(toLocaleString, toLocaleString, "toLocaleString") \
+ macro(toSource, toSource, "toSource") \
+ macro(toString, toString, "toString") \
+ macro(toUTCString, toUTCString, "toUTCString") \
+ macro(true, true_, "true") \
+ macro(type, type, "type") \
+ macro(uint8, uint8, "uint8") \
+ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
+ macro(uint16, uint16, "uint16") \
+ macro(uint32, uint32, "uint32") \
+ macro(Uint8x16, Uint8x16, "Uint8x16") \
+ macro(Uint16x8, Uint16x8, "Uint16x8") \
+ macro(Uint32x4, Uint32x4, "Uint32x4") \
+ macro(unescape, unescape, "unescape") \
+ macro(uneval, uneval, "uneval") \
+ macro(unicode, unicode, "unicode") \
+ macro(uninitialized, uninitialized, "uninitialized") \
+ macro(unsized, unsized, "unsized") \
+ macro(unwatch, unwatch, "unwatch") \
+ macro(UnwrapAndCallRegExpBuiltinExec, UnwrapAndCallRegExpBuiltinExec, "UnwrapAndCallRegExpBuiltinExec") \
+ macro(url, url, "url") \
+ macro(usage, usage, "usage") \
+ macro(useAsm, useAsm, "use asm") \
+ macro(useGrouping, useGrouping, "useGrouping") \
+ macro(useStrict, useStrict, "use strict") \
+ macro(value, value, "value") \
+ macro(valueOf, valueOf, "valueOf") \
+ macro(values, values, "values") \
+ macro(var, var, "var") \
+ macro(variable, variable, "variable") \
+ macro(void0, void0, "(void 0)") \
+ macro(wasm, wasm, "wasm") \
+ macro(watch, watch, "watch") \
+ macro(WeakMapConstructorInit, WeakMapConstructorInit, "WeakMapConstructorInit") \
+ macro(WeakSetConstructorInit, WeakSetConstructorInit, "WeakSetConstructorInit") \
+ macro(WeakSet_add, WeakSet_add, "WeakSet_add") \
+ macro(weekday, weekday, "weekday") \
+ macro(weekendEnd, weekendEnd, "weekendEnd") \
+ macro(weekendStart, weekendStart, "weekendStart") \
+ macro(writable, writable, "writable") \
+ macro(year, year, "year") \
+ macro(yield, yield, "yield") \
+ /* Type names must be contiguous and ordered; see js::TypeName. */ \
+ macro(undefined, undefined, "undefined") \
+ macro(object, object, "object") \
+ macro(function, function, "function") \
+ macro(string, string, "string") \
+ macro(number, number, "number") \
+ macro(boolean, boolean, "boolean") \
+ macro(null, null, "null") \
+ macro(symbol, symbol, "symbol") \
+
+#endif /* vm_CommonPropertyNames_h */
diff --git a/js/src/vm/Compression.cpp b/js/src/vm/Compression.cpp
new file mode 100644
index 000000000..adefefcb3
--- /dev/null
+++ b/js/src/vm/Compression.cpp
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Compression.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MemoryChecking.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/ScopeExit.h"
+
+#include "jsutil.h"
+
+#include "js/Utility.h"
+
+using namespace js;
+
+static void*
+zlib_alloc(void* cx, uInt items, uInt size)
+{
+ return js_calloc(items, size);
+}
+
+static void
+zlib_free(void* cx, void* addr)
+{
+ js_free(addr);
+}
+
+Compressor::Compressor(const unsigned char* inp, size_t inplen)
+ : inp(inp),
+ inplen(inplen),
+ initialized(false),
+ finished(false),
+ currentChunkSize(0),
+ chunkOffsets()
+{
+ MOZ_ASSERT(inplen > 0);
+ zs.opaque = nullptr;
+ zs.next_in = (Bytef*)inp;
+ zs.avail_in = 0;
+ zs.next_out = nullptr;
+ zs.avail_out = 0;
+ zs.zalloc = zlib_alloc;
+ zs.zfree = zlib_free;
+
+ // Reserve space for the CompressedDataHeader.
+ outbytes = sizeof(CompressedDataHeader);
+}
+
+Compressor::~Compressor()
+{
+ if (initialized) {
+ int ret = deflateEnd(&zs);
+ if (ret != Z_OK) {
+ // If we finished early, we can get a Z_DATA_ERROR.
+ MOZ_ASSERT(ret == Z_DATA_ERROR);
+ MOZ_ASSERT(!finished);
+ }
+ }
+}
+
+// According to the zlib docs, the default value for windowBits is 15. Passing
+// -15 is treated the same, but it also forces 'raw deflate' (no zlib header or
+// trailer). Raw deflate is necessary for chunked decompression.
+static const int WindowBits = -15;
+
+bool
+Compressor::init()
+{
+ if (inplen >= UINT32_MAX)
+ return false;
+ // zlib is slow and we'd rather be done compression sooner
+ // even if it means decompression is slower which penalizes
+ // Function.toString()
+ int ret = deflateInit2(&zs, Z_BEST_SPEED, Z_DEFLATED, WindowBits, 8, Z_DEFAULT_STRATEGY);
+ if (ret != Z_OK) {
+ MOZ_ASSERT(ret == Z_MEM_ERROR);
+ return false;
+ }
+ initialized = true;
+ return true;
+}
+
+void
+Compressor::setOutput(unsigned char* out, size_t outlen)
+{
+ MOZ_ASSERT(outlen > outbytes);
+ zs.next_out = out + outbytes;
+ zs.avail_out = outlen - outbytes;
+}
+
+Compressor::Status
+Compressor::compressMore()
+{
+ MOZ_ASSERT(zs.next_out);
+ uInt left = inplen - (zs.next_in - inp);
+ if (left <= MAX_INPUT_SIZE)
+ zs.avail_in = left;
+ else if (zs.avail_in == 0)
+ zs.avail_in = MAX_INPUT_SIZE;
+
+ // Finish the current chunk if needed.
+ bool flush = false;
+ MOZ_ASSERT(currentChunkSize <= CHUNK_SIZE);
+ if (currentChunkSize + zs.avail_in >= CHUNK_SIZE) {
+ // Adjust avail_in, so we don't get chunks that are larger than
+ // CHUNK_SIZE.
+ zs.avail_in = CHUNK_SIZE - currentChunkSize;
+ MOZ_ASSERT(currentChunkSize + zs.avail_in == CHUNK_SIZE);
+ flush = true;
+ }
+
+ MOZ_ASSERT(zs.avail_in <= left);
+ bool done = zs.avail_in == left;
+
+ Bytef* oldin = zs.next_in;
+ Bytef* oldout = zs.next_out;
+ int ret = deflate(&zs, done ? Z_FINISH : (flush ? Z_FULL_FLUSH : Z_NO_FLUSH));
+ outbytes += zs.next_out - oldout;
+ currentChunkSize += zs.next_in - oldin;
+ MOZ_ASSERT(currentChunkSize <= CHUNK_SIZE);
+
+ if (ret == Z_MEM_ERROR) {
+ zs.avail_out = 0;
+ return OOM;
+ }
+ if (ret == Z_BUF_ERROR || (ret == Z_OK && zs.avail_out == 0)) {
+ // We have to resize the output buffer. Note that we're not done yet
+ // because ret != Z_STREAM_END.
+ MOZ_ASSERT(zs.avail_out == 0);
+ return MOREOUTPUT;
+ }
+
+ if (done || currentChunkSize == CHUNK_SIZE) {
+ MOZ_ASSERT_IF(!done, flush);
+ MOZ_ASSERT(chunkSize(inplen, chunkOffsets.length()) == currentChunkSize);
+ if (!chunkOffsets.append(outbytes))
+ return OOM;
+ currentChunkSize = 0;
+ MOZ_ASSERT_IF(done, chunkOffsets.length() == (inplen - 1) / CHUNK_SIZE + 1);
+ }
+
+ MOZ_ASSERT_IF(!done, ret == Z_OK);
+ MOZ_ASSERT_IF(done, ret == Z_STREAM_END);
+ return done ? DONE : CONTINUE;
+}
+
+size_t
+Compressor::totalBytesNeeded() const
+{
+ return AlignBytes(outbytes, sizeof(uint32_t)) + sizeOfChunkOffsets();
+}
+
+void
+Compressor::finish(char* dest, size_t destBytes)
+{
+ MOZ_ASSERT(!chunkOffsets.empty());
+
+ CompressedDataHeader* compressedHeader = reinterpret_cast<CompressedDataHeader*>(dest);
+ compressedHeader->compressedBytes = outbytes;
+
+ size_t outbytesAligned = AlignBytes(outbytes, sizeof(uint32_t));
+
+ // Zero the padding bytes, the ImmutableStringsCache will hash them.
+ mozilla::PodZero(dest + outbytes, outbytesAligned - outbytes);
+
+ uint32_t* destArr = reinterpret_cast<uint32_t*>(dest + outbytesAligned);
+
+ MOZ_ASSERT(uintptr_t(dest + destBytes) == uintptr_t(destArr + chunkOffsets.length()));
+ mozilla::PodCopy(destArr, chunkOffsets.begin(), chunkOffsets.length());
+
+ finished = true;
+}
+
+bool
+js::DecompressString(const unsigned char* inp, size_t inplen, unsigned char* out, size_t outlen)
+{
+ MOZ_ASSERT(inplen <= UINT32_MAX);
+
+ // Mark the memory we pass to zlib as initialized for MSan.
+ MOZ_MAKE_MEM_DEFINED(out, outlen);
+
+ z_stream zs;
+ zs.zalloc = zlib_alloc;
+ zs.zfree = zlib_free;
+ zs.opaque = nullptr;
+ zs.next_in = (Bytef*)inp;
+ zs.avail_in = inplen;
+ zs.next_out = out;
+ MOZ_ASSERT(outlen);
+ zs.avail_out = outlen;
+ int ret = inflateInit(&zs);
+ if (ret != Z_OK) {
+ MOZ_ASSERT(ret == Z_MEM_ERROR);
+ return false;
+ }
+ ret = inflate(&zs, Z_FINISH);
+ MOZ_ASSERT(ret == Z_STREAM_END);
+ ret = inflateEnd(&zs);
+ MOZ_ASSERT(ret == Z_OK);
+ return true;
+}
+
+bool
+js::DecompressStringChunk(const unsigned char* inp, size_t chunk,
+ unsigned char* out, size_t outlen)
+{
+ MOZ_ASSERT(outlen <= Compressor::CHUNK_SIZE);
+
+ const CompressedDataHeader* header = reinterpret_cast<const CompressedDataHeader*>(inp);
+
+ size_t compressedBytes = header->compressedBytes;
+ size_t compressedBytesAligned = AlignBytes(compressedBytes, sizeof(uint32_t));
+
+ const unsigned char* offsetBytes = inp + compressedBytesAligned;
+ const uint32_t* offsets = reinterpret_cast<const uint32_t*>(offsetBytes);
+
+ uint32_t compressedStart = chunk > 0 ? offsets[chunk - 1] : sizeof(CompressedDataHeader);
+ uint32_t compressedEnd = offsets[chunk];
+
+ MOZ_ASSERT(compressedStart < compressedEnd);
+ MOZ_ASSERT(compressedEnd <= compressedBytes);
+
+ bool lastChunk = compressedEnd == compressedBytes;
+
+ // Mark the memory we pass to zlib as initialized for MSan.
+ MOZ_MAKE_MEM_DEFINED(out, outlen);
+
+ z_stream zs;
+ zs.zalloc = zlib_alloc;
+ zs.zfree = zlib_free;
+ zs.opaque = nullptr;
+ zs.next_in = (Bytef*)(inp + compressedStart);
+ zs.avail_in = compressedEnd - compressedStart;
+ zs.next_out = out;
+ MOZ_ASSERT(outlen);
+ zs.avail_out = outlen;
+
+ int ret = inflateInit2(&zs, WindowBits);
+ if (ret != Z_OK) {
+ MOZ_ASSERT(ret == Z_MEM_ERROR);
+ return false;
+ }
+
+ auto autoCleanup = mozilla::MakeScopeExit([&] {
+ mozilla::DebugOnly<int> ret = inflateEnd(&zs);
+ MOZ_ASSERT(ret == Z_OK);
+ });
+
+ if (lastChunk) {
+ ret = inflate(&zs, Z_FINISH);
+ MOZ_RELEASE_ASSERT(ret == Z_STREAM_END);
+ } else {
+ ret = inflate(&zs, Z_NO_FLUSH);
+ if (ret == Z_MEM_ERROR)
+ return false;
+ MOZ_RELEASE_ASSERT(ret == Z_OK);
+ }
+ MOZ_ASSERT(zs.avail_in == 0);
+ MOZ_ASSERT(zs.avail_out == 0);
+ return true;
+}
diff --git a/js/src/vm/Compression.h b/js/src/vm/Compression.h
new file mode 100644
index 000000000..2fb2df5b6
--- /dev/null
+++ b/js/src/vm/Compression.h
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Compression_h
+#define vm_Compression_h
+
+#include <zlib.h>
+
+#include "jsalloc.h"
+#include "jstypes.h"
+
+#include "js/Vector.h"
+
+namespace js {
+
+struct CompressedDataHeader
+{
+ uint32_t compressedBytes;
+};
+
+class Compressor
+{
+ public:
+ // After compressing CHUNK_SIZE bytes, we will do a full flush so we can
+ // start decompression at that point.
+ static const size_t CHUNK_SIZE = 64 * 1024;
+
+ private:
+ // Number of bytes we should hand to zlib each compressMore() call.
+ static const size_t MAX_INPUT_SIZE = 2 * 1024;
+
+ z_stream zs;
+ const unsigned char* inp;
+ size_t inplen;
+ size_t outbytes;
+ bool initialized;
+ bool finished;
+
+ // The number of uncompressed bytes written for the current chunk. When this
+ // reaches CHUNK_SIZE, we finish the current chunk and start a new chunk.
+ uint32_t currentChunkSize;
+
+ // At the end of each chunk (and the end of the uncompressed data if it's
+ // not a chunk boundary), we record the offset in the compressed data.
+ js::Vector<uint32_t, 8, SystemAllocPolicy> chunkOffsets;
+
+ public:
+ enum Status {
+ MOREOUTPUT,
+ DONE,
+ CONTINUE,
+ OOM
+ };
+
+ Compressor(const unsigned char* inp, size_t inplen);
+ ~Compressor();
+ bool init();
+ void setOutput(unsigned char* out, size_t outlen);
+ /* Compress some of the input. Return true if it should be called again. */
+ Status compressMore();
+ size_t sizeOfChunkOffsets() const { return chunkOffsets.length() * sizeof(chunkOffsets[0]); }
+
+ // Returns the number of bytes needed to store the data currently written +
+ // the chunk offsets.
+ size_t totalBytesNeeded() const;
+
+ // Append the chunk offsets to |dest|.
+ void finish(char* dest, size_t destBytes);
+
+ static void toChunkOffset(size_t uncompressedOffset, size_t* chunk, size_t* chunkOffset) {
+ *chunk = uncompressedOffset / CHUNK_SIZE;
+ *chunkOffset = uncompressedOffset % CHUNK_SIZE;
+ }
+ static size_t chunkSize(size_t uncompressedBytes, size_t chunk) {
+ MOZ_ASSERT(uncompressedBytes > 0);
+ size_t lastChunk = (uncompressedBytes - 1) / CHUNK_SIZE;
+ MOZ_ASSERT(chunk <= lastChunk);
+ if (chunk < lastChunk || uncompressedBytes % CHUNK_SIZE == 0)
+ return CHUNK_SIZE;
+ return uncompressedBytes % CHUNK_SIZE;
+ }
+};
+
+/*
+ * Decompress a string. The caller must know the length of the output and
+ * allocate |out| to a string of that length.
+ */
+bool DecompressString(const unsigned char* inp, size_t inplen,
+ unsigned char* out, size_t outlen);
+
+/*
+ * Decompress a single chunk of at most Compressor::CHUNK_SIZE bytes.
+ * |chunk| is the chunk index. The caller must know the length of the output
+ * (the uncompressed chunk) and allocate |out| to a string of that length.
+ */
+bool DecompressStringChunk(const unsigned char* inp, size_t chunk,
+ unsigned char* out, size_t outlen);
+
+} /* namespace js */
+
+#endif /* vm_Compression_h */
diff --git a/js/src/vm/DateObject.h b/js/src/vm/DateObject.h
new file mode 100644
index 000000000..682823765
--- /dev/null
+++ b/js/src/vm/DateObject.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_DateObject_h_
+#define vm_DateObject_h_
+
+#include "jsobj.h"
+
+#include "js/Date.h"
+#include "js/Value.h"
+
+namespace js {
+
+class DateObject : public NativeObject
+{
+ static const uint32_t UTC_TIME_SLOT = 0;
+ static const uint32_t TZA_SLOT = 1;
+
+ /*
+ * Cached slots holding local properties of the date.
+ * These are undefined until the first actual lookup occurs
+ * and are reset to undefined whenever the date's time is modified.
+ */
+ static const uint32_t COMPONENTS_START_SLOT = 2;
+
+ static const uint32_t LOCAL_TIME_SLOT = COMPONENTS_START_SLOT + 0;
+ static const uint32_t LOCAL_YEAR_SLOT = COMPONENTS_START_SLOT + 1;
+ static const uint32_t LOCAL_MONTH_SLOT = COMPONENTS_START_SLOT + 2;
+ static const uint32_t LOCAL_DATE_SLOT = COMPONENTS_START_SLOT + 3;
+ static const uint32_t LOCAL_DAY_SLOT = COMPONENTS_START_SLOT + 4;
+
+ /*
+ * Unlike the above slots that hold LocalTZA-adjusted component values,
+ * LOCAL_SECONDS_INTO_YEAR_SLOT holds a composite value that can be used
+ * to compute LocalTZA-adjusted hours, minutes, and seconds values.
+ * Specifically, LOCAL_SECONDS_INTO_YEAR_SLOT holds the number of
+ * LocalTZA-adjusted seconds into the year. Unix timestamps ignore leap
+ * seconds, so recovering hours/minutes/seconds requires only trivial
+ * division/modulus operations.
+ */
+ static const uint32_t LOCAL_SECONDS_INTO_YEAR_SLOT = COMPONENTS_START_SLOT + 5;
+
+ static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_INTO_YEAR_SLOT + 1;
+
+ public:
+ static const Class class_;
+ static const Class protoClass_;
+
+ JS::ClippedTime clippedTime() const {
+ double t = getFixedSlot(UTC_TIME_SLOT).toDouble();
+ JS::ClippedTime clipped = JS::TimeClip(t);
+ MOZ_ASSERT(mozilla::NumbersAreIdentical(clipped.toDouble(), t));
+ return clipped;
+ }
+
+ const js::Value& UTCTime() const {
+ return getFixedSlot(UTC_TIME_SLOT);
+ }
+
+ // Set UTC time to a given time and invalidate cached local time.
+ void setUTCTime(JS::ClippedTime t);
+ void setUTCTime(JS::ClippedTime t, MutableHandleValue vp);
+
+ inline double cachedLocalTime();
+
+ // Cache the local time, year, month, and so forth of the object.
+ // If UTC time is not finite (e.g., NaN), the local time
+ // slots will be set to the UTC time without conversion.
+ void fillLocalTimeSlots();
+
+ static MOZ_ALWAYS_INLINE bool getTime_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getYear_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getFullYear_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCFullYear_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getMonth_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCMonth_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getDate_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCDate_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getDay_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCDay_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getHours_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCHours_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getMinutes_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCMinutes_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCSeconds_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getUTCMilliseconds_impl(JSContext* cx, const CallArgs& args);
+ static MOZ_ALWAYS_INLINE bool getTimezoneOffset_impl(JSContext* cx, const CallArgs& args);
+};
+
+} // namespace js
+
+#endif // vm_DateObject_h_
diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp
new file mode 100644
index 000000000..e35ad4285
--- /dev/null
+++ b/js/src/vm/DateTime.cpp
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/DateTime.h"
+
+#include "mozilla/Atomics.h"
+
+#include <time.h>
+
+#include "jsutil.h"
+
+#include "js/Date.h"
+#if ENABLE_INTL_API
+#include "unicode/timezone.h"
+#endif
+
+using mozilla::Atomic;
+using mozilla::ReleaseAcquire;
+using mozilla::UnspecifiedNaN;
+
+/* static */ js::DateTimeInfo
+js::DateTimeInfo::instance;
+
+/* static */ mozilla::Atomic<bool, mozilla::ReleaseAcquire>
+js::DateTimeInfo::AcquireLock::spinLock;
+
+static bool
+ComputeLocalTime(time_t local, struct tm* ptm)
+{
+#if defined(_WIN32)
+ return localtime_s(ptm, &local) == 0;
+#elif defined(HAVE_LOCALTIME_R)
+ return localtime_r(&local, ptm);
+#else
+ struct tm* otm = localtime(&local);
+ if (!otm)
+ return false;
+ *ptm = *otm;
+ return true;
+#endif
+}
+
+static bool
+ComputeUTCTime(time_t t, struct tm* ptm)
+{
+#if defined(_WIN32)
+ return gmtime_s(ptm, &t) == 0;
+#elif defined(HAVE_GMTIME_R)
+ return gmtime_r(&t, ptm);
+#else
+ struct tm* otm = gmtime(&t);
+ if (!otm)
+ return false;
+ *ptm = *otm;
+ return true;
+#endif
+}
+
+/*
+ * Compute the offset in seconds from the current UTC time to the current local
+ * standard time (i.e. not including any offset due to DST).
+ *
+ * Examples:
+ *
+ * Suppose we are in California, USA on January 1, 2013 at 04:00 PST (UTC-8, no
+ * DST in effect), corresponding to 12:00 UTC. This function would then return
+ * -8 * SecondsPerHour, or -28800.
+ *
+ * Or suppose we are in Berlin, Germany on July 1, 2013 at 17:00 CEST (UTC+2,
+ * DST in effect), corresponding to 15:00 UTC. This function would then return
+ * +1 * SecondsPerHour, or +3600.
+ */
+static int32_t
+UTCToLocalStandardOffsetSeconds()
+{
+ using js::SecondsPerDay;
+ using js::SecondsPerHour;
+ using js::SecondsPerMinute;
+
+#if defined(XP_WIN)
+ // Windows doesn't follow POSIX: updates to the TZ environment variable are
+ // not reflected immediately on that platform as they are on other systems
+ // without this call.
+ _tzset();
+#endif
+
+ // Get the current time.
+ time_t currentMaybeWithDST = time(nullptr);
+ if (currentMaybeWithDST == time_t(-1))
+ return 0;
+
+ // Break down the current time into its (locally-valued, maybe with DST)
+ // components.
+ struct tm local;
+ if (!ComputeLocalTime(currentMaybeWithDST, &local))
+ return 0;
+
+ // Compute a |time_t| corresponding to |local| interpreted without DST.
+ time_t currentNoDST;
+ if (local.tm_isdst == 0) {
+ // If |local| wasn't DST, we can use the same time.
+ currentNoDST = currentMaybeWithDST;
+ } else {
+ // If |local| respected DST, we need a time broken down into components
+ // ignoring DST. Turn off DST in the broken-down time.
+ local.tm_isdst = 0;
+
+ // Compute a |time_t t| corresponding to the broken-down time with DST
+ // off. This has boundary-condition issues (for about the duration of
+ // a DST offset) near the time a location moves to a different time
+ // zone. But 1) errors will be transient; 2) locations rarely change
+ // time zone; and 3) in the absence of an API that provides the time
+ // zone offset directly, this may be the best we can do.
+ currentNoDST = mktime(&local);
+ if (currentNoDST == time_t(-1))
+ return 0;
+ }
+
+ // Break down the time corresponding to the no-DST |local| into UTC-based
+ // components.
+ struct tm utc;
+ if (!ComputeUTCTime(currentNoDST, &utc))
+ return 0;
+
+ // Finally, compare the seconds-based components of the local non-DST
+ // representation and the UTC representation to determine the actual
+ // difference.
+ int utc_secs = utc.tm_hour * SecondsPerHour + utc.tm_min * SecondsPerMinute;
+ int local_secs = local.tm_hour * SecondsPerHour + local.tm_min * SecondsPerMinute;
+
+ // Same-day? Just subtract the seconds counts.
+ if (utc.tm_mday == local.tm_mday)
+ return local_secs - utc_secs;
+
+ // If we have more UTC seconds, move local seconds into the UTC seconds'
+ // frame of reference and then subtract.
+ if (utc_secs > local_secs)
+ return (SecondsPerDay + local_secs) - utc_secs;
+
+ // Otherwise we have more local seconds, so move the UTC seconds into the
+ // local seconds' frame of reference and then subtract.
+ return local_secs - (utc_secs + SecondsPerDay);
+}
+
+void
+js::DateTimeInfo::internalUpdateTimeZoneAdjustment()
+{
+ /*
+ * The difference between local standard time and UTC will never change for
+ * a given time zone.
+ */
+ utcToLocalStandardOffsetSeconds = UTCToLocalStandardOffsetSeconds();
+
+ double newTZA = utcToLocalStandardOffsetSeconds * msPerSecond;
+ if (newTZA == localTZA_)
+ return;
+
+ localTZA_ = newTZA;
+
+ /*
+ * The initial range values are carefully chosen to result in a cache miss
+ * on first use given the range of possible values. Be careful to keep
+ * these values and the caching algorithm in sync!
+ */
+ offsetMilliseconds = 0;
+ rangeStartSeconds = rangeEndSeconds = INT64_MIN;
+ oldOffsetMilliseconds = 0;
+ oldRangeStartSeconds = oldRangeEndSeconds = INT64_MIN;
+
+ sanityCheck();
+}
+
+/*
+ * Since getDSTOffsetMilliseconds guarantees that all times seen will be
+ * positive, we can initialize the range at construction time with large
+ * negative numbers to ensure the first computation is always a cache miss and
+ * doesn't return a bogus offset.
+ */
+/* static */ void
+js::DateTimeInfo::init()
+{
+ DateTimeInfo* dtInfo = &DateTimeInfo::instance;
+
+ MOZ_ASSERT(dtInfo->localTZA_ == 0,
+ "we should be initializing only once, and the static instance "
+ "should have started out zeroed");
+
+ // Set to a totally impossible TZA so that the comparison above will fail
+ // and all fields will be properly initialized.
+ dtInfo->localTZA_ = UnspecifiedNaN<double>();
+ dtInfo->internalUpdateTimeZoneAdjustment();
+}
+
+int64_t
+js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
+{
+ MOZ_ASSERT(utcSeconds >= 0);
+ MOZ_ASSERT(utcSeconds <= MaxUnixTimeT);
+
+#if defined(XP_WIN)
+ // Windows does not follow POSIX. Updates to the TZ environment variable
+ // are not reflected immediately on that platform as they are on UNIX
+ // systems without this call.
+ _tzset();
+#endif
+
+ struct tm tm;
+ if (!ComputeLocalTime(static_cast<time_t>(utcSeconds), &tm))
+ return 0;
+
+ int32_t dayoff = int32_t((utcSeconds + utcToLocalStandardOffsetSeconds) % SecondsPerDay);
+ int32_t tmoff = tm.tm_sec + (tm.tm_min * SecondsPerMinute) + (tm.tm_hour * SecondsPerHour);
+
+ int32_t diff = tmoff - dayoff;
+
+ if (diff < 0)
+ diff += SecondsPerDay;
+
+ return diff * msPerSecond;
+}
+
+int64_t
+js::DateTimeInfo::internalGetDSTOffsetMilliseconds(int64_t utcMilliseconds)
+{
+ sanityCheck();
+
+ int64_t utcSeconds = utcMilliseconds / msPerSecond;
+
+ if (utcSeconds > MaxUnixTimeT) {
+ utcSeconds = MaxUnixTimeT;
+ } else if (utcSeconds < 0) {
+ /* Go ahead a day to make localtime work (does not work with 0). */
+ utcSeconds = SecondsPerDay;
+ }
+
+ /*
+ * NB: Be aware of the initial range values when making changes to this
+ * code: the first call to this method, with those initial range
+ * values, must result in a cache miss.
+ */
+
+ if (rangeStartSeconds <= utcSeconds && utcSeconds <= rangeEndSeconds)
+ return offsetMilliseconds;
+
+ if (oldRangeStartSeconds <= utcSeconds && utcSeconds <= oldRangeEndSeconds)
+ return oldOffsetMilliseconds;
+
+ oldOffsetMilliseconds = offsetMilliseconds;
+ oldRangeStartSeconds = rangeStartSeconds;
+ oldRangeEndSeconds = rangeEndSeconds;
+
+ if (rangeStartSeconds <= utcSeconds) {
+ int64_t newEndSeconds = Min(rangeEndSeconds + RangeExpansionAmount, MaxUnixTimeT);
+ if (newEndSeconds >= utcSeconds) {
+ int64_t endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
+ if (endOffsetMilliseconds == offsetMilliseconds) {
+ rangeEndSeconds = newEndSeconds;
+ return offsetMilliseconds;
+ }
+
+ offsetMilliseconds = computeDSTOffsetMilliseconds(utcSeconds);
+ if (offsetMilliseconds == endOffsetMilliseconds) {
+ rangeStartSeconds = utcSeconds;
+ rangeEndSeconds = newEndSeconds;
+ } else {
+ rangeEndSeconds = utcSeconds;
+ }
+ return offsetMilliseconds;
+ }
+
+ offsetMilliseconds = computeDSTOffsetMilliseconds(utcSeconds);
+ rangeStartSeconds = rangeEndSeconds = utcSeconds;
+ return offsetMilliseconds;
+ }
+
+ int64_t newStartSeconds = Max<int64_t>(rangeStartSeconds - RangeExpansionAmount, 0);
+ if (newStartSeconds <= utcSeconds) {
+ int64_t startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds);
+ if (startOffsetMilliseconds == offsetMilliseconds) {
+ rangeStartSeconds = newStartSeconds;
+ return offsetMilliseconds;
+ }
+
+ offsetMilliseconds = computeDSTOffsetMilliseconds(utcSeconds);
+ if (offsetMilliseconds == startOffsetMilliseconds) {
+ rangeStartSeconds = newStartSeconds;
+ rangeEndSeconds = utcSeconds;
+ } else {
+ rangeStartSeconds = utcSeconds;
+ }
+ return offsetMilliseconds;
+ }
+
+ rangeStartSeconds = rangeEndSeconds = utcSeconds;
+ offsetMilliseconds = computeDSTOffsetMilliseconds(utcSeconds);
+ return offsetMilliseconds;
+}
+
+void
+js::DateTimeInfo::sanityCheck()
+{
+ MOZ_ASSERT(rangeStartSeconds <= rangeEndSeconds);
+ MOZ_ASSERT_IF(rangeStartSeconds == INT64_MIN, rangeEndSeconds == INT64_MIN);
+ MOZ_ASSERT_IF(rangeEndSeconds == INT64_MIN, rangeStartSeconds == INT64_MIN);
+ MOZ_ASSERT_IF(rangeStartSeconds != INT64_MIN,
+ rangeStartSeconds >= 0 && rangeEndSeconds >= 0);
+ MOZ_ASSERT_IF(rangeStartSeconds != INT64_MIN,
+ rangeStartSeconds <= MaxUnixTimeT && rangeEndSeconds <= MaxUnixTimeT);
+}
+
+static struct IcuTimeZoneInfo
+{
+ Atomic<bool, ReleaseAcquire> locked;
+ enum { Valid = 0, NeedsUpdate } status;
+
+ void acquire() {
+ while (!locked.compareExchange(false, true))
+ continue;
+ }
+
+ void release() {
+ MOZ_ASSERT(locked, "should have been acquired");
+ locked = false;
+ }
+} TZInfo;
+
+
+JS_PUBLIC_API(void)
+JS::ResetTimeZone()
+{
+ js::DateTimeInfo::updateTimeZoneAdjustment();
+
+#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
+ TZInfo.acquire();
+ TZInfo.status = IcuTimeZoneInfo::NeedsUpdate;
+ TZInfo.release();
+#endif
+}
+
+void
+js::ResyncICUDefaultTimeZone()
+{
+#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
+ TZInfo.acquire();
+ if (TZInfo.status == IcuTimeZoneInfo::NeedsUpdate) {
+ icu::TimeZone::recreateDefault();
+ TZInfo.status = IcuTimeZoneInfo::Valid;
+ }
+ TZInfo.release();
+#endif
+}
diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h
new file mode 100644
index 000000000..6ce91e773
--- /dev/null
+++ b/js/src/vm/DateTime.h
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_DateTime_h
+#define vm_DateTime_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/MathAlgorithms.h"
+
+#include <stdint.h>
+
+#include "js/Conversions.h"
+#include "js/Date.h"
+#include "js/Initialization.h"
+#include "js/Value.h"
+
+namespace js {
+
+/* Constants defined by ES5 15.9.1.10. */
+const double HoursPerDay = 24;
+const double MinutesPerHour = 60;
+const double SecondsPerMinute = 60;
+const double msPerSecond = 1000;
+const double msPerMinute = msPerSecond * SecondsPerMinute;
+const double msPerHour = msPerMinute * MinutesPerHour;
+
+/* ES5 15.9.1.2. */
+const double msPerDay = msPerHour * HoursPerDay;
+
+/*
+ * Additional quantities not mentioned in the spec. Be careful using these!
+ * They aren't doubles (and aren't defined in terms of all the other constants
+ * so that they can be used in constexpr scenarios; if you need constants that
+ * trigger floating point semantics, you'll have to manually cast to get it.
+ */
+const unsigned SecondsPerHour = 60 * 60;
+const unsigned SecondsPerDay = SecondsPerHour * 24;
+
+const double StartOfTime = -8.64e15;
+const double EndOfTime = 8.64e15;
+
+/*
+ * Stores date/time information, particularly concerning the current local
+ * time zone, and implements a small cache for daylight saving time offset
+ * computation.
+ *
+ * The basic idea is premised upon this fact: the DST offset never changes more
+ * than once in any thirty-day period. If we know the offset at t_0 is o_0,
+ * the offset at [t_1, t_2] is also o_0, where t_1 + 3_0 days == t_2,
+ * t_1 <= t_0, and t0 <= t2. (In other words, t_0 is always somewhere within a
+ * thirty-day range where the DST offset is constant: DST changes never occur
+ * more than once in any thirty-day period.) Therefore, if we intelligently
+ * retain knowledge of the offset for a range of dates (which may vary over
+ * time), and if requests are usually for dates within that range, we can often
+ * provide a response without repeated offset calculation.
+ *
+ * Our caching strategy is as follows: on the first request at date t_0 compute
+ * the requested offset o_0. Save { start: t_0, end: t_0, offset: o_0 } as the
+ * cache's state. Subsequent requests within that range are straightforwardly
+ * handled. If a request for t_i is far outside the range (more than thirty
+ * days), compute o_i = dstOffset(t_i) and save { start: t_i, end: t_i,
+ * offset: t_i }. Otherwise attempt to *overextend* the range to either
+ * [start - 30d, end] or [start, end + 30d] as appropriate to encompass
+ * t_i. If the offset o_i30 is the same as the cached offset, extend the
+ * range. Otherwise the over-guess crossed a DST change -- compute
+ * o_i = dstOffset(t_i) and either extend the original range (if o_i == offset)
+ * or start a new one beneath/above the current one with o_i30 as the offset.
+ *
+ * This cache strategy results in 0 to 2 DST offset computations. The naive
+ * always-compute strategy is 1 computation, and since cache maintenance is a
+ * handful of integer arithmetic instructions the speed difference between
+ * always-1 and 1-with-cache is negligible. Caching loses if two computations
+ * happen: when the date is within 30 days of the cached range and when that
+ * 30-day range crosses a DST change. This is relatively uncommon. Further,
+ * instances of such are often dominated by in-range hits, so caching is an
+ * overall slight win.
+ *
+ * Why 30 days? For correctness the duration must be smaller than any possible
+ * duration between DST changes. Past that, note that 1) a large duration
+ * increases the likelihood of crossing a DST change while reducing the number
+ * of cache misses, and 2) a small duration decreases the size of the cached
+ * range while producing more misses. Using a month as the interval change is
+ * a balance between these two that tries to optimize for the calendar month at
+ * a time that a site might display. (One could imagine an adaptive duration
+ * that accommodates near-DST-change dates better; we don't believe the
+ * potential win from better caching offsets the loss from extra complexity.)
+ */
+class DateTimeInfo
+{
+ static DateTimeInfo instance;
+
+ // Date/time info is shared across all threads in DateTimeInfo::instance,
+ // for consistency with ICU's handling of its default time zone. Thus we
+ // need something to protect concurrent accesses.
+ //
+ // The spec implicitly assumes DST and time zone adjustment information
+ // never change in the course of a function -- sometimes even across
+ // reentrancy. So make critical sections as narrow as possible, and use a
+ // bog-standard spinlock with busy-waiting in case of contention for
+ // simplicity.
+ class MOZ_RAII AcquireLock
+ {
+ static mozilla::Atomic<bool, mozilla::ReleaseAcquire> spinLock;
+
+ public:
+ AcquireLock() {
+ while (!spinLock.compareExchange(false, true))
+ continue;
+ }
+ ~AcquireLock() {
+ MOZ_ASSERT(spinLock, "spinlock should have been acquired");
+ spinLock = false;
+ }
+ };
+
+ friend const char* JS::detail::InitWithFailureDiagnostic(bool);
+
+ // Initialize global date/time tracking state. This operation occurs
+ // during, and is restricted to, SpiderMonkey initialization.
+ static void init();
+
+ public:
+ /*
+ * Get the DST offset in milliseconds at a UTC time. This is usually
+ * either 0 or |msPerSecond * SecondsPerHour|, but at least one exotic time
+ * zone (Lord Howe Island, Australia) has a fractional-hour offset, just to
+ * keep things interesting.
+ */
+ static int64_t getDSTOffsetMilliseconds(int64_t utcMilliseconds) {
+ AcquireLock lock;
+
+ return DateTimeInfo::instance.internalGetDSTOffsetMilliseconds(utcMilliseconds);
+ }
+
+ /* ES5 15.9.1.7. */
+ static double localTZA() {
+ AcquireLock lock;
+
+ return DateTimeInfo::instance.localTZA_;
+ }
+
+ private:
+ // We don't want anyone accidentally calling *only*
+ // DateTimeInfo::updateTimeZoneAdjustment() to respond to a system time
+ // zone change (missing the necessary poking of ICU as well), so ensure
+ // only JS::ResetTimeZone() can call this via access restrictions.
+ friend void JS::ResetTimeZone();
+
+ static void updateTimeZoneAdjustment() {
+ AcquireLock lock;
+
+ DateTimeInfo::instance.internalUpdateTimeZoneAdjustment();
+ }
+
+ /*
+ * The current local time zone adjustment, cached because retrieving this
+ * dynamically is Slow, and a certain venerable benchmark which shall not
+ * be named depends on it being fast.
+ *
+ * SpiderMonkey occasionally and arbitrarily updates this value from the
+ * system time zone to attempt to keep this reasonably up-to-date. If
+ * temporary inaccuracy can't be tolerated, JSAPI clients may call
+ * JS::ResetTimeZone to forcibly sync this with the system time zone.
+ */
+ double localTZA_;
+
+ /*
+ * Compute the DST offset at the given UTC time in seconds from the epoch.
+ * (getDSTOffsetMilliseconds attempts to return a cached value, but in case
+ * of a cache miss it calls this method. The cache is represented through
+ * the offset* and *{Start,End}Seconds fields below.)
+ */
+ int64_t computeDSTOffsetMilliseconds(int64_t utcSeconds);
+
+ int64_t offsetMilliseconds;
+ int64_t rangeStartSeconds, rangeEndSeconds; // UTC-based
+
+ int64_t oldOffsetMilliseconds;
+ int64_t oldRangeStartSeconds, oldRangeEndSeconds; // UTC-based
+
+ /*
+ * Cached offset in seconds from the current UTC time to the current
+ * local standard time (i.e. not including any offset due to DST).
+ */
+ int32_t utcToLocalStandardOffsetSeconds;
+
+ static const int64_t MaxUnixTimeT = 2145859200; /* time_t 12/31/2037 */
+
+ static const int64_t RangeExpansionAmount = 30 * SecondsPerDay;
+
+ int64_t internalGetDSTOffsetMilliseconds(int64_t utcMilliseconds);
+ void internalUpdateTimeZoneAdjustment();
+
+ void sanityCheck();
+};
+
+/**
+ * ICU's default time zone, used for various date/time formatting operations
+ * that include the local time in the representation, is allowed to go stale
+ * for unfortunate performance reasons. Call this function when an up-to-date
+ * default time zone is required, to resync ICU's default time zone with
+ * reality.
+ */
+extern void
+ResyncICUDefaultTimeZone();
+
+} /* namespace js */
+
+#endif /* vm_DateTime_h */
diff --git a/js/src/vm/Debugger-inl.h b/js/src/vm/Debugger-inl.h
new file mode 100644
index 000000000..e973975d2
--- /dev/null
+++ b/js/src/vm/Debugger-inl.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Debugger_inl_h
+#define vm_Debugger_inl_h
+
+#include "vm/Debugger.h"
+
+#include "vm/Stack-inl.h"
+
+/* static */ inline bool
+js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool ok)
+{
+ MOZ_ASSERT_IF(frame.isInterpreterFrame(), frame.asInterpreterFrame() == cx->interpreterFrame());
+ MOZ_ASSERT_IF(frame.script()->isDebuggee(), frame.isDebuggee());
+ /* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */
+ mozilla::DebugOnly<bool> evalTraps = frame.isEvalFrame() &&
+ frame.script()->hasAnyBreakpointsOrStepMode();
+ MOZ_ASSERT_IF(evalTraps, frame.isDebuggee());
+ if (frame.isDebuggee())
+ ok = slowPathOnLeaveFrame(cx, frame, pc, ok);
+ MOZ_ASSERT(!inFrameMaps(frame));
+ return ok;
+}
+
+/* static */ inline js::Debugger*
+js::Debugger::fromJSObject(const JSObject* obj)
+{
+ MOZ_ASSERT(js::GetObjectClass(obj) == &class_);
+ return (Debugger*) obj->as<NativeObject>().getPrivate();
+}
+
+/* static */ inline bool
+js::Debugger::checkNoExecute(JSContext* cx, HandleScript script)
+{
+ if (!cx->compartment()->isDebuggee() || !cx->runtime()->noExecuteDebuggerTop)
+ return true;
+ return slowPathCheckNoExecute(cx, script);
+}
+
+/* static */ JSTrapStatus
+js::Debugger::onEnterFrame(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT_IF(frame.script()->isDebuggee(), frame.isDebuggee());
+ if (!frame.isDebuggee())
+ return JSTRAP_CONTINUE;
+ return slowPathOnEnterFrame(cx, frame);
+}
+
+/* static */ JSTrapStatus
+js::Debugger::onDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
+{
+ if (!cx->compartment()->isDebuggee())
+ return JSTRAP_CONTINUE;
+ return slowPathOnDebuggerStatement(cx, frame);
+}
+
+/* static */ JSTrapStatus
+js::Debugger::onExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
+{
+ if (!cx->compartment()->isDebuggee())
+ return JSTRAP_CONTINUE;
+ return slowPathOnExceptionUnwind(cx, frame);
+}
+
+/* static */ void
+js::Debugger::onNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance)
+{
+ if (cx->compartment()->isDebuggee())
+ slowPathOnNewWasmInstance(cx, wasmInstance);
+}
+
+inline bool
+js::Debugger::getScriptFrame(JSContext* cx, const ScriptFrameIter& iter,
+ MutableHandle<DebuggerFrame*> result)
+{
+ return getScriptFrameWithIter(cx, iter.abstractFramePtr(), &iter, result);
+}
+
+inline js::Debugger*
+js::DebuggerEnvironment::owner() const
+{
+ JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
+ return Debugger::fromJSObject(dbgobj);
+}
+
+inline js::Debugger*
+js::DebuggerFrame::owner() const
+{
+ JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
+ return Debugger::fromJSObject(dbgobj);
+}
+
+inline js::Debugger*
+js::DebuggerObject::owner() const
+{
+ JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject();
+ return Debugger::fromJSObject(dbgobj);
+}
+
+inline js::PromiseObject*
+js::DebuggerObject::promise() const
+{
+ MOZ_ASSERT(isPromise());
+
+ JSObject* referent = this->referent();
+ if (IsCrossCompartmentWrapper(referent)) {
+ referent = CheckedUnwrap(referent);
+ MOZ_ASSERT(referent);
+ }
+
+ return &referent->as<PromiseObject>();
+}
+
+#endif /* vm_Debugger_inl_h */
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
new file mode 100644
index 000000000..b6bc7d62a
--- /dev/null
+++ b/js/src/vm/Debugger.cpp
@@ -0,0 +1,11183 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Debugger-inl.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/ScopeExit.h"
+#include "mozilla/Sprintf.h"
+#include "mozilla/TypeTraits.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsfriendapi.h"
+#include "jshashutil.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsprf.h"
+#include "jswrapper.h"
+
+#include "frontend/BytecodeCompiler.h"
+#include "frontend/Parser.h"
+#include "gc/Marking.h"
+#include "gc/Policy.h"
+#include "jit/BaselineDebugModeOSR.h"
+#include "jit/BaselineJIT.h"
+#include "js/Date.h"
+#include "js/GCAPI.h"
+#include "js/UbiNodeBreadthFirst.h"
+#include "js/Vector.h"
+#include "proxy/ScriptedProxyHandler.h"
+#include "vm/ArgumentsObject.h"
+#include "vm/AsyncFunction.h"
+#include "vm/DebuggerMemory.h"
+#include "vm/GeneratorObject.h"
+#include "vm/SPSProfiler.h"
+#include "vm/TraceLogging.h"
+#include "vm/WrapperObject.h"
+#include "wasm/WasmInstance.h"
+
+#include "jsgcinlines.h"
+#include "jsobjinlines.h"
+#include "jsopcodeinlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+
+using JS::dbg::AutoEntryMonitor;
+using JS::dbg::Builder;
+using js::frontend::IsIdentifier;
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::MakeScopeExit;
+using mozilla::Maybe;
+using mozilla::Some;
+using mozilla::Nothing;
+using mozilla::Variant;
+using mozilla::AsVariant;
+
+
+/*** Forward declarations, ClassOps and Classes **************************************************/
+
+static void DebuggerFrame_finalize(FreeOp* fop, JSObject* obj);
+static void DebuggerEnv_trace(JSTracer* trc, JSObject* obj);
+static void DebuggerObject_trace(JSTracer* trc, JSObject* obj);
+static void DebuggerScript_trace(JSTracer* trc, JSObject* obj);
+static void DebuggerSource_trace(JSTracer* trc, JSObject* obj);
+
+enum {
+ JSSLOT_DEBUGFRAME_OWNER,
+ JSSLOT_DEBUGFRAME_ARGUMENTS,
+ JSSLOT_DEBUGFRAME_ONSTEP_HANDLER,
+ JSSLOT_DEBUGFRAME_ONPOP_HANDLER,
+ JSSLOT_DEBUGFRAME_COUNT
+};
+
+const ClassOps DebuggerFrame::classOps_ = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ DebuggerFrame_finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ nullptr, /* trace */
+};
+
+const Class DebuggerFrame::class_ = {
+ "Frame",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT) |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &DebuggerFrame::classOps_
+};
+
+enum {
+ JSSLOT_DEBUGARGUMENTS_FRAME,
+ JSSLOT_DEBUGARGUMENTS_COUNT
+};
+
+static const Class DebuggerArguments_class = {
+ "Arguments",
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT)
+};
+
+const ClassOps DebuggerEnvironment::classOps_ = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ DebuggerEnv_trace
+};
+
+const Class DebuggerEnvironment::class_ = {
+ "Environment",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(DebuggerEnvironment::RESERVED_SLOTS),
+ &classOps_
+};
+
+enum {
+ JSSLOT_DEBUGOBJECT_OWNER,
+ JSSLOT_DEBUGOBJECT_COUNT
+};
+
+const ClassOps DebuggerObject::classOps_ = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ DebuggerObject_trace
+};
+
+const Class DebuggerObject::class_ = {
+ "Object",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
+ &classOps_
+};
+
+enum {
+ JSSLOT_DEBUGSCRIPT_OWNER,
+ JSSLOT_DEBUGSCRIPT_COUNT
+};
+
+static const ClassOps DebuggerScript_classOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ DebuggerScript_trace
+};
+
+static const Class DebuggerScript_class = {
+ "Script",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
+ &DebuggerScript_classOps
+};
+
+enum {
+ JSSLOT_DEBUGSOURCE_OWNER,
+ JSSLOT_DEBUGSOURCE_TEXT,
+ JSSLOT_DEBUGSOURCE_COUNT
+};
+
+static const ClassOps DebuggerSource_classOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ DebuggerSource_trace
+};
+
+static const Class DebuggerSource_class = {
+ "Source",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
+ &DebuggerSource_classOps
+};
+
+
+/*** Utils ***************************************************************************************/
+
+static inline bool
+EnsureFunctionHasScript(JSContext* cx, HandleFunction fun)
+{
+ if (fun->isInterpretedLazy()) {
+ AutoCompartment ac(cx, fun);
+ return !!fun->getOrCreateScript(cx);
+ }
+ return true;
+}
+
+static inline JSScript*
+GetOrCreateFunctionScript(JSContext* cx, HandleFunction fun)
+{
+ MOZ_ASSERT(fun->isInterpreted());
+ if (!EnsureFunctionHasScript(cx, fun))
+ return nullptr;
+ return fun->nonLazyScript();
+}
+
+static bool
+ValueToIdentifier(JSContext* cx, HandleValue v, MutableHandleId id)
+{
+ if (!ValueToId<CanGC>(cx, v, id))
+ return false;
+ if (!JSID_IS_ATOM(id) || !IsIdentifier(JSID_TO_ATOM(id))) {
+ RootedValue val(cx, v);
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
+ JSDVG_SEARCH_STACK, val, nullptr, "not an identifier",
+ nullptr);
+ return false;
+ }
+ return true;
+}
+
+class AutoRestoreCompartmentDebugMode
+{
+ JSCompartment* comp_;
+ unsigned bits_;
+
+ public:
+ explicit AutoRestoreCompartmentDebugMode(JSCompartment* comp)
+ : comp_(comp), bits_(comp->debugModeBits)
+ {
+ MOZ_ASSERT(comp_);
+ }
+
+ ~AutoRestoreCompartmentDebugMode() {
+ if (comp_)
+ comp_->debugModeBits = bits_;
+ }
+
+ void release() {
+ comp_ = nullptr;
+ }
+};
+
+// Given a Debugger instance dbg, if it is enabled, prevents all its debuggee
+// compartments from executing scripts. Attempts to run script will throw an
+// instance of Debugger.DebuggeeWouldRun from the topmost locked Debugger's
+// compartment.
+class MOZ_RAII js::EnterDebuggeeNoExecute
+{
+ friend class js::LeaveDebuggeeNoExecute;
+
+ Debugger& dbg_;
+ EnterDebuggeeNoExecute** stack_;
+ EnterDebuggeeNoExecute* prev_;
+
+ // Non-nullptr when unlocked temporarily by a LeaveDebuggeeNoExecute.
+ LeaveDebuggeeNoExecute* unlocked_;
+
+ // When DebuggeeWouldRun is a warning instead of an error, whether we've
+ // reported a warning already.
+ bool reported_;
+
+ public:
+ explicit EnterDebuggeeNoExecute(JSContext* cx, Debugger& dbg)
+ : dbg_(dbg),
+ unlocked_(nullptr),
+ reported_(false)
+ {
+ stack_ = &cx->runtime()->noExecuteDebuggerTop;
+ prev_ = *stack_;
+ *stack_ = this;
+ }
+
+ ~EnterDebuggeeNoExecute() {
+ MOZ_ASSERT(*stack_ == this);
+ *stack_ = prev_;
+ }
+
+ Debugger& debugger() const {
+ return dbg_;
+ }
+
+#ifdef DEBUG
+ static bool isLockedInStack(JSContext* cx, Debugger& dbg) {
+ JSRuntime* rt = cx->runtime();
+ for (EnterDebuggeeNoExecute* it = rt->noExecuteDebuggerTop; it; it = it->prev_) {
+ if (&it->debugger() == &dbg)
+ return !it->unlocked_;
+ }
+ return false;
+ }
+#endif
+
+ // Given a JSContext entered into a debuggee compartment, find the lock
+ // that locks it. Returns nullptr if not found.
+ static EnterDebuggeeNoExecute* findInStack(JSContext* cx) {
+ JSRuntime* rt = cx->runtime();
+ JSCompartment* debuggee = cx->compartment();
+ for (EnterDebuggeeNoExecute* it = rt->noExecuteDebuggerTop; it; it = it->prev_) {
+ Debugger& dbg = it->debugger();
+ if (!it->unlocked_ && dbg.isEnabled() && dbg.observesGlobal(debuggee->maybeGlobal()))
+ return it;
+ }
+ return nullptr;
+ }
+
+ // Given a JSContext entered into a debuggee compartment, report a
+ // warning or an error if there is a lock that locks it.
+ static bool reportIfFoundInStack(JSContext* cx, HandleScript script) {
+ if (EnterDebuggeeNoExecute* nx = findInStack(cx)) {
+ bool warning = !cx->options().throwOnDebuggeeWouldRun();
+ if (!warning || !nx->reported_) {
+ AutoCompartment ac(cx, nx->debugger().toJSObject());
+ nx->reported_ = true;
+ if (cx->options().dumpStackOnDebuggeeWouldRun()) {
+ fprintf(stdout, "Dumping stack for DebuggeeWouldRun:\n");
+ DumpBacktrace(cx);
+ }
+ const char* filename = script->filename() ? script->filename() : "(none)";
+ char linenoStr[15];
+ SprintfLiteral(linenoStr, "%" PRIuSIZE, script->lineno());
+ unsigned flags = warning ? JSREPORT_WARNING : JSREPORT_ERROR;
+ // FIXME: filename should be UTF-8 (bug 987069).
+ return JS_ReportErrorFlagsAndNumberLatin1(cx, flags, GetErrorMessage, nullptr,
+ JSMSG_DEBUGGEE_WOULD_RUN,
+ filename, linenoStr);
+ }
+ }
+ return true;
+ }
+};
+
+// Given a JSContext entered into a debuggee compartment, if it is in
+// an NX section, unlock the topmost EnterDebuggeeNoExecute instance.
+//
+// Does nothing if debuggee is not in an NX section. For example, this
+// situation arises when invocation functions are called without entering
+// Debugger code, e.g., calling D.O.p.executeInGlobal or D.O.p.apply.
+class MOZ_RAII js::LeaveDebuggeeNoExecute
+{
+ EnterDebuggeeNoExecute* prevLocked_;
+
+ public:
+ explicit LeaveDebuggeeNoExecute(JSContext* cx)
+ : prevLocked_(EnterDebuggeeNoExecute::findInStack(cx))
+ {
+ if (prevLocked_) {
+ MOZ_ASSERT(!prevLocked_->unlocked_);
+ prevLocked_->unlocked_ = this;
+ }
+ }
+
+ ~LeaveDebuggeeNoExecute() {
+ if (prevLocked_) {
+ MOZ_ASSERT(prevLocked_->unlocked_ == this);
+ prevLocked_->unlocked_ = nullptr;
+ }
+ }
+};
+
+/* static */ bool
+Debugger::slowPathCheckNoExecute(JSContext* cx, HandleScript script)
+{
+ MOZ_ASSERT(cx->compartment()->isDebuggee());
+ MOZ_ASSERT(cx->runtime()->noExecuteDebuggerTop);
+ return EnterDebuggeeNoExecute::reportIfFoundInStack(cx, script);
+}
+
+static inline void
+NukeDebuggerWrapper(NativeObject *wrapper)
+{
+ // In some OOM failure cases, we need to destroy the edge to the referent,
+ // to avoid trying to trace it during untimely collections.
+ wrapper->setPrivate(nullptr);
+}
+
+static bool
+ValueToStableChars(JSContext* cx, const char *fnname, HandleValue value,
+ AutoStableStringChars& stableChars)
+{
+ if (!value.isString()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ fnname, "string", InformalValueTypeName(value));
+ return false;
+ }
+ RootedLinearString linear(cx, value.toString()->ensureLinear(cx));
+ if (!linear)
+ return false;
+ if (!stableChars.initTwoByte(cx, linear))
+ return false;
+ return true;
+}
+
+EvalOptions::~EvalOptions()
+{
+ js_free(const_cast<char*>(filename_));
+}
+
+bool
+EvalOptions::setFilename(JSContext* cx, const char* filename)
+{
+ char* copy = nullptr;
+ if (filename) {
+ copy = JS_strdup(cx, filename);
+ if (!copy)
+ return false;
+ }
+
+ // EvalOptions always owns filename_, so this cast is okay.
+ js_free(const_cast<char*>(filename_));
+
+ filename_ = copy;
+ return true;
+}
+
+static bool
+ParseEvalOptions(JSContext* cx, HandleValue value, EvalOptions& options)
+{
+ if (!value.isObject())
+ return true;
+
+ RootedObject opts(cx, &value.toObject());
+
+ RootedValue v(cx);
+ if (!JS_GetProperty(cx, opts, "url", &v))
+ return false;
+ if (!v.isUndefined()) {
+ RootedString url_str(cx, ToString<CanGC>(cx, v));
+ if (!url_str)
+ return false;
+ JSAutoByteString url_bytes(cx, url_str);
+ if (!url_bytes)
+ return false;
+ if (!options.setFilename(cx, url_bytes.ptr()))
+ return false;
+ }
+
+ if (!JS_GetProperty(cx, opts, "lineNumber", &v))
+ return false;
+ if (!v.isUndefined()) {
+ uint32_t lineno;
+ if (!ToUint32(cx, v, &lineno))
+ return false;
+ options.setLineno(lineno);
+ }
+
+ return true;
+}
+
+static bool
+RequireGlobalObject(JSContext* cx, HandleValue dbgobj, HandleObject referent)
+{
+ RootedObject obj(cx, referent);
+
+ if (!obj->is<GlobalObject>()) {
+ const char* isWrapper = "";
+ const char* isWindowProxy = "";
+
+ /* Help the poor programmer by pointing out wrappers around globals... */
+ if (obj->is<WrapperObject>()) {
+ obj = js::UncheckedUnwrap(obj);
+ isWrapper = "a wrapper around ";
+ }
+
+ /* ... and WindowProxies around Windows. */
+ if (IsWindowProxy(obj)) {
+ obj = ToWindowIfWindowProxy(obj);
+ isWindowProxy = "a WindowProxy referring to ";
+ }
+
+ if (obj->is<GlobalObject>()) {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_WRAPPER_IN_WAY,
+ JSDVG_SEARCH_STACK, dbgobj, nullptr,
+ isWrapper, isWindowProxy);
+ } else {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
+ JSDVG_SEARCH_STACK, dbgobj, nullptr,
+ "a global object", nullptr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+/*** Breakpoints *********************************************************************************/
+
+BreakpointSite::BreakpointSite(JSScript* script, jsbytecode* pc)
+ : script(script), pc(pc), enabledCount(0)
+{
+ MOZ_ASSERT(!script->hasBreakpointsAt(pc));
+ JS_INIT_CLIST(&breakpoints);
+}
+
+void
+BreakpointSite::recompile(FreeOp* fop)
+{
+ if (script->hasBaselineScript())
+ script->baselineScript()->toggleDebugTraps(script, pc);
+}
+
+void
+BreakpointSite::inc(FreeOp* fop)
+{
+ enabledCount++;
+ if (enabledCount == 1)
+ recompile(fop);
+}
+
+void
+BreakpointSite::dec(FreeOp* fop)
+{
+ MOZ_ASSERT(enabledCount > 0);
+ enabledCount--;
+ if (enabledCount == 0)
+ recompile(fop);
+}
+
+void
+BreakpointSite::destroyIfEmpty(FreeOp* fop)
+{
+ if (JS_CLIST_IS_EMPTY(&breakpoints))
+ script->destroyBreakpointSite(fop, pc);
+}
+
+Breakpoint*
+BreakpointSite::firstBreakpoint() const
+{
+ if (JS_CLIST_IS_EMPTY(&breakpoints))
+ return nullptr;
+ return Breakpoint::fromSiteLinks(JS_NEXT_LINK(&breakpoints));
+}
+
+bool
+BreakpointSite::hasBreakpoint(Breakpoint* bp)
+{
+ for (Breakpoint* p = firstBreakpoint(); p; p = p->nextInSite())
+ if (p == bp)
+ return true;
+ return false;
+}
+
+Breakpoint::Breakpoint(Debugger* debugger, BreakpointSite* site, JSObject* handler)
+ : debugger(debugger), site(site), handler(handler)
+{
+ MOZ_ASSERT(handler->compartment() == debugger->object->compartment());
+ JS_APPEND_LINK(&debuggerLinks, &debugger->breakpoints);
+ JS_APPEND_LINK(&siteLinks, &site->breakpoints);
+}
+
+Breakpoint*
+Breakpoint::fromDebuggerLinks(JSCList* links)
+{
+ return (Breakpoint*) ((unsigned char*) links - offsetof(Breakpoint, debuggerLinks));
+}
+
+Breakpoint*
+Breakpoint::fromSiteLinks(JSCList* links)
+{
+ return (Breakpoint*) ((unsigned char*) links - offsetof(Breakpoint, siteLinks));
+}
+
+void
+Breakpoint::destroy(FreeOp* fop)
+{
+ if (debugger->enabled)
+ site->dec(fop);
+ JS_REMOVE_LINK(&debuggerLinks);
+ JS_REMOVE_LINK(&siteLinks);
+ site->destroyIfEmpty(fop);
+ fop->delete_(this);
+}
+
+Breakpoint*
+Breakpoint::nextInDebugger()
+{
+ JSCList* link = JS_NEXT_LINK(&debuggerLinks);
+ return (link == &debugger->breakpoints) ? nullptr : fromDebuggerLinks(link);
+}
+
+Breakpoint*
+Breakpoint::nextInSite()
+{
+ JSCList* link = JS_NEXT_LINK(&siteLinks);
+ return (link == &site->breakpoints) ? nullptr : fromSiteLinks(link);
+}
+
+
+/*** Debugger hook dispatch **********************************************************************/
+
+Debugger::Debugger(JSContext* cx, NativeObject* dbg)
+ : object(dbg),
+ debuggees(cx->runtime()),
+ uncaughtExceptionHook(nullptr),
+ enabled(true),
+ allowUnobservedAsmJS(false),
+ collectCoverageInfo(false),
+ observedGCs(cx->runtime()),
+ allocationsLog(cx),
+ trackingAllocationSites(false),
+ allocationSamplingProbability(1.0),
+ maxAllocationsLogLength(DEFAULT_MAX_LOG_LENGTH),
+ allocationsLogOverflowed(false),
+ frames(cx->runtime()),
+ scripts(cx),
+ sources(cx),
+ objects(cx),
+ environments(cx),
+ wasmInstanceScripts(cx),
+ wasmInstanceSources(cx),
+#ifdef NIGHTLY_BUILD
+ traceLoggerLastDrainedSize(0),
+ traceLoggerLastDrainedIteration(0),
+#endif
+ traceLoggerScriptedCallsLastDrainedSize(0),
+ traceLoggerScriptedCallsLastDrainedIteration(0)
+{
+ assertSameCompartment(cx, dbg);
+
+ JS_INIT_CLIST(&breakpoints);
+ JS_INIT_CLIST(&onNewGlobalObjectWatchersLink);
+
+#ifdef JS_TRACE_LOGGING
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ if (logger) {
+#ifdef NIGHTLY_BUILD
+ logger->getIterationAndSize(&traceLoggerLastDrainedIteration, &traceLoggerLastDrainedSize);
+#endif
+ logger->getIterationAndSize(&traceLoggerScriptedCallsLastDrainedIteration,
+ &traceLoggerScriptedCallsLastDrainedSize);
+ }
+#endif
+}
+
+Debugger::~Debugger()
+{
+ MOZ_ASSERT_IF(debuggees.initialized(), debuggees.empty());
+ allocationsLog.clear();
+
+ /*
+ * Since the inactive state for this link is a singleton cycle, it's always
+ * safe to apply JS_REMOVE_LINK to it, regardless of whether we're in the list or not.
+ *
+ * We don't have to worry about locking here since Debugger is not
+ * background finalized.
+ */
+ JS_REMOVE_LINK(&onNewGlobalObjectWatchersLink);
+}
+
+bool
+Debugger::init(JSContext* cx)
+{
+ if (!debuggees.init() ||
+ !debuggeeZones.init() ||
+ !frames.init() ||
+ !scripts.init() ||
+ !sources.init() ||
+ !objects.init() ||
+ !observedGCs.init() ||
+ !environments.init() ||
+ !wasmInstanceScripts.init() ||
+ !wasmInstanceSources.init())
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ cx->runtime()->debuggerList.insertBack(this);
+ return true;
+}
+
+JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGSCRIPT_OWNER));
+JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGSOURCE_OWNER));
+JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(JSSLOT_DEBUGOBJECT_OWNER));
+JS_STATIC_ASSERT(unsigned(JSSLOT_DEBUGFRAME_OWNER) == unsigned(DebuggerEnvironment::OWNER_SLOT));
+
+/* static */ Debugger*
+Debugger::fromChildJSObject(JSObject* obj)
+{
+ MOZ_ASSERT(obj->getClass() == &DebuggerFrame::class_ ||
+ obj->getClass() == &DebuggerScript_class ||
+ obj->getClass() == &DebuggerSource_class ||
+ obj->getClass() == &DebuggerObject::class_ ||
+ obj->getClass() == &DebuggerEnvironment::class_);
+ JSObject* dbgobj = &obj->as<NativeObject>().getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER).toObject();
+ return fromJSObject(dbgobj);
+}
+
+bool
+Debugger::hasMemory() const
+{
+ return object->getReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE).isObject();
+}
+
+DebuggerMemory&
+Debugger::memory() const
+{
+ MOZ_ASSERT(hasMemory());
+ return object->getReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE).toObject().as<DebuggerMemory>();
+}
+
+bool
+Debugger::getScriptFrameWithIter(JSContext* cx, AbstractFramePtr referent,
+ const ScriptFrameIter* maybeIter, MutableHandleValue vp)
+{
+ RootedDebuggerFrame result(cx);
+ if (!Debugger::getScriptFrameWithIter(cx, referent, maybeIter, &result))
+ return false;
+
+ vp.setObject(*result);
+ return true;
+}
+
+bool
+Debugger::getScriptFrameWithIter(JSContext* cx, AbstractFramePtr referent,
+ const ScriptFrameIter* maybeIter,
+ MutableHandleDebuggerFrame result)
+{
+ MOZ_ASSERT_IF(maybeIter, maybeIter->abstractFramePtr() == referent);
+ MOZ_ASSERT(!referent.script()->selfHosted());
+
+ if (!referent.script()->ensureHasAnalyzedArgsUsage(cx))
+ return false;
+
+ FrameMap::AddPtr p = frames.lookupForAdd(referent);
+ if (!p) {
+ /* Create and populate the Debugger.Frame object. */
+ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_FRAME_PROTO).toObject());
+ RootedNativeObject debugger(cx, object);
+
+ RootedDebuggerFrame frame(cx, DebuggerFrame::create(cx, proto, referent, maybeIter,
+ debugger));
+ if (!frame)
+ return false;
+
+ if (!ensureExecutionObservabilityOfFrame(cx, referent))
+ return false;
+
+ if (!frames.add(p, referent, frame)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ result.set(&p->value()->as<DebuggerFrame>());
+ return true;
+}
+
+/* static */ bool
+Debugger::hasLiveHook(GlobalObject* global, Hook which)
+{
+ if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
+ for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
+ Debugger* dbg = *p;
+ if (dbg->enabled && dbg->getHook(which))
+ return true;
+ }
+ }
+ return false;
+}
+
+JSObject*
+Debugger::getHook(Hook hook) const
+{
+ MOZ_ASSERT(hook >= 0 && hook < HookCount);
+ const Value& v = object->getReservedSlot(JSSLOT_DEBUG_HOOK_START + hook);
+ return v.isUndefined() ? nullptr : &v.toObject();
+}
+
+bool
+Debugger::hasAnyLiveHooks(JSRuntime* rt) const
+{
+ if (!enabled)
+ return false;
+
+ if (getHook(OnDebuggerStatement) ||
+ getHook(OnExceptionUnwind) ||
+ getHook(OnNewScript) ||
+ getHook(OnEnterFrame))
+ {
+ return true;
+ }
+
+ /* If any breakpoints are in live scripts, return true. */
+ for (Breakpoint* bp = firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
+ if (IsMarkedUnbarriered(rt, &bp->site->script))
+ return true;
+ }
+
+ for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) {
+ NativeObject* frameObj = r.front().value();
+ if (!frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() ||
+ !frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined())
+ return true;
+ }
+
+ return false;
+}
+
+/* static */ JSTrapStatus
+Debugger::slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame)
+{
+ RootedValue rval(cx);
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [frame](Debugger* dbg) -> bool {
+ return dbg->observesFrame(frame) && dbg->observesEnterFrame();
+ },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ return dbg->fireEnterFrame(cx, &rval);
+ });
+
+ switch (status) {
+ case JSTRAP_CONTINUE:
+ break;
+
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ break;
+
+ case JSTRAP_ERROR:
+ cx->clearPendingException();
+ break;
+
+ case JSTRAP_RETURN:
+ frame.setReturnValue(rval);
+ break;
+
+ default:
+ MOZ_CRASH("bad Debugger::onEnterFrame JSTrapStatus value");
+ }
+
+ return status;
+}
+
+static void
+DebuggerFrame_maybeDecrementFrameScriptStepModeCount(FreeOp* fop, AbstractFramePtr frame,
+ NativeObject* frameobj);
+
+static void
+DebuggerFrame_freeScriptFrameIterData(FreeOp* fop, JSObject* obj);
+
+/*
+ * Handle leaving a frame with debuggers watching. |frameOk| indicates whether
+ * the frame is exiting normally or abruptly. Set |cx|'s exception and/or
+ * |cx->fp()|'s return value, and return a new success value.
+ */
+/* static */ bool
+Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool frameOk)
+{
+ mozilla::DebugOnly<Handle<GlobalObject*>> debuggeeGlobal = cx->global();
+
+ auto frameMapsGuard = MakeScopeExit([&] {
+ // Clean up all Debugger.Frame instances.
+ removeFromFrameMapsAndClearBreakpointsIn(cx, frame);
+ });
+
+ // The onPop handler and associated clean up logic should not run multiple
+ // times on the same frame. If slowPathOnLeaveFrame has already been
+ // called, the frame will not be present in the Debugger frame maps.
+ Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx));
+ if (!getDebuggerFrames(frame, &frames))
+ return false;
+ if (frames.empty())
+ return frameOk;
+
+ /* Save the frame's completion value. */
+ JSTrapStatus status;
+ RootedValue value(cx);
+ Debugger::resultToCompletion(cx, frameOk, frame.returnValue(), &status, &value);
+
+ // This path can be hit via unwinding the stack due to over-recursion or
+ // OOM. In those cases, don't fire the frames' onPop handlers, because
+ // invoking JS will only trigger the same condition. See
+ // slowPathOnExceptionUnwind.
+ if (!cx->isThrowingOverRecursed() && !cx->isThrowingOutOfMemory()) {
+ /* For each Debugger.Frame, fire its onPop handler, if any. */
+ for (size_t i = 0; i < frames.length(); i++) {
+ HandleDebuggerFrame frameobj = frames[i];
+ Debugger* dbg = Debugger::fromChildJSObject(frameobj);
+ EnterDebuggeeNoExecute nx(cx, *dbg);
+
+ if (dbg->enabled &&
+ !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined())
+ {
+ RootedValue handler(cx, frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER));
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, dbg->object);
+
+ RootedValue wrappedValue(cx, value);
+ RootedValue completion(cx);
+ if (!dbg->wrapDebuggeeValue(cx, &wrappedValue) ||
+ !dbg->newCompletionValue(cx, status, wrappedValue, &completion))
+ {
+ status = dbg->reportUncaughtException(ac);
+ break;
+ }
+
+ /* Call the onPop handler. */
+ RootedValue rval(cx);
+ bool hookOk = js::Call(cx, handler, frameobj, completion, &rval);
+ RootedValue nextValue(cx);
+ JSTrapStatus nextStatus = dbg->processHandlerResult(ac, hookOk, rval,
+ frame, pc, &nextValue);
+
+ /*
+ * At this point, we are back in the debuggee compartment, and any error has
+ * been wrapped up as a completion value.
+ */
+ MOZ_ASSERT(cx->compartment() == debuggeeGlobal->compartment());
+ MOZ_ASSERT(!cx->isExceptionPending());
+
+ /* JSTRAP_CONTINUE means "make no change". */
+ if (nextStatus != JSTRAP_CONTINUE) {
+ status = nextStatus;
+ value = nextValue;
+ }
+ }
+ }
+ }
+
+ /* Establish (status, value) as our resumption value. */
+ switch (status) {
+ case JSTRAP_RETURN:
+ frame.setReturnValue(value);
+ return true;
+
+ case JSTRAP_THROW:
+ cx->setPendingException(value);
+ return false;
+
+ case JSTRAP_ERROR:
+ MOZ_ASSERT(!cx->isExceptionPending());
+ return false;
+
+ default:
+ MOZ_CRASH("bad final trap status");
+ }
+}
+
+/* static */ JSTrapStatus
+Debugger::slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame)
+{
+ RootedValue rval(cx);
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [](Debugger* dbg) -> bool { return dbg->getHook(OnDebuggerStatement); },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ return dbg->fireDebuggerStatement(cx, &rval);
+ });
+
+ switch (status) {
+ case JSTRAP_CONTINUE:
+ case JSTRAP_ERROR:
+ break;
+
+ case JSTRAP_RETURN:
+ frame.setReturnValue(rval);
+ break;
+
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ break;
+
+ default:
+ MOZ_CRASH("Invalid onDebuggerStatement trap status");
+ }
+
+ return status;
+}
+
+/* static */ JSTrapStatus
+Debugger::slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame)
+{
+ // Invoking more JS on an over-recursed stack or after OOM is only going
+ // to result in more of the same error.
+ if (cx->isThrowingOverRecursed() || cx->isThrowingOutOfMemory())
+ return JSTRAP_CONTINUE;
+
+ // The Debugger API mustn't muck with frames from self-hosted scripts.
+ if (frame.script()->selfHosted())
+ return JSTRAP_CONTINUE;
+
+ RootedValue rval(cx);
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [](Debugger* dbg) -> bool { return dbg->getHook(OnExceptionUnwind); },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ return dbg->fireExceptionUnwind(cx, &rval);
+ });
+
+ switch (status) {
+ case JSTRAP_CONTINUE:
+ break;
+
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ break;
+
+ case JSTRAP_ERROR:
+ cx->clearPendingException();
+ break;
+
+ case JSTRAP_RETURN:
+ cx->clearPendingException();
+ frame.setReturnValue(rval);
+ break;
+
+ default:
+ MOZ_CRASH("Invalid onExceptionUnwind trap status");
+ }
+
+ return status;
+}
+
+// TODO: Remove Remove this function when all properties/methods returning a
+/// DebuggerEnvironment have been given a C++ interface (bug 1271649).
+bool
+Debugger::wrapEnvironment(JSContext* cx, Handle<Env*> env, MutableHandleValue rval)
+{
+ if (!env) {
+ rval.setNull();
+ return true;
+ }
+
+ RootedDebuggerEnvironment envobj(cx);
+
+ if (!wrapEnvironment(cx, env, &envobj))
+ return false;
+
+ rval.setObject(*envobj);
+ return true;
+}
+
+bool
+Debugger::wrapEnvironment(JSContext* cx, Handle<Env*> env,
+ MutableHandleDebuggerEnvironment result)
+{
+ MOZ_ASSERT(env);
+
+ /*
+ * DebuggerEnv should only wrap a debug scope chain obtained (transitively)
+ * from GetDebugEnvironmentFor(Frame|Function).
+ */
+ MOZ_ASSERT(!IsSyntacticEnvironment(env));
+
+ DependentAddPtr<ObjectWeakMap> p(cx, environments, env);
+ if (p) {
+ result.set(&p->value()->as<DebuggerEnvironment>());
+ } else {
+ /* Create a new Debugger.Environment for env. */
+ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_ENV_PROTO).toObject());
+ RootedNativeObject debugger(cx, object);
+
+ RootedDebuggerEnvironment envobj(cx,
+ DebuggerEnvironment::create(cx, proto, env, debugger));
+ if (!envobj)
+ return false;
+
+ if (!p.add(cx, environments, env, envobj)) {
+ NukeDebuggerWrapper(envobj);
+ return false;
+ }
+
+ CrossCompartmentKey key(object, env, CrossCompartmentKey::DebuggerEnvironment);
+ if (!object->compartment()->putWrapper(cx, key, ObjectValue(*envobj))) {
+ NukeDebuggerWrapper(envobj);
+ environments.remove(env);
+ return false;
+ }
+
+ result.set(envobj);
+ }
+
+ return true;
+}
+
+bool
+Debugger::wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp)
+{
+ assertSameCompartment(cx, object.get());
+
+ if (vp.isObject()) {
+ RootedObject obj(cx, &vp.toObject());
+ RootedDebuggerObject dobj(cx);
+
+ if (!wrapDebuggeeObject(cx, obj, &dobj))
+ return false;
+
+ vp.setObject(*dobj);
+ } else if (vp.isMagic()) {
+ RootedPlainObject optObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!optObj)
+ return false;
+
+ // We handle three sentinel values: missing arguments (overloading
+ // JS_OPTIMIZED_ARGUMENTS), optimized out slots (JS_OPTIMIZED_OUT),
+ // and uninitialized bindings (JS_UNINITIALIZED_LEXICAL).
+ //
+ // Other magic values should not have escaped.
+ PropertyName* name;
+ switch (vp.whyMagic()) {
+ case JS_OPTIMIZED_ARGUMENTS: name = cx->names().missingArguments; break;
+ case JS_OPTIMIZED_OUT: name = cx->names().optimizedOut; break;
+ case JS_UNINITIALIZED_LEXICAL: name = cx->names().uninitialized; break;
+ default: MOZ_CRASH("Unsupported magic value escaped to Debugger");
+ }
+
+ RootedValue trueVal(cx, BooleanValue(true));
+ if (!DefineProperty(cx, optObj, name, trueVal))
+ return false;
+
+ vp.setObject(*optObj);
+ } else if (!cx->compartment()->wrap(cx, vp)) {
+ vp.setUndefined();
+ return false;
+ }
+
+ return true;
+}
+
+bool
+Debugger::wrapDebuggeeObject(JSContext* cx, HandleObject obj,
+ MutableHandleDebuggerObject result)
+{
+ MOZ_ASSERT(obj);
+
+ if (obj->is<JSFunction>()) {
+ MOZ_ASSERT(!IsInternalFunctionObject(*obj));
+ RootedFunction fun(cx, &obj->as<JSFunction>());
+ if (!EnsureFunctionHasScript(cx, fun))
+ return false;
+ }
+
+ DependentAddPtr<ObjectWeakMap> p(cx, objects, obj);
+ if (p) {
+ result.set(&p->value()->as<DebuggerObject>());
+ } else {
+ /* Create a new Debugger.Object for obj. */
+ RootedNativeObject debugger(cx, object);
+ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_OBJECT_PROTO).toObject());
+ RootedDebuggerObject dobj(cx, DebuggerObject::create(cx, proto, obj, debugger));
+ if (!dobj)
+ return false;
+
+ if (!p.add(cx, objects, obj, dobj)) {
+ NukeDebuggerWrapper(dobj);
+ return false;
+ }
+
+ if (obj->compartment() != object->compartment()) {
+ CrossCompartmentKey key(object, obj, CrossCompartmentKey::DebuggerObject);
+ if (!object->compartment()->putWrapper(cx, key, ObjectValue(*dobj))) {
+ NukeDebuggerWrapper(dobj);
+ objects.remove(obj);
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ result.set(dobj);
+ }
+
+ return true;
+}
+
+static NativeObject*
+ToNativeDebuggerObject(JSContext* cx, MutableHandleObject obj)
+{
+ if (obj->getClass() != &DebuggerObject::class_) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ "Debugger", "Debugger.Object", obj->getClass()->name);
+ return nullptr;
+ }
+
+ NativeObject* ndobj = &obj->as<NativeObject>();
+
+ Value owner = ndobj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER);
+ if (owner.isUndefined()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEBUG_PROTO, "Debugger.Object", "Debugger.Object");
+ return nullptr;
+ }
+
+ return ndobj;
+}
+
+bool
+Debugger::unwrapDebuggeeObject(JSContext* cx, MutableHandleObject obj)
+{
+ NativeObject* ndobj = ToNativeDebuggerObject(cx, obj);
+ if (!ndobj)
+ return false;
+
+ Value owner = ndobj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER);
+ if (&owner.toObject() != object) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEBUG_WRONG_OWNER, "Debugger.Object");
+ return false;
+ }
+
+ obj.set(static_cast<JSObject*>(ndobj->getPrivate()));
+ return true;
+}
+
+bool
+Debugger::unwrapDebuggeeValue(JSContext* cx, MutableHandleValue vp)
+{
+ assertSameCompartment(cx, object.get(), vp);
+ if (vp.isObject()) {
+ RootedObject dobj(cx, &vp.toObject());
+ if (!unwrapDebuggeeObject(cx, &dobj))
+ return false;
+ vp.setObject(*dobj);
+ }
+ return true;
+}
+
+static bool
+CheckArgCompartment(JSContext* cx, JSObject* obj, JSObject* arg,
+ const char* methodname, const char* propname)
+{
+ if (arg->compartment() != obj->compartment()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_COMPARTMENT_MISMATCH,
+ methodname, propname);
+ return false;
+ }
+ return true;
+}
+
+static bool
+CheckArgCompartment(JSContext* cx, JSObject* obj, HandleValue v,
+ const char* methodname, const char* propname)
+{
+ if (v.isObject())
+ return CheckArgCompartment(cx, obj, &v.toObject(), methodname, propname);
+ return true;
+}
+
+bool
+Debugger::unwrapPropertyDescriptor(JSContext* cx, HandleObject obj,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ if (desc.hasValue()) {
+ RootedValue value(cx, desc.value());
+ if (!unwrapDebuggeeValue(cx, &value) ||
+ !CheckArgCompartment(cx, obj, value, "defineProperty", "value"))
+ {
+ return false;
+ }
+ desc.setValue(value);
+ }
+
+ if (desc.hasGetterObject()) {
+ RootedObject get(cx, desc.getterObject());
+ if (get) {
+ if (!unwrapDebuggeeObject(cx, &get))
+ return false;
+ if (!CheckArgCompartment(cx, obj, get, "defineProperty", "get"))
+ return false;
+ }
+ desc.setGetterObject(get);
+ }
+
+ if (desc.hasSetterObject()) {
+ RootedObject set(cx, desc.setterObject());
+ if (set) {
+ if (!unwrapDebuggeeObject(cx, &set))
+ return false;
+ if (!CheckArgCompartment(cx, obj, set, "defineProperty", "set"))
+ return false;
+ }
+ desc.setSetterObject(set);
+ }
+
+ return true;
+}
+
+namespace {
+class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer::Closure
+{
+public:
+ explicit ReportExceptionClosure(RootedValue& exn)
+ : exn_(exn)
+ {
+ }
+
+ bool operator()(JSContext* cx) override
+ {
+ cx->setPendingException(exn_);
+ return false;
+ }
+
+private:
+ RootedValue& exn_;
+};
+} // anonymous namespace
+
+JSTrapStatus
+Debugger::reportUncaughtException(Maybe<AutoCompartment>& ac)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ // Uncaught exceptions arise from Debugger code, and so we must already be
+ // in an NX section.
+ MOZ_ASSERT(EnterDebuggeeNoExecute::isLockedInStack(cx, *this));
+
+ if (cx->isExceptionPending()) {
+ /*
+ * We want to report the pending exception, but we want to let the
+ * embedding handle it however it wants to. So pretend like we're
+ * starting a new script execution on our current compartment (which
+ * is the debugger compartment, so reported errors won't get
+ * reported to various onerror handlers in debuggees) and as part of
+ * that "execution" simply throw our exception so the embedding can
+ * deal.
+ */
+ RootedValue exn(cx);
+ if (cx->getPendingException(&exn)) {
+ /*
+ * Clear the exception, because
+ * PrepareScriptEnvironmentAndInvoke will assert that we don't
+ * have one.
+ */
+ cx->clearPendingException();
+ ReportExceptionClosure reportExn(exn);
+ PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn);
+ }
+ /*
+ * And if not, or if PrepareScriptEnvironmentAndInvoke somehow left
+ * an exception on cx (which it totally shouldn't do), just give
+ * up.
+ */
+ cx->clearPendingException();
+ }
+
+ ac.reset();
+ return JSTRAP_ERROR;
+}
+
+JSTrapStatus
+Debugger::handleUncaughtExceptionHelper(Maybe<AutoCompartment>& ac, MutableHandleValue* vp,
+ const Maybe<HandleValue>& thisVForCheck,
+ AbstractFramePtr frame)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ // Uncaught exceptions arise from Debugger code, and so we must already be
+ // in an NX section.
+ MOZ_ASSERT(EnterDebuggeeNoExecute::isLockedInStack(cx, *this));
+
+ if (cx->isExceptionPending()) {
+ if (uncaughtExceptionHook) {
+ RootedValue exc(cx);
+ if (!cx->getPendingException(&exc))
+ return JSTRAP_ERROR;
+ cx->clearPendingException();
+
+ RootedValue fval(cx, ObjectValue(*uncaughtExceptionHook));
+ RootedValue rv(cx);
+ if (js::Call(cx, fval, object, exc, &rv)) {
+ if (vp) {
+ JSTrapStatus status = JSTRAP_CONTINUE;
+ if (processResumptionValue(ac, frame, thisVForCheck, rv, status, *vp))
+ return status;
+ } else {
+ return JSTRAP_CONTINUE;
+ }
+ }
+ }
+
+ return reportUncaughtException(ac);
+ }
+
+ ac.reset();
+ return JSTRAP_ERROR;
+}
+
+JSTrapStatus
+Debugger::handleUncaughtException(Maybe<AutoCompartment>& ac, MutableHandleValue vp,
+ const Maybe<HandleValue>& thisVForCheck, AbstractFramePtr frame)
+{
+ return handleUncaughtExceptionHelper(ac, &vp, thisVForCheck, frame);
+}
+
+JSTrapStatus
+Debugger::handleUncaughtException(Maybe<AutoCompartment>& ac)
+{
+ return handleUncaughtExceptionHelper(ac, nullptr, mozilla::Nothing(), NullFramePtr());
+}
+
+/* static */ void
+Debugger::resultToCompletion(JSContext* cx, bool ok, const Value& rv,
+ JSTrapStatus* status, MutableHandleValue value)
+{
+ MOZ_ASSERT_IF(ok, !cx->isExceptionPending());
+
+ if (ok) {
+ *status = JSTRAP_RETURN;
+ value.set(rv);
+ } else if (cx->isExceptionPending()) {
+ *status = JSTRAP_THROW;
+ if (!cx->getPendingException(value))
+ *status = JSTRAP_ERROR;
+ cx->clearPendingException();
+ } else {
+ *status = JSTRAP_ERROR;
+ value.setUndefined();
+ }
+}
+
+bool
+Debugger::newCompletionValue(JSContext* cx, JSTrapStatus status, const Value& value_,
+ MutableHandleValue result)
+{
+ /*
+ * We must be in the debugger's compartment, since that's where we want
+ * to construct the completion value.
+ */
+ assertSameCompartment(cx, object.get());
+ assertSameCompartment(cx, value_);
+
+ RootedId key(cx);
+ RootedValue value(cx, value_);
+
+ switch (status) {
+ case JSTRAP_RETURN:
+ key = NameToId(cx->names().return_);
+ break;
+
+ case JSTRAP_THROW:
+ key = NameToId(cx->names().throw_);
+ break;
+
+ case JSTRAP_ERROR:
+ result.setNull();
+ return true;
+
+ default:
+ MOZ_CRASH("bad status passed to Debugger::newCompletionValue");
+ }
+
+ /* Common tail for JSTRAP_RETURN and JSTRAP_THROW. */
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj ||
+ !NativeDefineProperty(cx, obj, key, value, nullptr, nullptr, JSPROP_ENUMERATE))
+ {
+ return false;
+ }
+
+ result.setObject(*obj);
+ return true;
+}
+
+bool
+Debugger::receiveCompletionValue(Maybe<AutoCompartment>& ac, bool ok,
+ HandleValue val,
+ MutableHandleValue vp)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ JSTrapStatus status;
+ RootedValue value(cx);
+ resultToCompletion(cx, ok, val, &status, &value);
+ ac.reset();
+ return wrapDebuggeeValue(cx, &value) &&
+ newCompletionValue(cx, status, value, vp);
+}
+
+static bool
+GetStatusProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, JSTrapStatus status,
+ JSTrapStatus& statusp, MutableHandleValue vp, int* hits)
+{
+ bool found;
+ if (!HasProperty(cx, obj, name, &found))
+ return false;
+ if (found) {
+ ++*hits;
+ statusp = status;
+ if (!GetProperty(cx, obj, obj, name, vp))
+ return false;
+ }
+ return true;
+}
+
+static bool
+ParseResumptionValueAsObject(JSContext* cx, HandleValue rv, JSTrapStatus& statusp,
+ MutableHandleValue vp)
+{
+ int hits = 0;
+ if (rv.isObject()) {
+ RootedObject obj(cx, &rv.toObject());
+ if (!GetStatusProperty(cx, obj, cx->names().return_, JSTRAP_RETURN, statusp, vp, &hits))
+ return false;
+ if (!GetStatusProperty(cx, obj, cx->names().throw_, JSTRAP_THROW, statusp, vp, &hits))
+ return false;
+ }
+
+ if (hits != 1) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_RESUMPTION);
+ return false;
+ }
+ return true;
+}
+
+static bool
+ParseResumptionValue(JSContext* cx, HandleValue rval, JSTrapStatus& statusp, MutableHandleValue vp)
+{
+ if (rval.isUndefined()) {
+ statusp = JSTRAP_CONTINUE;
+ vp.setUndefined();
+ return true;
+ }
+ if (rval.isNull()) {
+ statusp = JSTRAP_ERROR;
+ vp.setUndefined();
+ return true;
+ }
+ return ParseResumptionValueAsObject(cx, rval, statusp, vp);
+}
+
+static bool
+CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleValue>& maybeThisv,
+ JSTrapStatus status, MutableHandleValue vp)
+{
+ if (status == JSTRAP_RETURN && frame && frame.isFunctionFrame()) {
+ // Don't let a { return: ... } resumption value make a generator or
+ // async function violate the iterator protocol. The return value from
+ // such a frame must have the form { done: <bool>, value: <anything> }.
+ RootedFunction callee(cx, frame.callee());
+ if (callee->isAsync()) {
+ if (!CheckAsyncResumptionValue(cx, vp)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_AWAIT);
+ return false;
+ }
+ } else if (callee->isStarGenerator()) {
+ if (!CheckStarGeneratorResumptionValue(cx, vp)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_YIELD);
+ return false;
+ }
+ }
+ }
+
+ if (maybeThisv.isSome()) {
+ const HandleValue& thisv = maybeThisv.ref();
+ if (status == JSTRAP_RETURN && vp.isPrimitive()) {
+ if (vp.isUndefined()) {
+ if (thisv.isMagic(JS_UNINITIALIZED_LEXICAL))
+ return ThrowUninitializedThis(cx, frame);
+
+ vp.set(thisv);
+ } else {
+ ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, vp, nullptr);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool
+GetThisValueForCheck(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
+ MutableHandleValue thisv, Maybe<HandleValue>& maybeThisv)
+{
+ if (frame.debuggerNeedsCheckPrimitiveReturn()) {
+ {
+ AutoCompartment ac(cx, frame.environmentChain());
+ if (!GetThisValueForDebuggerMaybeOptimizedOut(cx, frame, pc, thisv))
+ return false;
+ }
+
+ if (!cx->compartment()->wrap(cx, thisv))
+ return false;
+
+ MOZ_ASSERT_IF(thisv.isMagic(), thisv.isMagic(JS_UNINITIALIZED_LEXICAL));
+ maybeThisv.emplace(HandleValue(thisv));
+ }
+
+ return true;
+}
+
+bool
+Debugger::processResumptionValue(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
+ const Maybe<HandleValue>& maybeThisv, HandleValue rval,
+ JSTrapStatus& statusp, MutableHandleValue vp)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ if (!ParseResumptionValue(cx, rval, statusp, vp) ||
+ !unwrapDebuggeeValue(cx, vp) ||
+ !CheckResumptionValue(cx, frame, maybeThisv, statusp, vp))
+ {
+ return false;
+ }
+
+ ac.reset();
+ if (!cx->compartment()->wrap(cx, vp)) {
+ statusp = JSTRAP_ERROR;
+ vp.setUndefined();
+ }
+
+ return true;
+}
+
+JSTrapStatus
+Debugger::processParsedHandlerResultHelper(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
+ const Maybe<HandleValue>& maybeThisv, bool success,
+ JSTrapStatus status, MutableHandleValue vp)
+{
+ if (!success)
+ return handleUncaughtException(ac, vp, maybeThisv, frame);
+
+ JSContext* cx = ac->context()->asJSContext();
+
+ if (!unwrapDebuggeeValue(cx, vp) ||
+ !CheckResumptionValue(cx, frame, maybeThisv, status, vp))
+ {
+ return handleUncaughtException(ac, vp, maybeThisv, frame);
+ }
+
+ ac.reset();
+ if (!cx->compartment()->wrap(cx, vp)) {
+ status = JSTRAP_ERROR;
+ vp.setUndefined();
+ }
+
+ return status;
+}
+
+JSTrapStatus
+Debugger::processParsedHandlerResult(Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
+ jsbytecode* pc, bool success, JSTrapStatus status,
+ MutableHandleValue vp)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ RootedValue thisv(cx);
+ Maybe<HandleValue> maybeThisv;
+ if (!GetThisValueForCheck(cx, frame, pc, &thisv, maybeThisv)) {
+ ac.reset();
+ return JSTRAP_ERROR;
+ }
+
+ return processParsedHandlerResultHelper(ac, frame, maybeThisv, success, status, vp);
+}
+
+JSTrapStatus
+Debugger::processHandlerResult(Maybe<AutoCompartment>& ac, bool success, const Value& rv,
+ AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp)
+{
+ JSContext* cx = ac->context()->asJSContext();
+
+ RootedValue thisv(cx);
+ Maybe<HandleValue> maybeThisv;
+ if (!GetThisValueForCheck(cx, frame, pc, &thisv, maybeThisv)) {
+ ac.reset();
+ return JSTRAP_ERROR;
+ }
+
+ if (!success)
+ return handleUncaughtException(ac, vp, maybeThisv, frame);
+
+ RootedValue rootRv(cx, rv);
+ JSTrapStatus status = JSTRAP_CONTINUE;
+ success = ParseResumptionValue(cx, rootRv, status, vp);
+
+ return processParsedHandlerResultHelper(ac, frame, maybeThisv, success, status, vp);
+}
+
+static bool
+CallMethodIfPresent(JSContext* cx, HandleObject obj, const char* name, size_t argc, Value* argv,
+ MutableHandleValue rval)
+{
+ rval.setUndefined();
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom)
+ return false;
+
+ RootedId id(cx, AtomToId(atom));
+ RootedValue fval(cx);
+ if (!GetProperty(cx, obj, obj, id, &fval))
+ return false;
+
+ if (!IsCallable(fval))
+ return true;
+
+ InvokeArgs args(cx);
+ if (!args.init(cx, argc))
+ return false;
+
+ for (size_t i = 0; i < argc; i++)
+ args[i].set(argv[i]);
+
+ rval.setObject(*obj); // overwritten by successful Call
+ return js::Call(cx, fval, rval, args, rval);
+}
+
+JSTrapStatus
+Debugger::fireDebuggerStatement(JSContext* cx, MutableHandleValue vp)
+{
+ RootedObject hook(cx, getHook(OnDebuggerStatement));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ ScriptFrameIter iter(cx);
+ RootedValue scriptFrame(cx);
+ if (!getScriptFrame(cx, iter, &scriptFrame))
+ return reportUncaughtException(ac);
+
+ RootedValue fval(cx, ObjectValue(*hook));
+ RootedValue rv(cx);
+ bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
+ return processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
+}
+
+JSTrapStatus
+Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
+{
+ RootedObject hook(cx, getHook(OnExceptionUnwind));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ RootedValue exc(cx);
+ if (!cx->getPendingException(&exc))
+ return JSTRAP_ERROR;
+ cx->clearPendingException();
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ RootedValue scriptFrame(cx);
+ RootedValue wrappedExc(cx, exc);
+
+ ScriptFrameIter iter(cx);
+ if (!getScriptFrame(cx, iter, &scriptFrame) || !wrapDebuggeeValue(cx, &wrappedExc))
+ return reportUncaughtException(ac);
+
+ RootedValue fval(cx, ObjectValue(*hook));
+ RootedValue rv(cx);
+ bool ok = js::Call(cx, fval, object, scriptFrame, wrappedExc, &rv);
+ JSTrapStatus st = processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
+ if (st == JSTRAP_CONTINUE)
+ cx->setPendingException(exc);
+ return st;
+}
+
+JSTrapStatus
+Debugger::fireEnterFrame(JSContext* cx, MutableHandleValue vp)
+{
+ RootedObject hook(cx, getHook(OnEnterFrame));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ RootedValue scriptFrame(cx);
+
+ ScriptFrameIter iter(cx);
+ if (!getScriptFrame(cx, iter, &scriptFrame))
+ return reportUncaughtException(ac);
+
+ RootedValue fval(cx, ObjectValue(*hook));
+ RootedValue rv(cx);
+ bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
+
+ return processHandlerResult(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
+}
+
+void
+Debugger::fireNewScript(JSContext* cx, Handle<DebuggerScriptReferent> scriptReferent)
+{
+ RootedObject hook(cx, getHook(OnNewScript));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ JSObject* dsobj = wrapVariantReferent(cx, scriptReferent);
+ if (!dsobj) {
+ reportUncaughtException(ac);
+ return;
+ }
+
+ RootedValue fval(cx, ObjectValue(*hook));
+ RootedValue dsval(cx, ObjectValue(*dsobj));
+ RootedValue rv(cx);
+ if (!js::Call(cx, fval, object, dsval, &rv))
+ handleUncaughtException(ac);
+}
+
+void
+Debugger::fireOnGarbageCollectionHook(JSContext* cx,
+ const JS::dbg::GarbageCollectionEvent::Ptr& gcData)
+{
+ MOZ_ASSERT(observedGC(gcData->majorGCNumber()));
+ observedGCs.remove(gcData->majorGCNumber());
+
+ RootedObject hook(cx, getHook(OnGarbageCollection));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ JSObject* dataObj = gcData->toJSObject(cx);
+ if (!dataObj) {
+ reportUncaughtException(ac);
+ return;
+ }
+
+ RootedValue fval(cx, ObjectValue(*hook));
+ RootedValue dataVal(cx, ObjectValue(*dataObj));
+ RootedValue rv(cx);
+ if (!js::Call(cx, fval, object, dataVal, &rv))
+ handleUncaughtException(ac);
+}
+
+template <typename HookIsEnabledFun /* bool (Debugger*) */,
+ typename FireHookFun /* JSTrapStatus (Debugger*) */>
+/* static */ JSTrapStatus
+Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFun fireHook)
+{
+ /*
+ * Determine which debuggers will receive this event, and in what order.
+ * Make a copy of the list, since the original is mutable and we will be
+ * calling into arbitrary JS.
+ *
+ * Note: In the general case, 'triggered' contains references to objects in
+ * different compartments--every compartment *except* this one.
+ */
+ AutoValueVector triggered(cx);
+ Handle<GlobalObject*> global = cx->global();
+ if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
+ for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
+ Debugger* dbg = *p;
+ if (dbg->enabled && hookIsEnabled(dbg)) {
+ if (!triggered.append(ObjectValue(*dbg->toJSObject())))
+ return JSTRAP_ERROR;
+ }
+ }
+ }
+
+ /*
+ * Deliver the event to each debugger, checking again to make sure it
+ * should still be delivered.
+ */
+ for (Value* p = triggered.begin(); p != triggered.end(); p++) {
+ Debugger* dbg = Debugger::fromJSObject(&p->toObject());
+ EnterDebuggeeNoExecute nx(cx, *dbg);
+ if (dbg->debuggees.has(global) && dbg->enabled && hookIsEnabled(dbg)) {
+ JSTrapStatus st = fireHook(dbg);
+ if (st != JSTRAP_CONTINUE)
+ return st;
+ }
+ }
+ return JSTRAP_CONTINUE;
+}
+
+void
+Debugger::slowPathOnNewScript(JSContext* cx, HandleScript script)
+{
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [script](Debugger* dbg) -> bool {
+ return dbg->observesNewScript() && dbg->observesScript(script);
+ },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ Rooted<DebuggerScriptReferent> scriptReferent(cx, script.get());
+ dbg->fireNewScript(cx, scriptReferent);
+ return JSTRAP_CONTINUE;
+ });
+
+ if (status == JSTRAP_ERROR)
+ return;
+
+ MOZ_ASSERT(status == JSTRAP_CONTINUE);
+}
+
+void
+Debugger::slowPathOnNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance)
+{
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [wasmInstance](Debugger* dbg) -> bool {
+ return dbg->observesNewScript() && dbg->observesGlobal(&wasmInstance->global());
+ },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ Rooted<DebuggerScriptReferent> scriptReferent(cx, wasmInstance.get());
+ dbg->fireNewScript(cx, scriptReferent);
+ return JSTRAP_CONTINUE;
+ });
+
+ if (status == JSTRAP_ERROR)
+ return;
+
+ MOZ_ASSERT(status == JSTRAP_CONTINUE);
+}
+
+/* static */ JSTrapStatus
+Debugger::onTrap(JSContext* cx, MutableHandleValue vp)
+{
+ ScriptFrameIter iter(cx);
+ RootedScript script(cx, iter.script());
+ MOZ_ASSERT(script->isDebuggee());
+ Rooted<GlobalObject*> scriptGlobal(cx, &script->global());
+ jsbytecode* pc = iter.pc();
+ BreakpointSite* site = script->getBreakpointSite(pc);
+ JSOp op = JSOp(*pc);
+
+ /* Build list of breakpoint handlers. */
+ Vector<Breakpoint*> triggered(cx);
+ for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = bp->nextInSite()) {
+ if (!triggered.append(bp))
+ return JSTRAP_ERROR;
+ }
+
+ for (Breakpoint** p = triggered.begin(); p != triggered.end(); p++) {
+ Breakpoint* bp = *p;
+
+ /* Handlers can clear breakpoints. Check that bp still exists. */
+ if (!site || !site->hasBreakpoint(bp))
+ continue;
+
+ /*
+ * There are two reasons we have to check whether dbg is enabled and
+ * debugging scriptGlobal.
+ *
+ * One is just that one breakpoint handler can disable other Debuggers
+ * or remove debuggees.
+ *
+ * The other has to do with non-compile-and-go scripts, which have no
+ * specific global--until they are executed. Only now do we know which
+ * global the script is running against.
+ */
+ Debugger* dbg = bp->debugger;
+ bool hasDebuggee = dbg->enabled && dbg->debuggees.has(scriptGlobal);
+ if (hasDebuggee) {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, dbg->object);
+ EnterDebuggeeNoExecute nx(cx, *dbg);
+
+ RootedValue scriptFrame(cx);
+ if (!dbg->getScriptFrame(cx, iter, &scriptFrame))
+ return dbg->reportUncaughtException(ac);
+ RootedValue rv(cx);
+ Rooted<JSObject*> handler(cx, bp->handler);
+ bool ok = CallMethodIfPresent(cx, handler, "hit", 1, scriptFrame.address(), &rv);
+ JSTrapStatus st = dbg->processHandlerResult(ac, ok, rv, iter.abstractFramePtr(),
+ iter.pc(), vp);
+ if (st != JSTRAP_CONTINUE)
+ return st;
+
+ /* Calling JS code invalidates site. Reload it. */
+ site = script->getBreakpointSite(pc);
+ }
+ }
+
+ /* By convention, return the true op to the interpreter in vp. */
+ vp.setInt32(op);
+ return JSTRAP_CONTINUE;
+}
+
+/* static */ JSTrapStatus
+Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
+{
+ ScriptFrameIter iter(cx);
+
+ /*
+ * We may be stepping over a JSOP_EXCEPTION, that pushes the context's
+ * pending exception for a 'catch' clause to handle. Don't let the
+ * onStep handlers mess with that (other than by returning a resumption
+ * value).
+ */
+ RootedValue exception(cx, UndefinedValue());
+ bool exceptionPending = cx->isExceptionPending();
+ if (exceptionPending) {
+ if (!cx->getPendingException(&exception))
+ return JSTRAP_ERROR;
+ cx->clearPendingException();
+ }
+
+ /*
+ * Build list of Debugger.Frame instances referring to this frame with
+ * onStep handlers.
+ */
+ Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx));
+ if (!getDebuggerFrames(iter.abstractFramePtr(), &frames))
+ return JSTRAP_ERROR;
+
+#ifdef DEBUG
+ /*
+ * Validate the single-step count on this frame's script, to ensure that
+ * we're not receiving traps we didn't ask for. Even when frames is
+ * non-empty (and thus we know this trap was requested), do the check
+ * anyway, to make sure the count has the correct non-zero value.
+ *
+ * The converse --- ensuring that we do receive traps when we should --- can
+ * be done with unit tests.
+ */
+ {
+ uint32_t stepperCount = 0;
+ JSScript* trappingScript = iter.script();
+ GlobalObject* global = cx->global();
+ if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
+ for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
+ Debugger* dbg = *p;
+ for (FrameMap::Range r = dbg->frames.all(); !r.empty(); r.popFront()) {
+ AbstractFramePtr frame = r.front().key();
+ NativeObject* frameobj = r.front().value();
+ if (frame.script() == trappingScript &&
+ !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
+ {
+ stepperCount++;
+ }
+ }
+ }
+ }
+ MOZ_ASSERT(stepperCount == trappingScript->stepModeCount());
+ }
+#endif
+
+ // Call onStep for frames that have the handler set.
+ for (size_t i = 0; i < frames.length(); i++) {
+ HandleDebuggerFrame frame = frames[i];
+ if (frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
+ continue;
+
+ Debugger* dbg = Debugger::fromChildJSObject(frame);
+ EnterDebuggeeNoExecute nx(cx, *dbg);
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, dbg->object);
+
+ RootedValue fval(cx, frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER));
+ RootedValue rval(cx);
+ bool ok = js::Call(cx, fval, frame, &rval);
+ JSTrapStatus st = dbg->processHandlerResult(ac, ok, rval, iter.abstractFramePtr(),
+ iter.pc(), vp);
+ if (st != JSTRAP_CONTINUE)
+ return st;
+ }
+
+ vp.setUndefined();
+ if (exceptionPending)
+ cx->setPendingException(exception);
+ return JSTRAP_CONTINUE;
+}
+
+JSTrapStatus
+Debugger::fireNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global, MutableHandleValue vp)
+{
+ RootedObject hook(cx, getHook(OnNewGlobalObject));
+ MOZ_ASSERT(hook);
+ MOZ_ASSERT(hook->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ RootedValue wrappedGlobal(cx, ObjectValue(*global));
+ if (!wrapDebuggeeValue(cx, &wrappedGlobal))
+ return reportUncaughtException(ac);
+
+ // onNewGlobalObject is infallible, and thus is only allowed to return
+ // undefined as a resumption value. If it returns anything else, we throw.
+ // And if that happens, or if the hook itself throws, we invoke the
+ // uncaughtExceptionHook so that we never leave an exception pending on the
+ // cx. This allows JS_NewGlobalObject to avoid handling failures from debugger
+ // hooks.
+ RootedValue rv(cx);
+ RootedValue fval(cx, ObjectValue(*hook));
+ bool ok = js::Call(cx, fval, object, wrappedGlobal, &rv);
+ if (ok && !rv.isUndefined()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED);
+ ok = false;
+ }
+ // NB: Even though we don't care about what goes into it, we have to pass vp
+ // to handleUncaughtException so that it parses resumption values from the
+ // uncaughtExceptionHook and tells the caller whether we should execute the
+ // rest of the onNewGlobalObject hooks or not.
+ JSTrapStatus status = ok ? JSTRAP_CONTINUE
+ : handleUncaughtException(ac, vp);
+ MOZ_ASSERT(!cx->isExceptionPending());
+ return status;
+}
+
+void
+Debugger::slowPathOnNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global)
+{
+ MOZ_ASSERT(!JS_CLIST_IS_EMPTY(&cx->runtime()->onNewGlobalObjectWatchers));
+ if (global->compartment()->creationOptions().invisibleToDebugger())
+ return;
+
+ /*
+ * Make a copy of the runtime's onNewGlobalObjectWatchers before running the
+ * handlers. Since one Debugger's handler can disable another's, the list
+ * can be mutated while we're walking it.
+ */
+ AutoObjectVector watchers(cx);
+ for (JSCList* link = JS_LIST_HEAD(&cx->runtime()->onNewGlobalObjectWatchers);
+ link != &cx->runtime()->onNewGlobalObjectWatchers;
+ link = JS_NEXT_LINK(link))
+ {
+ Debugger* dbg = fromOnNewGlobalObjectWatchersLink(link);
+ MOZ_ASSERT(dbg->observesNewGlobalObject());
+ JSObject* obj = dbg->object;
+ JS::ExposeObjectToActiveJS(obj);
+ if (!watchers.append(obj)) {
+ if (cx->isExceptionPending())
+ cx->clearPendingException();
+ return;
+ }
+ }
+
+ JSTrapStatus status = JSTRAP_CONTINUE;
+ RootedValue value(cx);
+
+ for (size_t i = 0; i < watchers.length(); i++) {
+ Debugger* dbg = fromJSObject(watchers[i]);
+ EnterDebuggeeNoExecute nx(cx, *dbg);
+
+ // We disallow resumption values from onNewGlobalObject hooks, because we
+ // want the debugger hooks for global object creation to be infallible.
+ // But if an onNewGlobalObject hook throws, and the uncaughtExceptionHook
+ // decides to raise an error, we want to at least avoid invoking the rest
+ // of the onNewGlobalObject handlers in the list (not for any super
+ // compelling reason, just because it seems like the right thing to do).
+ // So we ignore whatever comes out in |value|, but break out of the loop
+ // if a non-success trap status is returned.
+ if (dbg->observesNewGlobalObject()) {
+ status = dbg->fireNewGlobalObject(cx, global, &value);
+ if (status != JSTRAP_CONTINUE && status != JSTRAP_RETURN)
+ break;
+ }
+ }
+ MOZ_ASSERT(!cx->isExceptionPending());
+}
+
+/* static */ bool
+Debugger::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame,
+ double when, GlobalObject::DebuggerVector& dbgs)
+{
+ MOZ_ASSERT(!dbgs.empty());
+ mozilla::DebugOnly<ReadBarriered<Debugger*>*> begin = dbgs.begin();
+
+ // Root all the Debuggers while we're iterating over them;
+ // appendAllocationSite calls JSCompartment::wrap, and thus can GC.
+ //
+ // SpiderMonkey protocol is generally for the caller to prove that it has
+ // rooted the stuff it's asking you to operate on (i.e. by passing a
+ // Handle), but in this case, we're iterating over a global's list of
+ // Debuggers, and globals only hold their Debuggers weakly.
+ Rooted<GCVector<JSObject*>> activeDebuggers(cx, GCVector<JSObject*>(cx));
+ for (auto dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
+ if (!activeDebuggers.append((*dbgp)->object))
+ return false;
+ }
+
+ for (auto dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
+ // The set of debuggers had better not change while we're iterating,
+ // such that the vector gets reallocated.
+ MOZ_ASSERT(dbgs.begin() == begin);
+
+ if ((*dbgp)->trackingAllocationSites &&
+ (*dbgp)->enabled &&
+ !(*dbgp)->appendAllocationSite(cx, obj, frame, when))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+Debugger::isDebuggeeUnbarriered(const JSCompartment* compartment) const
+{
+ MOZ_ASSERT(compartment);
+ return compartment->isDebuggee() && debuggees.has(compartment->unsafeUnbarrieredMaybeGlobal());
+}
+
+bool
+Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame,
+ double when)
+{
+ MOZ_ASSERT(trackingAllocationSites && enabled);
+
+ AutoCompartment ac(cx, object);
+ RootedObject wrappedFrame(cx, frame);
+ if (!cx->compartment()->wrap(cx, &wrappedFrame))
+ return false;
+
+ RootedAtom ctorName(cx);
+ {
+ AutoCompartment ac(cx, obj);
+ if (!obj->constructorDisplayAtom(cx, &ctorName))
+ return false;
+ }
+
+ auto className = obj->getClass()->name;
+ auto size = JS::ubi::Node(obj.get()).size(cx->runtime()->debuggerMallocSizeOf);
+ auto inNursery = gc::IsInsideNursery(obj);
+
+ if (!allocationsLog.emplaceBack(wrappedFrame, when, className, ctorName, size, inNursery)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ if (allocationsLog.length() > maxAllocationsLogLength) {
+ if (!allocationsLog.popFront()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ MOZ_ASSERT(allocationsLog.length() == maxAllocationsLogLength);
+ allocationsLogOverflowed = true;
+ }
+
+ return true;
+}
+
+JSTrapStatus
+Debugger::firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp)
+{
+ MOZ_ASSERT(hook == OnNewPromise || hook == OnPromiseSettled);
+
+ RootedObject hookObj(cx, getHook(hook));
+ MOZ_ASSERT(hookObj);
+ MOZ_ASSERT(hookObj->isCallable());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, object);
+
+ RootedValue dbgObj(cx, ObjectValue(*promise));
+ if (!wrapDebuggeeValue(cx, &dbgObj))
+ return reportUncaughtException(ac);
+
+ // Like onNewGlobalObject, the Promise hooks are infallible and the comments
+ // in |Debugger::fireNewGlobalObject| apply here as well.
+ RootedValue fval(cx, ObjectValue(*hookObj));
+ RootedValue rv(cx);
+ bool ok = js::Call(cx, fval, object, dbgObj, &rv);
+ if (ok && !rv.isUndefined()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED);
+ ok = false;
+ }
+
+ JSTrapStatus status = ok ? JSTRAP_CONTINUE
+ : handleUncaughtException(ac, vp);
+ MOZ_ASSERT(!cx->isExceptionPending());
+ return status;
+}
+
+/* static */ void
+Debugger::slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise)
+{
+ MOZ_ASSERT(hook == OnNewPromise || hook == OnPromiseSettled);
+ RootedValue rval(cx);
+
+ JSTrapStatus status = dispatchHook(
+ cx,
+ [hook](Debugger* dbg) -> bool { return dbg->getHook(hook); },
+ [&](Debugger* dbg) -> JSTrapStatus {
+ (void) dbg->firePromiseHook(cx, hook, promise, &rval);
+ return JSTRAP_CONTINUE;
+ });
+
+ if (status == JSTRAP_ERROR) {
+ // The dispatch hook function might fail to append into the list of
+ // Debuggers which are watching for the hook.
+ cx->clearPendingException();
+ return;
+ }
+
+ // Promise hooks are infallible and we ignore errors from uncaught
+ // exceptions by design.
+ MOZ_ASSERT(status == JSTRAP_CONTINUE);
+}
+
+
+/*** Debugger code invalidation for observing execution ******************************************/
+
+class MOZ_RAII ExecutionObservableCompartments : public Debugger::ExecutionObservableSet
+{
+ HashSet<JSCompartment*> compartments_;
+ HashSet<Zone*> zones_;
+
+ public:
+ explicit ExecutionObservableCompartments(JSContext* cx
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : compartments_(cx),
+ zones_(cx)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+
+ bool init() { return compartments_.init() && zones_.init(); }
+ bool add(JSCompartment* comp) { return compartments_.put(comp) && zones_.put(comp->zone()); }
+
+ typedef HashSet<JSCompartment*>::Range CompartmentRange;
+ const HashSet<JSCompartment*>* compartments() const { return &compartments_; }
+
+ const HashSet<Zone*>* zones() const { return &zones_; }
+ bool shouldRecompileOrInvalidate(JSScript* script) const {
+ return script->hasBaselineScript() && compartments_.has(script->compartment());
+ }
+ bool shouldMarkAsDebuggee(ScriptFrameIter& iter) const {
+ // AbstractFramePtr can't refer to non-remateralized Ion frames, so if
+ // iter refers to one such, we know we don't match.
+ return iter.hasUsableAbstractFramePtr() && compartments_.has(iter.compartment());
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+// Given a particular AbstractFramePtr F that has become observable, this
+// represents the stack frames that need to be bailed out or marked as
+// debuggees, and the scripts that need to be recompiled, taking inlining into
+// account.
+class MOZ_RAII ExecutionObservableFrame : public Debugger::ExecutionObservableSet
+{
+ AbstractFramePtr frame_;
+
+ public:
+ explicit ExecutionObservableFrame(AbstractFramePtr frame
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : frame_(frame)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+
+ Zone* singleZone() const {
+ // We never inline across compartments, let alone across zones, so
+ // frames_'s script's zone is the only one of interest.
+ return frame_.script()->compartment()->zone();
+ }
+
+ JSScript* singleScriptForZoneInvalidation() const {
+ MOZ_CRASH("ExecutionObservableFrame shouldn't need zone-wide invalidation.");
+ return nullptr;
+ }
+
+ bool shouldRecompileOrInvalidate(JSScript* script) const {
+ // Normally, *this represents exactly one script: the one frame_ is
+ // running.
+ //
+ // However, debug-mode OSR uses *this for both invalidating Ion frames,
+ // and recompiling the Baseline scripts that those Ion frames will bail
+ // out into. Suppose frame_ is an inline frame, executing a copy of its
+ // JSScript, S_inner, that has been inlined into the IonScript of some
+ // other JSScript, S_outer. We must match S_outer, to decide which Ion
+ // frame to invalidate; and we must match S_inner, to decide which
+ // Baseline script to recompile.
+ //
+ // Note that this does not, by design, invalidate *all* inliners of
+ // frame_.script(), as only frame_ is made observable, not
+ // frame_.script().
+ if (!script->hasBaselineScript())
+ return false;
+
+ if (script == frame_.script())
+ return true;
+
+ return frame_.isRematerializedFrame() &&
+ script == frame_.asRematerializedFrame()->outerScript();
+ }
+
+ bool shouldMarkAsDebuggee(ScriptFrameIter& iter) const {
+ // AbstractFramePtr can't refer to non-remateralized Ion frames, so if
+ // iter refers to one such, we know we don't match.
+ //
+ // We never use this 'has' overload for frame invalidation, only for
+ // frame debuggee marking; so this overload doesn't need a parallel to
+ // the just-so inlining logic above.
+ return iter.hasUsableAbstractFramePtr() && iter.abstractFramePtr() == frame_;
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class MOZ_RAII ExecutionObservableScript : public Debugger::ExecutionObservableSet
+{
+ RootedScript script_;
+
+ public:
+ ExecutionObservableScript(JSContext* cx, JSScript* script
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : script_(cx, script)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+
+ Zone* singleZone() const { return script_->compartment()->zone(); }
+ JSScript* singleScriptForZoneInvalidation() const { return script_; }
+ bool shouldRecompileOrInvalidate(JSScript* script) const {
+ return script->hasBaselineScript() && script == script_;
+ }
+ bool shouldMarkAsDebuggee(ScriptFrameIter& iter) const {
+ // AbstractFramePtr can't refer to non-remateralized Ion frames, and
+ // while a non-rematerialized Ion frame may indeed be running script_,
+ // we cannot mark them as debuggees until they bail out.
+ //
+ // Upon bailing out, any newly constructed Baseline frames that came
+ // from Ion frames with scripts that are isDebuggee() is marked as
+ // debuggee. This is correct in that the only other way a frame may be
+ // marked as debuggee is via Debugger.Frame reflection, which would
+ // have rematerialized any Ion frames.
+ return iter.hasUsableAbstractFramePtr() && iter.abstractFramePtr().script() == script_;
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/* static */ bool
+Debugger::updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObservableSet& obs,
+ IsObserving observing)
+{
+ AutoSuppressProfilerSampling suppressProfilerSampling(cx);
+
+ {
+ jit::JitContext jctx(cx, nullptr);
+ if (!jit::RecompileOnStackBaselineScriptsForDebugMode(cx, obs, observing)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ AbstractFramePtr oldestEnabledFrame;
+ for (ScriptFrameIter iter(cx);
+ !iter.done();
+ ++iter)
+ {
+ if (obs.shouldMarkAsDebuggee(iter)) {
+ if (observing) {
+ if (!iter.abstractFramePtr().isDebuggee()) {
+ oldestEnabledFrame = iter.abstractFramePtr();
+ oldestEnabledFrame.setIsDebuggee();
+ }
+ } else {
+#ifdef DEBUG
+ // Debugger.Frame lifetimes are managed by the debug epilogue,
+ // so in general it's unsafe to unmark a frame if it has a
+ // Debugger.Frame associated with it.
+ MOZ_ASSERT(!inFrameMaps(iter.abstractFramePtr()));
+#endif
+ iter.abstractFramePtr().unsetIsDebuggee();
+ }
+ }
+ }
+
+ // See comment in unsetPrevUpToDateUntil.
+ if (oldestEnabledFrame) {
+ AutoCompartment ac(cx, oldestEnabledFrame.compartment());
+ DebugEnvironments::unsetPrevUpToDateUntil(cx, oldestEnabledFrame);
+ }
+
+ return true;
+}
+
+static inline void
+MarkBaselineScriptActiveIfObservable(JSScript* script, const Debugger::ExecutionObservableSet& obs)
+{
+ if (obs.shouldRecompileOrInvalidate(script))
+ script->baselineScript()->setActive();
+}
+
+static bool
+AppendAndInvalidateScript(JSContext* cx, Zone* zone, JSScript* script, Vector<JSScript*>& scripts)
+{
+ // Enter the script's compartment as addPendingRecompile attempts to
+ // cancel off-thread compilations, whose books are kept on the
+ // script's compartment.
+ MOZ_ASSERT(script->compartment()->zone() == zone);
+ AutoCompartment ac(cx, script->compartment());
+ zone->types.addPendingRecompile(cx, script);
+ return scripts.append(script);
+}
+
+static bool
+UpdateExecutionObservabilityOfScriptsInZone(JSContext* cx, Zone* zone,
+ const Debugger::ExecutionObservableSet& obs,
+ Debugger::IsObserving observing)
+{
+ using namespace js::jit;
+
+ AutoSuppressProfilerSampling suppressProfilerSampling(cx);
+
+ JSRuntime* rt = cx->runtime();
+ FreeOp* fop = cx->runtime()->defaultFreeOp();
+
+ Vector<JSScript*> scripts(cx);
+
+ // Iterate through observable scripts, invalidating their Ion scripts and
+ // appending them to a vector for discarding their baseline scripts later.
+ {
+ AutoEnterAnalysis enter(fop, zone);
+ if (JSScript* script = obs.singleScriptForZoneInvalidation()) {
+ if (obs.shouldRecompileOrInvalidate(script)) {
+ if (!AppendAndInvalidateScript(cx, zone, script, scripts))
+ return false;
+ }
+ } else {
+ for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+ JSScript* script = iter;
+ if (obs.shouldRecompileOrInvalidate(script) &&
+ !gc::IsAboutToBeFinalizedUnbarriered(&script))
+ {
+ if (!AppendAndInvalidateScript(cx, zone, script, scripts))
+ return false;
+ }
+ }
+ }
+ }
+
+ // Code below this point must be infallible to ensure the active bit of
+ // BaselineScripts is in a consistent state.
+ //
+ // Mark active baseline scripts in the observable set so that they don't
+ // get discarded. They will be recompiled.
+ for (JitActivationIterator actIter(rt); !actIter.done(); ++actIter) {
+ if (actIter->compartment()->zone() != zone)
+ continue;
+
+ for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
+ switch (iter.type()) {
+ case JitFrame_BaselineJS:
+ MarkBaselineScriptActiveIfObservable(iter.script(), obs);
+ break;
+ case JitFrame_IonJS:
+ MarkBaselineScriptActiveIfObservable(iter.script(), obs);
+ for (InlineFrameIterator inlineIter(rt, &iter); inlineIter.more(); ++inlineIter)
+ MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
+ break;
+ default:;
+ }
+ }
+ }
+
+ // Iterate through the scripts again and finish discarding
+ // BaselineScripts. This must be done as a separate phase as we can only
+ // discard the BaselineScript on scripts that have no IonScript.
+ for (size_t i = 0; i < scripts.length(); i++) {
+ MOZ_ASSERT_IF(scripts[i]->isDebuggee(), observing);
+ FinishDiscardBaselineScript(fop, scripts[i]);
+ }
+
+ return true;
+}
+
+/* static */ bool
+Debugger::updateExecutionObservabilityOfScripts(JSContext* cx, const ExecutionObservableSet& obs,
+ IsObserving observing)
+{
+ if (Zone* zone = obs.singleZone())
+ return UpdateExecutionObservabilityOfScriptsInZone(cx, zone, obs, observing);
+
+ typedef ExecutionObservableSet::ZoneRange ZoneRange;
+ for (ZoneRange r = obs.zones()->all(); !r.empty(); r.popFront()) {
+ if (!UpdateExecutionObservabilityOfScriptsInZone(cx, r.front(), obs, observing))
+ return false;
+ }
+
+ return true;
+}
+
+template <typename FrameFn>
+/* static */ void
+Debugger::forEachDebuggerFrame(AbstractFramePtr frame, FrameFn fn)
+{
+ GlobalObject* global = &frame.script()->global();
+ if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
+ for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
+ Debugger* dbg = *p;
+ if (FrameMap::Ptr entry = dbg->frames.lookup(frame))
+ fn(entry->value());
+ }
+ }
+}
+
+/* static */ bool
+Debugger::getDebuggerFrames(AbstractFramePtr frame, MutableHandle<DebuggerFrameVector> frames)
+{
+ bool hadOOM = false;
+ forEachDebuggerFrame(frame, [&](DebuggerFrame* frameobj) {
+ if (!hadOOM && !frames.append(frameobj))
+ hadOOM = true;
+ });
+ return !hadOOM;
+}
+
+/* static */ bool
+Debugger::updateExecutionObservability(JSContext* cx, ExecutionObservableSet& obs,
+ IsObserving observing)
+{
+ if (!obs.singleZone() && obs.zones()->empty())
+ return true;
+
+ // Invalidate scripts first so we can set the needsArgsObj flag on scripts
+ // before patching frames.
+ return updateExecutionObservabilityOfScripts(cx, obs, observing) &&
+ updateExecutionObservabilityOfFrames(cx, obs, observing);
+}
+
+/* static */ bool
+Debugger::ensureExecutionObservabilityOfScript(JSContext* cx, JSScript* script)
+{
+ if (script->isDebuggee())
+ return true;
+ ExecutionObservableScript obs(cx, script);
+ return updateExecutionObservability(cx, obs, Observing);
+}
+
+/* static */ bool
+Debugger::ensureExecutionObservabilityOfOsrFrame(JSContext* cx, InterpreterFrame* frame)
+{
+ MOZ_ASSERT(frame->isDebuggee());
+ if (frame->script()->hasBaselineScript() &&
+ frame->script()->baselineScript()->hasDebugInstrumentation())
+ {
+ return true;
+ }
+ ExecutionObservableFrame obs(frame);
+ return updateExecutionObservabilityOfFrames(cx, obs, Observing);
+}
+
+/* static */ bool
+Debugger::ensureExecutionObservabilityOfFrame(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT_IF(frame.script()->isDebuggee(), frame.isDebuggee());
+ if (frame.isDebuggee())
+ return true;
+ ExecutionObservableFrame obs(frame);
+ return updateExecutionObservabilityOfFrames(cx, obs, Observing);
+}
+
+/* static */ bool
+Debugger::ensureExecutionObservabilityOfCompartment(JSContext* cx, JSCompartment* comp)
+{
+ if (comp->debuggerObservesAllExecution())
+ return true;
+ ExecutionObservableCompartments obs(cx);
+ if (!obs.init() || !obs.add(comp))
+ return false;
+ comp->updateDebuggerObservesAllExecution();
+ return updateExecutionObservability(cx, obs, Observing);
+}
+
+/* static */ bool
+Debugger::hookObservesAllExecution(Hook which)
+{
+ return which == OnEnterFrame;
+}
+
+Debugger::IsObserving
+Debugger::observesAllExecution() const
+{
+ if (enabled && !!getHook(OnEnterFrame))
+ return Observing;
+ return NotObserving;
+}
+
+Debugger::IsObserving
+Debugger::observesAsmJS() const
+{
+ if (enabled && !allowUnobservedAsmJS)
+ return Observing;
+ return NotObserving;
+}
+
+Debugger::IsObserving
+Debugger::observesCoverage() const
+{
+ if (enabled && collectCoverageInfo)
+ return Observing;
+ return NotObserving;
+}
+
+// Toggle whether this Debugger's debuggees observe all execution. This is
+// called when a hook that observes all execution is set or unset. See
+// hookObservesAllExecution.
+bool
+Debugger::updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving observing)
+{
+ ExecutionObservableCompartments obs(cx);
+ if (!obs.init())
+ return false;
+
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+ GlobalObject* global = r.front();
+ JSCompartment* comp = global->compartment();
+
+ if (comp->debuggerObservesAllExecution() == observing)
+ continue;
+
+ // It's expensive to eagerly invalidate and recompile a compartment,
+ // so add the compartment to the set only if we are observing.
+ if (observing && !obs.add(comp))
+ return false;
+ }
+
+ if (!updateExecutionObservability(cx, obs, observing))
+ return false;
+
+ typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
+ for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
+ r.front()->updateDebuggerObservesAllExecution();
+
+ return true;
+}
+
+bool
+Debugger::updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing)
+{
+ ExecutionObservableCompartments obs(cx);
+ if (!obs.init())
+ return false;
+
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+ GlobalObject* global = r.front();
+ JSCompartment* comp = global->compartment();
+
+ if (comp->debuggerObservesCoverage() == observing)
+ continue;
+
+ // Invalidate and recompile a compartment to add or remove PCCounts
+ // increments. We have to eagerly invalidate, as otherwise we might have
+ // dangling pointers to freed PCCounts.
+ if (!obs.add(comp))
+ return false;
+ }
+
+ // If any frame on the stack belongs to the debuggee, then we cannot update
+ // the ScriptCounts, because this would imply to invalidate a Debugger.Frame
+ // to recompile it with/without ScriptCount support.
+ for (ScriptFrameIter iter(cx);
+ !iter.done();
+ ++iter)
+ {
+ if (obs.shouldMarkAsDebuggee(iter)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
+ return false;
+ }
+ }
+
+ if (!updateExecutionObservability(cx, obs, observing))
+ return false;
+
+ // All compartments can safely be toggled, and all scripts will be
+ // recompiled. Thus we can update each compartment accordingly.
+ typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
+ for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
+ r.front()->updateDebuggerObservesCoverage();
+
+ return true;
+}
+
+void
+Debugger::updateObservesAsmJSOnDebuggees(IsObserving observing)
+{
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+ GlobalObject* global = r.front();
+ JSCompartment* comp = global->compartment();
+
+ if (comp->debuggerObservesAsmJS() == observing)
+ continue;
+
+ comp->updateDebuggerObservesAsmJS();
+ }
+}
+
+
+/*** Allocations Tracking *************************************************************************/
+
+/* static */ bool
+Debugger::cannotTrackAllocations(const GlobalObject& global)
+{
+ auto existingCallback = global.compartment()->getAllocationMetadataBuilder();
+ return existingCallback && existingCallback != &SavedStacks::metadataBuilder;
+}
+
+/* static */ bool
+Debugger::isObservedByDebuggerTrackingAllocations(const GlobalObject& debuggee)
+{
+ if (auto* v = debuggee.getDebuggers()) {
+ for (auto p = v->begin(); p != v->end(); p++) {
+ if ((*p)->trackingAllocationSites && (*p)->enabled) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* static */ bool
+Debugger::addAllocationsTracking(JSContext* cx, Handle<GlobalObject*> debuggee)
+{
+ // Precondition: the given global object is being observed by at least one
+ // Debugger that is tracking allocations.
+ MOZ_ASSERT(isObservedByDebuggerTrackingAllocations(*debuggee));
+
+ if (Debugger::cannotTrackAllocations(*debuggee)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
+ return false;
+ }
+
+ debuggee->compartment()->setAllocationMetadataBuilder(&SavedStacks::metadataBuilder);
+ debuggee->compartment()->chooseAllocationSamplingProbability();
+ return true;
+}
+
+/* static */ void
+Debugger::removeAllocationsTracking(GlobalObject& global)
+{
+ // If there are still Debuggers that are observing allocations, we cannot
+ // remove the metadata callback yet. Recompute the sampling probability
+ // based on the remaining debuggers' needs.
+ if (isObservedByDebuggerTrackingAllocations(global)) {
+ global.compartment()->chooseAllocationSamplingProbability();
+ return;
+ }
+
+ global.compartment()->forgetAllocationMetadataBuilder();
+}
+
+bool
+Debugger::addAllocationsTrackingForAllDebuggees(JSContext* cx)
+{
+ MOZ_ASSERT(trackingAllocationSites);
+
+ // We don't want to end up in a state where we added allocations
+ // tracking to some of our debuggees, but failed to do so for
+ // others. Before attempting to start tracking allocations in *any* of
+ // our debuggees, ensure that we will be able to track allocations for
+ // *all* of our debuggees.
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+ if (Debugger::cannotTrackAllocations(*r.front().get())) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
+ return false;
+ }
+ }
+
+ Rooted<GlobalObject*> g(cx);
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+ // This should always succeed, since we already checked for the
+ // error case above.
+ g = r.front().get();
+ MOZ_ALWAYS_TRUE(Debugger::addAllocationsTracking(cx, g));
+ }
+
+ return true;
+}
+
+void
+Debugger::removeAllocationsTrackingForAllDebuggees()
+{
+ for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront())
+ Debugger::removeAllocationsTracking(*r.front().get());
+
+ allocationsLog.clear();
+}
+
+
+
+/*** Debugger JSObjects **************************************************************************/
+
+void
+Debugger::markCrossCompartmentEdges(JSTracer* trc)
+{
+ objects.markCrossCompartmentEdges<DebuggerObject_trace>(trc);
+ environments.markCrossCompartmentEdges<DebuggerEnv_trace>(trc);
+ scripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc);
+ sources.markCrossCompartmentEdges<DebuggerSource_trace>(trc);
+ wasmInstanceScripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc);
+ wasmInstanceSources.markCrossCompartmentEdges<DebuggerSource_trace>(trc);
+}
+
+/*
+ * Ordinarily, WeakMap keys and values are marked because at some point it was
+ * discovered that the WeakMap was live; that is, some object containing the
+ * WeakMap was marked during mark phase.
+ *
+ * However, during zone GC, we have to do something about cross-compartment
+ * edges in non-GC'd compartments. Since the source may be live, we
+ * conservatively assume it is and mark the edge.
+ *
+ * Each Debugger object keeps four cross-compartment WeakMaps: objects, scripts,
+ * script source objects, and environments. They have the property that all
+ * their values are in the same compartment as the Debugger object, but we have
+ * to mark the keys and the private pointer in the wrapper object.
+ *
+ * We must scan all Debugger objects regardless of whether they *currently* have
+ * any debuggees in a compartment being GC'd, because the WeakMap entries
+ * persist even when debuggees are removed.
+ *
+ * This happens during the initial mark phase, not iterative marking, because
+ * all the edges being reported here are strong references.
+ *
+ * This method is also used during compacting GC to update cross compartment
+ * pointers in zones that are not currently being compacted.
+ */
+/* static */ void
+Debugger::markIncomingCrossCompartmentEdges(JSTracer* trc)
+{
+ JSRuntime* rt = trc->runtime();
+ gc::State state = rt->gc.state();
+ MOZ_ASSERT(state == gc::State::MarkRoots || state == gc::State::Compact);
+
+ for (Debugger* dbg : rt->debuggerList) {
+ Zone* zone = MaybeForwarded(dbg->object.get())->zone();
+ if ((state == gc::State::MarkRoots && !zone->isCollecting()) ||
+ (state == gc::State::Compact && !zone->isGCCompacting()))
+ {
+ dbg->markCrossCompartmentEdges(trc);
+ }
+ }
+}
+
+/*
+ * This method has two tasks:
+ * 1. Mark Debugger objects that are unreachable except for debugger hooks that
+ * may yet be called.
+ * 2. Mark breakpoint handlers.
+ *
+ * This happens during the iterative part of the GC mark phase. This method
+ * returns true if it has to mark anything; GC calls it repeatedly until it
+ * returns false.
+ */
+/* static */ bool
+Debugger::markAllIteratively(GCMarker* trc)
+{
+ bool markedAny = false;
+
+ /*
+ * Find all Debugger objects in danger of GC. This code is a little
+ * convoluted since the easiest way to find them is via their debuggees.
+ */
+ JSRuntime* rt = trc->runtime();
+ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
+ if (c->isDebuggee()) {
+ GlobalObject* global = c->unsafeUnbarrieredMaybeGlobal();
+ if (!IsMarkedUnbarriered(rt, &global))
+ continue;
+
+ /*
+ * Every debuggee has at least one debugger, so in this case
+ * getDebuggers can't return nullptr.
+ */
+ const GlobalObject::DebuggerVector* debuggers = global->getDebuggers();
+ MOZ_ASSERT(debuggers);
+ for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
+ Debugger* dbg = *p;
+
+ /*
+ * dbg is a Debugger with at least one debuggee. Check three things:
+ * - dbg is actually in a compartment that is being marked
+ * - it isn't already marked
+ * - it actually has hooks that might be called
+ */
+ GCPtrNativeObject& dbgobj = dbg->toJSObjectRef();
+ if (!dbgobj->zone()->isGCMarking())
+ continue;
+
+ bool dbgMarked = IsMarked(rt, &dbgobj);
+ if (!dbgMarked && dbg->hasAnyLiveHooks(rt)) {
+ /*
+ * obj could be reachable only via its live, enabled
+ * debugger hooks, which may yet be called.
+ */
+ TraceEdge(trc, &dbgobj, "enabled Debugger");
+ markedAny = true;
+ dbgMarked = true;
+ }
+
+ if (dbgMarked) {
+ /* Search for breakpoints to mark. */
+ for (Breakpoint* bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
+ if (IsMarkedUnbarriered(rt, &bp->site->script)) {
+ /*
+ * The debugger and the script are both live.
+ * Therefore the breakpoint handler is live.
+ */
+ if (!IsMarked(rt, &bp->getHandlerRef())) {
+ TraceEdge(trc, &bp->getHandlerRef(), "breakpoint handler");
+ markedAny = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return markedAny;
+}
+
+/*
+ * Mark all debugger-owned GC things unconditionally. This is used by the minor
+ * GC: the minor GC cannot apply the weak constraints of the full GC because it
+ * visits only part of the heap.
+ */
+/* static */ void
+Debugger::markAll(JSTracer* trc)
+{
+ JSRuntime* rt = trc->runtime();
+ for (Debugger* dbg : rt->debuggerList) {
+ for (WeakGlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
+ TraceManuallyBarrieredEdge(trc, e.mutableFront().unsafeGet(), "Global Object");
+
+ GCPtrNativeObject& dbgobj = dbg->toJSObjectRef();
+ TraceEdge(trc, &dbgobj, "Debugger Object");
+
+ dbg->scripts.trace(trc);
+ dbg->sources.trace(trc);
+ dbg->objects.trace(trc);
+ dbg->environments.trace(trc);
+ dbg->wasmInstanceScripts.trace(trc);
+ dbg->wasmInstanceSources.trace(trc);
+
+ for (Breakpoint* bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
+ TraceManuallyBarrieredEdge(trc, &bp->site->script, "breakpoint script");
+ TraceEdge(trc, &bp->getHandlerRef(), "breakpoint handler");
+ }
+ }
+}
+
+/* static */ void
+Debugger::traceObject(JSTracer* trc, JSObject* obj)
+{
+ if (Debugger* dbg = Debugger::fromJSObject(obj))
+ dbg->trace(trc);
+}
+
+void
+Debugger::trace(JSTracer* trc)
+{
+ TraceNullableEdge(trc, &uncaughtExceptionHook, "hooks");
+
+ /*
+ * Mark Debugger.Frame objects. These are all reachable from JS, because the
+ * corresponding JS frames are still on the stack.
+ *
+ * (Once we support generator frames properly, we will need
+ * weakly-referenced Debugger.Frame objects as well, for suspended generator
+ * frames.)
+ */
+ for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) {
+ HeapPtr<DebuggerFrame*>& frameobj = r.front().value();
+ MOZ_ASSERT(MaybeForwarded(frameobj.get())->getPrivate());
+ TraceEdge(trc, &frameobj, "live Debugger.Frame");
+ }
+
+ allocationsLog.trace(trc);
+
+ /* Trace the weak map from JSScript instances to Debugger.Script objects. */
+ scripts.trace(trc);
+
+ /* Trace the referent -> Debugger.Source weak map */
+ sources.trace(trc);
+
+ /* Trace the referent -> Debugger.Object weak map. */
+ objects.trace(trc);
+
+ /* Trace the referent -> Debugger.Environment weak map. */
+ environments.trace(trc);
+
+ /* Trace the WasmInstanceObject -> synthesized Debugger.Script weak map. */
+ wasmInstanceScripts.trace(trc);
+
+ /* Trace the WasmInstanceObject -> synthesized Debugger.Source weak map. */
+ wasmInstanceSources.trace(trc);
+}
+
+/* static */ void
+Debugger::sweepAll(FreeOp* fop)
+{
+ JSRuntime* rt = fop->runtime();
+
+ for (Debugger* dbg : rt->debuggerList) {
+ if (IsAboutToBeFinalized(&dbg->object)) {
+ /*
+ * dbg is being GC'd. Detach it from its debuggees. The debuggee
+ * might be GC'd too. Since detaching requires access to both
+ * objects, this must be done before finalize time.
+ */
+ for (WeakGlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
+ dbg->removeDebuggeeGlobal(fop, e.front().unbarrieredGet(), &e);
+ }
+ }
+}
+
+/* static */ void
+Debugger::detachAllDebuggersFromGlobal(FreeOp* fop, GlobalObject* global)
+{
+ const GlobalObject::DebuggerVector* debuggers = global->getDebuggers();
+ MOZ_ASSERT(!debuggers->empty());
+ while (!debuggers->empty())
+ debuggers->back()->removeDebuggeeGlobal(fop, global, nullptr);
+}
+
+/* static */ void
+Debugger::findZoneEdges(Zone* zone, js::gc::ZoneComponentFinder& finder)
+{
+ /*
+ * For debugger cross compartment wrappers, add edges in the opposite
+ * direction to those already added by JSCompartment::findOutgoingEdges.
+ * This ensure that debuggers and their debuggees are finalized in the same
+ * group.
+ */
+ for (Debugger* dbg : zone->runtimeFromMainThread()->debuggerList) {
+ Zone* w = dbg->object->zone();
+ if (w == zone || !w->isGCMarking())
+ continue;
+ if (dbg->debuggeeZones.has(zone) ||
+ dbg->scripts.hasKeyInZone(zone) ||
+ dbg->sources.hasKeyInZone(zone) ||
+ dbg->objects.hasKeyInZone(zone) ||
+ dbg->environments.hasKeyInZone(zone) ||
+ dbg->wasmInstanceScripts.hasKeyInZone(zone) ||
+ dbg->wasmInstanceSources.hasKeyInZone(zone))
+ {
+ finder.addEdgeTo(w);
+ }
+ }
+}
+
+/* static */ void
+Debugger::finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->onMainThread());
+
+ Debugger* dbg = fromJSObject(obj);
+ if (!dbg)
+ return;
+ fop->delete_(dbg);
+}
+
+const ClassOps Debugger::classOps_ = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ Debugger::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ Debugger::traceObject
+};
+
+const Class Debugger::class_ = {
+ "Debugger",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT) |
+ JSCLASS_FOREGROUND_FINALIZE,
+ &Debugger::classOps_
+};
+
+static Debugger*
+Debugger_fromThisValue(JSContext* cx, const CallArgs& args, const char* fnname)
+{
+ JSObject* thisobj = NonNullObject(cx, args.thisv());
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &Debugger::class_) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ /*
+ * Forbid Debugger.prototype, which is of the Debugger JSClass but isn't
+ * really a Debugger object. The prototype object is distinguished by
+ * having a nullptr private value.
+ */
+ Debugger* dbg = Debugger::fromJSObject(thisobj);
+ if (!dbg) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger", fnname, "prototype object");
+ }
+ return dbg;
+}
+
+#define THIS_DEBUGGER(cx, argc, vp, fnname, args, dbg) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ Debugger* dbg = Debugger_fromThisValue(cx, args, fnname); \
+ if (!dbg) \
+ return false
+
+/* static */ bool
+Debugger::getEnabled(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "get enabled", args, dbg);
+ args.rval().setBoolean(dbg->enabled);
+ return true;
+}
+
+/* static */ bool
+Debugger::setEnabled(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "set enabled", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.set enabled", 1))
+ return false;
+
+ bool wasEnabled = dbg->enabled;
+ dbg->enabled = ToBoolean(args[0]);
+
+ if (wasEnabled != dbg->enabled) {
+ if (dbg->trackingAllocationSites) {
+ if (wasEnabled) {
+ dbg->removeAllocationsTrackingForAllDebuggees();
+ } else {
+ if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
+ dbg->enabled = false;
+ return false;
+ }
+ }
+ }
+
+ for (Breakpoint* bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
+ if (!wasEnabled)
+ bp->site->inc(cx->runtime()->defaultFreeOp());
+ else
+ bp->site->dec(cx->runtime()->defaultFreeOp());
+ }
+
+ /*
+ * Add or remove ourselves from the runtime's list of Debuggers
+ * that care about new globals.
+ */
+ if (dbg->getHook(OnNewGlobalObject)) {
+ if (!wasEnabled) {
+ /* If we were not enabled, the link should be a singleton list. */
+ MOZ_ASSERT(JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+ JS_APPEND_LINK(&dbg->onNewGlobalObjectWatchersLink,
+ &cx->runtime()->onNewGlobalObjectWatchers);
+ } else {
+ /* If we were enabled, the link should be inserted in the list. */
+ MOZ_ASSERT(!JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+ JS_REMOVE_AND_INIT_LINK(&dbg->onNewGlobalObjectWatchersLink);
+ }
+ }
+
+ // Ensure the compartment is observable if we are re-enabling a
+ // Debugger with hooks that observe all execution.
+ if (!dbg->updateObservesAllExecutionOnDebuggees(cx, dbg->observesAllExecution()))
+ return false;
+
+ // Note: To toogle code coverage, we currently need to have no live
+ // stack frame, thus the coverage does not depend on the enabled flag.
+
+ dbg->updateObservesAsmJSOnDebuggees(dbg->observesAsmJS());
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which)
+{
+ MOZ_ASSERT(which >= 0 && which < HookCount);
+ args.rval().set(dbg.object->getReservedSlot(JSSLOT_DEBUG_HOOK_START + which));
+ return true;
+}
+
+/* static */ bool
+Debugger::setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which)
+{
+ MOZ_ASSERT(which >= 0 && which < HookCount);
+ if (!args.requireAtLeast(cx, "Debugger.setHook", 1))
+ return false;
+ if (args[0].isObject()) {
+ if (!args[0].toObject().isCallable())
+ return ReportIsNotFunction(cx, args[0], args.length() - 1);
+ } else if (!args[0].isUndefined()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
+ return false;
+ }
+ uint32_t slot = JSSLOT_DEBUG_HOOK_START + which;
+ RootedValue oldHook(cx, dbg.object->getReservedSlot(slot));
+ dbg.object->setReservedSlot(slot, args[0]);
+ if (hookObservesAllExecution(which)) {
+ if (!dbg.updateObservesAllExecutionOnDebuggees(cx, dbg.observesAllExecution())) {
+ dbg.object->setReservedSlot(slot, oldHook);
+ return false;
+ }
+ }
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::getOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onDebuggerStatement)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnDebuggerStatement);
+}
+
+/* static */ bool
+Debugger::setOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onDebuggerStatement)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnDebuggerStatement);
+}
+
+/* static */ bool
+Debugger::getOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onExceptionUnwind)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnExceptionUnwind);
+}
+
+/* static */ bool
+Debugger::setOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onExceptionUnwind)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnExceptionUnwind);
+}
+
+/* static */ bool
+Debugger::getOnNewScript(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onNewScript)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnNewScript);
+}
+
+/* static */ bool
+Debugger::setOnNewScript(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onNewScript)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnNewScript);
+}
+
+/* static */ bool
+Debugger::getOnNewPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onNewPromise)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnNewPromise);
+}
+
+/* static */ bool
+Debugger::setOnNewPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onNewPromise)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnNewPromise);
+}
+
+/* static */ bool
+Debugger::getOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onPromiseSettled)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnPromiseSettled);
+}
+
+/* static */ bool
+Debugger::setOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onPromiseSettled)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnPromiseSettled);
+}
+
+/* static */ bool
+Debugger::getOnEnterFrame(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onEnterFrame)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnEnterFrame);
+}
+
+/* static */ bool
+Debugger::setOnEnterFrame(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(set onEnterFrame)", args, dbg);
+ return setHookImpl(cx, args, *dbg, OnEnterFrame);
+}
+
+/* static */ bool
+Debugger::getOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "(get onNewGlobalObject)", args, dbg);
+ return getHookImpl(cx, args, *dbg, OnNewGlobalObject);
+}
+
+/* static */ bool
+Debugger::setOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "setOnNewGlobalObject", args, dbg);
+ RootedObject oldHook(cx, dbg->getHook(OnNewGlobalObject));
+
+ if (!setHookImpl(cx, args, *dbg, OnNewGlobalObject))
+ return false;
+
+ /*
+ * Add or remove ourselves from the runtime's list of Debuggers that
+ * care about new globals.
+ */
+ if (dbg->enabled) {
+ JSObject* newHook = dbg->getHook(OnNewGlobalObject);
+ if (!oldHook && newHook) {
+ /* If we didn't have a hook, the link should be a singleton list. */
+ MOZ_ASSERT(JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+ JS_APPEND_LINK(&dbg->onNewGlobalObjectWatchersLink,
+ &cx->runtime()->onNewGlobalObjectWatchers);
+ } else if (oldHook && !newHook) {
+ /* If we did have a hook, the link should be inserted in the list. */
+ MOZ_ASSERT(!JS_CLIST_IS_EMPTY(&dbg->onNewGlobalObjectWatchersLink));
+ JS_REMOVE_AND_INIT_LINK(&dbg->onNewGlobalObjectWatchersLink);
+ }
+ }
+
+ return true;
+}
+
+/* static */ bool
+Debugger::getUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "get uncaughtExceptionHook", args, dbg);
+ args.rval().setObjectOrNull(dbg->uncaughtExceptionHook);
+ return true;
+}
+
+/* static */ bool
+Debugger::setUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "set uncaughtExceptionHook", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.set uncaughtExceptionHook", 1))
+ return false;
+ if (!args[0].isNull() && (!args[0].isObject() || !args[0].toObject().isCallable())) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ASSIGN_FUNCTION_OR_NULL,
+ "uncaughtExceptionHook");
+ return false;
+ }
+ dbg->uncaughtExceptionHook = args[0].toObjectOrNull();
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::getAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "get allowUnobservedAsmJS", args, dbg);
+ args.rval().setBoolean(dbg->allowUnobservedAsmJS);
+ return true;
+}
+
+/* static */ bool
+Debugger::setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "set allowUnobservedAsmJS", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.set allowUnobservedAsmJS", 1))
+ return false;
+ dbg->allowUnobservedAsmJS = ToBoolean(args[0]);
+
+ for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
+ GlobalObject* global = r.front();
+ JSCompartment* comp = global->compartment();
+ comp->updateDebuggerObservesAsmJS();
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::getCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "get collectCoverageInfo", args, dbg);
+ args.rval().setBoolean(dbg->collectCoverageInfo);
+ return true;
+}
+
+/* static */ bool
+Debugger::setCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "set collectCoverageInfo", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.set collectCoverageInfo", 1))
+ return false;
+ dbg->collectCoverageInfo = ToBoolean(args[0]);
+
+ IsObserving observing = dbg->collectCoverageInfo ? Observing : NotObserving;
+ if (!dbg->updateObservesCoverageOnDebuggees(cx, observing))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::getMemory(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "get memory", args, dbg);
+ Value memoryValue = dbg->object->getReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE);
+
+ if (!memoryValue.isObject()) {
+ RootedObject memory(cx, DebuggerMemory::create(cx, dbg));
+ if (!memory)
+ return false;
+ memoryValue = ObjectValue(*memory);
+ }
+
+ args.rval().set(memoryValue);
+ return true;
+}
+
+/*
+ * Given a value used to designate a global (there's quite a variety; see the
+ * docs), return the actual designee.
+ *
+ * Note that this does not check whether the designee is marked "invisible to
+ * Debugger" or not; different callers need to handle invisible-to-Debugger
+ * globals in different ways.
+ */
+GlobalObject*
+Debugger::unwrapDebuggeeArgument(JSContext* cx, const Value& v)
+{
+ if (!v.isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "argument", "not a global object");
+ return nullptr;
+ }
+
+ RootedObject obj(cx, &v.toObject());
+
+ /* If it's a Debugger.Object belonging to this debugger, dereference that. */
+ if (obj->getClass() == &DebuggerObject::class_) {
+ RootedValue rv(cx, v);
+ if (!unwrapDebuggeeValue(cx, &rv))
+ return nullptr;
+ obj = &rv.toObject();
+ }
+
+ /* If we have a cross-compartment wrapper, dereference as far as is secure. */
+ obj = CheckedUnwrap(obj);
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return nullptr;
+ }
+
+ /* If that produced a WindowProxy, get the Window (global). */
+ obj = ToWindowIfWindowProxy(obj);
+
+ /* If that didn't produce a global object, it's an error. */
+ if (!obj->is<GlobalObject>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "argument", "not a global object");
+ return nullptr;
+ }
+
+ return &obj->as<GlobalObject>();
+}
+
+/* static */ bool
+Debugger::addDebuggee(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "addDebuggee", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.addDebuggee", 1))
+ return false;
+ Rooted<GlobalObject*> global(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
+ if (!global)
+ return false;
+
+ if (!dbg->addDebuggeeGlobal(cx, global))
+ return false;
+
+ RootedValue v(cx, ObjectValue(*global));
+ if (!dbg->wrapDebuggeeValue(cx, &v))
+ return false;
+ args.rval().set(v);
+ return true;
+}
+
+/* static */ bool
+Debugger::addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
+ for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
+ for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
+ if (c == dbg->object->compartment() || c->creationOptions().invisibleToDebugger())
+ continue;
+ c->scheduledForDestruction = false;
+ GlobalObject* global = c->maybeGlobal();
+ if (global) {
+ Rooted<GlobalObject*> rg(cx, global);
+ if (!dbg->addDebuggeeGlobal(cx, rg))
+ return false;
+ }
+ }
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::removeDebuggee(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "removeDebuggee", args, dbg);
+
+ if (!args.requireAtLeast(cx, "Debugger.removeDebuggee", 1))
+ return false;
+ Rooted<GlobalObject*> global(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
+ if (!global)
+ return false;
+
+ ExecutionObservableCompartments obs(cx);
+ if (!obs.init())
+ return false;
+
+ if (dbg->debuggees.has(global)) {
+ dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), global, nullptr);
+
+ // Only update the compartment if there are no Debuggers left, as it's
+ // expensive to check if no other Debugger has a live script or frame hook
+ // on any of the current on-stack debuggee frames.
+ if (global->getDebuggers()->empty() && !obs.add(global->compartment()))
+ return false;
+ if (!updateExecutionObservability(cx, obs, NotObserving))
+ return false;
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::removeAllDebuggees(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
+
+ ExecutionObservableCompartments obs(cx);
+ if (!obs.init())
+ return false;
+
+ for (WeakGlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront()) {
+ Rooted<GlobalObject*> global(cx, e.front());
+ dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), global, &e);
+
+ // See note about adding to the observable set in removeDebuggee.
+ if (global->getDebuggers()->empty() && !obs.add(global->compartment()))
+ return false;
+ }
+
+ if (!updateExecutionObservability(cx, obs, NotObserving))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+Debugger::hasDebuggee(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "hasDebuggee", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.hasDebuggee", 1))
+ return false;
+ GlobalObject* global = dbg->unwrapDebuggeeArgument(cx, args[0]);
+ if (!global)
+ return false;
+ args.rval().setBoolean(!!dbg->debuggees.lookup(global));
+ return true;
+}
+
+/* static */ bool
+Debugger::getDebuggees(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "getDebuggees", args, dbg);
+
+ // Obtain the list of debuggees before wrapping each debuggee, as a GC could
+ // update the debuggees set while we are iterating it.
+ unsigned count = dbg->debuggees.count();
+ AutoValueVector debuggees(cx);
+ if (!debuggees.resize(count))
+ return false;
+ unsigned i = 0;
+ {
+ JS::AutoCheckCannotGC nogc;
+ for (WeakGlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
+ debuggees[i++].setObject(*e.front().get());
+ }
+
+ RootedArrayObject arrobj(cx, NewDenseFullyAllocatedArray(cx, count));
+ if (!arrobj)
+ return false;
+ arrobj->ensureDenseInitializedLength(cx, 0, count);
+ for (i = 0; i < count; i++) {
+ RootedValue v(cx, debuggees[i]);
+ if (!dbg->wrapDebuggeeValue(cx, &v))
+ return false;
+ arrobj->setDenseElement(i, v);
+ }
+
+ args.rval().setObject(*arrobj);
+ return true;
+}
+
+/* static */ bool
+Debugger::getNewestFrame(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "getNewestFrame", args, dbg);
+
+ /* Since there may be multiple contexts, use AllScriptFramesIter. */
+ for (AllScriptFramesIter i(cx); !i.done(); ++i) {
+ if (dbg->observesFrame(i)) {
+ // Ensure that Ion frames are rematerialized. Only rematerialized
+ // Ion frames may be used as AbstractFramePtrs.
+ if (i.isIon() && !i.ensureHasRematerializedFrame(cx))
+ return false;
+ AbstractFramePtr frame = i.abstractFramePtr();
+ ScriptFrameIter iter(i.activation()->cx());
+ while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != frame)
+ ++iter;
+ return dbg->getScriptFrame(cx, iter, args.rval());
+ }
+ }
+ args.rval().setNull();
+ return true;
+}
+
+/* static */ bool
+Debugger::clearAllBreakpoints(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "clearAllBreakpoints", args, dbg);
+ for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront())
+ r.front()->compartment()->clearBreakpointsIn(cx->runtime()->defaultFreeOp(),
+ dbg, nullptr);
+ return true;
+}
+
+/* static */ bool
+Debugger::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ /* Check that the arguments, if any, are cross-compartment wrappers. */
+ for (unsigned i = 0; i < args.length(); i++) {
+ JSObject* argobj = NonNullObject(cx, args[i]);
+ if (!argobj)
+ return false;
+ if (!argobj->is<CrossCompartmentWrapperObject>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_CCW_REQUIRED,
+ "Debugger");
+ return false;
+ }
+ }
+
+ /* Get Debugger.prototype. */
+ RootedValue v(cx);
+ RootedObject callee(cx, &args.callee());
+ if (!GetProperty(cx, callee, callee, cx->names().prototype, &v))
+ return false;
+ RootedNativeObject proto(cx, &v.toObject().as<NativeObject>());
+ MOZ_ASSERT(proto->getClass() == &Debugger::class_);
+ /*
+ * Make the new Debugger object. Each one has a reference to
+ * Debugger.{Frame,Object,Script,Memory}.prototype in reserved slots. The
+ * rest of the reserved slots are for hooks; they default to undefined.
+ */
+ RootedNativeObject obj(cx, NewNativeObjectWithGivenProto(cx, &Debugger::class_, proto));
+ if (!obj)
+ return false;
+ for (unsigned slot = JSSLOT_DEBUG_PROTO_START; slot < JSSLOT_DEBUG_PROTO_STOP; slot++)
+ obj->setReservedSlot(slot, proto->getReservedSlot(slot));
+ obj->setReservedSlot(JSSLOT_DEBUG_MEMORY_INSTANCE, NullValue());
+
+ Debugger* debugger;
+ {
+ /* Construct the underlying C++ object. */
+ auto dbg = cx->make_unique<Debugger>(cx, obj.get());
+ if (!dbg || !dbg->init(cx))
+ return false;
+
+ debugger = dbg.release();
+ obj->setPrivate(debugger); // owns the released pointer
+ }
+
+ /* Add the initial debuggees, if any. */
+ for (unsigned i = 0; i < args.length(); i++) {
+ Rooted<GlobalObject*>
+ debuggee(cx, &args[i].toObject().as<ProxyObject>().private_().toObject().global());
+ if (!debugger->addDebuggeeGlobal(cx, debuggee))
+ return false;
+ }
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+bool
+Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (debuggees.has(global))
+ return true;
+
+ // Callers should generally be unable to get a reference to a debugger-
+ // invisible global in order to pass it to addDebuggee. But this is possible
+ // with certain testing aides we expose in the shell, so just make addDebuggee
+ // throw in that case.
+ JSCompartment* debuggeeCompartment = global->compartment();
+ if (debuggeeCompartment->creationOptions().invisibleToDebugger()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_CANT_DEBUG_GLOBAL);
+ return false;
+ }
+
+ /*
+ * Check for cycles. If global's compartment is reachable from this
+ * Debugger object's compartment by following debuggee-to-debugger links,
+ * then adding global would create a cycle. (Typically nobody is debugging
+ * the debugger, in which case we zip through this code without looping.)
+ */
+ Vector<JSCompartment*> visited(cx);
+ if (!visited.append(object->compartment()))
+ return false;
+ for (size_t i = 0; i < visited.length(); i++) {
+ JSCompartment* c = visited[i];
+ if (c == debuggeeCompartment) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_LOOP);
+ return false;
+ }
+
+ /*
+ * Find all compartments containing debuggers debugging c's global
+ * object. Add those compartments to visited.
+ */
+ if (c->isDebuggee()) {
+ GlobalObject::DebuggerVector* v = c->maybeGlobal()->getDebuggers();
+ for (auto p = v->begin(); p != v->end(); p++) {
+ JSCompartment* next = (*p)->object->compartment();
+ if (Find(visited, next) == visited.end() && !visited.append(next))
+ return false;
+ }
+ }
+ }
+
+ /*
+ * For global to become this js::Debugger's debuggee:
+ *
+ * 1. this js::Debugger must be in global->getDebuggers(),
+ * 2. global must be in this->debuggees,
+ * 3. it must be in zone->getDebuggers(),
+ * 4. the debuggee's zone must be in this->debuggeeZones,
+ * 5. if we are tracking allocations, the SavedStacksMetadataBuilder must be
+ * installed for this compartment, and
+ * 6. JSCompartment::isDebuggee()'s bit must be set.
+ *
+ * All six indications must be kept consistent.
+ */
+
+ AutoCompartment ac(cx, global);
+ Zone* zone = global->zone();
+
+ // (1)
+ auto* globalDebuggers = GlobalObject::getOrCreateDebuggers(cx, global);
+ if (!globalDebuggers)
+ return false;
+ if (!globalDebuggers->append(this)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ auto globalDebuggersGuard = MakeScopeExit([&] {
+ globalDebuggers->popBack();
+ });
+
+ // (2)
+ if (!debuggees.put(global)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ auto debuggeesGuard = MakeScopeExit([&] {
+ debuggees.remove(global);
+ });
+
+ bool addingZoneRelation = !debuggeeZones.has(zone);
+
+ // (3)
+ auto* zoneDebuggers = zone->getOrCreateDebuggers(cx);
+ if (!zoneDebuggers)
+ return false;
+ if (addingZoneRelation && !zoneDebuggers->append(this)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ auto zoneDebuggersGuard = MakeScopeExit([&] {
+ if (addingZoneRelation)
+ zoneDebuggers->popBack();
+ });
+
+ // (4)
+ if (addingZoneRelation && !debuggeeZones.put(zone)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ auto debuggeeZonesGuard = MakeScopeExit([&] {
+ if (addingZoneRelation)
+ debuggeeZones.remove(zone);
+ });
+
+ // (5)
+ if (trackingAllocationSites && enabled && !Debugger::addAllocationsTracking(cx, global))
+ return false;
+
+ auto allocationsTrackingGuard = MakeScopeExit([&] {
+ if (trackingAllocationSites && enabled)
+ Debugger::removeAllocationsTracking(*global);
+ });
+
+ // (6)
+ AutoRestoreCompartmentDebugMode debugModeGuard(debuggeeCompartment);
+ debuggeeCompartment->setIsDebuggee();
+ debuggeeCompartment->updateDebuggerObservesAsmJS();
+ debuggeeCompartment->updateDebuggerObservesCoverage();
+ if (observesAllExecution() && !ensureExecutionObservabilityOfCompartment(cx, debuggeeCompartment))
+ return false;
+
+ globalDebuggersGuard.release();
+ debuggeesGuard.release();
+ zoneDebuggersGuard.release();
+ debuggeeZonesGuard.release();
+ allocationsTrackingGuard.release();
+ debugModeGuard.release();
+ return true;
+}
+
+void
+Debugger::recomputeDebuggeeZoneSet()
+{
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ debuggeeZones.clear();
+ for (auto range = debuggees.all(); !range.empty(); range.popFront()) {
+ if (!debuggeeZones.put(range.front().unbarrieredGet()->zone()))
+ oomUnsafe.crash("Debugger::removeDebuggeeGlobal");
+ }
+}
+
+template <typename T>
+static T*
+findDebuggerInVector(Debugger* dbg, Vector<T, 0, js::SystemAllocPolicy>* vec)
+{
+ T* p;
+ for (p = vec->begin(); p != vec->end(); p++) {
+ if (*p == dbg)
+ break;
+ }
+ MOZ_ASSERT(p != vec->end());
+ return p;
+}
+
+void
+Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
+ WeakGlobalObjectSet::Enum* debugEnum)
+{
+ /*
+ * The caller might have found global by enumerating this->debuggees; if
+ * so, use HashSet::Enum::removeFront rather than HashSet::remove below,
+ * to avoid invalidating the live enumerator.
+ */
+ MOZ_ASSERT(debuggees.has(global));
+ MOZ_ASSERT(debuggeeZones.has(global->zone()));
+ MOZ_ASSERT_IF(debugEnum, debugEnum->front().unbarrieredGet() == global);
+
+ /*
+ * FIXME Debugger::slowPathOnLeaveFrame needs to kill all Debugger.Frame
+ * objects referring to a particular JS stack frame. This is hard if
+ * Debugger objects that are no longer debugging the relevant global might
+ * have live Frame objects. So we take the easy way out and kill them here.
+ * This is a bug, since it's observable and contrary to the spec. One
+ * possible fix would be to put such objects into a compartment-wide bag
+ * which slowPathOnLeaveFrame would have to examine.
+ */
+ for (FrameMap::Enum e(frames); !e.empty(); e.popFront()) {
+ AbstractFramePtr frame = e.front().key();
+ NativeObject* frameobj = e.front().value();
+ if (&frame.script()->global() == global) {
+ DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
+ DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, frame, frameobj);
+ e.removeFront();
+ }
+ }
+
+ auto *globalDebuggersVector = global->getDebuggers();
+ auto *zoneDebuggersVector = global->zone()->getDebuggers();
+
+ /*
+ * The relation must be removed from up to three places:
+ * globalDebuggersVector and debuggees for sure, and possibly the
+ * compartment's debuggee set.
+ *
+ * The debuggee zone set is recomputed on demand. This avoids refcounting
+ * and in practice we have relatively few debuggees that tend to all be in
+ * the same zone. If after recomputing the debuggee zone set, this global's
+ * zone is not in the set, then we must remove ourselves from the zone's
+ * vector of observing debuggers.
+ */
+ globalDebuggersVector->erase(findDebuggerInVector(this, globalDebuggersVector));
+
+ if (debugEnum)
+ debugEnum->removeFront();
+ else
+ debuggees.remove(global);
+
+ recomputeDebuggeeZoneSet();
+
+ if (!debuggeeZones.has(global->zone()))
+ zoneDebuggersVector->erase(findDebuggerInVector(this, zoneDebuggersVector));
+
+ /* Remove all breakpoints for the debuggee. */
+ Breakpoint* nextbp;
+ for (Breakpoint* bp = firstBreakpoint(); bp; bp = nextbp) {
+ nextbp = bp->nextInDebugger();
+ if (bp->site->script->compartment() == global->compartment())
+ bp->destroy(fop);
+ }
+ MOZ_ASSERT_IF(debuggees.empty(), !firstBreakpoint());
+
+ /*
+ * If we are tracking allocation sites, we need to remove the object
+ * metadata callback from this global's compartment.
+ */
+ if (trackingAllocationSites)
+ Debugger::removeAllocationsTracking(*global);
+
+ if (global->getDebuggers()->empty()) {
+ global->compartment()->unsetIsDebuggee();
+ } else {
+ global->compartment()->updateDebuggerObservesAllExecution();
+ global->compartment()->updateDebuggerObservesAsmJS();
+ global->compartment()->updateDebuggerObservesCoverage();
+ }
+}
+
+
+static inline DebuggerSourceReferent GetSourceReferent(JSObject* obj);
+
+/*
+ * A class for parsing 'findScripts' query arguments and searching for
+ * scripts that match the criteria they represent.
+ */
+class MOZ_STACK_CLASS Debugger::ScriptQuery
+{
+ public:
+ /* Construct a ScriptQuery to use matching scripts for |dbg|. */
+ ScriptQuery(JSContext* cx, Debugger* dbg):
+ cx(cx),
+ debugger(dbg),
+ iterMarker(&cx->runtime()->gc),
+ compartments(cx->runtime()),
+ url(cx),
+ displayURLString(cx),
+ hasSource(false),
+ source(cx, AsVariant(static_cast<ScriptSourceObject*>(nullptr))),
+ innermostForCompartment(cx->runtime()),
+ vector(cx, ScriptVector(cx)),
+ wasmInstanceVector(cx, WasmInstanceObjectVector(cx))
+ {}
+
+ /*
+ * Initialize this ScriptQuery. Raise an error and return false if we
+ * haven't enough memory.
+ */
+ bool init() {
+ if (!compartments.init() ||
+ !innermostForCompartment.init())
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ * Parse the query object |query|, and prepare to match only the scripts
+ * it specifies.
+ */
+ bool parseQuery(HandleObject query) {
+ /*
+ * Check for a 'global' property, which limits the results to those
+ * scripts scoped to a particular global object.
+ */
+ RootedValue global(cx);
+ if (!GetProperty(cx, query, query, cx->names().global, &global))
+ return false;
+ if (global.isUndefined()) {
+ if (!matchAllDebuggeeGlobals())
+ return false;
+ } else {
+ GlobalObject* globalObject = debugger->unwrapDebuggeeArgument(cx, global);
+ if (!globalObject)
+ return false;
+
+ /*
+ * If the given global isn't a debuggee, just leave the set of
+ * acceptable globals empty; we'll return no scripts.
+ */
+ if (debugger->debuggees.has(globalObject)) {
+ if (!matchSingleGlobal(globalObject))
+ return false;
+ }
+ }
+
+ /* Check for a 'url' property. */
+ if (!GetProperty(cx, query, query, cx->names().url, &url))
+ return false;
+ if (!url.isUndefined() && !url.isString()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "query object's 'url' property",
+ "neither undefined nor a string");
+ return false;
+ }
+
+ /* Check for a 'source' property */
+ RootedValue debuggerSource(cx);
+ if (!GetProperty(cx, query, query, cx->names().source, &debuggerSource))
+ return false;
+ if (!debuggerSource.isUndefined()) {
+ if (!debuggerSource.isObject() ||
+ debuggerSource.toObject().getClass() != &DebuggerSource_class) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "query object's 'source' property",
+ "not undefined nor a Debugger.Source object");
+ return false;
+ }
+
+ Value owner = debuggerSource.toObject()
+ .as<NativeObject>()
+ .getReservedSlot(JSSLOT_DEBUGSOURCE_OWNER);
+
+ /*
+ * The given source must have an owner. Otherwise, it's a
+ * Debugger.Source.prototype, which would match no scripts, and is
+ * probably a mistake.
+ */
+ if (!owner.isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_PROTO,
+ "Debugger.Source", "Debugger.Source");
+ return false;
+ }
+
+ /*
+ * If it does have an owner, it should match the Debugger we're
+ * calling findScripts on. It would work fine even if it didn't,
+ * but mixing Debugger.Sources is probably a sign of confusion.
+ */
+ if (&owner.toObject() != debugger->object) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_WRONG_OWNER,
+ "Debugger.Source");
+ return false;
+ }
+
+ hasSource = true;
+ source = GetSourceReferent(&debuggerSource.toObject());
+ }
+
+ /* Check for a 'displayURL' property. */
+ RootedValue displayURL(cx);
+ if (!GetProperty(cx, query, query, cx->names().displayURL, &displayURL))
+ return false;
+ if (!displayURL.isUndefined() && !displayURL.isString()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "query object's 'displayURL' property",
+ "neither undefined nor a string");
+ return false;
+ }
+
+ if (displayURL.isString()) {
+ displayURLString = displayURL.toString()->ensureLinear(cx);
+ if (!displayURLString)
+ return false;
+ }
+
+ /* Check for a 'line' property. */
+ RootedValue lineProperty(cx);
+ if (!GetProperty(cx, query, query, cx->names().line, &lineProperty))
+ return false;
+ if (lineProperty.isUndefined()) {
+ hasLine = false;
+ } else if (lineProperty.isNumber()) {
+ if (displayURL.isUndefined() && url.isUndefined() && !hasSource) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_QUERY_LINE_WITHOUT_URL);
+ return false;
+ }
+ double doubleLine = lineProperty.toNumber();
+ if (doubleLine <= 0 || (unsigned int) doubleLine != doubleLine) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_LINE);
+ return false;
+ }
+ hasLine = true;
+ line = doubleLine;
+ } else {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "query object's 'line' property",
+ "neither undefined nor an integer");
+ return false;
+ }
+
+ /* Check for an 'innermost' property. */
+ PropertyName* innermostName = cx->names().innermost;
+ RootedValue innermostProperty(cx);
+ if (!GetProperty(cx, query, query, innermostName, &innermostProperty))
+ return false;
+ innermost = ToBoolean(innermostProperty);
+ if (innermost) {
+ /* Technically, we need only check hasLine, but this is clearer. */
+ if ((displayURL.isUndefined() && url.isUndefined() && !hasSource) || !hasLine) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /* Set up this ScriptQuery appropriately for a missing query argument. */
+ bool omittedQuery() {
+ url.setUndefined();
+ hasLine = false;
+ innermost = false;
+ displayURLString = nullptr;
+ return matchAllDebuggeeGlobals();
+ }
+
+ /*
+ * Search all relevant compartments and the stack for scripts matching
+ * this query, and append the matching scripts to |vector|.
+ */
+ bool findScripts() {
+ if (!prepareQuery() || !delazifyScripts())
+ return false;
+
+ JSCompartment* singletonComp = nullptr;
+ if (compartments.count() == 1)
+ singletonComp = compartments.all().front();
+
+ /* Search each compartment for debuggee scripts. */
+ MOZ_ASSERT(vector.empty());
+ oom = false;
+ IterateScripts(cx, singletonComp, this, considerScript);
+ if (oom) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ /* We cannot touch the gray bits while isHeapBusy, so do this now. */
+ for (JSScript** i = vector.begin(); i != vector.end(); ++i)
+ JS::ExposeScriptToActiveJS(*i);
+
+ /*
+ * For most queries, we just accumulate results in 'vector' as we find
+ * them. But if this is an 'innermost' query, then we've accumulated the
+ * results in the 'innermostForCompartment' map. In that case, we now need to
+ * walk that map and populate 'vector'.
+ */
+ if (innermost) {
+ for (CompartmentToScriptMap::Range r = innermostForCompartment.all();
+ !r.empty();
+ r.popFront())
+ {
+ JS::ExposeScriptToActiveJS(r.front().value());
+ if (!vector.append(r.front().value())) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+ }
+
+ // TODOshu: Until such time that wasm modules are real ES6 modules,
+ // unconditionally consider all wasm toplevel instance scripts.
+ for (WeakGlobalObjectSet::Range r = debugger->allDebuggees(); !r.empty(); r.popFront()) {
+ for (wasm::Instance* instance : r.front()->compartment()->wasm.instances()) {
+ consider(instance->object());
+ if (oom) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ Handle<ScriptVector> foundScripts() const {
+ return vector;
+ }
+
+ Handle<WasmInstanceObjectVector> foundWasmInstances() const {
+ return wasmInstanceVector;
+ }
+
+ private:
+ /* The context in which we should do our work. */
+ JSContext* cx;
+
+ /* The debugger for which we conduct queries. */
+ Debugger* debugger;
+
+ /* Require the set of compartments to stay fixed while the ScriptQuery is alive. */
+ gc::AutoEnterIteration iterMarker;
+
+ typedef HashSet<JSCompartment*, DefaultHasher<JSCompartment*>, RuntimeAllocPolicy>
+ CompartmentSet;
+
+ /* A script must be in one of these compartments to match the query. */
+ CompartmentSet compartments;
+
+ /* If this is a string, matching scripts have urls equal to it. */
+ RootedValue url;
+
+ /* url as a C string. */
+ JSAutoByteString urlCString;
+
+ /* If this is a string, matching scripts' sources have displayURLs equal to
+ * it. */
+ RootedLinearString displayURLString;
+
+ /*
+ * If this is a source referent, matching scripts will have sources equal
+ * to this instance. Ideally we'd use a Maybe here, but Maybe interacts
+ * very badly with Rooted's LIFO invariant.
+ */
+ bool hasSource;
+ Rooted<DebuggerSourceReferent> source;
+
+ /* True if the query contained a 'line' property. */
+ bool hasLine;
+
+ /* The line matching scripts must cover. */
+ unsigned int line;
+
+ /* True if the query has an 'innermost' property whose value is true. */
+ bool innermost;
+
+ typedef HashMap<JSCompartment*, JSScript*, DefaultHasher<JSCompartment*>, RuntimeAllocPolicy>
+ CompartmentToScriptMap;
+
+ /*
+ * For 'innermost' queries, a map from compartments to the innermost script
+ * we've seen so far in that compartment. (Template instantiation code size
+ * explosion ho!)
+ */
+ CompartmentToScriptMap innermostForCompartment;
+
+ /*
+ * Accumulate the scripts in an Rooted<ScriptVector>, instead of creating
+ * the JS array as we go, because we mustn't allocate JS objects or GC
+ * while we use the CellIter.
+ */
+ Rooted<ScriptVector> vector;
+
+ /*
+ * Like above, but for wasm modules.
+ */
+ Rooted<WasmInstanceObjectVector> wasmInstanceVector;
+
+ /* Indicates whether OOM has occurred while matching. */
+ bool oom;
+
+ bool addCompartment(JSCompartment* comp) {
+ return compartments.put(comp);
+ }
+
+ /* Arrange for this ScriptQuery to match only scripts that run in |global|. */
+ bool matchSingleGlobal(GlobalObject* global) {
+ MOZ_ASSERT(compartments.count() == 0);
+ if (!addCompartment(global->compartment())) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * Arrange for this ScriptQuery to match all scripts running in debuggee
+ * globals.
+ */
+ bool matchAllDebuggeeGlobals() {
+ MOZ_ASSERT(compartments.count() == 0);
+ /* Build our compartment set from the debugger's set of debuggee globals. */
+ for (WeakGlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
+ if (!addCompartment(r.front()->compartment())) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Given that parseQuery or omittedQuery has been called, prepare to match
+ * scripts. Set urlCString and displayURLChars as appropriate.
+ */
+ bool prepareQuery() {
+ /* Compute urlCString and displayURLChars, if a url or displayURL was
+ * given respectively. */
+ if (url.isString()) {
+ if (!urlCString.encodeLatin1(cx, url.toString()))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool delazifyScripts() {
+ // All scripts in debuggee compartments must be visible, so delazify
+ // everything.
+ for (auto r = compartments.all(); !r.empty(); r.popFront()) {
+ JSCompartment* comp = r.front();
+ AutoCompartment ac(cx, comp);
+ if (!comp->ensureDelazifyScriptsForDebugger(cx))
+ return false;
+ }
+ return true;
+ }
+
+ static void considerScript(JSRuntime* rt, void* data, JSScript* script) {
+ ScriptQuery* self = static_cast<ScriptQuery*>(data);
+ self->consider(script);
+ }
+
+ /*
+ * If |script| matches this query, append it to |vector| or place it in
+ * |innermostForCompartment|, as appropriate. Set |oom| if an out of memory
+ * condition occurred.
+ */
+ void consider(JSScript* script) {
+ // We check for presence of script->code() because it is possible that
+ // the script was created and thus exposed to GC, but *not* fully
+ // initialized from fullyInit{FromEmitter,Trivial} due to errors.
+ if (oom || script->selfHosted() || !script->code())
+ return;
+ JSCompartment* compartment = script->compartment();
+ if (!compartments.has(compartment))
+ return;
+ if (urlCString.ptr()) {
+ bool gotFilename = false;
+ if (script->filename() && strcmp(script->filename(), urlCString.ptr()) == 0)
+ gotFilename = true;
+
+ bool gotSourceURL = false;
+ if (!gotFilename && script->scriptSource()->introducerFilename() &&
+ strcmp(script->scriptSource()->introducerFilename(), urlCString.ptr()) == 0)
+ {
+ gotSourceURL = true;
+ }
+ if (!gotFilename && !gotSourceURL)
+ return;
+ }
+ if (hasLine) {
+ if (line < script->lineno() || script->lineno() + GetScriptLineExtent(script) < line)
+ return;
+ }
+ if (displayURLString) {
+ if (!script->scriptSource() || !script->scriptSource()->hasDisplayURL())
+ return;
+
+ const char16_t* s = script->scriptSource()->displayURL();
+ if (CompareChars(s, js_strlen(s), displayURLString) != 0)
+ return;
+ }
+ if (hasSource && !(source.is<ScriptSourceObject*>() &&
+ source.as<ScriptSourceObject*>()->source() == script->scriptSource()))
+ {
+ return;
+ }
+
+ if (innermost) {
+ /*
+ * For 'innermost' queries, we don't place scripts in |vector| right
+ * away; we may later find another script that is nested inside this
+ * one. Instead, we record the innermost script we've found so far
+ * for each compartment in innermostForCompartment, and only
+ * populate |vector| at the bottom of findScripts, when we've
+ * traversed all the scripts.
+ *
+ * So: check this script against the innermost one we've found so
+ * far (if any), as recorded in innermostForCompartment, and replace
+ * that if it's better.
+ */
+ CompartmentToScriptMap::AddPtr p = innermostForCompartment.lookupForAdd(compartment);
+ if (p) {
+ /* Is our newly found script deeper than the last one we found? */
+ JSScript* incumbent = p->value();
+ if (script->innermostScope()->chainLength() >
+ incumbent->innermostScope()->chainLength())
+ {
+ p->value() = script;
+ }
+ } else {
+ /*
+ * This is the first matching script we've encountered for this
+ * compartment, so it is thus the innermost such script.
+ */
+ if (!innermostForCompartment.add(p, compartment, script)) {
+ oom = true;
+ return;
+ }
+ }
+ } else {
+ /* Record this matching script in the results vector. */
+ if (!vector.append(script)) {
+ oom = true;
+ return;
+ }
+ }
+
+ return;
+ }
+
+ /*
+ * If |instanceObject| matches this query, append it to |wasmInstanceVector|.
+ * Set |oom| if an out of memory condition occurred.
+ */
+ void consider(WasmInstanceObject* instanceObject) {
+ if (oom)
+ return;
+
+ if (hasSource && source != AsVariant(instanceObject))
+ return;
+
+ if (!wasmInstanceVector.append(instanceObject))
+ oom = true;
+ }
+};
+
+/* static */ bool
+Debugger::findScripts(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "findScripts", args, dbg);
+
+ ScriptQuery query(cx, dbg);
+ if (!query.init())
+ return false;
+
+ if (args.length() >= 1) {
+ RootedObject queryObject(cx, NonNullObject(cx, args[0]));
+ if (!queryObject || !query.parseQuery(queryObject))
+ return false;
+ } else {
+ if (!query.omittedQuery())
+ return false;
+ }
+
+ if (!query.findScripts())
+ return false;
+
+ Handle<ScriptVector> scripts(query.foundScripts());
+ Handle<WasmInstanceObjectVector> wasmInstances(query.foundWasmInstances());
+
+ size_t resultLength = scripts.length() + wasmInstances.length();
+ RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, resultLength));
+ if (!result)
+ return false;
+
+ result->ensureDenseInitializedLength(cx, 0, resultLength);
+
+ for (size_t i = 0; i < scripts.length(); i++) {
+ JSObject* scriptObject = dbg->wrapScript(cx, scripts[i]);
+ if (!scriptObject)
+ return false;
+ result->setDenseElement(i, ObjectValue(*scriptObject));
+ }
+
+ size_t wasmStart = scripts.length();
+ for (size_t i = 0; i < wasmInstances.length(); i++) {
+ JSObject* scriptObject = dbg->wrapWasmScript(cx, wasmInstances[i]);
+ if (!scriptObject)
+ return false;
+ result->setDenseElement(wasmStart + i, ObjectValue(*scriptObject));
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/*
+ * A class for parsing 'findObjects' query arguments and searching for objects
+ * that match the criteria they represent.
+ */
+class MOZ_STACK_CLASS Debugger::ObjectQuery
+{
+ public:
+ /* Construct an ObjectQuery to use matching scripts for |dbg|. */
+ ObjectQuery(JSContext* cx, Debugger* dbg) :
+ objects(cx), cx(cx), dbg(dbg), className(cx)
+ { }
+
+ /* The vector that we are accumulating results in. */
+ AutoObjectVector objects;
+
+ /*
+ * Parse the query object |query|, and prepare to match only the objects it
+ * specifies.
+ */
+ bool parseQuery(HandleObject query) {
+ /* Check for the 'class' property */
+ RootedValue cls(cx);
+ if (!GetProperty(cx, query, query, cx->names().class_, &cls))
+ return false;
+ if (!cls.isUndefined()) {
+ if (!cls.isString()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "query object's 'class' property",
+ "neither undefined nor a string");
+ return false;
+ }
+ className = cls;
+ }
+ return true;
+ }
+
+ /* Set up this ObjectQuery appropriately for a missing query argument. */
+ void omittedQuery() {
+ className.setUndefined();
+ }
+
+ /*
+ * Traverse the heap to find all relevant objects and add them to the
+ * provided vector.
+ */
+ bool findObjects() {
+ if (!prepareQuery())
+ return false;
+
+ {
+ /*
+ * We can't tolerate the GC moving things around while we're
+ * searching the heap. Check that nothing we do causes a GC.
+ */
+ Maybe<JS::AutoCheckCannotGC> maybeNoGC;
+ RootedObject dbgObj(cx, dbg->object);
+ JS::ubi::RootList rootList(cx, maybeNoGC);
+ if (!rootList.init(dbgObj)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ Traversal traversal(cx, *this, maybeNoGC.ref());
+ if (!traversal.init()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ traversal.wantNames = false;
+
+ return traversal.addStart(JS::ubi::Node(&rootList)) &&
+ traversal.traverse();
+ }
+ }
+
+ /*
+ * |ubi::Node::BreadthFirst| interface.
+ */
+ class NodeData {};
+ typedef JS::ubi::BreadthFirst<ObjectQuery> Traversal;
+ bool operator() (Traversal& traversal, JS::ubi::Node origin, const JS::ubi::Edge& edge,
+ NodeData*, bool first)
+ {
+ if (!first)
+ return true;
+
+ JS::ubi::Node referent = edge.referent;
+ /*
+ * Only follow edges within our set of debuggee compartments; we don't
+ * care about the heap's subgraphs outside of our debuggee compartments,
+ * so we abandon the referent. Either (1) there is not a path from this
+ * non-debuggee node back to a node in our debuggee compartments, and we
+ * don't need to follow edges to or from this node, or (2) there does
+ * exist some path from this non-debuggee node back to a node in our
+ * debuggee compartments. However, if that were true, then the incoming
+ * cross compartment edge back into a debuggee compartment is already
+ * listed as an edge in the RootList we started traversal with, and
+ * therefore we don't need to follow edges to or from this non-debuggee
+ * node.
+ */
+ JSCompartment* comp = referent.compartment();
+ if (comp && !dbg->isDebuggeeUnbarriered(comp)) {
+ traversal.abandonReferent();
+ return true;
+ }
+
+ /*
+ * If the referent is an object and matches our query's restrictions,
+ * add it to the vector accumulating results. Skip objects that should
+ * never be exposed to JS, like EnvironmentObjects and internal
+ * functions.
+ */
+
+ if (!referent.is<JSObject>() || referent.exposeToJS().isUndefined())
+ return true;
+
+ JSObject* obj = referent.as<JSObject>();
+
+ if (!className.isUndefined()) {
+ const char* objClassName = obj->getClass()->name;
+ if (strcmp(objClassName, classNameCString.ptr()) != 0)
+ return true;
+ }
+
+ return objects.append(obj);
+ }
+
+ private:
+ /* The context in which we should do our work. */
+ JSContext* cx;
+
+ /* The debugger for which we conduct queries. */
+ Debugger* dbg;
+
+ /*
+ * If this is non-null, matching objects will have a class whose name is
+ * this property.
+ */
+ RootedValue className;
+
+ /* The className member, as a C string. */
+ JSAutoByteString classNameCString;
+
+ /*
+ * Given that either omittedQuery or parseQuery has been called, prepare the
+ * query for matching objects.
+ */
+ bool prepareQuery() {
+ if (className.isString()) {
+ if (!classNameCString.encodeLatin1(cx, className.toString()))
+ return false;
+ }
+
+ return true;
+ }
+};
+
+bool
+Debugger::findObjects(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "findObjects", args, dbg);
+
+ ObjectQuery query(cx, dbg);
+
+ if (args.length() >= 1) {
+ RootedObject queryObject(cx, NonNullObject(cx, args[0]));
+ if (!queryObject || !query.parseQuery(queryObject))
+ return false;
+ } else {
+ query.omittedQuery();
+ }
+
+ if (!query.findObjects())
+ return false;
+
+ size_t length = query.objects.length();
+ RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length));
+ if (!result)
+ return false;
+
+ result->ensureDenseInitializedLength(cx, 0, length);
+
+ for (size_t i = 0; i < length; i++) {
+ RootedValue debuggeeVal(cx, ObjectValue(*query.objects[i]));
+ if (!dbg->wrapDebuggeeValue(cx, &debuggeeVal))
+ return false;
+ result->setDenseElement(i, debuggeeVal);
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+Debugger::findAllGlobals(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "findAllGlobals", args, dbg);
+
+ AutoObjectVector globals(cx);
+
+ {
+ // Accumulate the list of globals before wrapping them, because
+ // wrapping can GC and collect compartments from under us, while
+ // iterating.
+ JS::AutoCheckCannotGC nogc;
+
+ for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
+ if (c->creationOptions().invisibleToDebugger())
+ continue;
+
+ c->scheduledForDestruction = false;
+
+ GlobalObject* global = c->maybeGlobal();
+
+ if (cx->runtime()->isSelfHostingGlobal(global))
+ continue;
+
+ if (global) {
+ /*
+ * We pulled |global| out of nowhere, so it's possible that it was
+ * marked gray by XPConnect. Since we're now exposing it to JS code,
+ * we need to mark it black.
+ */
+ JS::ExposeObjectToActiveJS(global);
+ if (!globals.append(global))
+ return false;
+ }
+ }
+ }
+
+ RootedObject result(cx, NewDenseEmptyArray(cx));
+ if (!result)
+ return false;
+
+ for (size_t i = 0; i < globals.length(); i++) {
+ RootedValue globalValue(cx, ObjectValue(*globals[i]));
+ if (!dbg->wrapDebuggeeValue(cx, &globalValue))
+ return false;
+ if (!NewbornArrayPush(cx, result, globalValue))
+ return false;
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+Debugger::makeGlobalObjectReference(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "makeGlobalObjectReference", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.makeGlobalObjectReference", 1))
+ return false;
+
+ Rooted<GlobalObject*> global(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
+ if (!global)
+ return false;
+
+ // If we create a D.O referring to a global in an invisible compartment,
+ // then from it we can reach function objects, scripts, environments, etc.,
+ // none of which we're ever supposed to see.
+ JSCompartment* globalCompartment = global->compartment();
+ if (globalCompartment->creationOptions().invisibleToDebugger()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEBUG_INVISIBLE_COMPARTMENT);
+ return false;
+ }
+
+ args.rval().setObject(*global);
+ return dbg->wrapDebuggeeValue(cx, args.rval());
+}
+
+static bool
+DefineProperty(JSContext* cx, HandleObject obj, HandleId id, const char* value, size_t n)
+{
+ JSString* text = JS_NewStringCopyN(cx, value, n);
+ if (!text)
+ return false;
+
+ RootedValue str(cx, StringValue(text));
+ return JS_DefinePropertyById(cx, obj, id, str, JSPROP_ENUMERATE);
+}
+
+#ifdef JS_TRACE_LOGGING
+# ifdef NIGHTLY_BUILD
+bool
+Debugger::setupTraceLogger(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "setupTraceLogger", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.setupTraceLogger", 1))
+ return false;
+
+ RootedObject obj(cx, ToObject(cx, args[0]));
+ if (!obj)
+ return false;
+
+ AutoIdVector ids(cx);
+ if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids))
+ return false;
+
+ if (ids.length() == 0) {
+ args.rval().setBoolean(true);
+ return true;
+ }
+
+ Vector<uint32_t> textIds(cx);
+ if (!textIds.reserve(ids.length()))
+ return false;
+
+ Vector<bool> values(cx);
+ if (!values.reserve(ids.length()))
+ return false;
+
+ for (size_t i = 0; i < ids.length(); i++) {
+ if (!JSID_IS_STRING(ids[i])) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ JSString* id = JSID_TO_STRING(ids[i]);
+ JSLinearString* linear = id->ensureLinear(cx);
+ if (!linear)
+ return false;
+
+ uint32_t textId = TLStringToTextId(linear);
+
+ if (!TLTextIdIsTogglable(textId)) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ RootedValue v(cx);
+ if (!GetProperty(cx, obj, obj, ids[i], &v))
+ return false;
+
+ textIds.infallibleAppend(textId);
+ values.infallibleAppend(ToBoolean(v));
+ }
+
+ MOZ_ASSERT(ids.length() == textIds.length());
+ MOZ_ASSERT(textIds.length() == values.length());
+
+ for (size_t i = 0; i < textIds.length(); i++) {
+ if (values[i])
+ TraceLogEnableTextId(cx, textIds[i]);
+ else
+ TraceLogDisableTextId(cx, textIds[i]);
+ }
+
+ args.rval().setBoolean(true);
+ return true;
+}
+
+bool
+Debugger::drainTraceLogger(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "drainTraceLogger", args, dbg);
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ bool lostEvents = logger->lostEvents(dbg->traceLoggerLastDrainedIteration,
+ dbg->traceLoggerLastDrainedSize);
+
+ size_t numEvents;
+ EventEntry* events = logger->getEventsStartingAt(&dbg->traceLoggerLastDrainedIteration,
+ &dbg->traceLoggerLastDrainedSize,
+ &numEvents);
+
+ RootedObject array(cx, NewDenseEmptyArray(cx));
+ if (!array)
+ return false;
+
+ JSAtom* dataAtom = Atomize(cx, "data", strlen("data"));
+ if (!dataAtom)
+ return false;
+
+ RootedId dataId(cx, AtomToId(dataAtom));
+
+ /* Add all events to the array. */
+ uint32_t index = 0;
+ for (EventEntry* eventItem = events; eventItem < events + numEvents; eventItem++, index++) {
+ RootedObject item(cx, NewObjectWithGivenProto(cx, &PlainObject::class_, nullptr));
+ if (!item)
+ return false;
+
+ const char* eventText = logger->eventText(eventItem->textId);
+ if (!DefineProperty(cx, item, dataId, eventText, strlen(eventText)))
+ return false;
+
+ RootedValue obj(cx, ObjectValue(*item));
+ if (!JS_DefineElement(cx, array, index, obj, JSPROP_ENUMERATE))
+ return false;
+ }
+
+ /* Add "lostEvents" indicating if there are events that were lost. */
+ RootedValue lost(cx, BooleanValue(lostEvents));
+ if (!JS_DefineProperty(cx, array, "lostEvents", lost, JSPROP_ENUMERATE))
+ return false;
+
+ args.rval().setObject(*array);
+
+ return true;
+}
+# endif // NIGHTLY_BUILD
+
+bool
+Debugger::setupTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "setupTraceLoggerScriptCalls", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.setupTraceLoggerScriptCalls", 0))
+ return false;
+
+ TraceLogEnableTextId(cx, TraceLogger_Scripts);
+ TraceLogEnableTextId(cx, TraceLogger_InlinedScripts);
+ TraceLogDisableTextId(cx, TraceLogger_AnnotateScripts);
+
+ args.rval().setBoolean(true);
+
+ return true;
+}
+
+bool
+Debugger::startTraceLogger(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "startTraceLogger", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.startTraceLogger", 0))
+ return false;
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ if (!TraceLoggerEnable(logger, cx))
+ return false;
+
+ args.rval().setUndefined();
+
+ return true;
+}
+
+bool
+Debugger::endTraceLogger(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "endTraceLogger", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.endTraceLogger", 0))
+ return false;
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ TraceLoggerDisable(logger);
+
+ args.rval().setUndefined();
+
+ return true;
+}
+
+bool
+Debugger::isCompilableUnit(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!args.requireAtLeast(cx, "Debugger.isCompilableUnit", 1))
+ return false;
+
+ if (!args[0].isString()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ "Debugger.isCompilableUnit", "string",
+ InformalValueTypeName(args[0]));
+ return false;
+ }
+
+ JSString* str = args[0].toString();
+ size_t length = GetStringLength(str);
+
+ AutoStableStringChars chars(cx);
+ if (!chars.initTwoByte(cx, str))
+ return false;
+
+ bool result = true;
+
+ CompileOptions options(cx);
+ frontend::UsedNameTracker usedNames(cx);
+ if (!usedNames.init())
+ return false;
+ frontend::Parser<frontend::FullParseHandler> parser(cx, cx->tempLifoAlloc(),
+ options, chars.twoByteChars(),
+ length, /* foldConstants = */ true,
+ usedNames, nullptr, nullptr);
+ JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr);
+ if (!parser.checkOptions() || !parser.parse()) {
+ // We ran into an error. If it was because we ran out of memory we report
+ // it in the usual way.
+ if (cx->isThrowingOutOfMemory()) {
+ JS::SetWarningReporter(cx, older);
+ return false;
+ }
+
+ // If it was because we ran out of source, we return false so our caller
+ // knows to try to collect more [source].
+ if (parser.isUnexpectedEOF())
+ result = false;
+
+ cx->clearPendingException();
+ }
+ JS::SetWarningReporter(cx, older);
+ args.rval().setBoolean(result);
+ return true;
+}
+
+
+bool
+Debugger::drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "drainTraceLoggerScriptCalls", args, dbg);
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ bool lostEvents = logger->lostEvents(dbg->traceLoggerScriptedCallsLastDrainedIteration,
+ dbg->traceLoggerScriptedCallsLastDrainedSize);
+
+ size_t numEvents;
+ EventEntry* events = logger->getEventsStartingAt(
+ &dbg->traceLoggerScriptedCallsLastDrainedIteration,
+ &dbg->traceLoggerScriptedCallsLastDrainedSize,
+ &numEvents);
+
+ RootedObject array(cx, NewDenseEmptyArray(cx));
+ if (!array)
+ return false;
+
+ JSAtom* logTypeAtom = Atomize(cx, "logType", strlen("logType"));
+ if (!logTypeAtom)
+ return false;
+
+ RootedId fileNameId(cx, AtomToId(cx->names().fileName));
+ RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber));
+ RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber));
+ RootedId logTypeId(cx, AtomToId(logTypeAtom));
+
+ /* Add all events to the array. */
+ uint32_t index = 0;
+ for (EventEntry* eventItem = events; eventItem < events + numEvents; eventItem++) {
+ RootedObject item(cx, NewObjectWithGivenProto(cx, &PlainObject::class_, nullptr));
+ if (!item)
+ return false;
+
+ // Filter out internal time.
+ uint32_t textId = eventItem->textId;
+ if (textId == TraceLogger_Internal) {
+ eventItem++;
+ MOZ_ASSERT(eventItem->textId == TraceLogger_Stop);
+ continue;
+ }
+
+ if (textId != TraceLogger_Stop && !logger->textIdIsScriptEvent(textId))
+ continue;
+
+ const char* type = (textId == TraceLogger_Stop) ? "Stop" : "Script";
+ if (!DefineProperty(cx, item, logTypeId, type, strlen(type)))
+ return false;
+
+ if (textId != TraceLogger_Stop) {
+ const char* filename;
+ const char* lineno;
+ const char* colno;
+ size_t filename_len, lineno_len, colno_len;
+ logger->extractScriptDetails(textId, &filename, &filename_len, &lineno, &lineno_len,
+ &colno, &colno_len);
+
+ if (!DefineProperty(cx, item, fileNameId, filename, filename_len))
+ return false;
+ if (!DefineProperty(cx, item, lineNumberId, lineno, lineno_len))
+ return false;
+ if (!DefineProperty(cx, item, columnNumberId, colno, colno_len))
+ return false;
+ }
+
+ RootedValue obj(cx, ObjectValue(*item));
+ if (!JS_DefineElement(cx, array, index, obj, JSPROP_ENUMERATE))
+ return false;
+
+ index++;
+ }
+
+ /* Add "lostEvents" indicating if there are events that were lost. */
+ RootedValue lost(cx, BooleanValue(lostEvents));
+ if (!JS_DefineProperty(cx, array, "lostEvents", lost, JSPROP_ENUMERATE))
+ return false;
+
+ args.rval().setObject(*array);
+
+ return true;
+}
+#endif
+
+bool
+Debugger::adoptDebuggeeValue(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER(cx, argc, vp, "adoptDebuggeeValue", args, dbg);
+ if (!args.requireAtLeast(cx, "Debugger.adoptDebuggeeValue", 1))
+ return false;
+
+ RootedValue v(cx, args[0]);
+ if (v.isObject()) {
+ RootedObject obj(cx, &v.toObject());
+ NativeObject* ndobj = ToNativeDebuggerObject(cx, &obj);
+ if (!ndobj) {
+ return false;
+ }
+
+ obj.set(static_cast<JSObject*>(ndobj->getPrivate()));
+ v = ObjectValue(*obj);
+
+ if (!dbg->wrapDebuggeeValue(cx, &v)) {
+ return false;
+ }
+ }
+
+ args.rval().set(v);
+ return true;
+}
+
+const JSPropertySpec Debugger::properties[] = {
+ JS_PSGS("enabled", Debugger::getEnabled, Debugger::setEnabled, 0),
+ JS_PSGS("onDebuggerStatement", Debugger::getOnDebuggerStatement,
+ Debugger::setOnDebuggerStatement, 0),
+ JS_PSGS("onExceptionUnwind", Debugger::getOnExceptionUnwind,
+ Debugger::setOnExceptionUnwind, 0),
+ JS_PSGS("onNewScript", Debugger::getOnNewScript, Debugger::setOnNewScript, 0),
+ JS_PSGS("onNewPromise", Debugger::getOnNewPromise, Debugger::setOnNewPromise, 0),
+ JS_PSGS("onPromiseSettled", Debugger::getOnPromiseSettled, Debugger::setOnPromiseSettled, 0),
+ JS_PSGS("onEnterFrame", Debugger::getOnEnterFrame, Debugger::setOnEnterFrame, 0),
+ JS_PSGS("onNewGlobalObject", Debugger::getOnNewGlobalObject, Debugger::setOnNewGlobalObject, 0),
+ JS_PSGS("uncaughtExceptionHook", Debugger::getUncaughtExceptionHook,
+ Debugger::setUncaughtExceptionHook, 0),
+ JS_PSGS("allowUnobservedAsmJS", Debugger::getAllowUnobservedAsmJS,
+ Debugger::setAllowUnobservedAsmJS, 0),
+ JS_PSGS("collectCoverageInfo", Debugger::getCollectCoverageInfo,
+ Debugger::setCollectCoverageInfo, 0),
+ JS_PSG("memory", Debugger::getMemory, 0),
+ JS_PS_END
+};
+
+const JSFunctionSpec Debugger::methods[] = {
+ JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0),
+ JS_FN("addAllGlobalsAsDebuggees", Debugger::addAllGlobalsAsDebuggees, 0, 0),
+ JS_FN("removeDebuggee", Debugger::removeDebuggee, 1, 0),
+ JS_FN("removeAllDebuggees", Debugger::removeAllDebuggees, 0, 0),
+ JS_FN("hasDebuggee", Debugger::hasDebuggee, 1, 0),
+ JS_FN("getDebuggees", Debugger::getDebuggees, 0, 0),
+ JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
+ JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 0, 0),
+ JS_FN("findScripts", Debugger::findScripts, 1, 0),
+ JS_FN("findObjects", Debugger::findObjects, 1, 0),
+ JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0),
+ JS_FN("makeGlobalObjectReference", Debugger::makeGlobalObjectReference, 1, 0),
+#ifdef JS_TRACE_LOGGING
+ JS_FN("setupTraceLoggerScriptCalls", Debugger::setupTraceLoggerScriptCalls, 0, 0),
+ JS_FN("drainTraceLoggerScriptCalls", Debugger::drainTraceLoggerScriptCalls, 0, 0),
+ JS_FN("startTraceLogger", Debugger::startTraceLogger, 0, 0),
+ JS_FN("endTraceLogger", Debugger::endTraceLogger, 0, 0),
+# ifdef NIGHTLY_BUILD
+ JS_FN("setupTraceLogger", Debugger::setupTraceLogger, 1, 0),
+ JS_FN("drainTraceLogger", Debugger::drainTraceLogger, 0, 0),
+# endif
+#endif
+ JS_FN("adoptDebuggeeValue", Debugger::adoptDebuggeeValue, 1, 0),
+ JS_FS_END
+};
+
+const JSFunctionSpec Debugger::static_methods[] {
+ JS_FN("isCompilableUnit", Debugger::isCompilableUnit, 1, 0),
+ JS_FS_END
+};
+
+/*** Debugger.Script *****************************************************************************/
+
+// Get the Debugger.Script referent as bare Cell. This should only be used for
+// GC operations like tracing. Please use GetScriptReferent below.
+static inline gc::Cell*
+GetScriptReferentCell(JSObject* obj)
+{
+ MOZ_ASSERT(obj->getClass() == &DebuggerScript_class);
+ return static_cast<gc::Cell*>(obj->as<NativeObject>().getPrivate());
+}
+
+static inline DebuggerScriptReferent
+GetScriptReferent(JSObject* obj)
+{
+ MOZ_ASSERT(obj->getClass() == &DebuggerScript_class);
+ if (gc::Cell* cell = GetScriptReferentCell(obj)) {
+ if (cell->getTraceKind() == JS::TraceKind::Script)
+ return AsVariant(static_cast<JSScript*>(cell));
+ MOZ_ASSERT(cell->getTraceKind() == JS::TraceKind::Object);
+ return AsVariant(&static_cast<NativeObject*>(cell)->as<WasmInstanceObject>());
+ }
+ return AsVariant(static_cast<JSScript*>(nullptr));
+}
+
+void
+DebuggerScript_trace(JSTracer* trc, JSObject* obj)
+{
+ /* This comes from a private pointer, so no barrier needed. */
+ gc::Cell* cell = GetScriptReferentCell(obj);
+ if (cell) {
+ if (cell->getTraceKind() == JS::TraceKind::Script) {
+ JSScript* script = static_cast<JSScript*>(cell);
+ TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &script,
+ "Debugger.Script script referent");
+ obj->as<NativeObject>().setPrivateUnbarriered(script);
+ } else {
+ JSObject* wasm = static_cast<JSObject*>(cell);
+ TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &wasm,
+ "Debugger.Script wasm referent");
+ MOZ_ASSERT(wasm->is<WasmInstanceObject>());
+ obj->as<NativeObject>().setPrivateUnbarriered(wasm);
+ }
+ }
+}
+
+class DebuggerScriptSetPrivateMatcher
+{
+ NativeObject* obj_;
+ public:
+ explicit DebuggerScriptSetPrivateMatcher(NativeObject* obj) : obj_(obj) { }
+ using ReturnType = void;
+ ReturnType match(HandleScript script) { obj_->setPrivateGCThing(script); }
+ ReturnType match(Handle<WasmInstanceObject*> instance) { obj_->setPrivateGCThing(instance); }
+};
+
+NativeObject*
+Debugger::newDebuggerScript(JSContext* cx, Handle<DebuggerScriptReferent> referent)
+{
+ assertSameCompartment(cx, object.get());
+
+ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_SCRIPT_PROTO).toObject());
+ MOZ_ASSERT(proto);
+ NativeObject* scriptobj = NewNativeObjectWithGivenProto(cx, &DebuggerScript_class,
+ proto, TenuredObject);
+ if (!scriptobj)
+ return nullptr;
+ scriptobj->setReservedSlot(JSSLOT_DEBUGSCRIPT_OWNER, ObjectValue(*object));
+ DebuggerScriptSetPrivateMatcher matcher(scriptobj);
+ referent.match(matcher);
+
+ return scriptobj;
+}
+
+template <typename ReferentVariant, typename Referent, typename Map>
+JSObject*
+Debugger::wrapVariantReferent(JSContext* cx, Map& map, Handle<CrossCompartmentKey> key,
+ Handle<ReferentVariant> referent)
+{
+ assertSameCompartment(cx, object);
+
+ Handle<Referent> untaggedReferent = referent.template as<Referent>();
+ MOZ_ASSERT(cx->compartment() != untaggedReferent->compartment());
+
+ DependentAddPtr<Map> p(cx, map, untaggedReferent);
+ if (!p) {
+ NativeObject* wrapper = newVariantWrapper(cx, referent);
+ if (!wrapper)
+ return nullptr;
+
+ if (!p.add(cx, map, untaggedReferent, wrapper)) {
+ NukeDebuggerWrapper(wrapper);
+ return nullptr;
+ }
+
+ if (!object->compartment()->putWrapper(cx, key, ObjectValue(*wrapper))) {
+ NukeDebuggerWrapper(wrapper);
+ map.remove(untaggedReferent);
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ }
+
+ return p->value();
+}
+
+JSObject*
+Debugger::wrapVariantReferent(JSContext* cx, Handle<DebuggerScriptReferent> referent)
+{
+ JSObject* obj;
+ if (referent.is<JSScript*>()) {
+ Handle<JSScript*> untaggedReferent = referent.template as<JSScript*>();
+ Rooted<CrossCompartmentKey> key(cx, CrossCompartmentKey(object, untaggedReferent));
+ obj = wrapVariantReferent<DebuggerScriptReferent, JSScript*, ScriptWeakMap>(
+ cx, scripts, key, referent);
+ } else {
+ Handle<WasmInstanceObject*> untaggedReferent = referent.template as<WasmInstanceObject*>();
+ Rooted<CrossCompartmentKey> key(cx, CrossCompartmentKey(object, untaggedReferent,
+ CrossCompartmentKey::DebuggerObjectKind::DebuggerWasmScript));
+ obj = wrapVariantReferent<DebuggerScriptReferent, WasmInstanceObject*, WasmInstanceWeakMap>(
+ cx, wasmInstanceScripts, key, referent);
+ }
+ MOZ_ASSERT_IF(obj, GetScriptReferent(obj) == referent);
+ return obj;
+}
+
+JSObject*
+Debugger::wrapScript(JSContext* cx, HandleScript script)
+{
+ Rooted<DebuggerScriptReferent> referent(cx, script.get());
+ return wrapVariantReferent(cx, referent);
+}
+
+JSObject*
+Debugger::wrapWasmScript(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance)
+{
+ Rooted<DebuggerScriptReferent> referent(cx, wasmInstance.get());
+ return wrapVariantReferent(cx, referent);
+}
+
+static JSObject*
+DebuggerScript_check(JSContext* cx, const Value& v, const char* fnname)
+{
+ JSObject* thisobj = NonNullObject(cx, v);
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &DebuggerScript_class) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Script", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ /*
+ * Check for Debugger.Script.prototype, which is of class DebuggerScript_class
+ * but whose script is null.
+ */
+ if (!GetScriptReferentCell(thisobj)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Script", fnname, "prototype object");
+ return nullptr;
+ }
+
+ return thisobj;
+}
+
+template <typename ReferentT>
+static JSObject*
+DebuggerScript_checkThis(JSContext* cx, const CallArgs& args, const char* fnname,
+ const char* refname)
+{
+ JSObject* thisobj = DebuggerScript_check(cx, args.thisv(), fnname);
+ if (!thisobj)
+ return nullptr;
+
+ if (!GetScriptReferent(thisobj).is<ReferentT>()) {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
+ JSDVG_SEARCH_STACK, args.thisv(), nullptr,
+ refname, nullptr);
+ return nullptr;
+ }
+
+ return thisobj;
+}
+
+#define THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, fnname, args, obj, referent) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedObject obj(cx, DebuggerScript_check(cx, args.thisv(), fnname)); \
+ if (!obj) \
+ return false; \
+ Rooted<DebuggerScriptReferent> referent(cx, GetScriptReferent(obj))
+
+#define THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, fnname, args, obj, script) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedObject obj(cx, DebuggerScript_checkThis<JSScript*>(cx, args, fnname, \
+ "a JS script")); \
+ if (!obj) \
+ return false; \
+ RootedScript script(cx, GetScriptReferent(obj).as<JSScript*>())
+
+static bool
+DebuggerScript_getDisplayName(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get displayName)", args, obj, script);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ JSFunction* func = script->functionNonDelazifying();
+ JSString* name = func ? func->displayAtom() : nullptr;
+ if (!name) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedValue namev(cx, StringValue(name));
+ if (!dbg->wrapDebuggeeValue(cx, &namev))
+ return false;
+ args.rval().set(namev);
+ return true;
+}
+
+static bool
+DebuggerScript_getUrl(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get url)", args, obj, script);
+
+ if (script->filename()) {
+ JSString* str;
+ if (script->scriptSource()->introducerFilename())
+ str = NewStringCopyZ<CanGC>(cx, script->scriptSource()->introducerFilename());
+ else
+ str = NewStringCopyZ<CanGC>(cx, script->filename());
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+static bool
+DebuggerScript_getStartLine(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get startLine)", args, obj, script);
+ args.rval().setNumber(uint32_t(script->lineno()));
+ return true;
+}
+
+static bool
+DebuggerScript_getLineCount(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get lineCount)", args, obj, script);
+
+ unsigned maxLine = GetScriptLineExtent(script);
+ args.rval().setNumber(double(maxLine));
+ return true;
+}
+
+class DebuggerScriptGetSourceMatcher
+{
+ JSContext* cx_;
+ Debugger* dbg_;
+
+ public:
+ DebuggerScriptGetSourceMatcher(JSContext* cx, Debugger* dbg)
+ : cx_(cx), dbg_(dbg)
+ { }
+
+ using ReturnType = JSObject*;
+
+ ReturnType match(HandleScript script) {
+ RootedScriptSource source(cx_,
+ &UncheckedUnwrap(script->sourceObject())->as<ScriptSourceObject>());
+ return dbg_->wrapSource(cx_, source);
+ }
+
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return dbg_->wrapWasmSource(cx_, wasmInstance);
+ }
+};
+
+static bool
+DebuggerScript_getSource(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, "(get source)", args, obj, referent);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ DebuggerScriptGetSourceMatcher matcher(cx, dbg);
+ RootedObject sourceObject(cx, referent.match(matcher));
+ if (!sourceObject)
+ return false;
+
+ args.rval().setObject(*sourceObject);
+ return true;
+}
+
+static bool
+DebuggerScript_getSourceStart(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get sourceStart)", args, obj, script);
+ args.rval().setNumber(uint32_t(script->sourceStart()));
+ return true;
+}
+
+static bool
+DebuggerScript_getSourceLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get sourceEnd)", args, obj, script);
+ args.rval().setNumber(uint32_t(script->sourceEnd() - script->sourceStart()));
+ return true;
+}
+
+static bool
+DebuggerScript_getGlobal(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "(get global)", args, obj, script);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ RootedValue v(cx, ObjectValue(script->global()));
+ if (!dbg->wrapDebuggeeValue(cx, &v))
+ return false;
+ args.rval().set(v);
+ return true;
+}
+
+class DebuggerScriptGetFormatMatcher
+{
+ const JSAtomState& names_;
+ public:
+ explicit DebuggerScriptGetFormatMatcher(const JSAtomState& names) : names_(names) { }
+ using ReturnType = JSAtom*;
+ ReturnType match(HandleScript script) { return names_.js; }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return names_.wasm; }
+};
+
+static bool
+DebuggerScript_getFormat(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, "(get format)", args, obj, referent);
+ DebuggerScriptGetFormatMatcher matcher(cx->names());
+ args.rval().setString(referent.match(matcher));
+ return true;
+}
+
+static bool
+DebuggerScript_getChildScripts(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getChildScripts", args, obj, script);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ RootedObject result(cx, NewDenseEmptyArray(cx));
+ if (!result)
+ return false;
+ if (script->hasObjects()) {
+ /*
+ * script->savedCallerFun indicates that this is a direct eval script
+ * and the calling function is stored as script->objects()->vector[0].
+ * It is not really a child script of this script, so skip it using
+ * innerObjectsStart().
+ */
+ ObjectArray* objects = script->objects();
+ RootedFunction fun(cx);
+ RootedScript funScript(cx);
+ RootedObject obj(cx), s(cx);
+ for (uint32_t i = 0; i < objects->length; i++) {
+ obj = objects->vector[i];
+ if (obj->is<JSFunction>()) {
+ fun = &obj->as<JSFunction>();
+ // The inner function could be a wasm native.
+ if (fun->isNative())
+ continue;
+ funScript = GetOrCreateFunctionScript(cx, fun);
+ if (!funScript)
+ return false;
+ s = dbg->wrapScript(cx, funScript);
+ if (!s || !NewbornArrayPush(cx, result, ObjectValue(*s)))
+ return false;
+ }
+ }
+ }
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+ScriptOffset(JSContext* cx, JSScript* script, const Value& v, size_t* offsetp)
+{
+ double d;
+ size_t off;
+
+ bool ok = v.isNumber();
+ if (ok) {
+ d = v.toNumber();
+ off = size_t(d);
+ }
+ if (!ok || off != d || !IsValidBytecodeOffset(cx, script, off)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_OFFSET);
+ return false;
+ }
+ *offsetp = off;
+ return true;
+}
+
+namespace {
+
+class BytecodeRangeWithPosition : private BytecodeRange
+{
+ public:
+ using BytecodeRange::empty;
+ using BytecodeRange::frontPC;
+ using BytecodeRange::frontOpcode;
+ using BytecodeRange::frontOffset;
+
+ BytecodeRangeWithPosition(JSContext* cx, JSScript* script)
+ : BytecodeRange(cx, script), lineno(script->lineno()), column(0),
+ sn(script->notes()), snpc(script->code()), isEntryPoint(false),
+ wasArtifactEntryPoint(false)
+ {
+ if (!SN_IS_TERMINATOR(sn))
+ snpc += SN_DELTA(sn);
+ updatePosition();
+ while (frontPC() != script->main())
+ popFront();
+
+ if (frontOpcode() != JSOP_JUMPTARGET)
+ isEntryPoint = true;
+ else
+ wasArtifactEntryPoint = true;
+ }
+
+ void popFront() {
+ BytecodeRange::popFront();
+ if (empty())
+ isEntryPoint = false;
+ else
+ updatePosition();
+
+ // The following conditions are handling artifacts introduced by the
+ // bytecode emitter, such that we do not add breakpoints on empty
+ // statements of the source code of the user.
+ if (wasArtifactEntryPoint) {
+ wasArtifactEntryPoint = false;
+ isEntryPoint = true;
+ }
+
+ if (isEntryPoint && frontOpcode() == JSOP_JUMPTARGET) {
+ wasArtifactEntryPoint = isEntryPoint;
+ isEntryPoint = false;
+ }
+ }
+
+ size_t frontLineNumber() const { return lineno; }
+ size_t frontColumnNumber() const { return column; }
+
+ // Entry points are restricted to bytecode offsets that have an
+ // explicit mention in the line table. This restriction avoids a
+ // number of failing cases caused by some instructions not having
+ // sensible (to the user) line numbers, and it is one way to
+ // implement the idea that the bytecode emitter should tell the
+ // debugger exactly which offsets represent "interesting" (to the
+ // user) places to stop.
+ bool frontIsEntryPoint() const { return isEntryPoint; }
+
+ private:
+ void updatePosition() {
+ /*
+ * Determine the current line number by reading all source notes up to
+ * and including the current offset.
+ */
+ jsbytecode *lastLinePC = nullptr;
+ while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
+ SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
+ if (type == SRC_COLSPAN) {
+ ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
+ MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
+ column += colspan;
+ lastLinePC = snpc;
+ } else if (type == SRC_SETLINE) {
+ lineno = size_t(GetSrcNoteOffset(sn, 0));
+ column = 0;
+ lastLinePC = snpc;
+ } else if (type == SRC_NEWLINE) {
+ lineno++;
+ column = 0;
+ lastLinePC = snpc;
+ }
+
+ sn = SN_NEXT(sn);
+ snpc += SN_DELTA(sn);
+ }
+ isEntryPoint = lastLinePC == frontPC();
+ }
+
+ size_t lineno;
+ size_t column;
+ jssrcnote* sn;
+ jsbytecode* snpc;
+ bool isEntryPoint;
+ bool wasArtifactEntryPoint;
+};
+
+/*
+ * FlowGraphSummary::populate(cx, script) computes a summary of script's
+ * control flow graph used by DebuggerScript_{getAllOffsets,getLineOffsets}.
+ *
+ * An instruction on a given line is an entry point for that line if it can be
+ * reached from (an instruction on) a different line. We distinguish between the
+ * following cases:
+ * - hasNoEdges:
+ * The instruction cannot be reached, so the instruction is not an entry
+ * point for the line it is on.
+ * - hasSingleEdge:
+ * - hasMultipleEdgesFromSingleLine:
+ * The instruction can be reached from a single line. If this line is
+ * different from the line the instruction is on, the instruction is an
+ * entry point for that line.
+ * - hasMultipleEdgesFromMultipleLines:
+ * The instruction can be reached from multiple lines. At least one of
+ * these lines is guaranteed to be different from the line the instruction
+ * is on, so the instruction is an entry point for that line.
+ *
+ * Similarly, an instruction on a given position (line/column pair) is an
+ * entry point for that position if it can be reached from (an instruction on) a
+ * different position. Again, we distinguish between the following cases:
+ * - hasNoEdges:
+ * The instruction cannot be reached, so the instruction is not an entry
+ * point for the position it is on.
+ * - hasSingleEdge:
+ * The instruction can be reached from a single position. If this line is
+ * different from the position the instruction is on, the instruction is
+ * an entry point for that position.
+ * - hasMultipleEdgesFromSingleLine:
+ * - hasMultipleEdgesFromMultipleLines:
+ * The instruction can be reached from multiple positions. At least one
+ * of these positions is guaranteed to be different from the position the
+ * instruction is on, so the instruction is an entry point for that
+ * position.
+ */
+class FlowGraphSummary {
+ public:
+ class Entry {
+ public:
+ static Entry createWithNoEdges() {
+ return Entry(SIZE_MAX, 0);
+ }
+
+ static Entry createWithSingleEdge(size_t lineno, size_t column) {
+ return Entry(lineno, column);
+ }
+
+ static Entry createWithMultipleEdgesFromSingleLine(size_t lineno) {
+ return Entry(lineno, SIZE_MAX);
+ }
+
+ static Entry createWithMultipleEdgesFromMultipleLines() {
+ return Entry(SIZE_MAX, SIZE_MAX);
+ }
+
+ Entry() : lineno_(SIZE_MAX), column_(0) {}
+
+ bool hasNoEdges() const {
+ return lineno_ == SIZE_MAX && column_ != SIZE_MAX;
+ }
+
+ bool hasSingleEdge() const {
+ return lineno_ != SIZE_MAX && column_ != SIZE_MAX;
+ }
+
+ bool hasMultipleEdgesFromSingleLine() const {
+ return lineno_ != SIZE_MAX && column_ == SIZE_MAX;
+ }
+
+ bool hasMultipleEdgesFromMultipleLines() const {
+ return lineno_ == SIZE_MAX && column_ == SIZE_MAX;
+ }
+
+ bool operator==(const Entry& other) const {
+ return lineno_ == other.lineno_ && column_ == other.column_;
+ }
+
+ bool operator!=(const Entry& other) const {
+ return lineno_ != other.lineno_ || column_ != other.column_;
+ }
+
+ size_t lineno() const {
+ return lineno_;
+ }
+
+ size_t column() const {
+ return column_;
+ }
+
+ private:
+ Entry(size_t lineno, size_t column) : lineno_(lineno), column_(column) {}
+
+ size_t lineno_;
+ size_t column_;
+ };
+
+ explicit FlowGraphSummary(JSContext* cx) : entries_(cx) {}
+
+ Entry& operator[](size_t index) {
+ return entries_[index];
+ }
+
+ bool populate(JSContext* cx, JSScript* script) {
+ if (!entries_.growBy(script->length()))
+ return false;
+ unsigned mainOffset = script->pcToOffset(script->main());
+ entries_[mainOffset] = Entry::createWithMultipleEdgesFromMultipleLines();
+
+ size_t prevLineno = script->lineno();
+ size_t prevColumn = 0;
+ JSOp prevOp = JSOP_NOP;
+ for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
+ size_t lineno = prevLineno;
+ size_t column = prevColumn;
+ JSOp op = r.frontOpcode();
+
+ if (FlowsIntoNext(prevOp))
+ addEdge(prevLineno, prevColumn, r.frontOffset());
+
+ if (BytecodeIsJumpTarget(op)) {
+ lineno = entries_[r.frontOffset()].lineno();
+ column = entries_[r.frontOffset()].column();
+ }
+
+ if (r.frontIsEntryPoint()) {
+ lineno = r.frontLineNumber();
+ column = r.frontColumnNumber();
+ }
+
+ if (CodeSpec[op].type() == JOF_JUMP) {
+ addEdge(lineno, column, r.frontOffset() + GET_JUMP_OFFSET(r.frontPC()));
+ } else if (op == JSOP_TABLESWITCH) {
+ jsbytecode* pc = r.frontPC();
+ size_t offset = r.frontOffset();
+ ptrdiff_t step = JUMP_OFFSET_LEN;
+ size_t defaultOffset = offset + GET_JUMP_OFFSET(pc);
+ pc += step;
+ addEdge(lineno, column, defaultOffset);
+
+ int32_t low = GET_JUMP_OFFSET(pc);
+ pc += JUMP_OFFSET_LEN;
+ int ncases = GET_JUMP_OFFSET(pc) - low + 1;
+ pc += JUMP_OFFSET_LEN;
+
+ for (int i = 0; i < ncases; i++) {
+ size_t target = offset + GET_JUMP_OFFSET(pc);
+ addEdge(lineno, column, target);
+ pc += step;
+ }
+ } else if (op == JSOP_TRY) {
+ // As there is no literal incoming edge into the catch block, we
+ // make a fake one by copying the JSOP_TRY location, as-if this
+ // was an incoming edge of the catch block. This is needed
+ // because we only report offsets of entry points which have
+ // valid incoming edges.
+ JSTryNote* tn = script->trynotes()->vector;
+ JSTryNote* tnlimit = tn + script->trynotes()->length;
+ for (; tn < tnlimit; tn++) {
+ uint32_t startOffset = script->mainOffset() + tn->start;
+ if (startOffset == r.frontOffset() + 1) {
+ uint32_t catchOffset = startOffset + tn->length;
+ if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY)
+ addEdge(lineno, column, catchOffset);
+ }
+ }
+ }
+
+ prevLineno = lineno;
+ prevColumn = column;
+ prevOp = op;
+ }
+
+ return true;
+ }
+
+ private:
+ void addEdge(size_t sourceLineno, size_t sourceColumn, size_t targetOffset) {
+ if (entries_[targetOffset].hasNoEdges())
+ entries_[targetOffset] = Entry::createWithSingleEdge(sourceLineno, sourceColumn);
+ else if (entries_[targetOffset].lineno() != sourceLineno)
+ entries_[targetOffset] = Entry::createWithMultipleEdgesFromMultipleLines();
+ else if (entries_[targetOffset].column() != sourceColumn)
+ entries_[targetOffset] = Entry::createWithMultipleEdgesFromSingleLine(sourceLineno);
+ }
+
+ Vector<Entry> entries_;
+};
+
+} /* anonymous namespace */
+
+static bool
+DebuggerScript_getOffsetLocation(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getOffsetLocation", args, obj, script);
+ if (!args.requireAtLeast(cx, "Debugger.Script.getOffsetLocation", 1))
+ return false;
+ size_t offset;
+ if (!ScriptOffset(cx, script, args[0], &offset))
+ return false;
+
+ FlowGraphSummary flowData(cx);
+ if (!flowData.populate(cx, script))
+ return false;
+
+ RootedPlainObject result(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!result)
+ return false;
+
+ BytecodeRangeWithPosition r(cx, script);
+ while (!r.empty() && r.frontOffset() < offset)
+ r.popFront();
+
+ offset = r.frontOffset();
+ bool isEntryPoint = r.frontIsEntryPoint();
+
+ // Line numbers are only correctly defined on entry points. Thus looks
+ // either for the next valid offset in the flowData, being the last entry
+ // point flowing into the current offset, or for the next valid entry point.
+ while (!r.frontIsEntryPoint() && !flowData[r.frontOffset()].hasSingleEdge()) {
+ r.popFront();
+ MOZ_ASSERT(!r.empty());
+ }
+
+ // If this is an entry point, take the line number associated with the entry
+ // point, otherwise settle on the next instruction and take the incoming
+ // edge position.
+ size_t lineno;
+ size_t column;
+ if (r.frontIsEntryPoint()) {
+ lineno = r.frontLineNumber();
+ column = r.frontColumnNumber();
+ } else {
+ MOZ_ASSERT(flowData[r.frontOffset()].hasSingleEdge());
+ lineno = flowData[r.frontOffset()].lineno();
+ column = flowData[r.frontOffset()].column();
+ }
+
+ RootedId id(cx, NameToId(cx->names().lineNumber));
+ RootedValue value(cx, NumberValue(lineno));
+ if (!DefineProperty(cx, result, id, value))
+ return false;
+
+ value = NumberValue(column);
+ if (!DefineProperty(cx, result, cx->names().columnNumber, value))
+ return false;
+
+ // The same entry point test that is used by getAllColumnOffsets.
+ isEntryPoint = (isEntryPoint &&
+ !flowData[offset].hasNoEdges() &&
+ (flowData[offset].lineno() != r.frontLineNumber() ||
+ flowData[offset].column() != r.frontColumnNumber()));
+ value.setBoolean(isEntryPoint);
+ if (!DefineProperty(cx, result, cx->names().isEntryPoint, value))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+DebuggerScript_getAllOffsets(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getAllOffsets", args, obj, script);
+
+ /*
+ * First pass: determine which offsets in this script are jump targets and
+ * which line numbers jump to them.
+ */
+ FlowGraphSummary flowData(cx);
+ if (!flowData.populate(cx, script))
+ return false;
+
+ /* Second pass: build the result array. */
+ RootedObject result(cx, NewDenseEmptyArray(cx));
+ if (!result)
+ return false;
+ for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
+ if (!r.frontIsEntryPoint())
+ continue;
+
+ size_t offset = r.frontOffset();
+ size_t lineno = r.frontLineNumber();
+
+ /* Make a note, if the current instruction is an entry point for the current line. */
+ if (!flowData[offset].hasNoEdges() && flowData[offset].lineno() != lineno) {
+ /* Get the offsets array for this line. */
+ RootedObject offsets(cx);
+ RootedValue offsetsv(cx);
+
+ RootedId id(cx, INT_TO_JSID(lineno));
+
+ bool found;
+ if (!HasOwnProperty(cx, result, id, &found))
+ return false;
+ if (found && !GetProperty(cx, result, result, id, &offsetsv))
+ return false;
+
+ if (offsetsv.isObject()) {
+ offsets = &offsetsv.toObject();
+ } else {
+ MOZ_ASSERT(offsetsv.isUndefined());
+
+ /*
+ * Create an empty offsets array for this line.
+ * Store it in the result array.
+ */
+ RootedId id(cx);
+ RootedValue v(cx, NumberValue(lineno));
+ offsets = NewDenseEmptyArray(cx);
+ if (!offsets ||
+ !ValueToId<CanGC>(cx, v, &id))
+ {
+ return false;
+ }
+
+ RootedValue value(cx, ObjectValue(*offsets));
+ if (!DefineProperty(cx, result, id, value))
+ return false;
+ }
+
+ /* Append the current offset to the offsets array. */
+ if (!NewbornArrayPush(cx, offsets, NumberValue(offset)))
+ return false;
+ }
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+DebuggerScript_getAllColumnOffsets(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getAllColumnOffsets", args, obj, script);
+
+ /*
+ * First pass: determine which offsets in this script are jump targets and
+ * which positions jump to them.
+ */
+ FlowGraphSummary flowData(cx);
+ if (!flowData.populate(cx, script))
+ return false;
+
+ /* Second pass: build the result array. */
+ RootedObject result(cx, NewDenseEmptyArray(cx));
+ if (!result)
+ return false;
+ for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
+ size_t lineno = r.frontLineNumber();
+ size_t column = r.frontColumnNumber();
+ size_t offset = r.frontOffset();
+
+ /* Make a note, if the current instruction is an entry point for the current position. */
+ if (r.frontIsEntryPoint() &&
+ !flowData[offset].hasNoEdges() &&
+ (flowData[offset].lineno() != lineno ||
+ flowData[offset].column() != column)) {
+ RootedPlainObject entry(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!entry)
+ return false;
+
+ RootedId id(cx, NameToId(cx->names().lineNumber));
+ RootedValue value(cx, NumberValue(lineno));
+ if (!DefineProperty(cx, entry, id, value))
+ return false;
+
+ value = NumberValue(column);
+ if (!DefineProperty(cx, entry, cx->names().columnNumber, value))
+ return false;
+
+ id = NameToId(cx->names().offset);
+ value = NumberValue(offset);
+ if (!DefineProperty(cx, entry, id, value))
+ return false;
+
+ if (!NewbornArrayPush(cx, result, ObjectValue(*entry)))
+ return false;
+ }
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+class DebuggerScriptGetLineOffsetsMatcher
+{
+ JSContext* cx_;
+ size_t lineno_;
+ RootedObject result_;
+
+ public:
+ explicit DebuggerScriptGetLineOffsetsMatcher(JSContext* cx, size_t lineno)
+ : cx_(cx), lineno_(lineno), result_(cx, NewDenseEmptyArray(cx)) { }
+ using ReturnType = bool;
+ ReturnType match(HandleScript script) {
+ if (!result_)
+ return false;
+
+ /*
+ * First pass: determine which offsets in this script are jump targets and
+ * which line numbers jump to them.
+ */
+ FlowGraphSummary flowData(cx_);
+ if (!flowData.populate(cx_, script))
+ return false;
+
+ /* Second pass: build the result array. */
+ for (BytecodeRangeWithPosition r(cx_, script); !r.empty(); r.popFront()) {
+ if (!r.frontIsEntryPoint())
+ continue;
+
+ size_t offset = r.frontOffset();
+
+ /* If the op at offset is an entry point, append offset to result. */
+ if (r.frontLineNumber() == lineno_ &&
+ !flowData[offset].hasNoEdges() &&
+ flowData[offset].lineno() != lineno_)
+ {
+ if (!NewbornArrayPush(cx_, result_, NumberValue(offset)))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ ReturnType match(Handle<WasmInstanceObject*> instance) {
+ if (!result_)
+ return false;
+
+ Vector<uint32_t> offsets(cx_);
+ if (!instance->instance().code().getLineOffsets(lineno_, offsets))
+ return false;
+ for (uint32_t i = 0; i < offsets.length(); i++) {
+ if (!NewbornArrayPush(cx_, result_, NumberValue(offsets[i])))
+ return false;
+ }
+ return true;
+ }
+
+ RootedObject& result() { return result_; }
+};
+
+static bool
+DebuggerScript_getLineOffsets(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_REFERENT(cx, argc, vp, "getLineOffsets", args, obj, referent);
+ if (!args.requireAtLeast(cx, "Debugger.Script.getLineOffsets", 1))
+ return false;
+
+ /* Parse lineno argument. */
+ RootedValue linenoValue(cx, args[0]);
+ size_t lineno;
+ if (!ToNumber(cx, &linenoValue))
+ return false;
+ {
+ double d = linenoValue.toNumber();
+ lineno = size_t(d);
+ if (lineno != d) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_LINE);
+ return false;
+ }
+ }
+
+ DebuggerScriptGetLineOffsetsMatcher matcher(cx, lineno);
+ if (!referent.match(matcher))
+ return false;
+
+ args.rval().setObject(*matcher.result());
+ return true;
+}
+
+bool
+Debugger::observesFrame(AbstractFramePtr frame) const
+{
+ return observesScript(frame.script());
+}
+
+bool
+Debugger::observesFrame(const FrameIter& iter) const
+{
+ // Skip frames not yet fully initialized during their prologue.
+ if (iter.isInterp() && iter.isFunctionFrame()) {
+ const Value& thisVal = iter.interpFrame()->thisArgument();
+ if (thisVal.isMagic() && thisVal.whyMagic() == JS_IS_CONSTRUCTING)
+ return false;
+ }
+ if (iter.isWasm())
+ return false;
+ return observesScript(iter.script());
+}
+
+bool
+Debugger::observesScript(JSScript* script) const
+{
+ if (!enabled)
+ return false;
+ // Don't ever observe self-hosted scripts: the Debugger API can break
+ // self-hosted invariants.
+ return observesGlobal(&script->global()) && !script->selfHosted();
+}
+
+/* static */ bool
+Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to,
+ ScriptFrameIter& iter)
+{
+ auto removeFromDebuggerFramesOnExit = MakeScopeExit([&] {
+ // Remove any remaining old entries on exit, as the 'from' frame will
+ // be gone. This is only done in the failure case. On failure, the
+ // removeToDebuggerFramesOnExit lambda below will rollback any frames
+ // that were replaced, resulting in !frameMaps(to). On success, the
+ // range will be empty, as all from Frame.Debugger instances will have
+ // been removed.
+ MOZ_ASSERT_IF(inFrameMaps(to), !inFrameMaps(from));
+ removeFromFrameMapsAndClearBreakpointsIn(cx, from);
+
+ // Rekey missingScopes to maintain Debugger.Environment identity and
+ // forward liveScopes to point to the new frame.
+ DebugEnvironments::forwardLiveFrame(cx, from, to);
+ });
+
+ // Forward live Debugger.Frame objects.
+ Rooted<DebuggerFrameVector> frames(cx, DebuggerFrameVector(cx));
+ if (!getDebuggerFrames(from, &frames)) {
+ // An OOM here means that all Debuggers' frame maps still contain
+ // entries for 'from' and no entries for 'to'. Since the 'from' frame
+ // will be gone, they are removed by removeFromDebuggerFramesOnExit
+ // above.
+ return false;
+ }
+
+ // If during the loop below we hit an OOM, we must also rollback any of
+ // the frames that were successfully replaced. For OSR frames, OOM here
+ // means those frames will pop from the OSR trampoline, which does not
+ // call Debugger::onLeaveFrame.
+ auto removeToDebuggerFramesOnExit = MakeScopeExit([&] {
+ removeFromFrameMapsAndClearBreakpointsIn(cx, to);
+ });
+
+ for (size_t i = 0; i < frames.length(); i++) {
+ HandleDebuggerFrame frameobj = frames[i];
+ Debugger* dbg = Debugger::fromChildJSObject(frameobj);
+
+ // Update frame object's ScriptFrameIter::data pointer.
+ DebuggerFrame_freeScriptFrameIterData(cx->runtime()->defaultFreeOp(), frameobj);
+ ScriptFrameIter::Data* data = iter.copyData();
+ if (!data) {
+ // An OOM here means that some Debuggers' frame maps may still
+ // contain entries for 'from' and some Debuggers' frame maps may
+ // also contain entries for 'to'. Thus both
+ // removeFromDebuggerFramesOnExit and
+ // removeToDebuggerFramesOnExit must both run.
+ //
+ // The current frameobj in question is still in its Debugger's
+ // frame map keyed by 'from', so it will be covered by
+ // removeFromDebuggerFramesOnExit.
+ return false;
+ }
+ frameobj->setPrivate(data);
+
+ // Remove old frame.
+ dbg->frames.remove(from);
+
+ // Add the frame object with |to| as key.
+ if (!dbg->frames.putNew(to, frameobj)) {
+ // This OOM is subtle. At this point, both
+ // removeFromDebuggerFramesOnExit and removeToDebuggerFramesOnExit
+ // must both run for the same reason given above.
+ //
+ // The difference is that the current frameobj is no longer in its
+ // Debugger's frame map, so it will not be cleaned up by neither
+ // lambda. Manually clean it up here.
+ FreeOp* fop = cx->runtime()->defaultFreeOp();
+ DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
+ DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, to, frameobj);
+
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ // All frames successfuly replaced, cancel the rollback.
+ removeToDebuggerFramesOnExit.release();
+
+ return true;
+}
+
+/* static */ bool
+Debugger::inFrameMaps(AbstractFramePtr frame)
+{
+ bool foundAny = false;
+ forEachDebuggerFrame(frame, [&](NativeObject* frameobj) { foundAny = true; });
+ return foundAny;
+}
+
+/* static */ void
+Debugger::removeFromFrameMapsAndClearBreakpointsIn(JSContext* cx, AbstractFramePtr frame)
+{
+ forEachDebuggerFrame(frame, [&](NativeObject* frameobj) {
+ Debugger* dbg = Debugger::fromChildJSObject(frameobj);
+
+ FreeOp* fop = cx->runtime()->defaultFreeOp();
+ DebuggerFrame_freeScriptFrameIterData(fop, frameobj);
+ DebuggerFrame_maybeDecrementFrameScriptStepModeCount(fop, frame, frameobj);
+
+ dbg->frames.remove(frame);
+ });
+
+ /*
+ * If this is an eval frame, then from the debugger's perspective the
+ * script is about to be destroyed. Remove any breakpoints in it.
+ */
+ if (frame.isEvalFrame()) {
+ RootedScript script(cx, frame.script());
+ script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), nullptr, nullptr);
+ }
+}
+
+/* static */ bool
+Debugger::handleBaselineOsr(JSContext* cx, InterpreterFrame* from, jit::BaselineFrame* to)
+{
+ ScriptFrameIter iter(cx);
+ MOZ_ASSERT(iter.abstractFramePtr() == to);
+ return replaceFrameGuts(cx, from, to, iter);
+}
+
+/* static */ bool
+Debugger::handleIonBailout(JSContext* cx, jit::RematerializedFrame* from, jit::BaselineFrame* to)
+{
+ // When we return to a bailed-out Ion real frame, we must update all
+ // Debugger.Frames that refer to its inline frames. However, since we
+ // can't pop individual inline frames off the stack (we can only pop the
+ // real frame that contains them all, as a unit), we cannot assume that
+ // the frame we're dealing with is the top frame. Advance the iterator
+ // across any inlined frames younger than |to|, the baseline frame
+ // reconstructed during bailout from the Ion frame corresponding to
+ // |from|.
+ ScriptFrameIter iter(cx);
+ while (iter.abstractFramePtr() != to)
+ ++iter;
+ return replaceFrameGuts(cx, from, to, iter);
+}
+
+/* static */ void
+Debugger::handleUnrecoverableIonBailoutError(JSContext* cx, jit::RematerializedFrame* frame)
+{
+ // Ion bailout can fail due to overrecursion. In such cases we cannot
+ // honor any further Debugger hooks on the frame, and need to ensure that
+ // its Debugger.Frame entry is cleaned up.
+ removeFromFrameMapsAndClearBreakpointsIn(cx, frame);
+}
+
+/* static */ void
+Debugger::propagateForcedReturn(JSContext* cx, AbstractFramePtr frame, HandleValue rval)
+{
+ // Invoking the interrupt handler is considered a step and invokes the
+ // youngest frame's onStep handler, if any. However, we cannot handle
+ // { return: ... } resumption values straightforwardly from the interrupt
+ // handler. Instead, we set the intended return value in the frame's rval
+ // slot and set the propagating-forced-return flag on the JSContext.
+ //
+ // The interrupt handler then returns false with no exception set,
+ // signaling an uncatchable exception. In the exception handlers, we then
+ // check for the special propagating-forced-return flag.
+ MOZ_ASSERT(!cx->isExceptionPending());
+ cx->setPropagatingForcedReturn();
+ frame.setReturnValue(rval);
+}
+
+static bool
+DebuggerScript_setBreakpoint(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script);
+ if (!args.requireAtLeast(cx, "Debugger.Script.setBreakpoint", 2))
+ return false;
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ if (!dbg->observesScript(script)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_DEBUGGING);
+ return false;
+ }
+
+ size_t offset;
+ if (!ScriptOffset(cx, script, args[0], &offset))
+ return false;
+
+ RootedObject handler(cx, NonNullObject(cx, args[1]));
+ if (!handler)
+ return false;
+
+ // Ensure observability *before* setting the breakpoint. If the script is
+ // not already a debuggee, trying to ensure observability after setting
+ // the breakpoint (and thus marking the script as a debuggee) will skip
+ // actually ensuring observability.
+ if (!dbg->ensureExecutionObservabilityOfScript(cx, script))
+ return false;
+
+ jsbytecode* pc = script->offsetToPC(offset);
+ BreakpointSite* site = script->getOrCreateBreakpointSite(cx, pc);
+ if (!site)
+ return false;
+ site->inc(cx->runtime()->defaultFreeOp());
+ if (cx->runtime()->new_<Breakpoint>(dbg, site, handler)) {
+ args.rval().setUndefined();
+ return true;
+ }
+ site->dec(cx->runtime()->defaultFreeOp());
+ site->destroyIfEmpty(cx->runtime()->defaultFreeOp());
+ return false;
+}
+
+static bool
+DebuggerScript_getBreakpoints(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getBreakpoints", args, obj, script);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ jsbytecode* pc;
+ if (args.length() > 0) {
+ size_t offset;
+ if (!ScriptOffset(cx, script, args[0], &offset))
+ return false;
+ pc = script->offsetToPC(offset);
+ } else {
+ pc = nullptr;
+ }
+
+ RootedObject arr(cx, NewDenseEmptyArray(cx));
+ if (!arr)
+ return false;
+
+ for (unsigned i = 0; i < script->length(); i++) {
+ BreakpointSite* site = script->getBreakpointSite(script->offsetToPC(i));
+ if (site && (!pc || site->pc == pc)) {
+ for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = bp->nextInSite()) {
+ if (bp->debugger == dbg &&
+ !NewbornArrayPush(cx, arr, ObjectValue(*bp->getHandler())))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ args.rval().setObject(*arr);
+ return true;
+}
+
+static bool
+DebuggerScript_clearBreakpoint(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
+ if (!args.requireAtLeast(cx, "Debugger.Script.clearBreakpoint", 1))
+ return false;
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+
+ JSObject* handler = NonNullObject(cx, args[0]);
+ if (!handler)
+ return false;
+
+ script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), dbg, handler);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+DebuggerScript_clearAllBreakpoints(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearAllBreakpoints", args, obj, script);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+ script->clearBreakpointsIn(cx->runtime()->defaultFreeOp(), dbg, nullptr);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+DebuggerScript_isInCatchScope(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "isInCatchScope", args, obj, script);
+ if (!args.requireAtLeast(cx, "Debugger.Script.isInCatchScope", 1))
+ return false;
+
+ size_t offset;
+ if (!ScriptOffset(cx, script, args[0], &offset))
+ return false;
+
+ /*
+ * Try note ranges are relative to the mainOffset of the script, so adjust
+ * offset accordingly.
+ */
+ offset -= script->mainOffset();
+
+ args.rval().setBoolean(false);
+ if (script->hasTrynotes()) {
+ JSTryNote* tnBegin = script->trynotes()->vector;
+ JSTryNote* tnEnd = tnBegin + script->trynotes()->length;
+ while (tnBegin != tnEnd) {
+ if (tnBegin->start <= offset &&
+ offset <= tnBegin->start + tnBegin->length &&
+ tnBegin->kind == JSTRY_CATCH)
+ {
+ args.rval().setBoolean(true);
+ break;
+ }
+ ++tnBegin;
+ }
+ }
+ return true;
+}
+
+static bool
+DebuggerScript_getOffsetsCoverage(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getOffsetsCoverage", args, obj, script);
+
+ // If the script has no coverage information, then skip this and return null
+ // instead.
+ if (!script->hasScriptCounts()) {
+ args.rval().setNull();
+ return true;
+ }
+
+ ScriptCounts* sc = &script->getScriptCounts();
+
+ // If the main ever got visited, then assume that any code before main got
+ // visited once.
+ uint64_t hits = 0;
+ const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(script->main()));
+ if (counts->numExec())
+ hits = 1;
+
+ // Build an array of objects which are composed of 4 properties:
+ // - offset PC offset of the current opcode.
+ // - lineNumber Line of the current opcode.
+ // - columnNumber Column of the current opcode.
+ // - count Number of times the instruction got executed.
+ RootedObject result(cx, NewDenseEmptyArray(cx));
+ if (!result)
+ return false;
+
+ RootedId offsetId(cx, AtomToId(cx->names().offset));
+ RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber));
+ RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber));
+ RootedId countId(cx, AtomToId(cx->names().count));
+
+ RootedObject item(cx);
+ RootedValue offsetValue(cx);
+ RootedValue lineNumberValue(cx);
+ RootedValue columnNumberValue(cx);
+ RootedValue countValue(cx);
+
+ // Iterate linearly over the bytecode.
+ for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
+ size_t offset = r.frontOffset();
+
+ // The beginning of each non-branching sequences of instruction set the
+ // number of execution of the current instruction and any following
+ // instruction.
+ counts = sc->maybeGetPCCounts(offset);
+ if (counts)
+ hits = counts->numExec();
+
+ offsetValue.setNumber(double(offset));
+ lineNumberValue.setNumber(double(r.frontLineNumber()));
+ columnNumberValue.setNumber(double(r.frontColumnNumber()));
+ countValue.setNumber(double(hits));
+
+ // Create a new object with the offset, line number, column number, the
+ // number of hit counts, and append it to the array.
+ item = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
+ if (!item ||
+ !DefineProperty(cx, item, offsetId, offsetValue) ||
+ !DefineProperty(cx, item, lineNumberId, lineNumberValue) ||
+ !DefineProperty(cx, item, columnNumberId, columnNumberValue) ||
+ !DefineProperty(cx, item, countId, countValue) ||
+ !NewbornArrayPush(cx, result, ObjectValue(*item)))
+ {
+ return false;
+ }
+
+ // If the current instruction has thrown, then decrement the hit counts
+ // with the number of throws.
+ counts = sc->maybeGetThrowCounts(offset);
+ if (counts)
+ hits -= counts->numExec();
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+DebuggerScript_construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Script");
+ return false;
+}
+
+static const JSPropertySpec DebuggerScript_properties[] = {
+ JS_PSG("displayName", DebuggerScript_getDisplayName, 0),
+ JS_PSG("url", DebuggerScript_getUrl, 0),
+ JS_PSG("startLine", DebuggerScript_getStartLine, 0),
+ JS_PSG("lineCount", DebuggerScript_getLineCount, 0),
+ JS_PSG("source", DebuggerScript_getSource, 0),
+ JS_PSG("sourceStart", DebuggerScript_getSourceStart, 0),
+ JS_PSG("sourceLength", DebuggerScript_getSourceLength, 0),
+ JS_PSG("global", DebuggerScript_getGlobal, 0),
+ JS_PSG("format", DebuggerScript_getFormat, 0),
+ JS_PS_END
+};
+
+static const JSFunctionSpec DebuggerScript_methods[] = {
+ JS_FN("getChildScripts", DebuggerScript_getChildScripts, 0, 0),
+ JS_FN("getAllOffsets", DebuggerScript_getAllOffsets, 0, 0),
+ JS_FN("getAllColumnOffsets", DebuggerScript_getAllColumnOffsets, 0, 0),
+ JS_FN("getLineOffsets", DebuggerScript_getLineOffsets, 1, 0),
+ JS_FN("getOffsetLocation", DebuggerScript_getOffsetLocation, 0, 0),
+ JS_FN("setBreakpoint", DebuggerScript_setBreakpoint, 2, 0),
+ JS_FN("getBreakpoints", DebuggerScript_getBreakpoints, 1, 0),
+ JS_FN("clearBreakpoint", DebuggerScript_clearBreakpoint, 1, 0),
+ JS_FN("clearAllBreakpoints", DebuggerScript_clearAllBreakpoints, 0, 0),
+ JS_FN("isInCatchScope", DebuggerScript_isInCatchScope, 1, 0),
+ JS_FN("getOffsetsCoverage", DebuggerScript_getOffsetsCoverage, 0, 0),
+ JS_FS_END
+};
+
+
+/*** Debugger.Source *****************************************************************************/
+
+// For internal use only.
+static inline NativeObject*
+GetSourceReferentRawObject(JSObject* obj)
+{
+ MOZ_ASSERT(obj->getClass() == &DebuggerSource_class);
+ return static_cast<NativeObject*>(obj->as<NativeObject>().getPrivate());
+}
+
+static inline DebuggerSourceReferent
+GetSourceReferent(JSObject* obj)
+{
+ if (NativeObject* referent = GetSourceReferentRawObject(obj)) {
+ if (referent->is<ScriptSourceObject>())
+ return AsVariant(&referent->as<ScriptSourceObject>());
+ return AsVariant(&referent->as<WasmInstanceObject>());
+ }
+ return AsVariant(static_cast<ScriptSourceObject*>(nullptr));
+}
+
+void
+DebuggerSource_trace(JSTracer* trc, JSObject* obj)
+{
+ /*
+ * There is a barrier on private pointers, so the Unbarriered marking
+ * is okay.
+ */
+ if (JSObject *referent = GetSourceReferentRawObject(obj)) {
+ TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+ "Debugger.Source referent");
+ obj->as<NativeObject>().setPrivateUnbarriered(referent);
+ }
+}
+
+class SetDebuggerSourcePrivateMatcher
+{
+ NativeObject* obj_;
+ public:
+ explicit SetDebuggerSourcePrivateMatcher(NativeObject* obj) : obj_(obj) { }
+ using ReturnType = void;
+ ReturnType match(HandleScriptSource source) { obj_->setPrivateGCThing(source); }
+ ReturnType match(Handle<WasmInstanceObject*> instance) { obj_->setPrivateGCThing(instance); }
+};
+
+NativeObject*
+Debugger::newDebuggerSource(JSContext* cx, Handle<DebuggerSourceReferent> referent)
+{
+ assertSameCompartment(cx, object.get());
+
+ RootedObject proto(cx, &object->getReservedSlot(JSSLOT_DEBUG_SOURCE_PROTO).toObject());
+ MOZ_ASSERT(proto);
+ NativeObject* sourceobj = NewNativeObjectWithGivenProto(cx, &DebuggerSource_class,
+ proto, TenuredObject);
+ if (!sourceobj)
+ return nullptr;
+ sourceobj->setReservedSlot(JSSLOT_DEBUGSOURCE_OWNER, ObjectValue(*object));
+ SetDebuggerSourcePrivateMatcher matcher(sourceobj);
+ referent.match(matcher);
+
+ return sourceobj;
+}
+
+JSObject*
+Debugger::wrapVariantReferent(JSContext* cx, Handle<DebuggerSourceReferent> referent)
+{
+ JSObject* obj;
+ if (referent.is<ScriptSourceObject*>()) {
+ Handle<ScriptSourceObject*> untaggedReferent = referent.template as<ScriptSourceObject*>();
+ Rooted<CrossCompartmentKey> key(cx, CrossCompartmentKey(object, untaggedReferent,
+ CrossCompartmentKey::DebuggerObjectKind::DebuggerSource));
+ obj = wrapVariantReferent<DebuggerSourceReferent, ScriptSourceObject*, SourceWeakMap>(
+ cx, sources, key, referent);
+ } else {
+ Handle<WasmInstanceObject*> untaggedReferent = referent.template as<WasmInstanceObject*>();
+ Rooted<CrossCompartmentKey> key(cx, CrossCompartmentKey(object, untaggedReferent,
+ CrossCompartmentKey::DebuggerObjectKind::DebuggerWasmSource));
+ obj = wrapVariantReferent<DebuggerSourceReferent, WasmInstanceObject*, WasmInstanceWeakMap>(
+ cx, wasmInstanceSources, key, referent);
+ }
+ MOZ_ASSERT_IF(obj, GetSourceReferent(obj) == referent);
+ return obj;
+}
+
+JSObject*
+Debugger::wrapSource(JSContext* cx, HandleScriptSource source)
+{
+ Rooted<DebuggerSourceReferent> referent(cx, source.get());
+ return wrapVariantReferent(cx, referent);
+}
+
+JSObject*
+Debugger::wrapWasmSource(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance)
+{
+ Rooted<DebuggerSourceReferent> referent(cx, wasmInstance.get());
+ return wrapVariantReferent(cx, referent);
+}
+
+static bool
+DebuggerSource_construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Source");
+ return false;
+}
+
+static NativeObject*
+DebuggerSource_check(JSContext* cx, HandleValue thisv, const char* fnname)
+{
+ JSObject* thisobj = NonNullObject(cx, thisv);
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &DebuggerSource_class) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Source", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ NativeObject* nthisobj = &thisobj->as<NativeObject>();
+
+ if (!GetSourceReferentRawObject(thisobj)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Source", fnname, "prototype object");
+ return nullptr;
+ }
+
+ return nthisobj;
+}
+
+template <typename ReferentT>
+static NativeObject*
+DebuggerSource_checkThis(JSContext* cx, const CallArgs& args, const char* fnname,
+ const char* refname)
+{
+ NativeObject* thisobj = DebuggerSource_check(cx, args.thisv(), fnname);
+ if (!thisobj)
+ return nullptr;
+
+ if (!GetSourceReferent(thisobj).is<ReferentT>()) {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
+ JSDVG_SEARCH_STACK, args.thisv(), nullptr,
+ refname, nullptr);
+ return nullptr;
+ }
+
+ return thisobj;
+}
+
+#define THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, fnname, args, obj, referent) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedNativeObject obj(cx, DebuggerSource_check(cx, args.thisv(), fnname)); \
+ if (!obj) \
+ return false; \
+ Rooted<DebuggerSourceReferent> referent(cx, GetSourceReferent(obj))
+
+#define THIS_DEBUGSOURCE_SOURCE(cx, argc, vp, fnname, args, obj, sourceObject) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedNativeObject obj(cx, \
+ DebuggerSource_checkThis<ScriptSourceObject*>(cx, args, fnname, \
+ "a JS source")); \
+ if (!obj) \
+ return false; \
+ RootedScriptSource sourceObject(cx, GetSourceReferent(obj).as<ScriptSourceObject*>())
+
+class DebuggerSourceGetTextMatcher
+{
+ JSContext* cx_;
+
+ public:
+ explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) { }
+
+ using ReturnType = JSString*;
+
+ ReturnType match(HandleScriptSource sourceObject) {
+ ScriptSource* ss = sourceObject->source();
+ bool hasSourceData = ss->hasSourceData();
+ if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData))
+ return nullptr;
+ return hasSourceData ? ss->substring(cx_, 0, ss->length())
+ : NewStringCopyZ<CanGC>(cx_, "[no source]");
+ }
+
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return wasmInstance->instance().code().createText(cx_);
+ }
+};
+
+static bool
+DebuggerSource_getText(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get text)", args, obj, referent);
+ Value textv = obj->getReservedSlot(JSSLOT_DEBUGSOURCE_TEXT);
+ if (!textv.isUndefined()) {
+ MOZ_ASSERT(textv.isString());
+ args.rval().set(textv);
+ return true;
+ }
+
+ DebuggerSourceGetTextMatcher matcher(cx);
+ JSString* str = referent.match(matcher);
+ if (!str)
+ return false;
+
+ args.rval().setString(str);
+ obj->setReservedSlot(JSSLOT_DEBUGSOURCE_TEXT, args.rval());
+ return true;
+}
+
+class DebuggerSourceGetURLMatcher
+{
+ JSContext* cx_;
+
+ public:
+ explicit DebuggerSourceGetURLMatcher(JSContext* cx) : cx_(cx) { }
+
+ using ReturnType = Maybe<JSString*>;
+
+ ReturnType match(HandleScriptSource sourceObject) {
+ ScriptSource* ss = sourceObject->source();
+ MOZ_ASSERT(ss);
+ if (ss->filename()) {
+ JSString* str = NewStringCopyZ<CanGC>(cx_, ss->filename());
+ return Some(str);
+ }
+ return Nothing();
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ // TODOshu: Until wasm modules have real URLs, append "> wasm" to the
+ // end to prevent them from being blacklisted by devtools by having
+ // the same value as a source mapped URL.
+ char* buf = JS_smprintf("%s > wasm", wasmInstance->instance().metadata().filename.get());
+ if (!buf)
+ return Nothing();
+ JSString* str = NewStringCopyZ<CanGC>(cx_, buf);
+ JS_smprintf_free(buf);
+ return Some(str);
+ }
+};
+
+static bool
+DebuggerSource_getURL(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get url)", args, obj, referent);
+
+ DebuggerSourceGetURLMatcher matcher(cx);
+ Maybe<JSString*> str = referent.match(matcher);
+ if (str.isSome()) {
+ if (!*str)
+ return false;
+ args.rval().setString(*str);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+struct DebuggerSourceGetDisplayURLMatcher
+{
+ using ReturnType = const char16_t*;
+ ReturnType match(HandleScriptSource sourceObject) {
+ ScriptSource* ss = sourceObject->source();
+ MOZ_ASSERT(ss);
+ return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return wasmInstance->instance().metadata().displayURL();
+ }
+};
+
+static bool
+DebuggerSource_getDisplayURL(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get url)", args, obj, referent);
+
+ DebuggerSourceGetDisplayURLMatcher matcher;
+ if (const char16_t* displayURL = referent.match(matcher)) {
+ JSString* str = JS_NewUCStringCopyZ(cx, displayURL);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+struct DebuggerSourceGetElementMatcher
+{
+ using ReturnType = JSObject*;
+ ReturnType match(HandleScriptSource sourceObject) {
+ return sourceObject->element();
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return nullptr;
+ }
+};
+
+static bool
+DebuggerSource_getElement(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get element)", args, obj, referent);
+
+ DebuggerSourceGetElementMatcher matcher;
+ if (JSObject* element = referent.match(matcher)) {
+ args.rval().setObjectOrNull(element);
+ if (!Debugger::fromChildJSObject(obj)->wrapDebuggeeValue(cx, args.rval()))
+ return false;
+ } else {
+ args.rval().setUndefined();
+ }
+ return true;
+}
+
+struct DebuggerSourceGetElementPropertyMatcher
+{
+ using ReturnType = Value;
+ ReturnType match(HandleScriptSource sourceObject) {
+ return sourceObject->elementAttributeName();
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return UndefinedValue();
+ }
+};
+
+static bool
+DebuggerSource_getElementProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get elementAttributeName)", args, obj, referent);
+ DebuggerSourceGetElementPropertyMatcher matcher;
+ args.rval().set(referent.match(matcher));
+ return Debugger::fromChildJSObject(obj)->wrapDebuggeeValue(cx, args.rval());
+}
+
+class DebuggerSourceGetIntroductionScriptMatcher
+{
+ JSContext* cx_;
+ Debugger* dbg_;
+ MutableHandleValue rval_;
+
+ public:
+ DebuggerSourceGetIntroductionScriptMatcher(JSContext* cx, Debugger* dbg,
+ MutableHandleValue rval)
+ : cx_(cx),
+ dbg_(dbg),
+ rval_(rval)
+ { }
+
+ using ReturnType = bool;
+
+ ReturnType match(HandleScriptSource sourceObject) {
+ RootedScript script(cx_, sourceObject->introductionScript());
+ if (script) {
+ RootedObject scriptDO(cx_, dbg_->wrapScript(cx_, script));
+ if (!scriptDO)
+ return false;
+ rval_.setObject(*scriptDO);
+ } else {
+ rval_.setUndefined();
+ }
+ return true;
+ }
+
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ RootedObject ds(cx_, dbg_->wrapWasmScript(cx_, wasmInstance));
+ if (!ds)
+ return false;
+ rval_.setObject(*ds);
+ return true;
+ }
+};
+
+static bool
+DebuggerSource_getIntroductionScript(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionScript)", args, obj, referent);
+ Debugger* dbg = Debugger::fromChildJSObject(obj);
+ DebuggerSourceGetIntroductionScriptMatcher matcher(cx, dbg, args.rval());
+ return referent.match(matcher);
+}
+
+struct DebuggerGetIntroductionOffsetMatcher
+{
+ using ReturnType = Value;
+ ReturnType match(HandleScriptSource sourceObject) {
+ // Regardless of what's recorded in the ScriptSourceObject and
+ // ScriptSource, only hand out the introduction offset if we also have
+ // the script within which it applies.
+ ScriptSource* ss = sourceObject->source();
+ if (ss->hasIntroductionOffset() && sourceObject->introductionScript())
+ return Int32Value(ss->introductionOffset());
+ return UndefinedValue();
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return UndefinedValue();
+ }
+};
+
+static bool
+DebuggerSource_getIntroductionOffset(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionOffset)", args, obj, referent);
+ DebuggerGetIntroductionOffsetMatcher matcher;
+ args.rval().set(referent.match(matcher));
+ return true;
+}
+
+struct DebuggerSourceGetIntroductionTypeMatcher
+{
+ using ReturnType = const char*;
+ ReturnType match(HandleScriptSource sourceObject) {
+ ScriptSource* ss = sourceObject->source();
+ MOZ_ASSERT(ss);
+ return ss->hasIntroductionType() ? ss->introductionType() : nullptr;
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return "wasm";
+ }
+};
+
+static bool
+DebuggerSource_getIntroductionType(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionType)", args, obj, referent);
+
+ DebuggerSourceGetIntroductionTypeMatcher matcher;
+ if (const char* introductionType = referent.match(matcher)) {
+ JSString* str = NewStringCopyZ<CanGC>(cx, introductionType);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ } else {
+ args.rval().setUndefined();
+ }
+
+ return true;
+}
+
+static bool
+DebuggerSource_setSourceMapURL(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_SOURCE(cx, argc, vp, "sourceMapURL", args, obj, sourceObject);
+ ScriptSource* ss = sourceObject->source();
+ MOZ_ASSERT(ss);
+
+ JSString* str = ToString<CanGC>(cx, args[0]);
+ if (!str)
+ return false;
+
+ AutoStableStringChars stableChars(cx);
+ if (!stableChars.initTwoByte(cx, str))
+ return false;
+
+ ss->setSourceMapURL(cx, stableChars.twoByteChars());
+ args.rval().setUndefined();
+ return true;
+}
+
+struct DebuggerSourceGetSourceMapURLMatcher
+{
+ using ReturnType = const char16_t*;
+ ReturnType match(HandleScriptSource sourceObject) {
+ ScriptSource* ss = sourceObject->source();
+ MOZ_ASSERT(ss);
+ return ss->hasSourceMapURL() ? ss->sourceMapURL() : nullptr;
+ }
+ ReturnType match(Handle<WasmInstanceObject*> wasmInstance) {
+ return nullptr;
+ }
+};
+
+static bool
+DebuggerSource_getSourceMapURL(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get sourceMapURL)", args, obj, referent);
+
+ DebuggerSourceGetSourceMapURLMatcher matcher;
+ if (const char16_t* sourceMapURL = referent.match(matcher)) {
+ JSString* str = JS_NewUCStringCopyZ(cx, sourceMapURL);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+static const JSPropertySpec DebuggerSource_properties[] = {
+ JS_PSG("text", DebuggerSource_getText, 0),
+ JS_PSG("url", DebuggerSource_getURL, 0),
+ JS_PSG("element", DebuggerSource_getElement, 0),
+ JS_PSG("displayURL", DebuggerSource_getDisplayURL, 0),
+ JS_PSG("introductionScript", DebuggerSource_getIntroductionScript, 0),
+ JS_PSG("introductionOffset", DebuggerSource_getIntroductionOffset, 0),
+ JS_PSG("introductionType", DebuggerSource_getIntroductionType, 0),
+ JS_PSG("elementAttributeName", DebuggerSource_getElementProperty, 0),
+ JS_PSGS("sourceMapURL", DebuggerSource_getSourceMapURL, DebuggerSource_setSourceMapURL, 0),
+ JS_PS_END
+};
+
+static const JSFunctionSpec DebuggerSource_methods[] = {
+ JS_FS_END
+};
+
+
+/*** Debugger.Frame ******************************************************************************/
+
+/* static */ NativeObject*
+DebuggerFrame::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj)
+{
+ Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+ RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+
+ return InitClass(cx, dbgCtor, objProto, &class_, construct, 0, properties_,
+ methods_, nullptr, nullptr);
+}
+
+/* static */ DebuggerFrame*
+DebuggerFrame::create(JSContext* cx, HandleObject proto, AbstractFramePtr referent,
+ const ScriptFrameIter* maybeIter, HandleNativeObject debugger)
+{
+ JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerFrame::class_, proto);
+ if (!obj)
+ return nullptr;
+
+ DebuggerFrame& frame = obj->as<DebuggerFrame>();
+
+ // Eagerly copy ScriptFrameIter data if we've already walked the stack.
+ if (maybeIter) {
+ AbstractFramePtr data = maybeIter->copyDataAsAbstractFramePtr();
+ if (!data)
+ return nullptr;
+ frame.setPrivate(data.raw());
+ } else {
+ frame.setPrivate(referent.raw());
+ }
+
+ frame.setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*debugger));
+
+ return &frame;
+}
+
+/* static */ bool
+DebuggerFrame::getCallee(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerObject result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
+ if (!referent.isFunctionFrame()) {
+ result.set(nullptr);
+ return true;
+ }
+
+ Debugger* dbg = frame->owner();
+
+ RootedObject callee(cx, referent.callee());
+ return dbg->wrapDebuggeeObject(cx, callee, result);
+}
+
+/* static */ bool
+DebuggerFrame::getIsConstructing(JSContext* cx, HandleDebuggerFrame frame, bool& result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ result = iter.isFunctionFrame() && iter.isConstructing();
+ return true;
+}
+
+static void
+UpdateFrameIterPc(FrameIter& iter)
+{
+ if (iter.abstractFramePtr().isRematerializedFrame()) {
+#ifdef DEBUG
+ // Rematerialized frames don't need their pc updated. The reason we
+ // need to update pc is because we might get the same Debugger.Frame
+ // object for multiple re-entries into debugger code from debuggee
+ // code. This reentrancy is not possible with rematerialized frames,
+ // because when returning to debuggee code, we would have bailed out
+ // to baseline.
+ //
+ // We walk the stack to assert that it doesn't need updating.
+ jit::RematerializedFrame* frame = iter.abstractFramePtr().asRematerializedFrame();
+ jit::JitFrameLayout* jsFrame = (jit::JitFrameLayout*)frame->top();
+ jit::JitActivation* activation = iter.activation()->asJit();
+
+ ActivationIterator activationIter(activation->cx()->runtime());
+ while (activationIter.activation() != activation)
+ ++activationIter;
+
+ jit::JitFrameIterator jitIter(activationIter);
+ while (!jitIter.isIonJS() || jitIter.jsFrame() != jsFrame)
+ ++jitIter;
+
+ jit::InlineFrameIterator ionInlineIter(activation->cx(), &jitIter);
+ while (ionInlineIter.frameNo() != frame->frameNo())
+ ++ionInlineIter;
+
+ MOZ_ASSERT(ionInlineIter.pc() == iter.pc());
+#endif
+ return;
+ }
+
+ iter.updatePcQuadratic();
+}
+
+/* static */ bool
+DebuggerFrame::getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerEnvironment result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Debugger* dbg = frame->owner();
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ Rooted<Env*> env(cx);
+ {
+ AutoCompartment ac(cx, iter.abstractFramePtr().environmentChain());
+ UpdateFrameIterPc(iter);
+ env = GetDebugEnvironmentForFrame(cx, iter.abstractFramePtr(), iter.pc());
+ if (!env)
+ return false;
+ }
+
+ return dbg->wrapEnvironment(cx, env, result);
+}
+
+/* static */ bool
+DebuggerFrame::getIsGenerator(HandleDebuggerFrame frame)
+{
+ return DebuggerFrame::getReferent(frame).script()->isGenerator();
+}
+
+/* static */ bool
+DebuggerFrame::getOffset(JSContext* cx, HandleDebuggerFrame frame, size_t& result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ JSScript* script = iter.script();
+ UpdateFrameIterPc(iter);
+ jsbytecode* pc = iter.pc();
+ result = script->pcToOffset(pc);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::getOlder(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerFrame result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Debugger* dbg = frame->owner();
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ for (++iter; !iter.done(); ++iter) {
+ if (dbg->observesFrame(iter)) {
+ if (iter.isIon() && !iter.ensureHasRematerializedFrame(cx))
+ return false;
+ return dbg->getScriptFrame(cx, iter, result);
+ }
+ }
+
+ result.set(nullptr);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::getThis(JSContext* cx, HandleDebuggerFrame frame, MutableHandleValue result)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Debugger* dbg = frame->owner();
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ {
+ AbstractFramePtr frame = iter.abstractFramePtr();
+ AutoCompartment ac(cx, frame.environmentChain());
+
+ UpdateFrameIterPc(iter);
+
+ if (!GetThisValueForDebuggerMaybeOptimizedOut(cx, frame, iter.pc(), result))
+ return false;
+ }
+
+ return dbg->wrapDebuggeeValue(cx, result);
+}
+
+/* static */ DebuggerFrameType
+DebuggerFrame::getType(HandleDebuggerFrame frame)
+{
+ AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
+
+ /*
+ * Indirect eval frames are both isGlobalFrame() and isEvalFrame(), so the
+ * order of checks here is significant.
+ */
+ if (referent.isEvalFrame())
+ return DebuggerFrameType::Eval;
+ else if (referent.isGlobalFrame())
+ return DebuggerFrameType::Global;
+ else if (referent.isFunctionFrame())
+ return DebuggerFrameType::Call;
+ else if (referent.isModuleFrame())
+ return DebuggerFrameType::Module;
+ MOZ_CRASH("Unknown frame type");
+}
+
+/* static */ DebuggerFrameImplementation
+DebuggerFrame::getImplementation(HandleDebuggerFrame frame)
+{
+ AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
+
+ if (referent.isBaselineFrame())
+ return DebuggerFrameImplementation::Baseline;
+ else if (referent.isRematerializedFrame())
+ return DebuggerFrameImplementation::Ion;
+ return DebuggerFrameImplementation::Interpreter;
+}
+
+/*
+ * Evaluate |chars[0..length-1]| in the environment |env|, treating that
+ * source as appearing starting at |lineno| in |filename|. Store the return
+ * value in |*rval|. Use |thisv| as the 'this' value.
+ *
+ * If |frame| is non-nullptr, evaluate as for a direct eval in that frame; |env|
+ * must be either |frame|'s DebugScopeObject, or some extension of that
+ * environment; either way, |frame|'s scope is where newly declared variables
+ * go. In this case, |frame| must have a computed 'this' value, equal to |thisv|.
+ */
+static bool
+EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
+ jsbytecode* pc, mozilla::Range<const char16_t> chars, const char* filename,
+ unsigned lineno, MutableHandleValue rval)
+{
+ assertSameCompartment(cx, env, frame);
+ MOZ_ASSERT_IF(frame, pc);
+
+ CompileOptions options(cx);
+ options.setIsRunOnce(true)
+ .setNoScriptRval(false)
+ .setFileAndLine(filename, lineno)
+ .setCanLazilyParse(false)
+ .setIntroductionType("debugger eval")
+ .maybeMakeStrictMode(frame ? frame.script()->strict() : false);
+ RootedScript callerScript(cx, frame ? frame.script() : nullptr);
+ SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), SourceBufferHolder::NoOwnership);
+ RootedScript script(cx);
+
+ ScopeKind scopeKind;
+ if (IsGlobalLexicalEnvironment(env))
+ scopeKind = ScopeKind::Global;
+ else
+ scopeKind = ScopeKind::NonSyntactic;
+
+ if (frame) {
+ MOZ_ASSERT(scopeKind == ScopeKind::NonSyntactic);
+ RootedScope scope(cx, GlobalScope::createEmpty(cx, ScopeKind::NonSyntactic));
+ if (!scope)
+ return false;
+ script = frontend::CompileEvalScript(cx, cx->tempLifoAlloc(), env, scope,
+ options, srcBuf);
+ if (script)
+ script->setActiveEval();
+ } else {
+ // Do not consider executeInGlobal{WithBindings} as an eval, but instead
+ // as executing a series of statements at the global level. This is to
+ // circumvent the fresh lexical scope that all eval have, so that the
+ // users of executeInGlobal, like the web console, may add new bindings to
+ // the global scope.
+ script = frontend::CompileGlobalScript(cx, cx->tempLifoAlloc(), scopeKind, options,
+ srcBuf);
+ }
+
+ if (!script)
+ return false;
+
+ return ExecuteKernel(cx, script, *env, NullValue(), frame, rval.address());
+}
+
+static bool
+DebuggerGenericEval(JSContext* cx, const mozilla::Range<const char16_t> chars,
+ HandleObject bindings, const EvalOptions& options,
+ JSTrapStatus& status, MutableHandleValue value,
+ Debugger* dbg, HandleObject envArg, ScriptFrameIter* iter)
+{
+ /* Either we're specifying the frame, or a global. */
+ MOZ_ASSERT_IF(iter, !envArg);
+ MOZ_ASSERT_IF(!iter, envArg && IsGlobalLexicalEnvironment(envArg));
+
+ /*
+ * Gather keys and values of bindings, if any. This must be done in the
+ * debugger compartment, since that is where any exceptions must be
+ * thrown.
+ */
+ AutoIdVector keys(cx);
+ AutoValueVector values(cx);
+ if (bindings) {
+ if (!GetPropertyKeys(cx, bindings, JSITER_OWNONLY, &keys) ||
+ !values.growBy(keys.length()))
+ {
+ return false;
+ }
+ for (size_t i = 0; i < keys.length(); i++) {
+ MutableHandleValue valp = values[i];
+ if (!GetProperty(cx, bindings, bindings, keys[i], valp) ||
+ !dbg->unwrapDebuggeeValue(cx, valp))
+ {
+ return false;
+ }
+ }
+ }
+
+ Maybe<AutoCompartment> ac;
+ if (iter)
+ ac.emplace(cx, iter->environmentChain(cx));
+ else
+ ac.emplace(cx, envArg);
+
+ Rooted<Env*> env(cx);
+ if (iter) {
+ env = GetDebugEnvironmentForFrame(cx, iter->abstractFramePtr(), iter->pc());
+ if (!env)
+ return false;
+ } else {
+ env = envArg;
+ }
+
+ /* If evalWithBindings, create the inner environment. */
+ if (bindings) {
+ RootedPlainObject nenv(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
+ if (!nenv)
+ return false;
+ RootedId id(cx);
+ for (size_t i = 0; i < keys.length(); i++) {
+ id = keys[i];
+ MutableHandleValue val = values[i];
+ if (!cx->compartment()->wrap(cx, val) ||
+ !NativeDefineProperty(cx, nenv, id, val, nullptr, nullptr, 0))
+ {
+ return false;
+ }
+ }
+
+ AutoObjectVector envChain(cx);
+ if (!envChain.append(nenv))
+ return false;
+
+ RootedObject newEnv(cx);
+ if (!CreateObjectsForEnvironmentChain(cx, envChain, env, &newEnv))
+ return false;
+
+ env = newEnv;
+ }
+
+ /* Run the code and produce the completion value. */
+ LeaveDebuggeeNoExecute nnx(cx);
+ RootedValue rval(cx);
+ AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
+ jsbytecode* pc = iter ? iter->pc() : nullptr;
+
+ bool ok = EvaluateInEnv(cx, env, frame, pc, chars,
+ options.filename() ? options.filename() : "debugger eval code",
+ options.lineno(), &rval);
+ Debugger::resultToCompletion(cx, ok, rval, &status, value);
+ ac.reset();
+ return dbg->wrapDebuggeeValue(cx, value);
+}
+
+/* static */ bool
+DebuggerFrame::eval(JSContext* cx, HandleDebuggerFrame frame, mozilla::Range<const char16_t> chars,
+ HandleObject bindings, const EvalOptions& options, JSTrapStatus& status,
+ MutableHandleValue value)
+{
+ MOZ_ASSERT(frame->isLive());
+
+ Debugger* dbg = frame->owner();
+
+ Maybe<ScriptFrameIter> maybeIter;
+ if (!DebuggerFrame::getScriptFrameIter(cx, frame, maybeIter))
+ return false;
+ ScriptFrameIter& iter = *maybeIter;
+
+ UpdateFrameIterPc(iter);
+
+ return DebuggerGenericEval(cx, chars, bindings, options, status, value, dbg, nullptr, &iter);
+}
+
+/* statuc */ bool
+DebuggerFrame::isLive() const
+{
+ return !!getPrivate();
+}
+
+static bool
+DebuggerFrame_requireLive(JSContext* cx, HandleDebuggerFrame frame)
+{
+ if (!frame->isLive()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+ "Debugger.Frame");
+ return false;
+ }
+
+ return true;
+}
+
+/* static */ AbstractFramePtr
+DebuggerFrame::getReferent(HandleDebuggerFrame frame)
+{
+ AbstractFramePtr referent = AbstractFramePtr::FromRaw(frame->getPrivate());
+ if (referent.isScriptFrameIterData()) {
+ ScriptFrameIter iter(*(ScriptFrameIter::Data*)(referent.raw()));
+ referent = iter.abstractFramePtr();
+ }
+ return referent;
+}
+
+/* static */ bool
+DebuggerFrame::getScriptFrameIter(JSContext* cx, HandleDebuggerFrame frame,
+ Maybe<ScriptFrameIter>& result)
+{
+ AbstractFramePtr referent = AbstractFramePtr::FromRaw(frame->getPrivate());
+ if (referent.isScriptFrameIterData()) {
+ result.emplace(*reinterpret_cast<ScriptFrameIter::Data*>(referent.raw()));
+ } else {
+ result.emplace(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK);
+ ScriptFrameIter& iter = *result;
+ while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != referent)
+ ++iter;
+ AbstractFramePtr data = iter.copyDataAsAbstractFramePtr();
+ if (!data)
+ return false;
+ frame->setPrivate(data.raw());
+ }
+ return true;
+}
+
+static void
+DebuggerFrame_freeScriptFrameIterData(FreeOp* fop, JSObject* obj)
+{
+ AbstractFramePtr frame = AbstractFramePtr::FromRaw(obj->as<NativeObject>().getPrivate());
+ if (frame.isScriptFrameIterData())
+ fop->delete_((ScriptFrameIter::Data*) frame.raw());
+ obj->as<NativeObject>().setPrivate(nullptr);
+}
+
+static void
+DebuggerFrame_maybeDecrementFrameScriptStepModeCount(FreeOp* fop, AbstractFramePtr frame,
+ NativeObject* frameobj)
+{
+ /* If this frame has an onStep handler, decrement the script's count. */
+ if (!frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
+ frame.script()->decrementStepModeCount(fop);
+}
+
+static void
+DebuggerFrame_finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->maybeOffMainThread());
+ DebuggerFrame_freeScriptFrameIterData(fop, obj);
+}
+
+static DebuggerFrame*
+DebuggerFrame_checkThis(JSContext* cx, const CallArgs& args, const char* fnname, bool checkLive)
+{
+ JSObject* thisobj = NonNullObject(cx, args.thisv());
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &DebuggerFrame::class_) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Frame", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ RootedDebuggerFrame frame(cx, &thisobj->as<DebuggerFrame>());
+
+ /*
+ * Forbid Debugger.Frame.prototype, which is of class DebuggerFrame::class_
+ * but isn't really a working Debugger.Frame object. The prototype object
+ * is distinguished by having a nullptr private value. Also, forbid popped
+ * frames.
+ */
+ if (!frame->getPrivate() &&
+ frame->getReservedSlot(JSSLOT_DEBUGFRAME_OWNER).isUndefined())
+ {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Frame", fnname, "prototype object");
+ return nullptr;
+ }
+
+ if (checkLive) {
+ if (!DebuggerFrame_requireLive(cx, frame))
+ return nullptr;
+ }
+
+ return frame;
+}
+
+/*
+ * To make frequently fired hooks like onEnterFrame more performant,
+ * Debugger.Frame methods should not create a ScriptFrameIter unless it
+ * absolutely needs to. That is, unless the method has to call a method on
+ * ScriptFrameIter that's otherwise not available on AbstractFramePtr.
+ *
+ * When a Debugger.Frame is first created, its private slot is set to the
+ * AbstractFramePtr itself. The first time the users asks for a
+ * ScriptFrameIter, we construct one, have it settle on the frame pointed to
+ * by the AbstractFramePtr and cache its internal Data in the Debugger.Frame
+ * object's private slot. Subsequent uses of the Debugger.Frame object will
+ * always create a ScriptFrameIter from the cached Data.
+ *
+ * Methods that only need the AbstractFramePtr should use THIS_FRAME.
+ * Methods that need a ScriptFrameIterator should use THIS_FRAME_ITER.
+ */
+
+#define THIS_DEBUGGER_FRAME(cx, argc, vp, fnname, args, frame) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedDebuggerFrame frame(cx, DebuggerFrame_checkThis(cx, args, fnname, true)); \
+ if (!frame) \
+ return false;
+
+#define THIS_FRAME_THISOBJ(cx, argc, vp, fnname, args, thisobj) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedNativeObject thisobj(cx, DebuggerFrame_checkThis(cx, args, fnname, true)); \
+ if (!thisobj) \
+ return false
+
+#define THIS_FRAME(cx, argc, vp, fnname, args, thisobj, frame) \
+ THIS_FRAME_THISOBJ(cx, argc, vp, fnname, args, thisobj); \
+ AbstractFramePtr frame = AbstractFramePtr::FromRaw(thisobj->getPrivate()); \
+ if (frame.isScriptFrameIterData()) { \
+ ScriptFrameIter iter(*(ScriptFrameIter::Data*)(frame.raw())); \
+ frame = iter.abstractFramePtr(); \
+ }
+
+#define THIS_FRAME_ITER(cx, argc, vp, fnname, args, thisobj, maybeIter, iter) \
+ THIS_FRAME_THISOBJ(cx, argc, vp, fnname, args, thisobj); \
+ Maybe<ScriptFrameIter> maybeIter; \
+ { \
+ AbstractFramePtr f = AbstractFramePtr::FromRaw(thisobj->getPrivate()); \
+ if (f.isScriptFrameIterData()) { \
+ maybeIter.emplace(*(ScriptFrameIter::Data*)(f.raw())); \
+ } else { \
+ maybeIter.emplace(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK); \
+ ScriptFrameIter& iter = *maybeIter; \
+ while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != f) \
+ ++iter; \
+ AbstractFramePtr data = iter.copyDataAsAbstractFramePtr(); \
+ if (!data) \
+ return false; \
+ thisobj->setPrivate(data.raw()); \
+ } \
+ } \
+ ScriptFrameIter& iter = *maybeIter
+
+#define THIS_FRAME_OWNER(cx, argc, vp, fnname, args, thisobj, frame, dbg) \
+ THIS_FRAME(cx, argc, vp, fnname, args, thisobj, frame); \
+ Debugger* dbg = Debugger::fromChildJSObject(thisobj)
+
+#define THIS_FRAME_OWNER_ITER(cx, argc, vp, fnname, args, thisobj, maybeIter, iter, dbg) \
+ THIS_FRAME_ITER(cx, argc, vp, fnname, args, thisobj, maybeIter, iter); \
+ Debugger* dbg = Debugger::fromChildJSObject(thisobj)
+
+/* static */ bool
+DebuggerFrame::typeGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get type", args, frame);
+
+ DebuggerFrameType type = DebuggerFrame::getType(frame);
+
+ JSString* str;
+ switch (type) {
+ case DebuggerFrameType::Eval:
+ str = cx->names().eval;
+ break;
+ case DebuggerFrameType::Global:
+ str = cx->names().global;
+ break;
+ case DebuggerFrameType::Call:
+ str = cx->names().call;
+ break;
+ case DebuggerFrameType::Module:
+ str = cx->names().module;
+ break;
+ default:
+ MOZ_CRASH("bad DebuggerFrameType value");
+ }
+
+ args.rval().setString(str);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::implementationGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get implementation", args, frame);
+
+ DebuggerFrameImplementation implementation = DebuggerFrame::getImplementation(frame);
+
+ const char* s;
+ switch (implementation) {
+ case DebuggerFrameImplementation::Baseline:
+ s = "baseline";
+ break;
+ case DebuggerFrameImplementation::Ion:
+ s = "ion";
+ break;
+ case DebuggerFrameImplementation::Interpreter:
+ s = "interpreter";
+ break;
+ default:
+ MOZ_CRASH("bad DebuggerFrameImplementation value");
+ }
+
+ JSAtom* str = Atomize(cx, s, strlen(s));
+ if (!str)
+ return false;
+
+ args.rval().setString(str);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::environmentGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get environment", args, frame);
+
+ RootedDebuggerEnvironment result(cx);
+ if (!DebuggerFrame::getEnvironment(cx, frame, &result))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::calleeGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get callee", args, frame);
+
+ RootedDebuggerObject result(cx);
+ if (!DebuggerFrame::getCallee(cx, frame, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::generatorGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get callee", args, frame);
+
+ args.rval().setBoolean(DebuggerFrame::getIsGenerator(frame));
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::constructingGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get callee", args, frame);
+
+ bool result;
+ if (!DebuggerFrame::getIsConstructing(cx, frame, result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::thisGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get this", args, frame);
+
+ return DebuggerFrame::getThis(cx, frame, args.rval());
+}
+
+/* static */ bool
+DebuggerFrame::olderGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get older", args, frame);
+
+ RootedDebuggerFrame result(cx);
+ if (!DebuggerFrame::getOlder(cx, frame, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* The getter used for each element of frame.arguments. See DebuggerFrame_getArguments. */
+static bool
+DebuggerArguments_getArg(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ int32_t i = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
+
+ /* Check that the this value is an Arguments object. */
+ RootedObject argsobj(cx, NonNullObject(cx, args.thisv()));
+ if (!argsobj)
+ return false;
+ if (argsobj->getClass() != &DebuggerArguments_class) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Arguments", "getArgument", argsobj->getClass()->name);
+ return false;
+ }
+
+ /*
+ * Put the Debugger.Frame into the this-value slot, then use THIS_FRAME
+ * to check that it is still live and get the fp.
+ */
+ args.setThis(argsobj->as<NativeObject>().getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME));
+ THIS_FRAME(cx, argc, vp, "get argument", ca2, thisobj, frame);
+
+ /*
+ * Since getters can be extracted and applied to other objects,
+ * there is no guarantee this object has an ith argument.
+ */
+ MOZ_ASSERT(i >= 0);
+ RootedValue arg(cx);
+ RootedScript script(cx);
+ if (unsigned(i) < frame.numActualArgs()) {
+ script = frame.script();
+ {
+ AutoCompartment ac(cx, script->compartment());
+ if (!script->ensureHasAnalyzedArgsUsage(cx))
+ return false;
+ }
+ if (unsigned(i) < frame.numFormalArgs()) {
+ for (PositionalFormalParameterIter fi(script); fi; fi++) {
+ if (fi.argumentSlot() == unsigned(i)) {
+ // We might've been called before the CallObject was
+ // created.
+ if (fi.closedOver() && frame.hasInitialEnvironment())
+ arg = frame.callObj().aliasedBinding(fi);
+ else
+ arg = frame.unaliasedActual(i, DONT_CHECK_ALIASING);
+ break;
+ }
+ }
+ } else if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
+ arg = frame.argsObj().arg(i);
+ } else {
+ arg = frame.unaliasedActual(i, DONT_CHECK_ALIASING);
+ }
+ } else {
+ arg.setUndefined();
+ }
+
+ if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &arg))
+ return false;
+ args.rval().set(arg);
+ return true;
+}
+
+static bool
+DebuggerFrame_getArguments(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "get arguments", args, thisobj, frame);
+ Value argumentsv = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ARGUMENTS);
+ if (!argumentsv.isUndefined()) {
+ MOZ_ASSERT(argumentsv.isObjectOrNull());
+ args.rval().set(argumentsv);
+ return true;
+ }
+
+ RootedNativeObject argsobj(cx);
+ if (frame.hasArgs()) {
+ /* Create an arguments object. */
+ Rooted<GlobalObject*> global(cx, &args.callee().global());
+ RootedObject proto(cx, GlobalObject::getOrCreateArrayPrototype(cx, global));
+ if (!proto)
+ return false;
+ argsobj = NewNativeObjectWithGivenProto(cx, &DebuggerArguments_class, proto);
+ if (!argsobj)
+ return false;
+ SetReservedSlot(argsobj, JSSLOT_DEBUGARGUMENTS_FRAME, ObjectValue(*thisobj));
+
+ MOZ_ASSERT(frame.numActualArgs() <= 0x7fffffff);
+ unsigned fargc = frame.numActualArgs();
+ RootedValue fargcVal(cx, Int32Value(fargc));
+ if (!NativeDefineProperty(cx, argsobj, cx->names().length, fargcVal, nullptr, nullptr,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ Rooted<jsid> id(cx);
+ for (unsigned i = 0; i < fargc; i++) {
+ RootedFunction getobj(cx);
+ getobj = NewNativeFunction(cx, DebuggerArguments_getArg, 0, nullptr,
+ gc::AllocKind::FUNCTION_EXTENDED);
+ if (!getobj)
+ return false;
+ id = INT_TO_JSID(i);
+ if (!getobj ||
+ !NativeDefineProperty(cx, argsobj, id, UndefinedHandleValue,
+ JS_DATA_TO_FUNC_PTR(GetterOp, getobj.get()), nullptr,
+ JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER))
+ {
+ return false;
+ }
+ getobj->setExtendedSlot(0, Int32Value(i));
+ }
+ } else {
+ argsobj = nullptr;
+ }
+ args.rval().setObjectOrNull(argsobj);
+ thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ARGUMENTS, args.rval());
+ return true;
+}
+
+static bool
+DebuggerFrame_getScript(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "get script", args, thisobj, frame);
+ Debugger* debug = Debugger::fromChildJSObject(thisobj);
+
+ RootedObject scriptObject(cx);
+ if (frame.isFunctionFrame()) {
+ RootedFunction callee(cx, frame.callee());
+ if (callee->isInterpreted()) {
+ RootedScript script(cx, callee->nonLazyScript());
+ scriptObject = debug->wrapScript(cx, script);
+ if (!scriptObject)
+ return false;
+ }
+ } else {
+ /*
+ * We got eval, JS_Evaluate*, or JS_ExecuteScript non-function script
+ * frames.
+ */
+ RootedScript script(cx, frame.script());
+ scriptObject = debug->wrapScript(cx, script);
+ if (!scriptObject)
+ return false;
+ }
+ args.rval().setObjectOrNull(scriptObject);
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::offsetGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "get offset", args, frame);
+
+ size_t result;
+ if (!DebuggerFrame::getOffset(cx, frame, result))
+ return false;
+
+ args.rval().setNumber(double(result));
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::liveGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedDebuggerFrame frame(cx, DebuggerFrame_checkThis(cx, args, "get live", false));
+ if (!frame)
+ return false;
+
+ args.rval().setBoolean(frame->isLive());
+ return true;
+}
+
+static bool
+IsValidHook(const Value& v)
+{
+ return v.isUndefined() || (v.isObject() && v.toObject().isCallable());
+}
+
+static bool
+DebuggerFrame_getOnStep(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "get onStep", args, thisobj, frame);
+ (void) frame; // Silence GCC warning
+ RootedValue handler(cx, thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER));
+ MOZ_ASSERT(IsValidHook(handler));
+ args.rval().set(handler);
+ return true;
+}
+
+static bool
+DebuggerFrame_setOnStep(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "set onStep", args, thisobj, frame);
+ if (!args.requireAtLeast(cx, "Debugger.Frame.set onStep", 1))
+ return false;
+ if (!IsValidHook(args[0])) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
+ return false;
+ }
+
+ Value prior = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
+ if (!args[0].isUndefined() && prior.isUndefined()) {
+ // Single stepping toggled off->on.
+ AutoCompartment ac(cx, frame.environmentChain());
+ // Ensure observability *before* incrementing the step mode
+ // count. Calling this function after calling incrementStepModeCount
+ // will make it a no-op.
+ Debugger* dbg = Debugger::fromChildJSObject(thisobj);
+ if (!dbg->ensureExecutionObservabilityOfScript(cx, frame.script()))
+ return false;
+ if (!frame.script()->incrementStepModeCount(cx))
+ return false;
+ } else if (args[0].isUndefined() && !prior.isUndefined()) {
+ // Single stepping toggled on->off.
+ frame.script()->decrementStepModeCount(cx->runtime()->defaultFreeOp());
+ }
+
+ /* Now that the step mode switch has succeeded, we can install the handler. */
+ thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER, args[0]);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+DebuggerFrame_getOnPop(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "get onPop", args, thisobj, frame);
+ (void) frame; // Silence GCC warning
+ RootedValue handler(cx, thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER));
+ MOZ_ASSERT(IsValidHook(handler));
+ args.rval().set(handler);
+ return true;
+}
+
+static bool
+DebuggerFrame_setOnPop(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_FRAME(cx, argc, vp, "set onPop", args, thisobj, frame);
+ if (!args.requireAtLeast(cx, "Debugger.Frame.set onPop", 1))
+ return false;
+ (void) frame; // Silence GCC warning
+ if (!IsValidHook(args[0])) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
+ return false;
+ }
+
+ thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER, args[0]);
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerFrame::evalMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "eval", args, frame);
+ if (!args.requireAtLeast(cx, "Debugger.Frame.prototype.eval", 1))
+ return false;
+
+ AutoStableStringChars stableChars(cx);
+ if (!ValueToStableChars(cx, "Debugger.Frame.prototype.eval", args[0], stableChars))
+ return false;
+ mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
+
+ EvalOptions options;
+ if (!ParseEvalOptions(cx, args.get(1), options))
+ return false;
+
+ JSTrapStatus status;
+ RootedValue value(cx);
+ if (!DebuggerFrame::eval(cx, frame, chars, nullptr, options, status, &value))
+ return false;
+
+ return frame->owner()->newCompletionValue(cx, status, value, args.rval());
+}
+
+/* static */ bool
+DebuggerFrame::evalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_FRAME(cx, argc, vp, "evalWithBindings", args, frame);
+ if (!args.requireAtLeast(cx, "Debugger.Frame.prototype.evalWithBindings", 2))
+ return false;
+
+ AutoStableStringChars stableChars(cx);
+ if (!ValueToStableChars(cx, "Debugger.Frame.prototype.evalWithBindings", args[0],
+ stableChars))
+ {
+ return false;
+ }
+ mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
+
+ RootedObject bindings(cx, NonNullObject(cx, args[1]));
+ if (!bindings)
+ return false;
+
+ EvalOptions options;
+ if (!ParseEvalOptions(cx, args.get(2), options))
+ return false;
+
+ JSTrapStatus status;
+ RootedValue value(cx);
+ if (!DebuggerFrame::eval(cx, frame, chars, bindings, options, status, &value))
+ return false;
+
+ return frame->owner()->newCompletionValue(cx, status, value, args.rval());
+}
+
+/* static */ bool
+DebuggerFrame::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Frame");
+ return false;
+}
+
+const JSPropertySpec DebuggerFrame::properties_[] = {
+ JS_PSG("arguments", DebuggerFrame_getArguments, 0),
+ JS_PSG("callee", DebuggerFrame::calleeGetter, 0),
+ JS_PSG("constructing", DebuggerFrame::constructingGetter, 0),
+ JS_PSG("environment", DebuggerFrame::environmentGetter, 0),
+ JS_PSG("generator", DebuggerFrame::generatorGetter, 0),
+ JS_PSG("live", DebuggerFrame::liveGetter, 0),
+ JS_PSG("offset", DebuggerFrame::offsetGetter, 0),
+ JS_PSG("older", DebuggerFrame::olderGetter, 0),
+ JS_PSG("script", DebuggerFrame_getScript, 0),
+ JS_PSG("this", DebuggerFrame::thisGetter, 0),
+ JS_PSG("type", DebuggerFrame::typeGetter, 0),
+ JS_PSG("implementation", DebuggerFrame::implementationGetter, 0),
+ JS_PSGS("onStep", DebuggerFrame_getOnStep, DebuggerFrame_setOnStep, 0),
+ JS_PSGS("onPop", DebuggerFrame_getOnPop, DebuggerFrame_setOnPop, 0),
+ JS_PS_END
+};
+
+const JSFunctionSpec DebuggerFrame::methods_[] = {
+ JS_FN("eval", DebuggerFrame::evalMethod, 1, 0),
+ JS_FN("evalWithBindings", DebuggerFrame::evalWithBindingsMethod, 1, 0),
+ JS_FS_END
+};
+
+
+/*** Debugger.Object *****************************************************************************/
+
+void
+DebuggerObject_trace(JSTracer* trc, JSObject* obj)
+{
+ /*
+ * There is a barrier on private pointers, so the Unbarriered marking
+ * is okay.
+ */
+ if (JSObject* referent = (JSObject*) obj->as<NativeObject>().getPrivate()) {
+ TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+ "Debugger.Object referent");
+ obj->as<NativeObject>().setPrivateUnbarriered(referent);
+ }
+}
+
+static DebuggerObject*
+DebuggerObject_checkThis(JSContext* cx, const CallArgs& args, const char* fnname)
+{
+ JSObject* thisobj = NonNullObject(cx, args.thisv());
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &DebuggerObject::class_) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Object", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ /*
+ * Forbid Debugger.Object.prototype, which is of class DebuggerObject::class_
+ * but isn't a real working Debugger.Object. The prototype object is
+ * distinguished by having no referent.
+ */
+ DebuggerObject* nthisobj = &thisobj->as<DebuggerObject>();
+ if (!nthisobj->getPrivate()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Object", fnname, "prototype object");
+ return nullptr;
+ }
+ return nthisobj;
+}
+
+#define THIS_DEBUGOBJECT(cx, argc, vp, fnname, args, object) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedDebuggerObject object(cx, DebuggerObject_checkThis(cx, args, fnname)); \
+ if (!object) \
+ return false; \
+
+#define THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, fnname, args, obj) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedObject obj(cx, DebuggerObject_checkThis(cx, args, fnname)); \
+ if (!obj) \
+ return false; \
+ obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
+ MOZ_ASSERT(obj)
+
+#define THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedObject obj(cx, DebuggerObject_checkThis(cx, args, fnname)); \
+ if (!obj) \
+ return false; \
+ Debugger* dbg = Debugger::fromChildJSObject(obj); \
+ obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
+ MOZ_ASSERT(obj)
+
+#define THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, fnname, args, obj) \
+ THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, fnname, args, obj); \
+ obj = CheckedUnwrap(obj); \
+ if (!obj) { \
+ JS_ReportErrorASCII(cx, "Permission denied to access object"); \
+ return false; \
+ } \
+ if (!obj->is<PromiseObject>()) { \
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,\
+ "Debugger", "Promise", obj->getClass()->name); \
+ return false; \
+ } \
+ Rooted<PromiseObject*> promise(cx, &obj->as<PromiseObject>());
+
+#define THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, fnname, args, dbg, obj) \
+ THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj); \
+ obj = CheckedUnwrap(obj); \
+ if (!obj) { \
+ JS_ReportErrorASCII(cx, "Permission denied to access object"); \
+ return false; \
+ } \
+ if (!obj->is<PromiseObject>()) { \
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,\
+ "Debugger", "Promise", obj->getClass()->name); \
+ return false; \
+ } \
+ Rooted<PromiseObject*> promise(cx, &obj->as<PromiseObject>());
+
+/* static */ bool
+DebuggerObject::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Object");
+ return false;
+}
+
+/* static */ bool
+DebuggerObject::callableGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get callable", args, object)
+
+ args.rval().setBoolean(object->isCallable());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get isBoundFunction", args, object)
+
+ if (!object->isDebuggeeFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ args.rval().setBoolean(object->isBoundFunction());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get isArrowFunction", args, object)
+
+ if (!object->isDebuggeeFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ args.rval().setBoolean(object->isArrowFunction());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::protoGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get proto", args, object)
+
+ RootedDebuggerObject result(cx);
+ if (!DebuggerObject::getPrototypeOf(cx, object, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::classGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get class", args, object)
+
+ RootedString result(cx);
+ if (!DebuggerObject::getClassName(cx, object, &result))
+ return false;
+
+ args.rval().setString(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::nameGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get name", args, object)
+
+ if (!object->isFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedString result(cx, object->name());
+ if (result)
+ args.rval().setString(result);
+ else
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::displayNameGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get displayName", args, object)
+
+ if (!object->isFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedString result(cx, object->displayName());
+ if (result)
+ args.rval().setString(result);
+ else
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::parameterNamesGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get parameterNames", args, object)
+
+ if (!object->isDebuggeeFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ Rooted<StringVector> names(cx, StringVector(cx));
+ if (!DebuggerObject::getParameterNames(cx, object, &names))
+ return false;
+
+ RootedArrayObject obj(cx, NewDenseFullyAllocatedArray(cx, names.length()));
+ if (!obj)
+ return false;
+
+ obj->ensureDenseInitializedLength(cx, 0, names.length());
+ for (size_t i = 0; i < names.length(); ++i) {
+ Value v;
+ if (names[i])
+ v = StringValue(names[i]);
+ else
+ v = UndefinedValue();
+ obj->setDenseElement(i, v);
+ }
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::scriptGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get script", args, dbg, obj);
+
+ if (!obj->is<JSFunction>()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedFunction fun(cx, &obj->as<JSFunction>());
+ if (!fun->isInterpreted()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
+ if (!script)
+ return false;
+
+ /* Only hand out debuggee scripts. */
+ if (!dbg->observesScript(script)) {
+ args.rval().setNull();
+ return true;
+ }
+
+ RootedObject scriptObject(cx, dbg->wrapScript(cx, script));
+ if (!scriptObject)
+ return false;
+
+ args.rval().setObject(*scriptObject);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::environmentGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get environment", args, dbg, obj);
+
+ /* Don't bother switching compartments just to check obj's type and get its env. */
+ if (!obj->is<JSFunction>() || !obj->as<JSFunction>().isInterpreted()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ /* Only hand out environments of debuggee functions. */
+ if (!dbg->observesGlobal(&obj->global())) {
+ args.rval().setNull();
+ return true;
+ }
+
+ Rooted<Env*> env(cx);
+ {
+ AutoCompartment ac(cx, obj);
+ RootedFunction fun(cx, &obj->as<JSFunction>());
+ env = GetDebugEnvironmentForFunction(cx, fun);
+ if (!env)
+ return false;
+ }
+
+ return dbg->wrapEnvironment(cx, env, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::boundTargetFunctionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get boundTargetFunction", args, object)
+
+ if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ RootedDebuggerObject result(cx);
+ if (!DebuggerObject::getBoundTargetFunction(cx, object, &result))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::boundThisGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get boundThis", args, object)
+
+ if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ return DebuggerObject::getBoundThis(cx, object, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::boundArgumentsGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get boundArguments", args, object)
+
+ if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ Rooted<ValueVector> result(cx, ValueVector(cx));
+ if (!DebuggerObject::getBoundArguments(cx, object, &result))
+ return false;
+
+ RootedObject obj(cx, NewDenseCopiedArray(cx, result.length(), result.begin()));
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::globalGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get global", args, object)
+
+ RootedDebuggerObject result(cx);
+ if (!DebuggerObject::getGlobal(cx, object, &result))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get allocationSite", args, object)
+
+ RootedObject result(cx);
+ if (!DebuggerObject::getAllocationSite(cx, object, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+// Returns the "name" field (see js.msg), which may be used as a unique
+// identifier, for any error object with a JSErrorReport or undefined
+// if the object has no JSErrorReport.
+/* static */ bool
+DebuggerObject::errorMessageNameGetter(JSContext *cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get errorMessageName", args, object)
+
+ RootedString result(cx);
+ if (!DebuggerObject::getErrorMessageName(cx, object, &result))
+ return false;
+
+ if (result)
+ args.rval().setString(result);
+ else
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::errorLineNumberGetter(JSContext *cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get errorLineNumber", args, object)
+
+ return DebuggerObject::getErrorLineNumber(cx, object, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::errorColumnNumberGetter(JSContext *cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get errorColumnNumber", args, object)
+
+ return DebuggerObject::getErrorColumnNumber(cx, object, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::isProxyGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get isProxy", args, object)
+
+ args.rval().setBoolean(object->isScriptedProxy());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get proxyTarget", args, object)
+
+ if (!object->isScriptedProxy()) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ Rooted<DebuggerObject*> result(cx);
+ if (!DebuggerObject::getScriptedProxyTarget(cx, object, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get proxyHandler", args, object)
+
+ if (!object->isScriptedProxy()) {
+ args.rval().setUndefined();
+ return true;
+ }
+ Rooted<DebuggerObject*> result(cx);
+ if (!DebuggerObject::getScriptedProxyHandler(cx, object, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+#ifdef SPIDERMONKEY_PROMISE
+/* static */ bool
+DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get isPromise", args, object)
+
+ args.rval().setBoolean(object->isPromise());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseStateGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get promiseState", args, object);
+
+ if (!DebuggerObject::requirePromise(cx, object))
+ return false;
+
+ RootedValue result(cx);
+ switch (object->promiseState()) {
+ case JS::PromiseState::Pending:
+ result.setString(cx->names().pending);
+ break;
+ case JS::PromiseState::Fulfilled:
+ result.setString(cx->names().fulfilled);
+ break;
+ case JS::PromiseState::Rejected:
+ result.setString(cx->names().rejected);
+ break;
+ }
+
+ args.rval().set(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseValueGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get promiseValue", args, object);
+
+ if (!DebuggerObject::requirePromise(cx, object))
+ return false;
+
+ if (object->promiseState() != JS::PromiseState::Fulfilled) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_PROMISE_NOT_FULFILLED);
+ return false;
+ }
+
+ return DebuggerObject::getPromiseValue(cx, object, args.rval());;
+}
+
+/* static */ bool
+DebuggerObject::promiseReasonGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get promiseReason", args, object);
+
+ if (!DebuggerObject::requirePromise(cx, object))
+ return false;
+
+ if (object->promiseState() != JS::PromiseState::Rejected) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_PROMISE_NOT_REJECTED);
+ return false;
+ }
+
+ return DebuggerObject::getPromiseReason(cx, object, args.rval());;
+}
+
+/* static */ bool
+DebuggerObject::promiseLifetimeGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get promiseLifetime", args, object);
+
+ if (!DebuggerObject::requirePromise(cx, object))
+ return false;
+
+ args.rval().setNumber(object->promiseLifetime());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseTimeToResolutionGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "get promiseTimeToResolution", args, object);
+
+ if (!DebuggerObject::requirePromise(cx, object))
+ return false;
+
+ if (object->promiseState() == JS::PromiseState::Pending) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_PROMISE_NOT_RESOLVED);
+ return false;
+ }
+
+ args.rval().setNumber(object->promiseTimeToResolution());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseAllocationSiteGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseAllocationSite", args, refobj);
+
+ RootedObject allocSite(cx, promise->allocationSite());
+ if (!allocSite) {
+ args.rval().setNull();
+ return true;
+ }
+
+ if (!cx->compartment()->wrap(cx, &allocSite))
+ return false;
+ args.rval().set(ObjectValue(*allocSite));
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseResolutionSiteGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseResolutionSite", args, refobj);
+
+ if (promise->state() == JS::PromiseState::Pending) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_PROMISE_NOT_RESOLVED);
+ return false;
+ }
+
+ RootedObject resolutionSite(cx, promise->resolutionSite());
+ if (!resolutionSite) {
+ args.rval().setNull();
+ return true;
+ }
+
+ if (!cx->compartment()->wrap(cx, &resolutionSite))
+ return false;
+ args.rval().set(ObjectValue(*resolutionSite));
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseIDGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseID", args, refobj);
+
+ args.rval().setNumber(double(promise->getID()));
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseDependentPromises", args, dbg, refobj);
+
+ Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
+ {
+ JSAutoCompartment ac(cx, promise);
+ if (!promise->dependentPromises(cx, &values))
+ return false;
+ }
+ for (size_t i = 0; i < values.length(); i++) {
+ if (!dbg->wrapDebuggeeValue(cx, values[i]))
+ return false;
+ }
+ RootedArrayObject promises(cx);
+ if (values.length() == 0)
+ promises = NewDenseEmptyArray(cx);
+ else
+ promises = NewDenseCopiedArray(cx, values.length(), values[0].address());
+ if (!promises)
+ return false;
+ args.rval().setObject(*promises);
+ return true;
+}
+#endif // SPIDERMONKEY_PROMISE
+
+/* static */ bool
+DebuggerObject::isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "isExtensible", args, object)
+
+ bool result;
+ if (!DebuggerObject::isExtensible(cx, object, result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::isSealedMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "isSealed", args, object)
+
+ bool result;
+ if (!DebuggerObject::isSealed(cx, object, result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::isFrozenMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "isFrozen", args, object)
+
+ bool result;
+ if (!DebuggerObject::isFrozen(cx, object, result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+static JSObject*
+IdVectorToArray(JSContext* cx, Handle<IdVector> ids)
+{
+ Rooted<ValueVector> vals(cx, ValueVector(cx));
+ if (!vals.growBy(ids.length()))
+ return nullptr;
+
+ for (size_t i = 0, len = ids.length(); i < len; i++) {
+ jsid id = ids[i];
+ if (JSID_IS_INT(id)) {
+ JSString* str = Int32ToString<CanGC>(cx, JSID_TO_INT(id));
+ if (!str)
+ return nullptr;
+ vals[i].setString(str);
+ } else if (JSID_IS_ATOM(id)) {
+ vals[i].setString(JSID_TO_STRING(id));
+ } else if (JSID_IS_SYMBOL(id)) {
+ vals[i].setSymbol(JSID_TO_SYMBOL(id));
+ } else {
+ MOZ_ASSERT_UNREACHABLE("IdVector must contain only string, int, and Symbol jsids");
+ }
+ }
+
+ return NewDenseCopiedArray(cx, vals.length(), vals.begin());
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertyNamesMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertyNames", args, object)
+
+ Rooted<IdVector> ids(cx, IdVector(cx));
+ if (!DebuggerObject::getOwnPropertyNames(cx, object, &ids))
+ return false;
+
+ RootedObject obj(cx, IdVectorToArray(cx, ids));
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertySymbolsMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertySymbols", args, object)
+
+ Rooted<IdVector> ids(cx, IdVector(cx));
+ if (!DebuggerObject::getOwnPropertySymbols(cx, object, &ids))
+ return false;
+
+ RootedObject obj(cx, IdVectorToArray(cx, ids));
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertyDescriptorMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "getOwnPropertyDescriptor", args, object)
+
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, args.get(0), &id))
+ return false;
+
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!DebuggerObject::getOwnPropertyDescriptor(cx, object, id, &desc))
+ return false;
+
+ return JS::FromPropertyDescriptor(cx, desc, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::preventExtensionsMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "preventExtensions", args, object)
+
+ if (!DebuggerObject::preventExtensions(cx, object))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::sealMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "seal", args, object)
+
+ if (!DebuggerObject::seal(cx, object))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::freezeMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "freeze", args, object)
+
+ if (!DebuggerObject::freeze(cx, object))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::definePropertyMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "defineProperty", args, object)
+ if (!args.requireAtLeast(cx, "Debugger.Object.defineProperty", 2))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, args[0], &id))
+ return false;
+
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!ToPropertyDescriptor(cx, args[1], false, &desc))
+ return false;
+
+ if (!DebuggerObject::defineProperty(cx, object, id, desc))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::definePropertiesMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "defineProperties", args, object);
+ if (!args.requireAtLeast(cx, "Debugger.Object.defineProperties", 1))
+ return false;
+
+ RootedValue arg(cx, args[0]);
+ RootedObject props(cx, ToObject(cx, arg));
+ if (!props)
+ return false;
+ AutoIdVector ids(cx);
+ Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx));
+ if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs))
+ return false;
+ Rooted<IdVector> ids2(cx, IdVector(cx));
+ if (!ids2.append(ids.begin(), ids.end()))
+ return false;
+
+ if (!DebuggerObject::defineProperties(cx, object, ids2, descs))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/*
+ * This does a non-strict delete, as a matter of API design. The case where the
+ * property is non-configurable isn't necessarily exceptional here.
+ */
+/* static */ bool
+DebuggerObject::deletePropertyMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "deleteProperty", args, object)
+
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, args.get(0), &id))
+ return false;
+
+ ObjectOpResult result;
+ if (!DebuggerObject::deleteProperty(cx, object, id, result))
+ return false;
+
+ args.rval().setBoolean(result.ok());
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::callMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "call", callArgs, object);
+
+ RootedValue thisv(cx, callArgs.get(0));
+
+ Rooted<ValueVector> args(cx, ValueVector(cx));
+ if (callArgs.length() >= 2) {
+ if (!args.growBy(callArgs.length() - 1))
+ return false;
+ for (size_t i = 1; i < callArgs.length(); ++i)
+ args[i - 1].set(callArgs[i]);
+ }
+
+ return object->call(cx, object, thisv, args, callArgs.rval());
+}
+
+/* static */ bool
+DebuggerObject::applyMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "apply", callArgs, object);
+
+ RootedValue thisv(cx, callArgs.get(0));
+
+ Rooted<ValueVector> args(cx, ValueVector(cx));
+ if (callArgs.length() >= 2 && !callArgs[1].isNullOrUndefined()) {
+ if (!callArgs[1].isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_APPLY_ARGS,
+ js_apply_str);
+ return false;
+ }
+
+ RootedObject argsobj(cx, &callArgs[1].toObject());
+
+ unsigned argc = 0;
+ if (!GetLengthProperty(cx, argsobj, &argc))
+ return false;
+ argc = unsigned(Min(argc, ARGS_LENGTH_MAX));
+
+ if (!args.growBy(argc) || !GetElements(cx, argsobj, argc, args.begin()))
+ return false;
+ }
+
+ return object->call(cx, object, thisv, args, callArgs.rval());
+}
+
+/* static */ bool
+DebuggerObject::asEnvironmentMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "asEnvironment", args, dbg, referent);
+ if (!RequireGlobalObject(cx, args.thisv(), referent))
+ return false;
+
+ Rooted<Env*> env(cx);
+ {
+ AutoCompartment ac(cx, referent);
+ env = GetDebugEnvironmentForGlobalLexicalEnvironment(cx);
+ if (!env)
+ return false;
+ }
+
+ return dbg->wrapEnvironment(cx, env, args.rval());
+}
+
+// Lookup a binding on the referent's global scope and change it to undefined
+// if it is an uninitialized lexical, otherwise do nothing. The method's
+// JavaScript return value is true _only_ when an uninitialized lexical has been
+// altered, otherwise it is false.
+/* static */ bool
+DebuggerObject::forceLexicalInitializationByNameMethod(JSContext *cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "forceLexicalInitializationByName", args, object)
+ if (!args.requireAtLeast(cx, "Debugger.Object.prototype.forceLexicalInitializationByName", 1))
+ return false;
+
+ if (!DebuggerObject::requireGlobal(cx, object))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToIdentifier(cx, args[0], &id))
+ return false;
+
+ bool result;
+ if (!DebuggerObject::forceLexicalInitializationByName(cx, object, id, result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::executeInGlobalMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "executeInGlobal", args, object);
+ if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal", 1))
+ return false;
+
+ if (!DebuggerObject::requireGlobal(cx, object))
+ return false;
+
+ AutoStableStringChars stableChars(cx);
+ if (!ValueToStableChars(cx, "Debugger.Object.prototype.executeInGlobal", args[0],
+ stableChars))
+ {
+ return false;
+ }
+ mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
+
+ EvalOptions options;
+ if (!ParseEvalOptions(cx, args.get(1), options))
+ return false;
+
+ JSTrapStatus status;
+ RootedValue value(cx);
+ if (!DebuggerObject::executeInGlobal(cx, object, chars, nullptr, options, status, &value))
+ return false;
+
+ return object->owner()->newCompletionValue(cx, status, value, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::executeInGlobalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "executeInGlobalWithBindings", args, object);
+ if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobalWithBindings", 2))
+ return false;
+
+ if (!DebuggerObject::requireGlobal(cx, object))
+ return false;
+
+ AutoStableStringChars stableChars(cx);
+ if (!ValueToStableChars(cx, "Debugger.Object.prototype.executeInGlobalWithBindings", args[0],
+ stableChars))
+ {
+ return false;
+ }
+ mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
+
+ RootedObject bindings(cx, NonNullObject(cx, args[1]));
+ if (!bindings)
+ return false;
+
+ EvalOptions options;
+ if (!ParseEvalOptions(cx, args.get(2), options))
+ return false;
+
+ JSTrapStatus status;
+ RootedValue value(cx);
+ if (!DebuggerObject::executeInGlobal(cx, object, chars, bindings, options, status, &value))
+ return false;
+
+ return object->owner()->newCompletionValue(cx, status, value, args.rval());
+}
+
+/* static */ bool
+DebuggerObject::makeDebuggeeValueMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "makeDebuggeeValue", args, object);
+ if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue", 1))
+ return false;
+
+ return DebuggerObject::makeDebuggeeValue(cx, object, args[0], args.rval());
+}
+
+/* static */ bool
+DebuggerObject::unsafeDereferenceMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "unsafeDereference", args, object);
+
+ RootedObject result(cx);
+ if (!DebuggerObject::unsafeDereference(cx, object, &result))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::unwrapMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGOBJECT(cx, argc, vp, "unwrap", args, object);
+
+ RootedDebuggerObject result(cx);
+ if (!DebuggerObject::unwrap(cx, object, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+const JSPropertySpec DebuggerObject::properties_[] = {
+ JS_PSG("callable", DebuggerObject::callableGetter, 0),
+ JS_PSG("isBoundFunction", DebuggerObject::isBoundFunctionGetter, 0),
+ JS_PSG("isArrowFunction", DebuggerObject::isArrowFunctionGetter, 0),
+ JS_PSG("proto", DebuggerObject::protoGetter, 0),
+ JS_PSG("class", DebuggerObject::classGetter, 0),
+ JS_PSG("name", DebuggerObject::nameGetter, 0),
+ JS_PSG("displayName", DebuggerObject::displayNameGetter, 0),
+ JS_PSG("parameterNames", DebuggerObject::parameterNamesGetter, 0),
+ JS_PSG("script", DebuggerObject::scriptGetter, 0),
+ JS_PSG("environment", DebuggerObject::environmentGetter, 0),
+ JS_PSG("boundTargetFunction", DebuggerObject::boundTargetFunctionGetter, 0),
+ JS_PSG("boundThis", DebuggerObject::boundThisGetter, 0),
+ JS_PSG("boundArguments", DebuggerObject::boundArgumentsGetter, 0),
+ JS_PSG("global", DebuggerObject::globalGetter, 0),
+ JS_PSG("allocationSite", DebuggerObject::allocationSiteGetter, 0),
+ JS_PSG("errorMessageName", DebuggerObject::errorMessageNameGetter, 0),
+ JS_PSG("errorLineNumber", DebuggerObject::errorLineNumberGetter, 0),
+ JS_PSG("errorColumnNumber", DebuggerObject::errorColumnNumberGetter, 0),
+ JS_PSG("isProxy", DebuggerObject::isProxyGetter, 0),
+ JS_PSG("proxyTarget", DebuggerObject::proxyTargetGetter, 0),
+ JS_PSG("proxyHandler", DebuggerObject::proxyHandlerGetter, 0),
+ JS_PS_END
+};
+
+#ifdef SPIDERMONKEY_PROMISE
+const JSPropertySpec DebuggerObject::promiseProperties_[] = {
+ JS_PSG("isPromise", DebuggerObject::isPromiseGetter, 0),
+ JS_PSG("promiseState", DebuggerObject::promiseStateGetter, 0),
+ JS_PSG("promiseValue", DebuggerObject::promiseValueGetter, 0),
+ JS_PSG("promiseReason", DebuggerObject::promiseReasonGetter, 0),
+ JS_PSG("promiseLifetime", DebuggerObject::promiseLifetimeGetter, 0),
+ JS_PSG("promiseTimeToResolution", DebuggerObject::promiseTimeToResolutionGetter, 0),
+ JS_PSG("promiseAllocationSite", DebuggerObject::promiseAllocationSiteGetter, 0),
+ JS_PSG("promiseResolutionSite", DebuggerObject::promiseResolutionSiteGetter, 0),
+ JS_PSG("promiseID", DebuggerObject::promiseIDGetter, 0),
+ JS_PSG("promiseDependentPromises", DebuggerObject::promiseDependentPromisesGetter, 0),
+ JS_PS_END
+};
+#endif // SPIDERMONKEY_PROMISE
+
+const JSFunctionSpec DebuggerObject::methods_[] = {
+ JS_FN("isExtensible", DebuggerObject::isExtensibleMethod, 0, 0),
+ JS_FN("isSealed", DebuggerObject::isSealedMethod, 0, 0),
+ JS_FN("isFrozen", DebuggerObject::isFrozenMethod, 0, 0),
+ JS_FN("getOwnPropertyNames", DebuggerObject::getOwnPropertyNamesMethod, 0, 0),
+ JS_FN("getOwnPropertySymbols", DebuggerObject::getOwnPropertySymbolsMethod, 0, 0),
+ JS_FN("getOwnPropertyDescriptor", DebuggerObject::getOwnPropertyDescriptorMethod, 1, 0),
+ JS_FN("preventExtensions", DebuggerObject::preventExtensionsMethod, 0, 0),
+ JS_FN("seal", DebuggerObject::sealMethod, 0, 0),
+ JS_FN("freeze", DebuggerObject::freezeMethod, 0, 0),
+ JS_FN("defineProperty", DebuggerObject::definePropertyMethod, 2, 0),
+ JS_FN("defineProperties", DebuggerObject::definePropertiesMethod, 1, 0),
+ JS_FN("deleteProperty", DebuggerObject::deletePropertyMethod, 1, 0),
+ JS_FN("call", DebuggerObject::callMethod, 0, 0),
+ JS_FN("apply", DebuggerObject::applyMethod, 0, 0),
+ JS_FN("asEnvironment", DebuggerObject::asEnvironmentMethod, 0, 0),
+ JS_FN("forceLexicalInitializationByName", DebuggerObject::forceLexicalInitializationByNameMethod, 1, 0),
+ JS_FN("executeInGlobal", DebuggerObject::executeInGlobalMethod, 1, 0),
+ JS_FN("executeInGlobalWithBindings", DebuggerObject::executeInGlobalWithBindingsMethod, 2, 0),
+ JS_FN("makeDebuggeeValue", DebuggerObject::makeDebuggeeValueMethod, 1, 0),
+ JS_FN("unsafeDereference", DebuggerObject::unsafeDereferenceMethod, 0, 0),
+ JS_FN("unwrap", DebuggerObject::unwrapMethod, 0, 0),
+ JS_FS_END
+};
+
+/* static */ NativeObject*
+DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor)
+{
+ Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+ RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+
+ RootedNativeObject objectProto(cx, InitClass(cx, debugCtor, objProto, &class_,
+ construct, 0, properties_,
+ methods_, nullptr, nullptr));
+
+ if (!objectProto)
+ return nullptr;
+
+#ifdef SPIDERMONKEY_PROMISE
+ if (!DefinePropertiesAndFunctions(cx, objectProto, promiseProperties_, nullptr))
+ return nullptr;
+#endif // SPIDERMONKEY_PROMISE
+
+ return objectProto;
+}
+
+/* static */ DebuggerObject*
+DebuggerObject::create(JSContext* cx, HandleObject proto, HandleObject referent,
+ HandleNativeObject debugger)
+{
+ NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
+ JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerObject::class_, proto, newKind);
+ if (!obj)
+ return nullptr;
+
+ DebuggerObject& object = obj->as<DebuggerObject>();
+ object.setPrivateGCThing(referent);
+ object.setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
+
+ return &object;
+}
+
+bool
+DebuggerObject::isCallable() const
+{
+ return referent()->isCallable();
+}
+
+bool
+DebuggerObject::isFunction() const
+{
+ return referent()->is<JSFunction>();
+}
+
+bool
+DebuggerObject::isDebuggeeFunction() const
+{
+ return referent()->is<JSFunction>() &&
+ owner()->observesGlobal(&referent()->as<JSFunction>().global());
+}
+
+bool
+DebuggerObject::isBoundFunction() const
+{
+ MOZ_ASSERT(isDebuggeeFunction());
+
+ return referent()->isBoundFunction();
+}
+
+bool
+DebuggerObject::isArrowFunction() const
+{
+ MOZ_ASSERT(isDebuggeeFunction());
+
+ return referent()->as<JSFunction>().isArrow();
+}
+
+bool
+DebuggerObject::isGlobal() const
+{
+ return referent()->is<GlobalObject>();
+}
+
+bool
+DebuggerObject::isScriptedProxy() const
+{
+ return js::IsScriptedProxy(referent());
+}
+
+#ifdef SPIDERMONKEY_PROMISE
+bool
+DebuggerObject::isPromise() const
+{
+ JSObject* referent = this->referent();
+
+ if (IsCrossCompartmentWrapper(referent)) {
+ referent = CheckedUnwrap(referent);
+ if (!referent)
+ return false;
+ }
+
+ return referent->is<PromiseObject>();
+}
+#endif // SPIDERMONKEY_PROMISE
+
+/* static */ bool
+DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleString result)
+{
+ RootedObject referent(cx, object->referent());
+
+ const char* className;
+ {
+ AutoCompartment ac(cx, referent);
+ className = GetObjectClassName(cx, referent);
+ }
+
+ JSAtom* str = Atomize(cx, className, strlen(className));
+ if (!str)
+ return false;
+
+ result.set(str);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getGlobal(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ RootedObject global(cx, &referent->global());
+ return dbg->wrapDebuggeeObject(cx, global, result);
+}
+
+JSAtom*
+DebuggerObject::name() const
+{
+ MOZ_ASSERT(isFunction());
+
+ return referent()->as<JSFunction>().name();
+}
+
+JSAtom*
+DebuggerObject::displayName() const
+{
+ MOZ_ASSERT(isFunction());
+
+ return referent()->as<JSFunction>().displayAtom();
+}
+
+JS::PromiseState
+DebuggerObject::promiseState() const
+{
+ return promise()->state();
+}
+
+double
+DebuggerObject::promiseLifetime() const
+{
+ return promise()->lifetime();
+}
+
+double
+DebuggerObject::promiseTimeToResolution() const
+{
+ MOZ_ASSERT(promiseState() != JS::PromiseState::Pending);
+
+ return promise()->timeToResolution();
+}
+
+/* static */ bool
+DebuggerObject::getParameterNames(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<StringVector> result)
+{
+ MOZ_ASSERT(object->isDebuggeeFunction());
+
+ RootedFunction referent(cx, &object->referent()->as<JSFunction>());
+
+ if (!result.growBy(referent->nargs()))
+ return false;
+ if (referent->isInterpreted()) {
+ RootedScript script(cx, GetOrCreateFunctionScript(cx, referent));
+ if (!script)
+ return false;
+
+ MOZ_ASSERT(referent->nargs() == script->numArgs());
+
+ if (referent->nargs() > 0) {
+ PositionalFormalParameterIter fi(script);
+ for (size_t i = 0; i < referent->nargs(); i++, fi++) {
+ MOZ_ASSERT(fi.argumentSlot() == i);
+ result[i].set(fi.name());
+ }
+ }
+ } else {
+ for (size_t i = 0; i < referent->nargs(); i++)
+ result[i].set(nullptr);
+ }
+
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getBoundTargetFunction(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ MOZ_ASSERT(object->isBoundFunction());
+
+ RootedFunction referent(cx, &object->referent()->as<JSFunction>());
+ Debugger* dbg = object->owner();
+
+ RootedObject target(cx, referent->getBoundFunctionTarget());
+ return dbg->wrapDebuggeeObject(cx, target, result);
+}
+
+/* static */ bool
+DebuggerObject::getBoundThis(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result)
+{
+ MOZ_ASSERT(object->isBoundFunction());
+
+ RootedFunction referent(cx, &object->referent()->as<JSFunction>());
+ Debugger* dbg = object->owner();
+
+ result.set(referent->getBoundFunctionThis());
+ return dbg->wrapDebuggeeValue(cx, result);
+}
+
+/* static */ bool
+DebuggerObject::getBoundArguments(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<ValueVector> result)
+{
+ MOZ_ASSERT(object->isBoundFunction());
+
+ RootedFunction referent(cx, &object->referent()->as<JSFunction>());
+ Debugger* dbg = object->owner();
+
+ size_t length = referent->getBoundFunctionArgumentCount();
+ if (!result.resize(length))
+ return false;
+ for (size_t i = 0; i < length; i++) {
+ result[i].set(referent->getBoundFunctionArgument(cx, i));
+ if (!dbg->wrapDebuggeeValue(cx, result[i]))
+ return false;
+ }
+ return true;
+}
+
+/* static */ SavedFrame*
+Debugger::getObjectAllocationSite(JSObject& obj)
+{
+ JSObject* metadata = GetAllocationMetadata(&obj);
+ if (!metadata)
+ return nullptr;
+
+ MOZ_ASSERT(!metadata->is<WrapperObject>());
+ return SavedFrame::isSavedFrameAndNotProto(*metadata)
+ ? &metadata->as<SavedFrame>()
+ : nullptr;
+}
+
+/* static */ bool
+DebuggerObject::getAllocationSite(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleObject result)
+{
+ RootedObject referent(cx, object->referent());
+
+ RootedObject allocSite(cx, Debugger::getObjectAllocationSite(*referent));
+ if (!cx->compartment()->wrap(cx, &allocSite))
+ return false;
+
+ result.set(allocSite);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getErrorReport(JSContext* cx, HandleObject maybeError, JSErrorReport*& report)
+{
+ JSObject* obj = maybeError;
+ if (IsCrossCompartmentWrapper(obj))
+ obj = CheckedUnwrap(obj);
+
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ if (!obj->is<ErrorObject>()) {
+ report = nullptr;
+ return true;
+ }
+
+ report = obj->as<ErrorObject>().getErrorReport();
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getErrorMessageName(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleString result)
+{
+ RootedObject referent(cx, object->referent());
+ JSErrorReport* report;
+ if (!getErrorReport(cx, referent, report))
+ return false;
+
+ if (!report) {
+ result.set(nullptr);
+ return true;
+ }
+
+ const JSErrorFormatString* efs = GetErrorMessage(nullptr, report->errorNumber);
+ if (!efs) {
+ result.set(nullptr);
+ return true;
+ }
+
+ RootedString str(cx, JS_NewStringCopyZ(cx, efs->name));
+ if (!cx->compartment()->wrap(cx, &str))
+ return false;
+
+ result.set(str);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getErrorLineNumber(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result)
+{
+ RootedObject referent(cx, object->referent());
+ JSErrorReport* report;
+ if (!getErrorReport(cx, referent, report))
+ return false;
+
+ if (!report) {
+ result.setUndefined();
+ return true;
+ }
+
+ result.setNumber(report->lineno);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result)
+{
+ RootedObject referent(cx, object->referent());
+ JSErrorReport* report;
+ if (!getErrorReport(cx, referent, report))
+ return false;
+
+ if (!report) {
+ result.setUndefined();
+ return true;
+ }
+
+ result.setNumber(report->column);
+ return true;
+}
+
+#ifdef SPIDERMONKEY_PROMISE
+/* static */ bool
+DebuggerObject::getPromiseValue(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result)
+{
+ MOZ_ASSERT(object->promiseState() == JS::PromiseState::Fulfilled);
+
+ result.set(object->promise()->value());
+ return object->owner()->wrapDebuggeeValue(cx, result);
+}
+
+/* static */ bool
+DebuggerObject::getPromiseReason(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result)
+{
+ MOZ_ASSERT(object->promiseState() == JS::PromiseState::Rejected);
+
+ result.set(object->promise()->reason());
+ return object->owner()->wrapDebuggeeValue(cx, result);
+}
+#endif // SPIDERMONKEY_PROMISE
+
+/* static */ bool
+DebuggerObject::isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+ ErrorCopier ec(ac);
+ return IsExtensible(cx, referent, &result);
+}
+
+/* static */ bool
+DebuggerObject::isSealed(JSContext* cx, HandleDebuggerObject object, bool& result)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return TestIntegrityLevel(cx, referent, IntegrityLevel::Sealed, &result);
+}
+
+/* static */ bool
+DebuggerObject::isFrozen(JSContext* cx, HandleDebuggerObject object, bool& result)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return TestIntegrityLevel(cx, referent, IntegrityLevel::Frozen, &result);
+}
+
+/* static */ bool
+DebuggerObject::getPrototypeOf(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ RootedObject proto(cx);
+ {
+ AutoCompartment ac(cx, referent);
+ if (!GetPrototype(cx, referent, &proto))
+ return false;
+ }
+
+ if (!proto) {
+ result.set(nullptr);
+ return true;
+ }
+
+ return dbg->wrapDebuggeeObject(cx, proto, result);
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertyNames(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<IdVector> result)
+{
+ RootedObject referent(cx, object->referent());
+
+ AutoIdVector ids(cx);
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ if (!GetPropertyKeys(cx, referent, JSITER_OWNONLY | JSITER_HIDDEN, &ids))
+ return false;
+ }
+
+ return result.append(ids.begin(), ids.end());
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertySymbols(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<IdVector> result)
+{
+ RootedObject referent(cx, object->referent());
+
+ AutoIdVector ids(cx);
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ if (!GetPropertyKeys(cx, referent,
+ JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY,
+ &ids))
+ return false;
+ }
+
+ return result.append(ids.begin(), ids.end());
+}
+
+/* static */ bool
+DebuggerObject::getOwnPropertyDescriptor(JSContext* cx, HandleDebuggerObject object,
+ HandleId id, MutableHandle<PropertyDescriptor> desc)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ /* Bug: This can cause the debuggee to run! */
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ if (!GetOwnPropertyDescriptor(cx, referent, id, desc))
+ return false;
+ }
+
+ if (desc.object()) {
+ /* Rewrap the debuggee values in desc for the debugger. */
+ if (!dbg->wrapDebuggeeValue(cx, desc.value()))
+ return false;
+
+ if (desc.hasGetterObject()) {
+ RootedValue get(cx, ObjectOrNullValue(desc.getterObject()));
+ if (!dbg->wrapDebuggeeValue(cx, &get))
+ return false;
+ desc.setGetterObject(get.toObjectOrNull());
+ }
+ if (desc.hasSetterObject()) {
+ RootedValue set(cx, ObjectOrNullValue(desc.setterObject()));
+ if (!dbg->wrapDebuggeeValue(cx, &set))
+ return false;
+ desc.setSetterObject(set.toObjectOrNull());
+ }
+
+ // Avoid tripping same-compartment assertions in JS::FromPropertyDescriptor().
+ desc.object().set(object);
+ }
+
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::preventExtensions(JSContext* cx, HandleDebuggerObject object)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return PreventExtensions(cx, referent);
+}
+
+/* static */ bool
+DebuggerObject::seal(JSContext* cx, HandleDebuggerObject object)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return SetIntegrityLevel(cx, referent, IntegrityLevel::Sealed);
+}
+
+/* static */ bool
+DebuggerObject::freeze(JSContext* cx, HandleDebuggerObject object)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return SetIntegrityLevel(cx, referent, IntegrityLevel::Frozen);
+}
+
+/* static */ bool
+DebuggerObject::defineProperty(JSContext* cx, HandleDebuggerObject object, HandleId id,
+ Handle<PropertyDescriptor> desc_)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ Rooted<PropertyDescriptor> desc(cx, desc_);
+ if (!dbg->unwrapPropertyDescriptor(cx, referent, &desc))
+ return false;
+ if (!CheckPropertyDescriptorAccessors(cx, desc))
+ return false;
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+ if (!cx->compartment()->wrap(cx, &desc))
+ return false;
+
+ ErrorCopier ec(ac);
+ if (!DefineProperty(cx, referent, id, desc))
+ return false;
+
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::defineProperties(JSContext* cx, HandleDebuggerObject object,
+ Handle<IdVector> ids,
+ Handle<PropertyDescriptorVector> descs_)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx));
+ if (!descs.append(descs_.begin(), descs_.end()))
+ return false;
+ for (size_t i = 0; i < descs.length(); i++) {
+ if (!dbg->unwrapPropertyDescriptor(cx, referent, descs[i]))
+ return false;
+ if (!CheckPropertyDescriptorAccessors(cx, descs[i]))
+ return false;
+ }
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+ for (size_t i = 0; i < descs.length(); i++) {
+ if (!cx->compartment()->wrap(cx, descs[i]))
+ return false;
+ }
+
+ ErrorCopier ec(ac);
+ for (size_t i = 0; i < descs.length(); i++) {
+ if (!DefineProperty(cx, referent, ids[i], descs[i]))
+ return false;
+ }
+
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::deleteProperty(JSContext* cx, HandleDebuggerObject object, HandleId id,
+ ObjectOpResult& result)
+{
+ RootedObject referent(cx, object->referent());
+
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ return DeleteProperty(cx, referent, id, result);
+}
+
+/* static */ bool
+DebuggerObject::call(JSContext* cx, HandleDebuggerObject object, HandleValue thisv_,
+ Handle<ValueVector> args, MutableHandleValue result)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ if (!referent->isCallable()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Object", "call", referent->getClass()->name);
+ return false;
+ }
+
+ RootedValue calleev(cx, ObjectValue(*referent));
+
+ /*
+ * Unwrap Debugger.Objects. This happens in the debugger's compartment since
+ * that is where any exceptions must be reported.
+ */
+ RootedValue thisv(cx, thisv_);
+ if (!dbg->unwrapDebuggeeValue(cx, &thisv))
+ return false;
+ Rooted<ValueVector> args2(cx, ValueVector(cx));
+ if (!args2.append(args.begin(), args.end()))
+ return false;
+ for (unsigned i = 0; i < args2.length(); ++i) {
+ if (!dbg->unwrapDebuggeeValue(cx, args2[i]))
+ return false;
+ }
+
+ /*
+ * Enter the debuggee compartment and rewrap all input value for that compartment.
+ * (Rewrapping always takes place in the destination compartment.)
+ */
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+ if (!cx->compartment()->wrap(cx, &calleev) || !cx->compartment()->wrap(cx, &thisv))
+ return false;
+ for (unsigned i = 0; i < args2.length(); ++i) {
+ if (!cx->compartment()->wrap(cx, args2[i]))
+ return false;
+ }
+
+ /*
+ * Call the function. Use receiveCompletionValue to return to the debugger
+ * compartment and populate args.rval().
+ */
+ LeaveDebuggeeNoExecute nnx(cx);
+
+ bool ok;
+ {
+ InvokeArgs invokeArgs(cx);
+
+ ok = invokeArgs.init(cx, args2.length());
+ if (ok) {
+ for (size_t i = 0; i < args2.length(); ++i)
+ invokeArgs[i].set(args2[i]);
+
+ ok = js::Call(cx, calleev, thisv, invokeArgs, result);
+ }
+ }
+
+ return dbg->receiveCompletionValue(ac, ok, result, result);
+}
+
+/* static */ bool
+DebuggerObject::forceLexicalInitializationByName(JSContext* cx, HandleDebuggerObject object,
+ HandleId id, bool& result)
+{
+ if (!JSID_IS_STRING(id)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ "Debugger.Object.prototype.forceLexicalInitializationByName",
+ "string", InformalValueTypeName(IdToValue(id)));
+ return false;
+ }
+
+ MOZ_ASSERT(object->isGlobal());
+
+ Rooted<GlobalObject*> referent(cx, &object->referent()->as<GlobalObject>());
+
+ RootedObject globalLexical(cx, &referent->lexicalEnvironment());
+ RootedObject pobj(cx);
+ RootedShape shape(cx);
+ if (!LookupProperty(cx, globalLexical, id, &pobj, &shape))
+ return false;
+
+ result = false;
+ if (shape) {
+ Value v = globalLexical->as<NativeObject>().getSlot(shape->slot());
+ if (shape->hasSlot() && v.isMagic() && v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
+ globalLexical->as<NativeObject>().setSlot(shape->slot(), UndefinedValue());
+ result = true;
+ }
+ }
+
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::executeInGlobal(JSContext* cx, HandleDebuggerObject object,
+ mozilla::Range<const char16_t> chars, HandleObject bindings,
+ const EvalOptions& options, JSTrapStatus& status,
+ MutableHandleValue value)
+{
+ MOZ_ASSERT(object->isGlobal());
+
+ Rooted<GlobalObject*> referent(cx, &object->referent()->as<GlobalObject>());
+ Debugger* dbg = object->owner();
+
+ RootedObject globalLexical(cx, &referent->lexicalEnvironment());
+ return DebuggerGenericEval(cx, chars, bindings, options, status, value, dbg, globalLexical,
+ nullptr);
+}
+
+/* static */ bool
+DebuggerObject::makeDebuggeeValue(JSContext* cx, HandleDebuggerObject object,
+ HandleValue value_, MutableHandleValue result)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ RootedValue value(cx, value_);
+
+ /* Non-objects are already debuggee values. */
+ if (value.isObject()) {
+ // Enter this Debugger.Object's referent's compartment, and wrap the
+ // argument as appropriate for references from there.
+ {
+ AutoCompartment ac(cx, referent);
+ if (!cx->compartment()->wrap(cx, &value))
+ return false;
+ }
+
+ // Back in the debugger's compartment, produce a new Debugger.Object
+ // instance referring to the wrapped argument.
+ if (!dbg->wrapDebuggeeValue(cx, &value))
+ return false;
+ }
+
+ result.set(value);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::unsafeDereference(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleObject result)
+{
+ RootedObject referent(cx, object->referent());
+
+ if (!cx->compartment()->wrap(cx, &referent))
+ return false;
+
+ // Wrapping should return the WindowProxy.
+ MOZ_ASSERT(!IsWindow(referent));
+
+ result.set(referent);
+ return true;
+}
+
+/* static */ bool
+DebuggerObject::unwrap(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+
+ RootedObject unwrapped(cx, UnwrapOneChecked(referent));
+ if (!unwrapped) {
+ result.set(nullptr);
+ return true;
+ }
+
+ // Don't allow unwrapping to create a D.O whose referent is in an
+ // invisible-to-Debugger global. (If our referent is a *wrapper* to such,
+ // and the wrapper is in a visible compartment, that's fine.)
+ JSCompartment* unwrappedCompartment = unwrapped->compartment();
+ if (unwrappedCompartment->creationOptions().invisibleToDebugger()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_INVISIBLE_COMPARTMENT);
+ return false;
+ }
+
+ return dbg->wrapDebuggeeObject(cx, unwrapped, result);
+}
+
+/* static */ bool
+DebuggerObject::requireGlobal(JSContext* cx, HandleDebuggerObject object)
+{
+ if (!object->isGlobal()) {
+ RootedObject referent(cx, object->referent());
+
+ const char* isWrapper = "";
+ const char* isWindowProxy = "";
+
+ /* Help the poor programmer by pointing out wrappers around globals... */
+ if (referent->is<WrapperObject>()) {
+ referent = js::UncheckedUnwrap(referent);
+ isWrapper = "a wrapper around ";
+ }
+
+ /* ... and WindowProxies around Windows. */
+ if (IsWindowProxy(referent)) {
+ referent = ToWindowIfWindowProxy(referent);
+ isWindowProxy = "a WindowProxy referring to ";
+ }
+
+ RootedValue dbgobj(cx, ObjectValue(*object));
+ if (referent->is<GlobalObject>()) {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_WRAPPER_IN_WAY,
+ JSDVG_SEARCH_STACK, dbgobj, nullptr,
+ isWrapper, isWindowProxy);
+ } else {
+ ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_DEBUG_BAD_REFERENT,
+ JSDVG_SEARCH_STACK, dbgobj, nullptr,
+ "a global object", nullptr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+#ifdef SPIDERMONKEY_PROMISE
+/* static */ bool
+DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
+{
+ RootedObject referent(cx, object->referent());
+
+ if (IsCrossCompartmentWrapper(referent)) {
+ referent = CheckedUnwrap(referent);
+ if (!referent) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+ }
+
+ if (!referent->is<PromiseObject>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ "Debugger", "Promise", object->getClass()->name);
+ return false;
+ }
+
+ return true;
+}
+#endif // SPIDERMONKEY_PROMISE
+
+/* static */ bool
+DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ MOZ_ASSERT(object->isScriptedProxy());
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+ RootedObject unwrapped(cx, js::GetProxyTargetObject(referent));
+ if(!unwrapped) {
+ result.set(nullptr);
+ return true;
+ }
+ return dbg->wrapDebuggeeObject(cx, unwrapped, result);
+}
+
+/* static */ bool
+DebuggerObject::getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result)
+{
+ MOZ_ASSERT(object->isScriptedProxy());
+ RootedObject referent(cx, object->referent());
+ Debugger* dbg = object->owner();
+ RootedObject unwrapped(cx, ScriptedProxyHandler::handlerObject(referent));
+ if(!unwrapped) {
+ result.set(nullptr);
+ return true;
+ }
+ return dbg->wrapDebuggeeObject(cx, unwrapped, result);
+}
+
+
+/*** Debugger.Environment ************************************************************************/
+
+void
+DebuggerEnv_trace(JSTracer* trc, JSObject* obj)
+{
+ /*
+ * There is a barrier on private pointers, so the Unbarriered marking
+ * is okay.
+ */
+ if (Env* referent = (JSObject*) obj->as<NativeObject>().getPrivate()) {
+ TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+ "Debugger.Environment referent");
+ obj->as<NativeObject>().setPrivateUnbarriered(referent);
+ }
+}
+
+static DebuggerEnvironment*
+DebuggerEnvironment_checkThis(JSContext* cx, const CallArgs& args, const char* fnname,
+ bool requireDebuggee)
+{
+ JSObject* thisobj = NonNullObject(cx, args.thisv());
+ if (!thisobj)
+ return nullptr;
+ if (thisobj->getClass() != &DebuggerEnvironment::class_) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Environment", fnname, thisobj->getClass()->name);
+ return nullptr;
+ }
+
+ /*
+ * Forbid Debugger.Environment.prototype, which is of class DebuggerEnvironment::class_
+ * but isn't a real working Debugger.Environment. The prototype object is
+ * distinguished by having no referent.
+ */
+ DebuggerEnvironment* nthisobj = &thisobj->as<DebuggerEnvironment>();
+ if (!nthisobj->getPrivate()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ "Debugger.Environment", fnname, "prototype object");
+ return nullptr;
+ }
+
+ /*
+ * Forbid access to Debugger.Environment objects that are not debuggee
+ * environments.
+ */
+ if (requireDebuggee) {
+ Rooted<Env*> env(cx, static_cast<Env*>(nthisobj->getPrivate()));
+ if (!Debugger::fromChildJSObject(nthisobj)->observesGlobal(&env->global())) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_DEBUGGEE,
+ "Debugger.Environment", "environment");
+ return nullptr;
+ }
+ }
+
+ return nthisobj;
+}
+
+#define THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, fnname, args, environment) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ Rooted<DebuggerEnvironment*> environment(cx, DebuggerEnvironment_checkThis(cx, args, fnname, false)); \
+ if (!environment) \
+ return false; \
+
+/* static */ bool
+DebuggerEnvironment::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Environment");
+ return false;
+}
+
+static bool
+IsDeclarative(Env* env)
+{
+ return env->is<DebugEnvironmentProxy>() &&
+ env->as<DebugEnvironmentProxy>().isForDeclarative();
+}
+
+template <typename T>
+static bool
+IsDebugEnvironmentWrapper(Env* env)
+{
+ return env->is<DebugEnvironmentProxy>() &&
+ env->as<DebugEnvironmentProxy>().environment().is<T>();
+}
+
+bool
+DebuggerEnvironment::typeGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ DebuggerEnvironmentType type = environment->type();
+
+ const char* s;
+ switch (type) {
+ case DebuggerEnvironmentType::Declarative:
+ s = "declarative";
+ break;
+ case DebuggerEnvironmentType::With:
+ s = "with";
+ break;
+ case DebuggerEnvironmentType::Object:
+ s = "object";
+ break;
+ }
+
+ JSAtom* str = Atomize(cx, s, strlen(s), PinAtom);
+ if (!str)
+ return false;
+
+ args.rval().setString(str);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::parentGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ RootedDebuggerEnvironment result(cx);
+ if (!environment->getParent(cx, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::objectGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get type", args, environment);
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ if (environment->type() == DebuggerEnvironmentType::Declarative) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NO_ENV_OBJECT);
+ return false;
+ }
+
+ RootedDebuggerObject result(cx);
+ if (!environment->getObject(cx, &result))
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::calleeGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get callee", args, environment);
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ RootedDebuggerObject result(cx);
+ if (!environment->getCallee(cx, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::inspectableGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get inspectable", args, environment);
+
+ args.rval().setBoolean(environment->isDebuggee());
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::optimizedOutGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "get optimizedOut", args, environment);
+
+ args.rval().setBoolean(environment->isOptimized());
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::namesMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "names", args, environment);
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ Rooted<IdVector> ids(cx, IdVector(cx));
+ if (!DebuggerEnvironment::getNames(cx, environment, &ids))
+ return false;
+
+ RootedObject obj(cx, IdVectorToArray(cx, ids));
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::findMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "find", args, environment);
+ if (!args.requireAtLeast(cx, "Debugger.Environment.find", 1))
+ return false;
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToIdentifier(cx, args[0], &id))
+ return false;
+
+ RootedDebuggerEnvironment result(cx);
+ if (!DebuggerEnvironment::find(cx, environment, id, &result))
+ return false;
+
+ args.rval().setObjectOrNull(result);
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::getVariableMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "getVariable", args, environment);
+ if (!args.requireAtLeast(cx, "Debugger.Environment.getVariable", 1))
+ return false;
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToIdentifier(cx, args[0], &id))
+ return false;
+
+ return DebuggerEnvironment::getVariable(cx, environment, id, args.rval());
+}
+
+/* static */ bool
+DebuggerEnvironment::setVariableMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_ENVIRONMENT(cx, argc, vp, "setVariable", args, environment);
+ if (!args.requireAtLeast(cx, "Debugger.Environment.setVariable", 2))
+ return false;
+
+ if (!environment->requireDebuggee(cx))
+ return false;
+
+ RootedId id(cx);
+ if (!ValueToIdentifier(cx, args[0], &id))
+ return false;
+
+ if (!DebuggerEnvironment::setVariable(cx, environment, id, args[1]))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DebuggerEnvironment::requireDebuggee(JSContext* cx) const
+{
+ if (!isDebuggee()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_DEBUGGEE,
+ "Debugger.Environment", "environment");
+
+ return false;
+ }
+
+ return true;
+}
+
+const JSPropertySpec DebuggerEnvironment::properties_[] = {
+ JS_PSG("type", DebuggerEnvironment::typeGetter, 0),
+ JS_PSG("parent", DebuggerEnvironment::parentGetter, 0),
+ JS_PSG("object", DebuggerEnvironment::objectGetter, 0),
+ JS_PSG("callee", DebuggerEnvironment::calleeGetter, 0),
+ JS_PSG("inspectable", DebuggerEnvironment::inspectableGetter, 0),
+ JS_PSG("optimizedOut", DebuggerEnvironment::optimizedOutGetter, 0),
+ JS_PS_END
+};
+
+const JSFunctionSpec DebuggerEnvironment::methods_[] = {
+ JS_FN("names", DebuggerEnvironment::namesMethod, 0, 0),
+ JS_FN("find", DebuggerEnvironment::findMethod, 1, 0),
+ JS_FN("getVariable", DebuggerEnvironment::getVariableMethod, 1, 0),
+ JS_FN("setVariable", DebuggerEnvironment::setVariableMethod, 2, 0),
+ JS_FS_END
+};
+
+/* static */ NativeObject*
+DebuggerEnvironment::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj)
+{
+ Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+ RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+
+ return InitClass(cx, dbgCtor, objProto, &DebuggerEnvironment::class_, construct, 0,
+ properties_, methods_, nullptr, nullptr);
+}
+
+/* static */ DebuggerEnvironment*
+DebuggerEnvironment::create(JSContext* cx, HandleObject proto, HandleObject referent,
+ HandleNativeObject debugger)
+{
+ NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
+ RootedObject obj(cx, NewObjectWithGivenProto(cx, &DebuggerEnvironment::class_, proto, newKind));
+ if (!obj)
+ return nullptr;
+
+ DebuggerEnvironment& environment = obj->as<DebuggerEnvironment>();
+ environment.setPrivateGCThing(referent);
+ environment.setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
+
+ return &environment;
+}
+
+/* static */ DebuggerEnvironmentType
+DebuggerEnvironment::type() const
+{
+ /* Don't bother switching compartments just to check env's type. */
+ if (IsDeclarative(referent()))
+ return DebuggerEnvironmentType::Declarative;
+ if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent()))
+ return DebuggerEnvironmentType::With;
+ return DebuggerEnvironmentType::Object;
+}
+
+bool
+DebuggerEnvironment::getParent(JSContext* cx, MutableHandleDebuggerEnvironment result) const
+{
+ /* Don't bother switching compartments just to get env's parent. */
+ Rooted<Env*> parent(cx, referent()->enclosingEnvironment());
+ if (!parent) {
+ result.set(nullptr);
+ return true;
+ }
+
+ return owner()->wrapEnvironment(cx, parent, result);
+}
+
+bool
+DebuggerEnvironment::getObject(JSContext* cx, MutableHandleDebuggerObject result) const
+{
+ MOZ_ASSERT(type() != DebuggerEnvironmentType::Declarative);
+
+ /* Don't bother switching compartments just to get env's object. */
+ RootedObject object(cx);
+ if (IsDebugEnvironmentWrapper<WithEnvironmentObject>(referent())) {
+ object.set(&referent()->as<DebugEnvironmentProxy>()
+ .environment().as<WithEnvironmentObject>().object());
+ } else if (IsDebugEnvironmentWrapper<NonSyntacticVariablesObject>(referent())) {
+ object.set(&referent()->as<DebugEnvironmentProxy>()
+ .environment().as<NonSyntacticVariablesObject>());
+ } else {
+ object.set(referent());
+ MOZ_ASSERT(!object->is<DebugEnvironmentProxy>());
+ }
+
+ return owner()->wrapDebuggeeObject(cx, object, result);
+}
+
+bool
+DebuggerEnvironment::getCallee(JSContext* cx, MutableHandleDebuggerObject result) const
+{
+ if (!referent()->is<DebugEnvironmentProxy>()) {
+ result.set(nullptr);
+ return true;
+ }
+
+ JSObject& scope = referent()->as<DebugEnvironmentProxy>().environment();
+ if (!scope.is<CallObject>()) {
+ result.set(nullptr);
+ return true;
+ }
+
+ RootedObject callee(cx, &scope.as<CallObject>().callee());
+ if (IsInternalFunctionObject(*callee)) {
+ result.set(nullptr);
+ return true;
+ }
+
+ return owner()->wrapDebuggeeObject(cx, callee, result);
+}
+
+bool
+DebuggerEnvironment::isDebuggee() const
+{
+ MOZ_ASSERT(referent());
+ MOZ_ASSERT(!referent()->is<EnvironmentObject>());
+
+ return owner()->observesGlobal(&referent()->global());
+}
+
+bool
+DebuggerEnvironment::isOptimized() const
+{
+ return referent()->is<DebugEnvironmentProxy>() &&
+ referent()->as<DebugEnvironmentProxy>().isOptimizedOut();
+}
+
+/* static */ bool
+DebuggerEnvironment::getNames(JSContext* cx, HandleDebuggerEnvironment environment,
+ MutableHandle<IdVector> result)
+{
+ MOZ_ASSERT(environment->isDebuggee());
+
+ Rooted<Env*> referent(cx, environment->referent());
+
+ AutoIdVector ids(cx);
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ ErrorCopier ec(ac);
+ if (!GetPropertyKeys(cx, referent, JSITER_HIDDEN, &ids))
+ return false;
+ }
+
+ for (size_t i = 0; i < ids.length(); ++i) {
+ jsid id = ids[i];
+ if (JSID_IS_ATOM(id) && IsIdentifier(JSID_TO_ATOM(id))) {
+ if (!result.append(id))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */ bool
+DebuggerEnvironment::find(JSContext* cx, HandleDebuggerEnvironment environment, HandleId id,
+ MutableHandleDebuggerEnvironment result)
+{
+ MOZ_ASSERT(environment->isDebuggee());
+
+ Rooted<Env*> env(cx, environment->referent());
+ Debugger* dbg = environment->owner();
+
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, env);
+
+ /* This can trigger resolve hooks. */
+ ErrorCopier ec(ac);
+ for (; env; env = env->enclosingEnvironment()) {
+ bool found;
+ if (!HasProperty(cx, env, id, &found))
+ return false;
+ if (found)
+ break;
+ }
+ }
+
+ if (!env) {
+ result.set(nullptr);
+ return true;
+ }
+
+ return dbg->wrapEnvironment(cx, env, result);
+}
+
+/* static */ bool
+DebuggerEnvironment::getVariable(JSContext* cx, HandleDebuggerEnvironment environment,
+ HandleId id, MutableHandleValue result)
+{
+ MOZ_ASSERT(environment->isDebuggee());
+
+ Rooted<Env*> referent(cx, environment->referent());
+ Debugger* dbg = environment->owner();
+
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+
+ /* This can trigger getters. */
+ ErrorCopier ec(ac);
+
+ bool found;
+ if (!HasProperty(cx, referent, id, &found))
+ return false;
+ if (!found) {
+ result.setUndefined();
+ return true;
+ }
+
+ // For DebugEnvironmentProxys, we get sentinel values for optimized out
+ // slots and arguments instead of throwing (the default behavior).
+ //
+ // See wrapDebuggeeValue for how the sentinel values are wrapped.
+ if (referent->is<DebugEnvironmentProxy>()) {
+ if (!referent->as<DebugEnvironmentProxy>().getMaybeSentinelValue(cx, id, result))
+ return false;
+ } else {
+ if (!GetProperty(cx, referent, referent, id, result))
+ return false;
+ }
+ }
+
+ // When we've faked up scope chain objects for optimized-out scopes,
+ // declarative environments may contain internal JSFunction objects, which
+ // we shouldn't expose to the user.
+ if (result.isObject()) {
+ RootedObject obj(cx, &result.toObject());
+ if (obj->is<JSFunction>() &&
+ IsInternalFunctionObject(obj->as<JSFunction>()))
+ result.setMagic(JS_OPTIMIZED_OUT);
+ }
+
+ return dbg->wrapDebuggeeValue(cx, result);
+}
+
+/* static */ bool
+DebuggerEnvironment::setVariable(JSContext* cx, HandleDebuggerEnvironment environment,
+ HandleId id, HandleValue value_)
+{
+ MOZ_ASSERT(environment->isDebuggee());
+
+ Rooted<Env*> referent(cx, environment->referent());
+ Debugger* dbg = environment->owner();
+
+ RootedValue value(cx, value_);
+ if (!dbg->unwrapDebuggeeValue(cx, &value))
+ return false;
+
+ {
+ Maybe<AutoCompartment> ac;
+ ac.emplace(cx, referent);
+ if (!cx->compartment()->wrap(cx, &value))
+ return false;
+
+ /* This can trigger setters. */
+ ErrorCopier ec(ac);
+
+ /* Make sure the environment actually has the specified binding. */
+ bool found;
+ if (!HasProperty(cx, referent, id, &found))
+ return false;
+ if (!found) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_VARIABLE_NOT_FOUND);
+ return false;
+ }
+
+ /* Just set the property. */
+ if (!SetProperty(cx, referent, id, value))
+ return false;
+ }
+
+ return true;
+}
+
+
+/*** JS::dbg::Builder ****************************************************************************/
+
+Builder::Builder(JSContext* cx, js::Debugger* debugger)
+ : debuggerObject(cx, debugger->toJSObject().get()),
+ debugger(debugger)
+{ }
+
+
+#if DEBUG
+void
+Builder::assertBuilt(JSObject* obj)
+{
+ // We can't use assertSameCompartment here, because that is always keyed to
+ // some JSContext's current compartment, whereas BuiltThings can be
+ // constructed and assigned to without respect to any particular context;
+ // the only constraint is that they should be in their debugger's compartment.
+ MOZ_ASSERT_IF(obj, debuggerObject->compartment() == obj->compartment());
+}
+#endif
+
+bool
+Builder::Object::definePropertyToTrusted(JSContext* cx, const char* name,
+ JS::MutableHandleValue trusted)
+{
+ // We should have checked for false Objects before calling this.
+ MOZ_ASSERT(value);
+
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom)
+ return false;
+ RootedId id(cx, AtomToId(atom));
+
+ return DefineProperty(cx, value, id, trusted);
+}
+
+bool
+Builder::Object::defineProperty(JSContext* cx, const char* name, JS::HandleValue propval_)
+{
+ AutoCompartment ac(cx, debuggerObject());
+
+ RootedValue propval(cx, propval_);
+ if (!debugger()->wrapDebuggeeValue(cx, &propval))
+ return false;
+
+ return definePropertyToTrusted(cx, name, &propval);
+}
+
+bool
+Builder::Object::defineProperty(JSContext* cx, const char* name, JS::HandleObject propval_)
+{
+ RootedValue propval(cx, ObjectOrNullValue(propval_));
+ return defineProperty(cx, name, propval);
+}
+
+bool
+Builder::Object::defineProperty(JSContext* cx, const char* name, Builder::Object& propval_)
+{
+ AutoCompartment ac(cx, debuggerObject());
+
+ RootedValue propval(cx, ObjectOrNullValue(propval_.value));
+ return definePropertyToTrusted(cx, name, &propval);
+}
+
+Builder::Object
+Builder::newObject(JSContext* cx)
+{
+ AutoCompartment ac(cx, debuggerObject);
+
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+
+ // If the allocation failed, this will return a false Object, as the spec promises.
+ return Object(cx, *this, obj);
+}
+
+
+/*** JS::dbg::AutoEntryMonitor ******************************************************************/
+
+AutoEntryMonitor::AutoEntryMonitor(JSContext* cx)
+ : runtime_(cx->runtime()),
+ savedMonitor_(cx->runtime()->entryMonitor)
+{
+ runtime_->entryMonitor = this;
+}
+
+AutoEntryMonitor::~AutoEntryMonitor()
+{
+ runtime_->entryMonitor = savedMonitor_;
+}
+
+
+/*** Glue ****************************************************************************************/
+
+extern JS_PUBLIC_API(bool)
+JS_DefineDebuggerObject(JSContext* cx, HandleObject obj)
+{
+ RootedNativeObject
+ objProto(cx),
+ debugCtor(cx),
+ debugProto(cx),
+ frameProto(cx),
+ scriptProto(cx),
+ sourceProto(cx),
+ objectProto(cx),
+ envProto(cx),
+ memoryProto(cx);
+ RootedObject debuggeeWouldRunProto(cx);
+ RootedValue debuggeeWouldRunCtor(cx);
+ Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+
+ objProto = global->getOrCreateObjectPrototype(cx);
+ if (!objProto)
+ return false;
+ debugProto = InitClass(cx, obj,
+ objProto, &Debugger::class_, Debugger::construct,
+ 1, Debugger::properties, Debugger::methods, nullptr,
+ Debugger::static_methods, debugCtor.address());
+ if (!debugProto)
+ return false;
+
+ frameProto = DebuggerFrame::initClass(cx, debugCtor, obj);
+ if (!frameProto)
+ return false;
+
+ scriptProto = InitClass(cx, debugCtor, objProto, &DebuggerScript_class,
+ DebuggerScript_construct, 0,
+ DebuggerScript_properties, DebuggerScript_methods,
+ nullptr, nullptr);
+ if (!scriptProto)
+ return false;
+
+ sourceProto = InitClass(cx, debugCtor, sourceProto, &DebuggerSource_class,
+ DebuggerSource_construct, 0,
+ DebuggerSource_properties, DebuggerSource_methods,
+ nullptr, nullptr);
+ if (!sourceProto)
+ return false;
+
+ objectProto = DebuggerObject::initClass(cx, obj, debugCtor);
+ if (!objectProto)
+ return false;
+
+ envProto = DebuggerEnvironment::initClass(cx, debugCtor, obj);
+ if (!envProto)
+ return false;
+
+ memoryProto = InitClass(cx, debugCtor, objProto, &DebuggerMemory::class_,
+ DebuggerMemory::construct, 0, DebuggerMemory::properties,
+ DebuggerMemory::methods, nullptr, nullptr);
+ if (!memoryProto)
+ return false;
+
+ debuggeeWouldRunProto =
+ GlobalObject::getOrCreateCustomErrorPrototype(cx, global, JSEXN_DEBUGGEEWOULDRUN);
+ if (!debuggeeWouldRunProto)
+ return false;
+ debuggeeWouldRunCtor = global->getConstructor(JSProto_DebuggeeWouldRun);
+ RootedId debuggeeWouldRunId(cx, NameToId(ClassName(JSProto_DebuggeeWouldRun, cx)));
+ if (!DefineProperty(cx, debugCtor, debuggeeWouldRunId, debuggeeWouldRunCtor,
+ nullptr, nullptr, 0))
+ {
+ return false;
+ }
+
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_FRAME_PROTO, ObjectValue(*frameProto));
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_OBJECT_PROTO, ObjectValue(*objectProto));
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SCRIPT_PROTO, ObjectValue(*scriptProto));
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_SOURCE_PROTO, ObjectValue(*sourceProto));
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_ENV_PROTO, ObjectValue(*envProto));
+ debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO, ObjectValue(*memoryProto));
+ return true;
+}
+
+static inline void
+AssertIsPromise(JSContext* cx, HandleObject promise)
+{
+ MOZ_ASSERT(promise);
+ assertSameCompartment(cx, promise);
+ MOZ_ASSERT(strcmp(promise->getClass()->name, "Promise") == 0);
+}
+
+JS_PUBLIC_API(void)
+JS::dbg::onNewPromise(JSContext* cx, HandleObject promise_)
+{
+ RootedObject promise(cx, promise_);
+ if (IsWrapper(promise))
+ promise = UncheckedUnwrap(promise);
+ AutoCompartment ac(cx, promise);
+ AssertIsPromise(cx, promise);
+ Debugger::slowPathPromiseHook(cx, Debugger::OnNewPromise, promise);
+}
+
+JS_PUBLIC_API(void)
+JS::dbg::onPromiseSettled(JSContext* cx, HandleObject promise)
+{
+ AssertIsPromise(cx, promise);
+ Debugger::slowPathPromiseHook(cx, Debugger::OnPromiseSettled, promise);
+}
+
+JS_PUBLIC_API(bool)
+JS::dbg::IsDebugger(JSObject& obj)
+{
+ JSObject* unwrapped = CheckedUnwrap(&obj);
+ return unwrapped &&
+ js::GetObjectClass(unwrapped) == &Debugger::class_ &&
+ js::Debugger::fromJSObject(unwrapped) != nullptr;
+}
+
+JS_PUBLIC_API(bool)
+JS::dbg::GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, AutoObjectVector& vector)
+{
+ MOZ_ASSERT(IsDebugger(dbgObj));
+ js::Debugger* dbg = js::Debugger::fromJSObject(CheckedUnwrap(&dbgObj));
+
+ if (!vector.reserve(vector.length() + dbg->debuggees.count())) {
+ JS_ReportOutOfMemory(cx);
+ return false;
+ }
+
+ for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront())
+ vector.infallibleAppend(static_cast<JSObject*>(r.front()));
+
+ return true;
+}
+
+
+/*** JS::dbg::GarbageCollectionEvent **************************************************************/
+
+namespace JS {
+namespace dbg {
+
+/* static */ GarbageCollectionEvent::Ptr
+GarbageCollectionEvent::Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t gcNumber)
+{
+ auto data = rt->make_unique<GarbageCollectionEvent>(gcNumber);
+ if (!data)
+ return nullptr;
+
+ data->nonincrementalReason = stats.nonincrementalReason();
+
+ for (auto range = stats.sliceRange(); !range.empty(); range.popFront()) {
+ if (!data->reason) {
+ // There is only one GC reason for the whole cycle, but for legacy
+ // reasons this data is stored and replicated on each slice. Each
+ // slice used to have its own GCReason, but now they are all the
+ // same.
+ data->reason = gcreason::ExplainReason(range.front().reason);
+ MOZ_ASSERT(data->reason);
+ }
+
+ if (!data->collections.growBy(1))
+ return nullptr;
+
+ data->collections.back().startTimestamp = range.front().startTimestamp;
+ data->collections.back().endTimestamp = range.front().endTimestamp;
+ }
+
+
+ return data;
+}
+
+static bool
+DefineStringProperty(JSContext* cx, HandleObject obj, PropertyName* propName, const char* strVal)
+{
+ RootedValue val(cx, UndefinedValue());
+ if (strVal) {
+ JSAtom* atomized = Atomize(cx, strVal, strlen(strVal));
+ if (!atomized)
+ return false;
+ val = StringValue(atomized);
+ }
+ return DefineProperty(cx, obj, propName, val);
+}
+
+JSObject*
+GarbageCollectionEvent::toJSObject(JSContext* cx) const
+{
+ RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ RootedValue gcCycleNumberVal(cx, NumberValue(majorGCNumber_));
+ if (!obj ||
+ !DefineStringProperty(cx, obj, cx->names().nonincrementalReason, nonincrementalReason) ||
+ !DefineStringProperty(cx, obj, cx->names().reason, reason) ||
+ !DefineProperty(cx, obj, cx->names().gcCycleNumber, gcCycleNumberVal))
+ {
+ return nullptr;
+ }
+
+ RootedArrayObject slicesArray(cx, NewDenseEmptyArray(cx));
+ if (!slicesArray)
+ return nullptr;
+
+ size_t idx = 0;
+ for (auto range = collections.all(); !range.empty(); range.popFront()) {
+ RootedPlainObject collectionObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!collectionObj)
+ return nullptr;
+
+ RootedValue start(cx, NumberValue(range.front().startTimestamp));
+ RootedValue end(cx, NumberValue(range.front().endTimestamp));
+ if (!DefineProperty(cx, collectionObj, cx->names().startTimestamp, start) ||
+ !DefineProperty(cx, collectionObj, cx->names().endTimestamp, end))
+ {
+ return nullptr;
+ }
+
+ RootedValue collectionVal(cx, ObjectValue(*collectionObj));
+ if (!DefineElement(cx, slicesArray, idx++, collectionVal))
+ return nullptr;
+ }
+
+ RootedValue slicesValue(cx, ObjectValue(*slicesArray));
+ if (!DefineProperty(cx, obj, cx->names().collections, slicesValue))
+ return nullptr;
+
+ return obj;
+}
+
+JS_PUBLIC_API(bool)
+FireOnGarbageCollectionHook(JSContext* cx, JS::dbg::GarbageCollectionEvent::Ptr&& data)
+{
+ AutoObjectVector triggered(cx);
+
+ {
+ // We had better not GC (and potentially get a dangling Debugger
+ // pointer) while finding all Debuggers observing a debuggee that
+ // participated in this GC.
+ AutoCheckCannotGC noGC;
+
+ for (Debugger* dbg : cx->runtime()->debuggerList) {
+ if (dbg->enabled &&
+ dbg->observedGC(data->majorGCNumber()) &&
+ dbg->getHook(Debugger::OnGarbageCollection))
+ {
+ if (!triggered.append(dbg->object)) {
+ JS_ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+ }
+ }
+
+ for ( ; !triggered.empty(); triggered.popBack()) {
+ Debugger* dbg = Debugger::fromJSObject(triggered.back());
+ dbg->fireOnGarbageCollectionHook(cx, data);
+ MOZ_ASSERT(!cx->isExceptionPending());
+ }
+
+ return true;
+}
+
+} // namespace dbg
+} // namespace JS
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
new file mode 100644
index 000000000..3239ade6d
--- /dev/null
+++ b/js/src/vm/Debugger.h
@@ -0,0 +1,1584 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Debugger_h
+#define vm_Debugger_h
+
+#include "mozilla/GuardObjects.h"
+#include "mozilla/LinkedList.h"
+#include "mozilla/Range.h"
+#include "mozilla/Vector.h"
+
+#include "jsclist.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsweakmap.h"
+#include "jswrapper.h"
+
+#include "builtin/Promise.h"
+#include "ds/TraceableFifo.h"
+#include "gc/Barrier.h"
+#include "js/Debug.h"
+#include "js/GCVariant.h"
+#include "js/HashTable.h"
+#include "vm/GlobalObject.h"
+#include "vm/SavedStacks.h"
+#include "wasm/WasmJS.h"
+
+enum JSTrapStatus {
+ JSTRAP_ERROR,
+ JSTRAP_CONTINUE,
+ JSTRAP_RETURN,
+ JSTRAP_THROW,
+ JSTRAP_LIMIT
+};
+
+namespace js {
+
+class Breakpoint;
+class DebuggerMemory;
+class WasmInstanceObject;
+
+typedef HashSet<ReadBarrieredGlobalObject,
+ MovableCellHasher<ReadBarrieredGlobalObject>,
+ RuntimeAllocPolicy> WeakGlobalObjectSet;
+
+/*
+ * A weakmap from GC thing keys to JSObject values that supports the keys being
+ * in different compartments to the values. All values must be in the same
+ * compartment.
+ *
+ * The purpose of this is to allow the garbage collector to easily find edges
+ * from debuggee object compartments to debugger compartments when calculating
+ * the compartment groups. Note that these edges are the inverse of the edges
+ * stored in the cross compartment map.
+ *
+ * The current implementation results in all debuggee object compartments being
+ * swept in the same group as the debugger. This is a conservative approach,
+ * and compartments may be unnecessarily grouped, however it results in a
+ * simpler and faster implementation.
+ *
+ * If InvisibleKeysOk is true, then the map can have keys in invisible-to-
+ * debugger compartments. If it is false, we assert that such entries are never
+ * created.
+ *
+ * Also note that keys in these weakmaps can be in any compartment, debuggee or
+ * not, because they cannot be deleted when a compartment is no longer a
+ * debuggee: the values need to maintain object identity across add/remove/add
+ * transitions.
+ */
+template <class UnbarrieredKey, bool InvisibleKeysOk=false>
+class DebuggerWeakMap : private WeakMap<HeapPtr<UnbarrieredKey>, HeapPtr<JSObject*>,
+ MovableCellHasher<HeapPtr<UnbarrieredKey>>>
+{
+ private:
+ typedef HeapPtr<UnbarrieredKey> Key;
+ typedef HeapPtr<JSObject*> Value;
+
+ typedef HashMap<JS::Zone*,
+ uintptr_t,
+ DefaultHasher<JS::Zone*>,
+ RuntimeAllocPolicy> CountMap;
+
+ CountMap zoneCounts;
+ JSCompartment* compartment;
+
+ public:
+ typedef WeakMap<Key, Value, MovableCellHasher<Key>> Base;
+
+ explicit DebuggerWeakMap(JSContext* cx)
+ : Base(cx),
+ zoneCounts(cx->runtime()),
+ compartment(cx->compartment())
+ { }
+
+ public:
+ /* Expose those parts of HashMap public interface that are used by Debugger methods. */
+
+ typedef typename Base::Entry Entry;
+ typedef typename Base::Ptr Ptr;
+ typedef typename Base::AddPtr AddPtr;
+ typedef typename Base::Range Range;
+ typedef typename Base::Enum Enum;
+ typedef typename Base::Lookup Lookup;
+
+ /* Expose WeakMap public interface */
+
+ using Base::lookupForAdd;
+ using Base::all;
+ using Base::trace;
+
+ MOZ_MUST_USE bool init(uint32_t len = 16) {
+ return Base::init(len) && zoneCounts.init();
+ }
+
+ template<typename KeyInput, typename ValueInput>
+ bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) {
+ MOZ_ASSERT(v->compartment() == this->compartment);
+ MOZ_ASSERT(!k->compartment()->creationOptions().mergeable());
+ MOZ_ASSERT_IF(!InvisibleKeysOk,
+ !k->compartment()->creationOptions().invisibleToDebugger());
+ MOZ_ASSERT(!Base::has(k));
+ if (!incZoneCount(k->zone()))
+ return false;
+ bool ok = Base::relookupOrAdd(p, k, v);
+ if (!ok)
+ decZoneCount(k->zone());
+ return ok;
+ }
+
+ void remove(const Lookup& l) {
+ MOZ_ASSERT(Base::has(l));
+ Base::remove(l);
+ decZoneCount(l->zone());
+ }
+
+ public:
+ template <void (traceValueEdges)(JSTracer*, JSObject*)>
+ void markCrossCompartmentEdges(JSTracer* tracer) {
+ for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
+ traceValueEdges(tracer, e.front().value());
+ Key key = e.front().key();
+ TraceEdge(tracer, &key, "Debugger WeakMap key");
+ if (key != e.front().key())
+ e.rekeyFront(key);
+ key.unsafeSet(nullptr);
+ }
+ }
+
+ bool hasKeyInZone(JS::Zone* zone) {
+ CountMap::Ptr p = zoneCounts.lookup(zone);
+ MOZ_ASSERT_IF(p.found(), p->value() > 0);
+ return p.found();
+ }
+
+ private:
+ /* Override sweep method to also update our edge cache. */
+ void sweep() {
+ for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
+ if (gc::IsAboutToBeFinalized(&e.front().mutableKey())) {
+ decZoneCount(e.front().key()->zone());
+ e.removeFront();
+ }
+ }
+ Base::assertEntriesNotAboutToBeFinalized();
+ }
+
+ MOZ_MUST_USE bool incZoneCount(JS::Zone* zone) {
+ CountMap::Ptr p = zoneCounts.lookupWithDefault(zone, 0);
+ if (!p)
+ return false;
+ ++p->value();
+ return true;
+ }
+
+ void decZoneCount(JS::Zone* zone) {
+ CountMap::Ptr p = zoneCounts.lookup(zone);
+ MOZ_ASSERT(p);
+ MOZ_ASSERT(p->value() > 0);
+ --p->value();
+ if (p->value() == 0)
+ zoneCounts.remove(zone);
+ }
+};
+
+class LeaveDebuggeeNoExecute;
+
+// Suppresses all debuggee NX checks, i.e., allow all execution. Used to allow
+// certain whitelisted operations to execute code.
+//
+// WARNING
+// WARNING Do not use this unless you know what you are doing!
+// WARNING
+class AutoSuppressDebuggeeNoExecuteChecks
+{
+ EnterDebuggeeNoExecute** stack_;
+ EnterDebuggeeNoExecute* prev_;
+
+ public:
+ explicit AutoSuppressDebuggeeNoExecuteChecks(JSContext* cx) {
+ stack_ = &cx->runtime()->noExecuteDebuggerTop;
+ prev_ = *stack_;
+ *stack_ = nullptr;
+ }
+
+ ~AutoSuppressDebuggeeNoExecuteChecks() {
+ MOZ_ASSERT(!*stack_);
+ *stack_ = prev_;
+ }
+};
+
+class MOZ_RAII EvalOptions {
+ const char* filename_;
+ unsigned lineno_;
+
+ public:
+ EvalOptions() : filename_(nullptr), lineno_(1) {}
+ ~EvalOptions();
+ const char* filename() const { return filename_; }
+ unsigned lineno() const { return lineno_; }
+ MOZ_MUST_USE bool setFilename(JSContext* cx, const char* filename);
+ void setLineno(unsigned lineno) { lineno_ = lineno; }
+};
+
+/*
+ * Env is the type of what ES5 calls "lexical environments" (runtime activations
+ * of lexical scopes). This is currently just JSObject, and is implemented by
+ * CallObject, LexicalEnvironmentObject, and WithEnvironmentObject, among
+ * others--but environments and objects are really two different concepts.
+ */
+typedef JSObject Env;
+
+// Either a real JSScript or synthesized.
+//
+// If synthesized, the referent is one of the following:
+//
+// 1. A WasmInstanceObject, denoting a synthesized toplevel wasm module
+// script.
+// 2. A wasm JSFunction, denoting a synthesized wasm function script.
+// NYI!
+typedef mozilla::Variant<JSScript*, WasmInstanceObject*> DebuggerScriptReferent;
+
+// Either a ScriptSourceObject, for ordinary JS, or a WasmInstanceObject,
+// denoting the synthesized source of a wasm module.
+typedef mozilla::Variant<ScriptSourceObject*, WasmInstanceObject*> DebuggerSourceReferent;
+
+class Debugger : private mozilla::LinkedListElement<Debugger>
+{
+ friend class Breakpoint;
+ friend class DebuggerMemory;
+ friend class SavedStacks;
+ friend class mozilla::LinkedListElement<Debugger>;
+ friend class mozilla::LinkedList<Debugger>;
+ friend bool (::JS_DefineDebuggerObject)(JSContext* cx, JS::HandleObject obj);
+ friend bool (::JS::dbg::IsDebugger)(JSObject&);
+ friend bool (::JS::dbg::GetDebuggeeGlobals)(JSContext*, JSObject&, AutoObjectVector&);
+ friend void JS::dbg::onNewPromise(JSContext* cx, HandleObject promise);
+ friend void JS::dbg::onPromiseSettled(JSContext* cx, HandleObject promise);
+ friend bool JS::dbg::FireOnGarbageCollectionHook(JSContext* cx,
+ JS::dbg::GarbageCollectionEvent::Ptr&& data);
+
+ public:
+ enum Hook {
+ OnDebuggerStatement,
+ OnExceptionUnwind,
+ OnNewScript,
+ OnEnterFrame,
+ OnNewGlobalObject,
+ OnNewPromise,
+ OnPromiseSettled,
+ OnGarbageCollection,
+ HookCount
+ };
+ enum {
+ JSSLOT_DEBUG_PROTO_START,
+ JSSLOT_DEBUG_FRAME_PROTO = JSSLOT_DEBUG_PROTO_START,
+ JSSLOT_DEBUG_ENV_PROTO,
+ JSSLOT_DEBUG_OBJECT_PROTO,
+ JSSLOT_DEBUG_SCRIPT_PROTO,
+ JSSLOT_DEBUG_SOURCE_PROTO,
+ JSSLOT_DEBUG_MEMORY_PROTO,
+ JSSLOT_DEBUG_PROTO_STOP,
+ JSSLOT_DEBUG_HOOK_START = JSSLOT_DEBUG_PROTO_STOP,
+ JSSLOT_DEBUG_HOOK_STOP = JSSLOT_DEBUG_HOOK_START + HookCount,
+ JSSLOT_DEBUG_MEMORY_INSTANCE = JSSLOT_DEBUG_HOOK_STOP,
+ JSSLOT_DEBUG_COUNT
+ };
+
+ class ExecutionObservableSet
+ {
+ public:
+ typedef HashSet<Zone*>::Range ZoneRange;
+
+ virtual Zone* singleZone() const { return nullptr; }
+ virtual JSScript* singleScriptForZoneInvalidation() const { return nullptr; }
+ virtual const HashSet<Zone*>* zones() const { return nullptr; }
+
+ virtual bool shouldRecompileOrInvalidate(JSScript* script) const = 0;
+ virtual bool shouldMarkAsDebuggee(ScriptFrameIter& iter) const = 0;
+ };
+
+ // This enum is converted to and compare with bool values; NotObserving
+ // must be 0 and Observing must be 1.
+ enum IsObserving {
+ NotObserving = 0,
+ Observing = 1
+ };
+
+ // Return true if the given compartment is a debuggee of this debugger,
+ // false otherwise.
+ bool isDebuggeeUnbarriered(const JSCompartment* compartment) const;
+
+ // 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);
+ }
+
+ // Notify this Debugger that one or more of its debuggees is participating
+ // in the GC identified by the given GC number.
+ bool debuggeeIsBeingCollected(uint64_t majorGCNumber) {
+ return observedGCs.put(majorGCNumber);
+ }
+
+ bool isEnabled() const {
+ return enabled;
+ }
+
+ static SavedFrame* getObjectAllocationSite(JSObject& obj);
+
+ struct AllocationsLogEntry
+ {
+ AllocationsLogEntry(HandleObject frame, double when, const char* className,
+ HandleAtom ctorName, size_t size, bool inNursery)
+ : frame(frame),
+ when(when),
+ className(className),
+ ctorName(ctorName),
+ size(size),
+ inNursery(inNursery)
+ {
+ MOZ_ASSERT_IF(frame, UncheckedUnwrap(frame)->is<SavedFrame>());
+ };
+
+ HeapPtr<JSObject*> frame;
+ double when;
+ const char* className;
+ HeapPtr<JSAtom*> ctorName;
+ size_t size;
+ bool inNursery;
+
+ void trace(JSTracer* trc) {
+ TraceNullableEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame");
+ TraceNullableEdge(trc, &ctorName, "Debugger::AllocationsLogEntry::ctorName");
+ }
+ };
+
+ // Barrier methods so we can have ReadBarriered<Debugger*>.
+ static void readBarrier(Debugger* dbg) {
+ InternalBarrierMethods<JSObject*>::readBarrier(dbg->object);
+ }
+ static void writeBarrierPost(Debugger** vp, Debugger* prev, Debugger* next) {}
+
+ private:
+ GCPtrNativeObject object; /* The Debugger object. Strong reference. */
+ WeakGlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */
+ JS::ZoneSet debuggeeZones; /* Set of zones that we have debuggees in. */
+ js::GCPtrObject uncaughtExceptionHook; /* Strong reference. */
+ bool enabled;
+ bool allowUnobservedAsmJS;
+
+ // Whether to enable code coverage on the Debuggee.
+ bool collectCoverageInfo;
+
+ JSCList breakpoints; /* Circular list of all js::Breakpoints in this debugger */
+
+ // The set of GC numbers for which one or more of this Debugger's observed
+ // debuggees participated in.
+ using GCNumberSet = HashSet<uint64_t, DefaultHasher<uint64_t>, RuntimeAllocPolicy>;
+ GCNumberSet observedGCs;
+
+ using AllocationsLog = js::TraceableFifo<AllocationsLogEntry>;
+
+ AllocationsLog allocationsLog;
+ bool trackingAllocationSites;
+ double allocationSamplingProbability;
+ size_t maxAllocationsLogLength;
+ bool allocationsLogOverflowed;
+
+ static const size_t DEFAULT_MAX_LOG_LENGTH = 5000;
+
+ MOZ_MUST_USE bool appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame,
+ double when);
+
+ /*
+ * Recompute the set of debuggee zones based on the set of debuggee globals.
+ */
+ void recomputeDebuggeeZoneSet();
+
+ /*
+ * Return true if there is an existing object metadata callback for the
+ * given global's compartment that will prevent our instrumentation of
+ * allocations.
+ */
+ static bool cannotTrackAllocations(const GlobalObject& global);
+
+ /*
+ * Return true if the given global is being observed by at least one
+ * Debugger that is tracking allocations.
+ */
+ static bool isObservedByDebuggerTrackingAllocations(const GlobalObject& global);
+
+ /*
+ * Add allocations tracking for objects allocated within the given
+ * debuggee's compartment. The given debuggee global must be observed by at
+ * least one Debugger that is enabled and tracking allocations.
+ */
+ static MOZ_MUST_USE bool addAllocationsTracking(JSContext* cx, Handle<GlobalObject*> debuggee);
+
+ /*
+ * Remove allocations tracking for objects allocated within the given
+ * global's compartment. This is a no-op if there are still Debuggers
+ * observing this global and who are tracking allocations.
+ */
+ static void removeAllocationsTracking(GlobalObject& global);
+
+ /*
+ * Add or remove allocations tracking for all debuggees.
+ */
+ MOZ_MUST_USE bool addAllocationsTrackingForAllDebuggees(JSContext* cx);
+ void removeAllocationsTrackingForAllDebuggees();
+
+ /*
+ * If this Debugger is enabled, and has a onNewGlobalObject handler, then
+ * this link is inserted into the circular list headed by
+ * JSRuntime::onNewGlobalObjectWatchers. Otherwise, this is set to a
+ * singleton cycle.
+ */
+ JSCList onNewGlobalObjectWatchersLink;
+
+ /*
+ * Map from stack frames that are currently on the stack to Debugger.Frame
+ * instances.
+ *
+ * The keys are always live stack frames. We drop them from this map as
+ * soon as they leave the stack (see slowPathOnLeaveFrame) and in
+ * removeDebuggee.
+ *
+ * We don't trace the keys of this map (the frames are on the stack and
+ * thus necessarily live), but we do trace the values. It's like a WeakMap
+ * that way, but since stack frames are not gc-things, the implementation
+ * has to be different.
+ */
+ typedef HashMap<AbstractFramePtr,
+ HeapPtr<DebuggerFrame*>,
+ DefaultHasher<AbstractFramePtr>,
+ RuntimeAllocPolicy> FrameMap;
+ FrameMap frames;
+
+ /* An ephemeral map from JSScript* to Debugger.Script instances. */
+ typedef DebuggerWeakMap<JSScript*> ScriptWeakMap;
+ ScriptWeakMap scripts;
+
+ /* The map from debuggee source script objects to their Debugger.Source instances. */
+ typedef DebuggerWeakMap<JSObject*, true> SourceWeakMap;
+ SourceWeakMap sources;
+
+ /* The map from debuggee objects to their Debugger.Object instances. */
+ typedef DebuggerWeakMap<JSObject*> ObjectWeakMap;
+ ObjectWeakMap objects;
+
+ /* The map from debuggee Envs to Debugger.Environment instances. */
+ ObjectWeakMap environments;
+
+ /* The map from WasmInstanceObjects to synthesized Debugger.Script instances. */
+ typedef DebuggerWeakMap<WasmInstanceObject*> WasmInstanceWeakMap;
+ WasmInstanceWeakMap wasmInstanceScripts;
+
+ /* The map from WasmInstanceObjects to synthesized Debugger.Source instances. */
+ WasmInstanceWeakMap wasmInstanceSources;
+
+ /*
+ * Keep track of tracelogger last drained identifiers to know if there are
+ * lost events.
+ */
+#ifdef NIGHTLY_BUILD
+ uint32_t traceLoggerLastDrainedSize;
+ uint32_t traceLoggerLastDrainedIteration;
+#endif
+ uint32_t traceLoggerScriptedCallsLastDrainedSize;
+ uint32_t traceLoggerScriptedCallsLastDrainedIteration;
+
+ class ScriptQuery;
+ class ObjectQuery;
+
+ MOZ_MUST_USE bool addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> obj);
+ void removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
+ WeakGlobalObjectSet::Enum* debugEnum);
+
+ /*
+ * Report and clear the pending exception on ac.context, if any, and return
+ * JSTRAP_ERROR.
+ */
+ JSTrapStatus reportUncaughtException(mozilla::Maybe<AutoCompartment>& ac);
+
+ /*
+ * Cope with an error or exception in a debugger hook.
+ *
+ * If callHook is true, then call the uncaughtExceptionHook, if any. If, in
+ * addition, vp is given, then parse the value returned by
+ * uncaughtExceptionHook as a resumption value.
+ *
+ * If there is no uncaughtExceptionHook, or if it fails, report and clear
+ * the pending exception on ac.context and return JSTRAP_ERROR.
+ *
+ * This always calls ac.leave(); ac is a parameter because this method must
+ * do some things in the debugger compartment and some things in the
+ * debuggee compartment.
+ */
+ JSTrapStatus handleUncaughtException(mozilla::Maybe<AutoCompartment>& ac);
+ JSTrapStatus handleUncaughtException(mozilla::Maybe<AutoCompartment>& ac,
+ MutableHandleValue vp,
+ const mozilla::Maybe<HandleValue>& thisVForCheck = mozilla::Nothing(),
+ AbstractFramePtr frame = NullFramePtr());
+
+ JSTrapStatus handleUncaughtExceptionHelper(mozilla::Maybe<AutoCompartment>& ac,
+ MutableHandleValue* vp,
+ const mozilla::Maybe<HandleValue>& thisVForCheck,
+ AbstractFramePtr frame);
+
+ /*
+ * Handle the result of a hook that is expected to return a resumption
+ * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called
+ * when we return from a debugging hook to debuggee code. The interpreter wants
+ * a (JSTrapStatus, Value) pair telling it how to proceed.
+ *
+ * Precondition: ac is entered. We are in the debugger compartment.
+ *
+ * Postcondition: This called ac.leave(). See handleUncaughtException.
+ *
+ * If ok is false, the hook failed. If an exception is pending in
+ * ac.context(), return handleUncaughtException(ac, vp, callhook).
+ * Otherwise just return JSTRAP_ERROR.
+ *
+ * If ok is true, there must be no exception pending in ac.context(). rv may be:
+ * undefined - Return JSTRAP_CONTINUE to continue execution normally.
+ * {return: value} or {throw: value} - Call unwrapDebuggeeValue to
+ * unwrap value. Store the result in *vp and return JSTRAP_RETURN
+ * or JSTRAP_THROW. The interpreter will force the current frame to
+ * return or throw an exception.
+ * null - Return JSTRAP_ERROR to terminate the debuggee with an
+ * uncatchable error.
+ * anything else - Make a new TypeError the pending exception and
+ * return handleUncaughtException(ac, vp, callHook).
+ */
+ JSTrapStatus processHandlerResult(mozilla::Maybe<AutoCompartment>& ac, bool OK, const Value& rv,
+ AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp);
+
+ JSTrapStatus processParsedHandlerResult(mozilla::Maybe<AutoCompartment>& ac,
+ AbstractFramePtr frame, jsbytecode* pc,
+ bool success, JSTrapStatus status,
+ MutableHandleValue vp);
+
+ JSTrapStatus processParsedHandlerResultHelper(mozilla::Maybe<AutoCompartment>& ac,
+ AbstractFramePtr frame,
+ const mozilla::Maybe<HandleValue>& maybeThisv,
+ bool success, JSTrapStatus status,
+ MutableHandleValue vp);
+
+ bool processResumptionValue(mozilla::Maybe<AutoCompartment>& ac, AbstractFramePtr frame,
+ const mozilla::Maybe<HandleValue>& maybeThis, HandleValue rval,
+ JSTrapStatus& statusp, MutableHandleValue vp);
+
+ GlobalObject* unwrapDebuggeeArgument(JSContext* cx, const Value& v);
+
+ static void traceObject(JSTracer* trc, JSObject* obj);
+ void trace(JSTracer* trc);
+ static void finalize(FreeOp* fop, JSObject* obj);
+ void markCrossCompartmentEdges(JSTracer* tracer);
+
+ static const ClassOps classOps_;
+
+ public:
+ static const Class class_;
+
+ private:
+ static MOZ_MUST_USE bool getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which);
+ static MOZ_MUST_USE bool setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which);
+
+ static bool getEnabled(JSContext* cx, unsigned argc, Value* vp);
+ static bool setEnabled(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnNewScript(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnNewScript(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnEnterFrame(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnEnterFrame(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnNewPromise(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnNewPromise(JSContext* cx, unsigned argc, Value* vp);
+ static bool getOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnPromiseSettled(JSContext* cx, unsigned argc, Value* vp);
+ static bool getUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp);
+ static bool setUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp);
+ static bool getAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
+ static bool setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
+ static bool getCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
+ static bool setCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
+ static bool getMemory(JSContext* cx, unsigned argc, Value* vp);
+ static bool addDebuggee(JSContext* cx, unsigned argc, Value* vp);
+ static bool addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp);
+ static bool removeDebuggee(JSContext* cx, unsigned argc, Value* vp);
+ static bool removeAllDebuggees(JSContext* cx, unsigned argc, Value* vp);
+ static bool hasDebuggee(JSContext* cx, unsigned argc, Value* vp);
+ static bool getDebuggees(JSContext* cx, unsigned argc, Value* vp);
+ static bool getNewestFrame(JSContext* cx, unsigned argc, Value* vp);
+ static bool clearAllBreakpoints(JSContext* cx, unsigned argc, Value* vp);
+ static bool findScripts(JSContext* cx, unsigned argc, Value* vp);
+ static bool findObjects(JSContext* cx, unsigned argc, Value* vp);
+ static bool findAllGlobals(JSContext* cx, unsigned argc, Value* vp);
+ static bool makeGlobalObjectReference(JSContext* cx, unsigned argc, Value* vp);
+ static bool setupTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp);
+ static bool drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp);
+ static bool startTraceLogger(JSContext* cx, unsigned argc, Value* vp);
+ static bool endTraceLogger(JSContext* cx, unsigned argc, Value* vp);
+ static bool isCompilableUnit(JSContext* cx, unsigned argc, Value* vp);
+#ifdef NIGHTLY_BUILD
+ static bool setupTraceLogger(JSContext* cx, unsigned argc, Value* vp);
+ static bool drainTraceLogger(JSContext* cx, unsigned argc, Value* vp);
+#endif
+ static bool adoptDebuggeeValue(JSContext* cx, unsigned argc, Value* vp);
+ static bool construct(JSContext* cx, unsigned argc, Value* vp);
+ static const JSPropertySpec properties[];
+ static const JSFunctionSpec methods[];
+ static const JSFunctionSpec static_methods[];
+
+ static void removeFromFrameMapsAndClearBreakpointsIn(JSContext* cx, AbstractFramePtr frame);
+ static bool updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObservableSet& obs,
+ IsObserving observing);
+ static bool updateExecutionObservabilityOfScripts(JSContext* cx, const ExecutionObservableSet& obs,
+ IsObserving observing);
+ static bool updateExecutionObservability(JSContext* cx, ExecutionObservableSet& obs,
+ IsObserving observing);
+
+ template <typename FrameFn /* void (NativeObject*) */>
+ static void forEachDebuggerFrame(AbstractFramePtr frame, FrameFn fn);
+
+ /*
+ * Return a vector containing all Debugger.Frame instances referring to
+ * |frame|. |global| is |frame|'s global object; if nullptr or omitted, we
+ * compute it ourselves from |frame|.
+ */
+ using DebuggerFrameVector = GCVector<DebuggerFrame*>;
+ static MOZ_MUST_USE bool getDebuggerFrames(AbstractFramePtr frame,
+ MutableHandle<DebuggerFrameVector> frames);
+
+ public:
+ static MOZ_MUST_USE bool ensureExecutionObservabilityOfOsrFrame(JSContext* cx,
+ InterpreterFrame* frame);
+
+ // Public for DebuggerScript_setBreakpoint.
+ static MOZ_MUST_USE bool ensureExecutionObservabilityOfScript(JSContext* cx, JSScript* script);
+
+ // Whether the Debugger instance needs to observe all non-AOT JS
+ // execution of its debugees.
+ IsObserving observesAllExecution() const;
+
+ // Whether the Debugger instance needs to observe AOT-compiled asm.js
+ // execution of its debuggees.
+ IsObserving observesAsmJS() const;
+
+ // Whether the Debugger instance needs to observe coverage of any JavaScript
+ // execution.
+ IsObserving observesCoverage() const;
+
+ private:
+ static MOZ_MUST_USE bool ensureExecutionObservabilityOfFrame(JSContext* cx,
+ AbstractFramePtr frame);
+ static MOZ_MUST_USE bool ensureExecutionObservabilityOfCompartment(JSContext* cx,
+ JSCompartment* comp);
+
+ static bool hookObservesAllExecution(Hook which);
+
+ MOZ_MUST_USE bool updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving observing);
+ MOZ_MUST_USE bool updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing);
+ void updateObservesAsmJSOnDebuggees(IsObserving observing);
+
+ JSObject* getHook(Hook hook) const;
+ bool hasAnyLiveHooks(JSRuntime* rt) const;
+
+ static MOZ_MUST_USE bool slowPathCheckNoExecute(JSContext* cx, HandleScript script);
+ static JSTrapStatus slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame);
+ static MOZ_MUST_USE bool slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame,
+ jsbytecode* pc, bool ok);
+ static JSTrapStatus slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame);
+ static JSTrapStatus slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame);
+ static void slowPathOnNewScript(JSContext* cx, HandleScript script);
+ static void slowPathOnNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
+ static void slowPathOnNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global);
+ static MOZ_MUST_USE bool slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj,
+ HandleSavedFrame frame, double when,
+ GlobalObject::DebuggerVector& dbgs);
+ static void slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise);
+
+ template <typename HookIsEnabledFun /* bool (Debugger*) */,
+ typename FireHookFun /* JSTrapStatus (Debugger*) */>
+ static JSTrapStatus dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled,
+ FireHookFun fireHook);
+
+ JSTrapStatus fireDebuggerStatement(JSContext* cx, MutableHandleValue vp);
+ JSTrapStatus fireExceptionUnwind(JSContext* cx, MutableHandleValue vp);
+ JSTrapStatus fireEnterFrame(JSContext* cx, MutableHandleValue vp);
+ JSTrapStatus fireNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global, MutableHandleValue vp);
+ JSTrapStatus firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp);
+
+ NativeObject* newVariantWrapper(JSContext* cx, Handle<DebuggerScriptReferent> referent) {
+ return newDebuggerScript(cx, referent);
+ }
+ NativeObject* newVariantWrapper(JSContext* cx, Handle<DebuggerSourceReferent> referent) {
+ return newDebuggerSource(cx, referent);
+ }
+
+ /*
+ * Helper function to help wrap Debugger objects whose referents may be
+ * variants. Currently Debugger.Script and Debugger.Source referents may
+ * be variants.
+ *
+ * Prefer using wrapScript, wrapWasmScript, wrapSource, and wrapWasmSource
+ * whenever possible.
+ */
+ template <typename ReferentVariant, typename Referent, typename Map>
+ JSObject* wrapVariantReferent(JSContext* cx, Map& map, Handle<CrossCompartmentKey> key,
+ Handle<ReferentVariant> referent);
+ JSObject* wrapVariantReferent(JSContext* cx, Handle<DebuggerScriptReferent> referent);
+ JSObject* wrapVariantReferent(JSContext* cx, Handle<DebuggerSourceReferent> referent);
+
+ /*
+ * Allocate and initialize a Debugger.Script instance whose referent is
+ * |referent|.
+ */
+ NativeObject* newDebuggerScript(JSContext* cx, Handle<DebuggerScriptReferent> referent);
+
+ /*
+ * Allocate and initialize a Debugger.Source instance whose referent is
+ * |referent|.
+ */
+ NativeObject* newDebuggerSource(JSContext* cx, Handle<DebuggerSourceReferent> referent);
+
+ /*
+ * Receive a "new script" event from the engine. A new script was compiled
+ * or deserialized.
+ */
+ void fireNewScript(JSContext* cx, Handle<DebuggerScriptReferent> scriptReferent);
+
+ /*
+ * Receive a "garbage collection" event from the engine. A GC cycle with the
+ * given data was recently completed.
+ */
+ void fireOnGarbageCollectionHook(JSContext* cx,
+ const JS::dbg::GarbageCollectionEvent::Ptr& gcData);
+
+ /*
+ * Gets a Debugger.Frame object. If maybeIter is non-null, we eagerly copy
+ * its data if we need to make a new Debugger.Frame.
+ */
+ MOZ_MUST_USE bool getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame,
+ const ScriptFrameIter* maybeIter,
+ MutableHandleValue vp);
+ MOZ_MUST_USE bool getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame,
+ const ScriptFrameIter* maybeIter,
+ MutableHandleDebuggerFrame result);
+
+ inline Breakpoint* firstBreakpoint() const;
+
+ static inline Debugger* fromOnNewGlobalObjectWatchersLink(JSCList* link);
+
+ static MOZ_MUST_USE bool replaceFrameGuts(JSContext* cx, AbstractFramePtr from,
+ AbstractFramePtr to,
+ ScriptFrameIter& iter);
+
+ public:
+ Debugger(JSContext* cx, NativeObject* dbg);
+ ~Debugger();
+
+ MOZ_MUST_USE bool init(JSContext* cx);
+ inline const js::GCPtrNativeObject& toJSObject() const;
+ inline js::GCPtrNativeObject& toJSObjectRef();
+ static inline Debugger* fromJSObject(const JSObject* obj);
+ static Debugger* fromChildJSObject(JSObject* obj);
+
+ bool hasMemory() const;
+ DebuggerMemory& memory() const;
+
+ WeakGlobalObjectSet::Range allDebuggees() const { return debuggees.all(); }
+
+ /*********************************** Methods for interaction with the GC. */
+
+ /*
+ * A Debugger object is live if:
+ * * the Debugger JSObject is live (Debugger::trace handles this case); OR
+ * * it is in the middle of dispatching an event (the event dispatching
+ * code roots it in this case); OR
+ * * it is enabled, and it is debugging at least one live compartment,
+ * and at least one of the following is true:
+ * - it has a debugger hook installed
+ * - it has a breakpoint set on a live script
+ * - it has a watchpoint set on a live object.
+ *
+ * Debugger::markAllIteratively handles the last case. If it finds any
+ * Debugger objects that are definitely live but not yet marked, it marks
+ * them and returns true. If not, it returns false.
+ */
+ static void markIncomingCrossCompartmentEdges(JSTracer* tracer);
+ static MOZ_MUST_USE bool markAllIteratively(GCMarker* trc);
+ static void markAll(JSTracer* trc);
+ static void sweepAll(FreeOp* fop);
+ static void detachAllDebuggersFromGlobal(FreeOp* fop, GlobalObject* global);
+ static void findZoneEdges(JS::Zone* v, gc::ZoneComponentFinder& finder);
+
+ // Checks it the current compartment is allowed to execute code.
+ static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx, HandleScript script);
+
+ /*
+ * JSTrapStatus Overview
+ * ---------------------
+ *
+ * The |onEnterFrame|, |onDebuggerStatement|, and |onExceptionUnwind|
+ * methods below return a JSTrapStatus code that indicates how execution
+ * should proceed:
+ *
+ * - JSTRAP_CONTINUE: Continue execution normally.
+ *
+ * - JSTRAP_THROW: Throw an exception. The method has set |cx|'s
+ * pending exception to the value to be thrown.
+ *
+ * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
+ * for running too long). The method has cleared |cx|'s pending
+ * exception.
+ *
+ * - JSTRAP_RETURN: Return from the new frame immediately. The method has
+ * set the youngest JS frame's return value appropriately.
+ */
+
+ /*
+ * Announce to the debugger that the context has entered a new JavaScript
+ * frame, |frame|. Call whatever hooks have been registered to observe new
+ * frames.
+ */
+ static inline JSTrapStatus onEnterFrame(JSContext* cx, AbstractFramePtr frame);
+
+ /*
+ * Announce to the debugger a |debugger;| statement on has been
+ * encountered on the youngest JS frame on |cx|. Call whatever hooks have
+ * been registered to observe this.
+ *
+ * Note that this method is called for all |debugger;| statements,
+ * regardless of the frame's debuggee-ness.
+ */
+ static inline JSTrapStatus onDebuggerStatement(JSContext* cx, AbstractFramePtr frame);
+
+ /*
+ * Announce to the debugger that an exception has been thrown and propagated
+ * to |frame|. Call whatever hooks have been registered to observe this.
+ */
+ static inline JSTrapStatus onExceptionUnwind(JSContext* cx, AbstractFramePtr frame);
+
+ /*
+ * Announce to the debugger that the thread has exited a JavaScript frame, |frame|.
+ * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
+ * is throwing an exception or terminating.
+ *
+ * Change cx's current exception and |frame|'s return value to reflect the changes
+ * in behavior the hooks request, if any. Return the new error/success value.
+ *
+ * This function may be called twice for the same outgoing frame; only the
+ * first call has any effect. (Permitting double calls simplifies some
+ * cases where an onPop handler's resumption value changes a return to a
+ * throw, or vice versa: we can redirect to a complete copy of the
+ * alternative path, containing its own call to onLeaveFrame.)
+ */
+ static inline MOZ_MUST_USE bool onLeaveFrame(JSContext* cx, AbstractFramePtr frame,
+ jsbytecode* pc, bool ok);
+
+ static inline void onNewScript(JSContext* cx, HandleScript script);
+ static inline void onNewWasmInstance(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
+ static inline void onNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global);
+ static inline MOZ_MUST_USE bool onLogAllocationSite(JSContext* cx, JSObject* obj,
+ HandleSavedFrame frame, double when);
+ static JSTrapStatus onTrap(JSContext* cx, MutableHandleValue vp);
+ static JSTrapStatus onSingleStep(JSContext* cx, MutableHandleValue vp);
+ static MOZ_MUST_USE bool handleBaselineOsr(JSContext* cx, InterpreterFrame* from,
+ jit::BaselineFrame* to);
+ static MOZ_MUST_USE bool handleIonBailout(JSContext* cx, jit::RematerializedFrame* from,
+ jit::BaselineFrame* to);
+ static void handleUnrecoverableIonBailoutError(JSContext* cx, jit::RematerializedFrame* frame);
+ static void propagateForcedReturn(JSContext* cx, AbstractFramePtr frame, HandleValue rval);
+ static bool hasLiveHook(GlobalObject* global, Hook which);
+ static bool inFrameMaps(AbstractFramePtr frame);
+
+ /************************************* Functions for use by Debugger.cpp. */
+
+ inline bool observesEnterFrame() const;
+ inline bool observesNewScript() const;
+ inline bool observesNewGlobalObject() const;
+ inline bool observesGlobal(GlobalObject* global) const;
+ bool observesFrame(AbstractFramePtr frame) const;
+ bool observesFrame(const FrameIter& iter) const;
+ bool observesScript(JSScript* script) const;
+
+ /*
+ * If env is nullptr, call vp->setNull() and return true. Otherwise, find
+ * or create a Debugger.Environment object for the given Env. On success,
+ * store the Environment object in *vp and return true.
+ */
+ MOZ_MUST_USE bool wrapEnvironment(JSContext* cx, Handle<Env*> env, MutableHandleValue vp);
+ MOZ_MUST_USE bool wrapEnvironment(JSContext* cx, Handle<Env*> env,
+ MutableHandleDebuggerEnvironment result);
+
+ /*
+ * Like cx->compartment()->wrap(cx, vp), but for the debugger compartment.
+ *
+ * Preconditions: *vp is a value from a debuggee compartment; cx is in the
+ * debugger's compartment.
+ *
+ * If *vp is an object, this produces a (new or existing) Debugger.Object
+ * wrapper for it. Otherwise this is the same as JSCompartment::wrap.
+ *
+ * If *vp is a magic JS_OPTIMIZED_OUT value, this produces a plain object
+ * of the form { optimizedOut: true }.
+ *
+ * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing
+ * arguments, this produces a plain object of the form { missingArguments:
+ * true }.
+ *
+ * If *vp is a magic JS_UNINITIALIZED_LEXICAL value signifying an
+ * unaccessible uninitialized binding, this produces a plain object of the
+ * form { uninitialized: true }.
+ */
+ MOZ_MUST_USE bool wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp);
+ MOZ_MUST_USE bool wrapDebuggeeObject(JSContext* cx, HandleObject obj,
+ MutableHandleDebuggerObject result);
+
+ /*
+ * Unwrap a Debug.Object, without rewrapping it for any particular debuggee
+ * compartment.
+ *
+ * Preconditions: cx is in the debugger compartment. *vp is a value in that
+ * compartment. (*vp should be a "debuggee value", meaning it is the
+ * debugger's reflection of a value in the debuggee.)
+ *
+ * If *vp is a Debugger.Object, store the referent in *vp. Otherwise, if *vp
+ * is an object, throw a TypeError, because it is not a debuggee
+ * value. Otherwise *vp is a primitive, so leave it alone.
+ *
+ * When passing values from the debuggee to the debugger:
+ * enter debugger compartment;
+ * call wrapDebuggeeValue; // compartment- and debugger-wrapping
+ *
+ * When passing values from the debugger to the debuggee:
+ * call unwrapDebuggeeValue; // debugger-unwrapping
+ * enter debuggee compartment;
+ * call cx->compartment()->wrap; // compartment-rewrapping
+ *
+ * (Extreme nerd sidebar: Unwrapping happens in two steps because there are
+ * two different kinds of symmetry at work: regardless of which direction
+ * we're going, we want any exceptions to be created and thrown in the
+ * debugger compartment--mirror symmetry. But compartment wrapping always
+ * happens in the target compartment--rotational symmetry.)
+ */
+ MOZ_MUST_USE bool unwrapDebuggeeValue(JSContext* cx, MutableHandleValue vp);
+ MOZ_MUST_USE bool unwrapDebuggeeObject(JSContext* cx, MutableHandleObject obj);
+ MOZ_MUST_USE bool unwrapPropertyDescriptor(JSContext* cx, HandleObject obj,
+ MutableHandle<PropertyDescriptor> desc);
+
+ /*
+ * Store the Debugger.Frame object for frame in *vp.
+ *
+ * Use this if you have already access to a frame pointer without having
+ * to incur the cost of walking the stack.
+ */
+ MOZ_MUST_USE bool getScriptFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleValue vp) {
+ return getScriptFrameWithIter(cx, frame, nullptr, vp);
+ }
+
+ /*
+ * Store the Debugger.Frame object for iter in *vp/result. Eagerly copies a
+ * ScriptFrameIter::Data.
+ *
+ * Use this if you had to make a ScriptFrameIter to get the required
+ * frame, in which case the cost of walking the stack has already been
+ * paid.
+ */
+ MOZ_MUST_USE bool getScriptFrame(JSContext* cx, const ScriptFrameIter& iter,
+ MutableHandleValue vp) {
+ return getScriptFrameWithIter(cx, iter.abstractFramePtr(), &iter, vp);
+ }
+ MOZ_MUST_USE bool getScriptFrame(JSContext* cx, const ScriptFrameIter& iter,
+ MutableHandleDebuggerFrame result);
+
+
+ /*
+ * Set |*status| and |*value| to a (JSTrapStatus, Value) pair reflecting a
+ * standard SpiderMonkey call state: a boolean success value |ok|, a return
+ * value |rv|, and a context |cx| that may or may not have an exception set.
+ * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
+ * to be false).
+ */
+ static void resultToCompletion(JSContext* cx, bool ok, const Value& rv,
+ JSTrapStatus* status, MutableHandleValue value);
+
+ /*
+ * Set |*result| to a JavaScript completion value corresponding to |status|
+ * and |value|. |value| should be the return value or exception value, not
+ * wrapped as a debuggee value. |cx| must be in the debugger compartment.
+ */
+ MOZ_MUST_USE bool newCompletionValue(JSContext* cx, JSTrapStatus status, const Value& value,
+ MutableHandleValue result);
+
+ /*
+ * Precondition: we are in the debuggee compartment (ac is entered) and ok
+ * is true if the operation in the debuggee compartment succeeded, false on
+ * error or exception.
+ *
+ * Postcondition: we are in the debugger compartment, having called
+ * ac.leave() even if an error occurred.
+ *
+ * On success, a completion value is in vp and ac.context does not have a
+ * pending exception. (This ordinarily returns true even if the ok argument
+ * is false.)
+ */
+ MOZ_MUST_USE bool receiveCompletionValue(mozilla::Maybe<AutoCompartment>& ac, bool ok,
+ HandleValue val,
+ MutableHandleValue vp);
+
+ /*
+ * Return the Debugger.Script object for |script|, or create a new one if
+ * needed. The context |cx| must be in the debugger compartment; |script|
+ * must be a script in a debuggee compartment.
+ */
+ JSObject* wrapScript(JSContext* cx, HandleScript script);
+
+ /*
+ * Return the Debugger.Script object for |wasmInstance| (the toplevel
+ * script), synthesizing a new one if needed. The context |cx| must be in
+ * the debugger compartment; |wasmInstance| must be a WasmInstanceObject in
+ * the debuggee compartment.
+ */
+ JSObject* wrapWasmScript(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
+
+ /*
+ * Return the Debugger.Source object for |source|, or create a new one if
+ * needed. The context |cx| must be in the debugger compartment; |source|
+ * must be a script source object in a debuggee compartment.
+ */
+ JSObject* wrapSource(JSContext* cx, js::HandleScriptSource source);
+
+ /*
+ * Return the Debugger.Source object for |wasmInstance| (the entire module),
+ * synthesizing a new one if needed. The context |cx| must be in the
+ * debugger compartment; |wasmInstance| must be a WasmInstanceObject in the
+ * debuggee compartment.
+ */
+ JSObject* wrapWasmSource(JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
+
+ private:
+ Debugger(const Debugger&) = delete;
+ Debugger & operator=(const Debugger&) = delete;
+};
+
+enum class DebuggerEnvironmentType {
+ Declarative,
+ With,
+ Object
+};
+
+class DebuggerEnvironment : public NativeObject
+{
+ public:
+ enum {
+ OWNER_SLOT
+ };
+
+ static const unsigned RESERVED_SLOTS = 1;
+
+ static const Class class_;
+
+ static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
+ static DebuggerEnvironment* create(JSContext* cx, HandleObject proto, HandleObject referent,
+ HandleNativeObject debugger);
+
+ DebuggerEnvironmentType type() const;
+ MOZ_MUST_USE bool getParent(JSContext* cx, MutableHandleDebuggerEnvironment result) const;
+ MOZ_MUST_USE bool getObject(JSContext* cx, MutableHandleDebuggerObject result) const;
+ MOZ_MUST_USE bool getCallee(JSContext* cx, MutableHandleDebuggerObject result) const;
+ bool isDebuggee() const;
+ bool isOptimized() const;
+
+ static MOZ_MUST_USE bool getNames(JSContext* cx, HandleDebuggerEnvironment environment,
+ MutableHandle<IdVector> result);
+ static MOZ_MUST_USE bool find(JSContext* cx, HandleDebuggerEnvironment environment,
+ HandleId id, MutableHandleDebuggerEnvironment result);
+ static MOZ_MUST_USE bool getVariable(JSContext* cx, HandleDebuggerEnvironment environment,
+ HandleId id, MutableHandleValue result);
+ static MOZ_MUST_USE bool setVariable(JSContext* cx, HandleDebuggerEnvironment environment,
+ HandleId id, HandleValue value);
+
+ private:
+ static const ClassOps classOps_;
+
+ static const JSPropertySpec properties_[];
+ static const JSFunctionSpec methods_[];
+
+ Env* referent() const {
+ Env* env = static_cast<Env*>(getPrivate());
+ MOZ_ASSERT(env);
+ return env;
+ }
+
+ Debugger* owner() const;
+
+ bool requireDebuggee(JSContext* cx) const;
+
+ static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+
+ static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool parentGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool objectGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool inspectableGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool optimizedOutGetter(JSContext* cx, unsigned argc, Value* vp);
+
+ static MOZ_MUST_USE bool namesMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool findMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool getVariableMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool setVariableMethod(JSContext* cx, unsigned argc, Value* vp);
+};
+
+enum class DebuggerFrameType {
+ Eval,
+ Global,
+ Call,
+ Module
+};
+
+enum class DebuggerFrameImplementation {
+ Interpreter,
+ Baseline,
+ Ion
+};
+
+class DebuggerFrame : public NativeObject
+{
+ public:
+ enum {
+ OWNER_SLOT
+ };
+
+ static const unsigned RESERVED_SLOTS = 1;
+
+ static const Class class_;
+
+ static NativeObject* initClass(JSContext* cx, HandleObject dbgCtor, HandleObject objProto);
+ static DebuggerFrame* create(JSContext* cx, HandleObject proto, AbstractFramePtr referent,
+ const ScriptFrameIter* maybeIter, HandleNativeObject debugger);
+
+ static MOZ_MUST_USE bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerObject result);
+ static MOZ_MUST_USE bool getIsConstructing(JSContext* cx, HandleDebuggerFrame frame,
+ bool& result);
+ static MOZ_MUST_USE bool getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerEnvironment result);
+ static bool getIsGenerator(HandleDebuggerFrame frame);
+ static MOZ_MUST_USE bool getOffset(JSContext* cx, HandleDebuggerFrame frame, size_t& result);
+ static MOZ_MUST_USE bool getOlder(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleDebuggerFrame result);
+ static MOZ_MUST_USE bool getThis(JSContext* cx, HandleDebuggerFrame frame,
+ MutableHandleValue result);
+ static DebuggerFrameType getType(HandleDebuggerFrame frame);
+ static DebuggerFrameImplementation getImplementation(HandleDebuggerFrame frame);
+
+ static MOZ_MUST_USE bool eval(JSContext* cx, HandleDebuggerFrame frame,
+ mozilla::Range<const char16_t> chars, HandleObject bindings,
+ const EvalOptions& options, JSTrapStatus& status,
+ MutableHandleValue value);
+
+ bool isLive() const;
+
+ private:
+ static const ClassOps classOps_;
+
+ static const JSPropertySpec properties_[];
+ static const JSFunctionSpec methods_[];
+
+ static AbstractFramePtr getReferent(HandleDebuggerFrame frame);
+ static MOZ_MUST_USE bool getScriptFrameIter(JSContext* cx, HandleDebuggerFrame frame,
+ mozilla::Maybe<ScriptFrameIter>& result);
+
+ static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+
+ static MOZ_MUST_USE bool calleeGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool constructingGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool generatorGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool liveGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool offsetGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool olderGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool thisGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool typeGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool implementationGetter(JSContext* cx, unsigned argc, Value* vp);
+
+ static MOZ_MUST_USE bool evalMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool evalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp);
+
+ Debugger* owner() const;
+};
+
+class DebuggerObject : public NativeObject
+{
+ public:
+ static const Class class_;
+
+ static NativeObject* initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor);
+ static DebuggerObject* create(JSContext* cx, HandleObject proto, HandleObject obj,
+ HandleNativeObject debugger);
+
+ // Properties
+ static MOZ_MUST_USE bool getClassName(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleString result);
+ static MOZ_MUST_USE bool getGlobal(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+ static MOZ_MUST_USE bool getParameterNames(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<StringVector> result);
+ static MOZ_MUST_USE bool getBoundTargetFunction(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+ static MOZ_MUST_USE bool getBoundThis(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result);
+ static MOZ_MUST_USE bool getBoundArguments(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<ValueVector> result);
+ static MOZ_MUST_USE bool getAllocationSite(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleObject result);
+ static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleString result);
+ static MOZ_MUST_USE bool getErrorLineNumber(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result);
+ static MOZ_MUST_USE bool getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result);
+ static MOZ_MUST_USE bool getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+ static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+#ifdef SPIDERMONKEY_PROMISE
+ static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result);
+ static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleValue result);
+#endif // SPIDERMONKEY_PROMISE
+
+ // Methods
+ static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
+ bool& result);
+ static MOZ_MUST_USE bool isSealed(JSContext* cx, HandleDebuggerObject object, bool& result);
+ static MOZ_MUST_USE bool isFrozen(JSContext* cx, HandleDebuggerObject object, bool& result);
+ static MOZ_MUST_USE bool getPrototypeOf(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+ static MOZ_MUST_USE bool getOwnPropertyNames(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<IdVector> result);
+ static MOZ_MUST_USE bool getOwnPropertySymbols(JSContext* cx, HandleDebuggerObject object,
+ MutableHandle<IdVector> result);
+ static MOZ_MUST_USE bool getOwnPropertyDescriptor(JSContext* cx, HandleDebuggerObject object,
+ HandleId id,
+ MutableHandle<PropertyDescriptor> desc);
+ static MOZ_MUST_USE bool preventExtensions(JSContext* cx, HandleDebuggerObject object);
+ static MOZ_MUST_USE bool seal(JSContext* cx, HandleDebuggerObject object);
+ static MOZ_MUST_USE bool freeze(JSContext* cx, HandleDebuggerObject object);
+ static MOZ_MUST_USE bool defineProperty(JSContext* cx, HandleDebuggerObject object,
+ HandleId id, Handle<PropertyDescriptor> desc);
+ static MOZ_MUST_USE bool defineProperties(JSContext* cx, HandleDebuggerObject object,
+ Handle<IdVector> ids,
+ Handle<PropertyDescriptorVector> descs);
+ static MOZ_MUST_USE bool deleteProperty(JSContext* cx, HandleDebuggerObject object,
+ HandleId id, ObjectOpResult& result);
+ static MOZ_MUST_USE bool call(JSContext* cx, HandleDebuggerObject object, HandleValue thisv,
+ Handle<ValueVector> args, MutableHandleValue result);
+ static MOZ_MUST_USE bool forceLexicalInitializationByName(JSContext* cx,
+ HandleDebuggerObject object,
+ HandleId id, bool& result);
+ static MOZ_MUST_USE bool executeInGlobal(JSContext* cx, HandleDebuggerObject object,
+ mozilla::Range<const char16_t> chars,
+ HandleObject bindings, const EvalOptions& options,
+ JSTrapStatus& status, MutableHandleValue value);
+ static MOZ_MUST_USE bool makeDebuggeeValue(JSContext* cx, HandleDebuggerObject object,
+ HandleValue value, MutableHandleValue result);
+ static MOZ_MUST_USE bool unsafeDereference(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleObject result);
+ static MOZ_MUST_USE bool unwrap(JSContext* cx, HandleDebuggerObject object,
+ MutableHandleDebuggerObject result);
+
+ // Infallible properties
+ bool isCallable() const;
+ bool isFunction() const;
+ bool isDebuggeeFunction() const;
+ bool isBoundFunction() const;
+ bool isArrowFunction() const;
+ bool isGlobal() const;
+ bool isScriptedProxy() const;
+#ifdef SPIDERMONKEY_PROMISE
+ bool isPromise() const;
+#endif // SPIDERMONKEY_PROMISE
+ JSAtom* name() const;
+ JSAtom* displayName() const;
+#ifdef SPIDERMONKEY_PROMISE
+ JS::PromiseState promiseState() const;
+ double promiseLifetime() const;
+ double promiseTimeToResolution() const;
+#endif // SPIDERMONKEY_PROMISE
+
+ private:
+ enum {
+ OWNER_SLOT
+ };
+
+ static const unsigned RESERVED_SLOTS = 1;
+
+ static const ClassOps classOps_;
+
+ static const JSPropertySpec properties_[];
+#ifdef SPIDERMONKEY_PROMISE
+ static const JSPropertySpec promiseProperties_[];
+#endif // SPIDERMONKEY_PROMISE
+ static const JSFunctionSpec methods_[];
+
+ JSObject* referent() const {
+ JSObject* obj = (JSObject*) getPrivate();
+ MOZ_ASSERT(obj);
+ return obj;
+ }
+
+ Debugger* owner() const;
+
+#ifdef SPIDERMONKEY_PROMISE
+ PromiseObject* promise() const;
+#endif // SPIDERMONKEY_PROMISE
+
+ static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object);
+#ifdef SPIDERMONKEY_PROMISE
+ static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object);
+#endif // SPIDERMONKEY_PROMISE
+
+ static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+
+ // JSNative properties
+ static MOZ_MUST_USE bool callableGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool isBoundFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool isArrowFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool protoGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool classGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool nameGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool displayNameGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool parameterNamesGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool scriptGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool environmentGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool boundTargetFunctionGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool boundThisGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool boundArgumentsGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool globalGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool errorLineNumberGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool errorColumnNumberGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp);
+#ifdef SPIDERMONKEY_PROMISE
+ static MOZ_MUST_USE bool isPromiseGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseStateGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseValueGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseReasonGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseLifetimeGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseTimeToResolutionGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseAllocationSiteGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseResolutionSiteGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseIDGetter(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp);
+#endif // SPIDERMONKEY_PROMISE
+
+ // JSNative methods
+ static MOZ_MUST_USE bool isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool isSealedMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool isFrozenMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool getOwnPropertyNamesMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool getOwnPropertySymbolsMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool getOwnPropertyDescriptorMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool preventExtensionsMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool sealMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool freezeMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool definePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool definePropertiesMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool deletePropertyMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool callMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool applyMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool asEnvironmentMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool forceLexicalInitializationByNameMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool executeInGlobalMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool executeInGlobalWithBindingsMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool makeDebuggeeValueMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool unsafeDereferenceMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool unwrapMethod(JSContext* cx, unsigned argc, Value* vp);
+ static MOZ_MUST_USE bool getErrorReport(JSContext* cx, HandleObject maybeError,
+ JSErrorReport*& report);
+};
+
+class BreakpointSite {
+ friend class Breakpoint;
+ friend struct ::JSCompartment;
+ friend class ::JSScript;
+ friend class Debugger;
+
+ public:
+ JSScript* script;
+ jsbytecode * const pc;
+
+ private:
+ JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */
+ size_t enabledCount; /* number of breakpoints in the list that are enabled */
+
+ void recompile(FreeOp* fop);
+
+ public:
+ BreakpointSite(JSScript* script, jsbytecode* pc);
+ Breakpoint* firstBreakpoint() const;
+ bool hasBreakpoint(Breakpoint* bp);
+
+ void inc(FreeOp* fop);
+ void dec(FreeOp* fop);
+ void destroyIfEmpty(FreeOp* fop);
+};
+
+/*
+ * Each Breakpoint is a member of two linked lists: its debugger's list and its
+ * site's list.
+ *
+ * GC rules:
+ * - script is live, breakpoint exists, and debugger is enabled
+ * ==> debugger is live
+ * - script is live, breakpoint exists, and debugger is live
+ * ==> retain the breakpoint and the handler object is live
+ *
+ * Debugger::markAllIteratively implements these two rules. It uses
+ * Debugger::hasAnyLiveHooks to check for rule 1.
+ *
+ * Nothing else causes a breakpoint to be retained, so if its script or
+ * debugger is collected, the breakpoint is destroyed during GC sweep phase,
+ * even if the debugger compartment isn't being GC'd. This is implemented in
+ * Zone::sweepBreakpoints.
+ */
+class Breakpoint {
+ friend struct ::JSCompartment;
+ friend class Debugger;
+
+ public:
+ Debugger * const debugger;
+ BreakpointSite * const site;
+ private:
+ /* |handler| is marked unconditionally during minor GC. */
+ js::PreBarrieredObject handler;
+ JSCList debuggerLinks;
+ JSCList siteLinks;
+
+ public:
+ static Breakpoint* fromDebuggerLinks(JSCList* links);
+ static Breakpoint* fromSiteLinks(JSCList* links);
+ Breakpoint(Debugger* debugger, BreakpointSite* site, JSObject* handler);
+ void destroy(FreeOp* fop);
+ Breakpoint* nextInDebugger();
+ Breakpoint* nextInSite();
+ const PreBarrieredObject& getHandler() const { return handler; }
+ PreBarrieredObject& getHandlerRef() { return handler; }
+};
+
+Breakpoint*
+Debugger::firstBreakpoint() const
+{
+ if (JS_CLIST_IS_EMPTY(&breakpoints))
+ return nullptr;
+ return Breakpoint::fromDebuggerLinks(JS_NEXT_LINK(&breakpoints));
+}
+
+/* static */ Debugger*
+Debugger::fromOnNewGlobalObjectWatchersLink(JSCList* link) {
+ char* p = reinterpret_cast<char*>(link);
+ return reinterpret_cast<Debugger*>(p - offsetof(Debugger, onNewGlobalObjectWatchersLink));
+}
+
+const js::GCPtrNativeObject&
+Debugger::toJSObject() const
+{
+ MOZ_ASSERT(object);
+ return object;
+}
+
+js::GCPtrNativeObject&
+Debugger::toJSObjectRef()
+{
+ MOZ_ASSERT(object);
+ return object;
+}
+
+bool
+Debugger::observesEnterFrame() const
+{
+ return enabled && getHook(OnEnterFrame);
+}
+
+bool
+Debugger::observesNewScript() const
+{
+ return enabled && getHook(OnNewScript);
+}
+
+bool
+Debugger::observesNewGlobalObject() const
+{
+ return enabled && getHook(OnNewGlobalObject);
+}
+
+bool
+Debugger::observesGlobal(GlobalObject* global) const
+{
+ ReadBarriered<GlobalObject*> debuggee(global);
+ return debuggees.has(debuggee);
+}
+
+/* static */ void
+Debugger::onNewScript(JSContext* cx, HandleScript script)
+{
+ // We early return in slowPathOnNewScript for self-hosted scripts, so we can
+ // ignore those in our assertion here.
+ MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() &&
+ !script->selfHosted(),
+ script->compartment()->firedOnNewGlobalObject);
+ if (script->compartment()->isDebuggee())
+ slowPathOnNewScript(cx, script);
+}
+
+/* static */ void
+Debugger::onNewGlobalObject(JSContext* cx, Handle<GlobalObject*> global)
+{
+ MOZ_ASSERT(!global->compartment()->firedOnNewGlobalObject);
+#ifdef DEBUG
+ global->compartment()->firedOnNewGlobalObject = true;
+#endif
+ if (!JS_CLIST_IS_EMPTY(&cx->runtime()->onNewGlobalObjectWatchers))
+ Debugger::slowPathOnNewGlobalObject(cx, global);
+}
+
+/* static */ bool
+Debugger::onLogAllocationSite(JSContext* cx, JSObject* obj, HandleSavedFrame frame, double when)
+{
+ GlobalObject::DebuggerVector* dbgs = cx->global()->getDebuggers();
+ if (!dbgs || dbgs->empty())
+ return true;
+ RootedObject hobj(cx, obj);
+ return Debugger::slowPathOnLogAllocationSite(cx, hobj, frame, when, *dbgs);
+}
+
+MOZ_MUST_USE bool ReportObjectRequired(JSContext* cx);
+
+} /* namespace js */
+
+namespace JS {
+
+template <>
+struct DeletePolicy<js::Debugger> : public js::GCManagedDeletePolicy<js::Debugger>
+{};
+
+} /* namespace JS */
+
+#endif /* vm_Debugger_h */
diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp
new file mode 100644
index 000000000..c120a0057
--- /dev/null
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -0,0 +1,460 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/DebuggerMemory.h"
+
+#include "mozilla/Maybe.h"
+#include "mozilla/Move.h"
+#include "mozilla/Vector.h"
+
+#include <stdlib.h>
+
+#include "jsalloc.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+
+#include "builtin/MapObject.h"
+#include "gc/Marking.h"
+#include "js/Debug.h"
+#include "js/TracingAPI.h"
+#include "js/UbiNode.h"
+#include "js/UbiNodeCensus.h"
+#include "js/Utility.h"
+#include "vm/Debugger.h"
+#include "vm/GlobalObject.h"
+#include "vm/SavedStacks.h"
+
+#include "vm/Debugger-inl.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+using JS::ubi::BreadthFirst;
+using JS::ubi::Edge;
+using JS::ubi::Node;
+
+using mozilla::Forward;
+using mozilla::Maybe;
+using mozilla::Move;
+using mozilla::Nothing;
+
+/* static */ DebuggerMemory*
+DebuggerMemory::create(JSContext* cx, Debugger* dbg)
+{
+ Value memoryProtoValue = dbg->object->getReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO);
+ RootedObject memoryProto(cx, &memoryProtoValue.toObject());
+ RootedNativeObject memory(cx, NewNativeObjectWithGivenProto(cx, &class_, memoryProto));
+ if (!memory)
+ return nullptr;
+
+ dbg->object->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_INSTANCE, ObjectValue(*memory));
+ memory->setReservedSlot(JSSLOT_DEBUGGER, ObjectValue(*dbg->object));
+
+ return &memory->as<DebuggerMemory>();
+}
+
+Debugger*
+DebuggerMemory::getDebugger()
+{
+ const Value& dbgVal = getReservedSlot(JSSLOT_DEBUGGER);
+ return Debugger::fromJSObject(&dbgVal.toObject());
+}
+
+/* static */ bool
+DebuggerMemory::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "Debugger.Source");
+ return false;
+}
+
+/* static */ const Class DebuggerMemory::class_ = {
+ "Memory",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_COUNT)
+};
+
+/* static */ DebuggerMemory*
+DebuggerMemory::checkThis(JSContext* cx, CallArgs& args, const char* fnName)
+{
+ const Value& thisValue = args.thisv();
+
+ if (!thisValue.isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
+ InformalValueTypeName(thisValue));
+ return nullptr;
+ }
+
+ JSObject& thisObject = thisValue.toObject();
+ if (!thisObject.is<DebuggerMemory>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ class_.name, fnName, thisObject.getClass()->name);
+ return nullptr;
+ }
+
+ // Check for Debugger.Memory.prototype, which has the same class as
+ // Debugger.Memory instances, however doesn't actually represent an instance
+ // of Debugger.Memory. It is the only object that is<DebuggerMemory>() but
+ // doesn't have a Debugger instance.
+ if (thisObject.as<DebuggerMemory>().getReservedSlot(JSSLOT_DEBUGGER).isUndefined()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ class_.name, fnName, "prototype object");
+ return nullptr;
+ }
+
+ return &thisObject.as<DebuggerMemory>();
+}
+
+/**
+ * Get the |DebuggerMemory*| from the current this value and handle any errors
+ * that might occur therein.
+ *
+ * These parameters must already exist when calling this macro:
+ * - JSContext* cx
+ * - unsigned argc
+ * - Value* vp
+ * - const char* fnName
+ * These parameters will be defined after calling this macro:
+ * - CallArgs args
+ * - DebuggerMemory* memory (will be non-null)
+ */
+#define THIS_DEBUGGER_MEMORY(cx, argc, vp, fnName, args, memory) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ Rooted<DebuggerMemory*> memory(cx, checkThis(cx, args, fnName)); \
+ if (!memory) \
+ return false
+
+static bool
+undefined(CallArgs& args)
+{
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::setTrackingAllocationSites(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set trackingAllocationSites)", args, memory);
+ if (!args.requireAtLeast(cx, "(set trackingAllocationSites)", 1))
+ return false;
+
+ Debugger* dbg = memory->getDebugger();
+ bool enabling = ToBoolean(args[0]);
+
+ if (enabling == dbg->trackingAllocationSites)
+ return undefined(args);
+
+ dbg->trackingAllocationSites = enabling;
+
+ if (!dbg->enabled)
+ return undefined(args);
+
+ if (enabling) {
+ if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
+ dbg->trackingAllocationSites = false;
+ return false;
+ }
+ } else {
+ dbg->removeAllocationsTrackingForAllDebuggees();
+ }
+
+ return undefined(args);
+}
+
+/* static */ bool
+DebuggerMemory::getTrackingAllocationSites(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get trackingAllocationSites)", args, memory);
+ args.rval().setBoolean(memory->getDebugger()->trackingAllocationSites);
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "drainAllocationsLog", args, memory);
+ Debugger* dbg = memory->getDebugger();
+
+ if (!dbg->trackingAllocationSites) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_TRACKING_ALLOCATIONS,
+ "drainAllocationsLog");
+ return false;
+ }
+
+ size_t length = dbg->allocationsLog.length();
+
+ RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length));
+ if (!result)
+ return false;
+ result->ensureDenseInitializedLength(cx, 0, length);
+
+ for (size_t i = 0; i < length; i++) {
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj)
+ return false;
+
+ // Don't pop the AllocationsLogEntry yet. The queue's links are followed
+ // by the GC to find the AllocationsLogEntry, but are not barriered, so
+ // we must edit them with great care. Use the queue entry in place, and
+ // then pop and delete together.
+ Debugger::AllocationsLogEntry& entry = dbg->allocationsLog.front();
+
+ RootedValue frame(cx, ObjectOrNullValue(entry.frame));
+ if (!DefineProperty(cx, obj, cx->names().frame, frame))
+ return false;
+
+ RootedValue timestampValue(cx, NumberValue(entry.when));
+ if (!DefineProperty(cx, obj, cx->names().timestamp, timestampValue))
+ return false;
+
+ RootedString className(cx, Atomize(cx, entry.className, strlen(entry.className)));
+ if (!className)
+ return false;
+ RootedValue classNameValue(cx, StringValue(className));
+ if (!DefineProperty(cx, obj, cx->names().class_, classNameValue))
+ return false;
+
+ RootedValue ctorName(cx, NullValue());
+ if (entry.ctorName)
+ ctorName.setString(entry.ctorName);
+ if (!DefineProperty(cx, obj, cx->names().constructor, ctorName))
+ return false;
+
+ RootedValue size(cx, NumberValue(entry.size));
+ if (!DefineProperty(cx, obj, cx->names().size, size))
+ return false;
+
+ RootedValue inNursery(cx, BooleanValue(entry.inNursery));
+ if (!DefineProperty(cx, obj, cx->names().inNursery, inNursery))
+ return false;
+
+ result->setDenseElement(i, ObjectValue(*obj));
+
+ // Pop the front queue entry, and delete it immediately, so that the GC
+ // sees the AllocationsLogEntry's HeapPtr barriers run atomically with
+ // the change to the graph (the queue link).
+ if (!dbg->allocationsLog.popFront()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ dbg->allocationsLogOverflowed = false;
+ args.rval().setObject(*result);
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::getMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get maxAllocationsLogLength)", args, memory);
+ args.rval().setInt32(memory->getDebugger()->maxAllocationsLogLength);
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::setMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set maxAllocationsLogLength)", args, memory);
+ if (!args.requireAtLeast(cx, "(set maxAllocationsLogLength)", 1))
+ return false;
+
+ int32_t max;
+ if (!ToInt32(cx, args[0], &max))
+ return false;
+
+ if (max < 1) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "(set maxAllocationsLogLength)'s parameter",
+ "not a positive integer");
+ return false;
+ }
+
+ Debugger* dbg = memory->getDebugger();
+ dbg->maxAllocationsLogLength = max;
+
+ while (dbg->allocationsLog.length() > dbg->maxAllocationsLogLength) {
+ if (!dbg->allocationsLog.popFront()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::getAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get allocationSamplingProbability)", args, memory);
+ args.rval().setDouble(memory->getDebugger()->allocationSamplingProbability);
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::setAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set allocationSamplingProbability)", args, memory);
+ if (!args.requireAtLeast(cx, "(set allocationSamplingProbability)", 1))
+ return false;
+
+ double probability;
+ if (!ToNumber(cx, args[0], &probability))
+ return false;
+
+ // Careful! This must also reject NaN.
+ if (!(0.0 <= probability && probability <= 1.0)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
+ "(set allocationSamplingProbability)'s parameter",
+ "not a number between 0 and 1");
+ return false;
+ }
+
+ Debugger* dbg = memory->getDebugger();
+ if (dbg->allocationSamplingProbability != probability) {
+ dbg->allocationSamplingProbability = probability;
+
+ // If this is a change any debuggees would observe, have all debuggee
+ // compartments recompute their sampling probabilities.
+ if (dbg->enabled && dbg->trackingAllocationSites) {
+ for (auto r = dbg->debuggees.all(); !r.empty(); r.popFront())
+ r.front()->compartment()->chooseAllocationSamplingProbability();
+ }
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::getAllocationsLogOverflowed(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get allocationsLogOverflowed)", args, memory);
+ args.rval().setBoolean(memory->getDebugger()->allocationsLogOverflowed);
+ return true;
+}
+
+/* static */ bool
+DebuggerMemory::getOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get onGarbageCollection)", args, memory);
+ return Debugger::getHookImpl(cx, args, *memory->getDebugger(), Debugger::OnGarbageCollection);
+}
+
+/* static */ bool
+DebuggerMemory::setOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set onGarbageCollection)", args, memory);
+ return Debugger::setHookImpl(cx, args, *memory->getDebugger(), Debugger::OnGarbageCollection);
+}
+
+
+/* Debugger.Memory.prototype.takeCensus */
+
+JS_PUBLIC_API(void)
+JS::dbg::SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf)
+{
+ cx->debuggerMallocSizeOf = mallocSizeOf;
+}
+
+JS_PUBLIC_API(mozilla::MallocSizeOf)
+JS::dbg::GetDebuggerMallocSizeOf(JSContext* cx)
+{
+ return cx->debuggerMallocSizeOf;
+}
+
+using JS::ubi::Census;
+using JS::ubi::CountTypePtr;
+using JS::ubi::CountBasePtr;
+
+// The takeCensus function works in three phases:
+//
+// 1) We examine the 'breakdown' property of our 'options' argument, and
+// use that to build a CountType tree.
+//
+// 2) We create a count node for the root of our CountType tree, and then walk
+// the heap, counting each node we find, expanding our tree of counts as we
+// go.
+//
+// 3) We walk the tree of counts and produce JavaScript objects reporting the
+// accumulated results.
+bool
+DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_DEBUGGER_MEMORY(cx, argc, vp, "Debugger.Memory.prototype.census", args, memory);
+
+ Census census(cx);
+ if (!census.init())
+ return false;
+ CountTypePtr rootType;
+
+ RootedObject options(cx);
+ if (args.get(0).isObject())
+ options = &args[0].toObject();
+
+ if (!JS::ubi::ParseCensusOptions(cx, census, options, rootType))
+ return false;
+
+ JS::ubi::RootedCount rootCount(cx, rootType->makeCount());
+ if (!rootCount)
+ return false;
+ JS::ubi::CensusHandler handler(census, rootCount, cx->runtime()->debuggerMallocSizeOf);
+
+ Debugger* dbg = memory->getDebugger();
+ RootedObject dbgObj(cx, dbg->object);
+
+ // Populate our target set of debuggee zones.
+ for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) {
+ if (!census.targetZones.put(r.front()->zone()))
+ return false;
+ }
+
+ {
+ Maybe<JS::AutoCheckCannotGC> maybeNoGC;
+ JS::ubi::RootList rootList(cx, maybeNoGC);
+ if (!rootList.init(dbgObj)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ JS::ubi::CensusTraversal traversal(cx, handler, maybeNoGC.ref());
+ if (!traversal.init()) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ traversal.wantNames = false;
+
+ if (!traversal.addStart(JS::ubi::Node(&rootList)) ||
+ !traversal.traverse())
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return handler.report(cx, args.rval());
+}
+
+
+/* Debugger.Memory property and method tables. */
+
+
+/* static */ const JSPropertySpec DebuggerMemory::properties[] = {
+ JS_PSGS("trackingAllocationSites", getTrackingAllocationSites, setTrackingAllocationSites, 0),
+ JS_PSGS("maxAllocationsLogLength", getMaxAllocationsLogLength, setMaxAllocationsLogLength, 0),
+ JS_PSGS("allocationSamplingProbability", getAllocationSamplingProbability, setAllocationSamplingProbability, 0),
+ JS_PSG("allocationsLogOverflowed", getAllocationsLogOverflowed, 0),
+
+ JS_PSGS("onGarbageCollection", getOnGarbageCollection, setOnGarbageCollection, 0),
+ JS_PS_END
+};
+
+/* static */ const JSFunctionSpec DebuggerMemory::methods[] = {
+ JS_FN("drainAllocationsLog", DebuggerMemory::drainAllocationsLog, 0, 0),
+ JS_FN("takeCensus", takeCensus, 0, 0),
+ JS_FS_END
+};
diff --git a/js/src/vm/DebuggerMemory.h b/js/src/vm/DebuggerMemory.h
new file mode 100644
index 000000000..a5fadc35e
--- /dev/null
+++ b/js/src/vm/DebuggerMemory.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_DebuggerMemory_h
+#define vm_DebuggerMemory_h
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsobj.h"
+#include "js/Class.h"
+#include "js/Value.h"
+
+namespace js {
+
+class DebuggerMemory : public NativeObject {
+ friend class Debugger;
+
+ static DebuggerMemory* checkThis(JSContext* cx, CallArgs& args, const char* fnName);
+
+ Debugger* getDebugger();
+
+ public:
+ static DebuggerMemory* create(JSContext* cx, Debugger* dbg);
+
+ enum {
+ JSSLOT_DEBUGGER,
+ JSSLOT_COUNT
+ };
+
+ static bool construct(JSContext* cx, unsigned argc, Value* vp);
+ static const Class class_;
+ static const JSPropertySpec properties[];
+ static const JSFunctionSpec methods[];
+
+ // Accessor properties of Debugger.Memory.prototype.
+
+ static bool setTrackingAllocationSites(JSContext* cx, unsigned argc, Value* vp);
+ static bool getTrackingAllocationSites(JSContext* cx, unsigned argc, Value* vp);
+ static bool setMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* vp);
+ static bool getMaxAllocationsLogLength(JSContext* cx, unsigned argc, Value* vp);
+ static bool setAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp);
+ static bool getAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp);
+ static bool getAllocationsLogOverflowed(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp);
+ static bool setOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp);
+
+ // Function properties of Debugger.Memory.prototype.
+
+ static bool takeCensus(JSContext* cx, unsigned argc, Value* vp);
+ static bool drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp);
+};
+
+} /* namespace js */
+
+#endif /* vm_DebuggerMemory_h */
diff --git a/js/src/vm/DerivedCoreProperties.txt b/js/src/vm/DerivedCoreProperties.txt
new file mode 100644
index 000000000..0db031db0
--- /dev/null
+++ b/js/src/vm/DerivedCoreProperties.txt
@@ -0,0 +1,11309 @@
+# DerivedCoreProperties-9.0.0.txt
+# Date: 2016-06-01, 10:34:24 GMT
+# © 2016 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Unicode Character Database
+# For documentation, see http://www.unicode.org/reports/tr44/
+
+# ================================================
+
+# Derived Property: Math
+# Generated from: Sm + Other_Math
+
+002B ; Math # Sm PLUS SIGN
+003C..003E ; Math # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+005E ; Math # Sk CIRCUMFLEX ACCENT
+007C ; Math # Sm VERTICAL LINE
+007E ; Math # Sm TILDE
+00AC ; Math # Sm NOT SIGN
+00B1 ; Math # Sm PLUS-MINUS SIGN
+00D7 ; Math # Sm MULTIPLICATION SIGN
+00F7 ; Math # Sm DIVISION SIGN
+03D0..03D2 ; Math # L& [3] GREEK BETA SYMBOL..GREEK UPSILON WITH HOOK SYMBOL
+03D5 ; Math # L& GREEK PHI SYMBOL
+03F0..03F1 ; Math # L& [2] GREEK KAPPA SYMBOL..GREEK RHO SYMBOL
+03F4..03F5 ; Math # L& [2] GREEK CAPITAL THETA SYMBOL..GREEK LUNATE EPSILON SYMBOL
+03F6 ; Math # Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+0606..0608 ; Math # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+2016 ; Math # Po DOUBLE VERTICAL LINE
+2032..2034 ; Math # Po [3] PRIME..TRIPLE PRIME
+2040 ; Math # Pc CHARACTER TIE
+2044 ; Math # Sm FRACTION SLASH
+2052 ; Math # Sm COMMERCIAL MINUS SIGN
+2061..2064 ; Math # Cf [4] FUNCTION APPLICATION..INVISIBLE PLUS
+207A..207C ; Math # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+207D ; Math # Ps SUPERSCRIPT LEFT PARENTHESIS
+207E ; Math # Pe SUPERSCRIPT RIGHT PARENTHESIS
+208A..208C ; Math # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+208D ; Math # Ps SUBSCRIPT LEFT PARENTHESIS
+208E ; Math # Pe SUBSCRIPT RIGHT PARENTHESIS
+20D0..20DC ; Math # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20E1 ; Math # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E5..20E6 ; Math # Mn [2] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING DOUBLE VERTICAL STROKE OVERLAY
+20EB..20EF ; Math # Mn [5] COMBINING LONG DOUBLE SOLIDUS OVERLAY..COMBINING RIGHT ARROW BELOW
+2102 ; Math # L& DOUBLE-STRUCK CAPITAL C
+2107 ; Math # L& EULER CONSTANT
+210A..2113 ; Math # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; Math # L& DOUBLE-STRUCK CAPITAL N
+2118 ; Math # Sm SCRIPT CAPITAL P
+2119..211D ; Math # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; Math # L& DOUBLE-STRUCK CAPITAL Z
+2128 ; Math # L& BLACK-LETTER CAPITAL Z
+2129 ; Math # So TURNED GREEK SMALL LETTER IOTA
+212C..212D ; Math # L& [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C
+212F..2131 ; Math # L& [3] SCRIPT SMALL E..SCRIPT CAPITAL F
+2133..2134 ; Math # L& [2] SCRIPT CAPITAL M..SCRIPT SMALL O
+2135..2138 ; Math # Lo [4] ALEF SYMBOL..DALET SYMBOL
+213C..213F ; Math # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2140..2144 ; Math # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+2145..2149 ; Math # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214B ; Math # Sm TURNED AMPERSAND
+2190..2194 ; Math # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+2195..2199 ; Math # So [5] UP DOWN ARROW..SOUTH WEST ARROW
+219A..219B ; Math # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+219C..219F ; Math # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+21A0 ; Math # Sm RIGHTWARDS TWO HEADED ARROW
+21A1..21A2 ; Math # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+21A3 ; Math # Sm RIGHTWARDS ARROW WITH TAIL
+21A4..21A5 ; Math # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+21A6 ; Math # Sm RIGHTWARDS ARROW FROM BAR
+21A7 ; Math # So DOWNWARDS ARROW FROM BAR
+21A9..21AD ; Math # So [5] LEFTWARDS ARROW WITH HOOK..LEFT RIGHT WAVE ARROW
+21AE ; Math # Sm LEFT RIGHT ARROW WITH STROKE
+21B0..21B1 ; Math # So [2] UPWARDS ARROW WITH TIP LEFTWARDS..UPWARDS ARROW WITH TIP RIGHTWARDS
+21B6..21B7 ; Math # So [2] ANTICLOCKWISE TOP SEMICIRCLE ARROW..CLOCKWISE TOP SEMICIRCLE ARROW
+21BC..21CD ; Math # So [18] LEFTWARDS HARPOON WITH BARB UPWARDS..LEFTWARDS DOUBLE ARROW WITH STROKE
+21CE..21CF ; Math # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+21D0..21D1 ; Math # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+21D2 ; Math # Sm RIGHTWARDS DOUBLE ARROW
+21D3 ; Math # So DOWNWARDS DOUBLE ARROW
+21D4 ; Math # Sm LEFT RIGHT DOUBLE ARROW
+21D5..21DB ; Math # So [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW
+21DD ; Math # So RIGHTWARDS SQUIGGLE ARROW
+21E4..21E5 ; Math # So [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR
+21F4..22FF ; Math # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
+2308 ; Math # Ps LEFT CEILING
+2309 ; Math # Pe RIGHT CEILING
+230A ; Math # Ps LEFT FLOOR
+230B ; Math # Pe RIGHT FLOOR
+2320..2321 ; Math # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+237C ; Math # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+239B..23B3 ; Math # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+23B4..23B5 ; Math # So [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET
+23B7 ; Math # So RADICAL SYMBOL BOTTOM
+23D0 ; Math # So VERTICAL LINE EXTENSION
+23DC..23E1 ; Math # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+23E2 ; Math # So WHITE TRAPEZIUM
+25A0..25A1 ; Math # So [2] BLACK SQUARE..WHITE SQUARE
+25AE..25B6 ; Math # So [9] BLACK VERTICAL RECTANGLE..BLACK RIGHT-POINTING TRIANGLE
+25B7 ; Math # Sm WHITE RIGHT-POINTING TRIANGLE
+25BC..25C0 ; Math # So [5] BLACK DOWN-POINTING TRIANGLE..BLACK LEFT-POINTING TRIANGLE
+25C1 ; Math # Sm WHITE LEFT-POINTING TRIANGLE
+25C6..25C7 ; Math # So [2] BLACK DIAMOND..WHITE DIAMOND
+25CA..25CB ; Math # So [2] LOZENGE..WHITE CIRCLE
+25CF..25D3 ; Math # So [5] BLACK CIRCLE..CIRCLE WITH UPPER HALF BLACK
+25E2 ; Math # So BLACK LOWER RIGHT TRIANGLE
+25E4 ; Math # So BLACK UPPER LEFT TRIANGLE
+25E7..25EC ; Math # So [6] SQUARE WITH LEFT HALF BLACK..WHITE UP-POINTING TRIANGLE WITH DOT
+25F8..25FF ; Math # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+2605..2606 ; Math # So [2] BLACK STAR..WHITE STAR
+2640 ; Math # So FEMALE SIGN
+2642 ; Math # So MALE SIGN
+2660..2663 ; Math # So [4] BLACK SPADE SUIT..BLACK CLUB SUIT
+266D..266E ; Math # So [2] MUSIC FLAT SIGN..MUSIC NATURAL SIGN
+266F ; Math # Sm MUSIC SHARP SIGN
+27C0..27C4 ; Math # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+27C5 ; Math # Ps LEFT S-SHAPED BAG DELIMITER
+27C6 ; Math # Pe RIGHT S-SHAPED BAG DELIMITER
+27C7..27E5 ; Math # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK
+27E6 ; Math # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+27E7 ; Math # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+27E8 ; Math # Ps MATHEMATICAL LEFT ANGLE BRACKET
+27E9 ; Math # Pe MATHEMATICAL RIGHT ANGLE BRACKET
+27EA ; Math # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+27EB ; Math # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+27EC ; Math # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+27ED ; Math # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+27EE ; Math # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+27EF ; Math # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+27F0..27FF ; Math # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+2900..2982 ; Math # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON
+2983 ; Math # Ps LEFT WHITE CURLY BRACKET
+2984 ; Math # Pe RIGHT WHITE CURLY BRACKET
+2985 ; Math # Ps LEFT WHITE PARENTHESIS
+2986 ; Math # Pe RIGHT WHITE PARENTHESIS
+2987 ; Math # Ps Z NOTATION LEFT IMAGE BRACKET
+2988 ; Math # Pe Z NOTATION RIGHT IMAGE BRACKET
+2989 ; Math # Ps Z NOTATION LEFT BINDING BRACKET
+298A ; Math # Pe Z NOTATION RIGHT BINDING BRACKET
+298B ; Math # Ps LEFT SQUARE BRACKET WITH UNDERBAR
+298C ; Math # Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+298D ; Math # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+298E ; Math # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+298F ; Math # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2990 ; Math # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+2991 ; Math # Ps LEFT ANGLE BRACKET WITH DOT
+2992 ; Math # Pe RIGHT ANGLE BRACKET WITH DOT
+2993 ; Math # Ps LEFT ARC LESS-THAN BRACKET
+2994 ; Math # Pe RIGHT ARC GREATER-THAN BRACKET
+2995 ; Math # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+2996 ; Math # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+2997 ; Math # Ps LEFT BLACK TORTOISE SHELL BRACKET
+2998 ; Math # Pe RIGHT BLACK TORTOISE SHELL BRACKET
+2999..29D7 ; Math # Sm [63] DOTTED FENCE..BLACK HOURGLASS
+29D8 ; Math # Ps LEFT WIGGLY FENCE
+29D9 ; Math # Pe RIGHT WIGGLY FENCE
+29DA ; Math # Ps LEFT DOUBLE WIGGLY FENCE
+29DB ; Math # Pe RIGHT DOUBLE WIGGLY FENCE
+29DC..29FB ; Math # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+29FC ; Math # Ps LEFT-POINTING CURVED ANGLE BRACKET
+29FD ; Math # Pe RIGHT-POINTING CURVED ANGLE BRACKET
+29FE..2AFF ; Math # Sm [258] TINY..N-ARY WHITE VERTICAL BAR
+2B30..2B44 ; Math # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+2B47..2B4C ; Math # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+FB29 ; Math # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+FE61 ; Math # Po SMALL ASTERISK
+FE62 ; Math # Sm SMALL PLUS SIGN
+FE63 ; Math # Pd SMALL HYPHEN-MINUS
+FE64..FE66 ; Math # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+FE68 ; Math # Po SMALL REVERSE SOLIDUS
+FF0B ; Math # Sm FULLWIDTH PLUS SIGN
+FF1C..FF1E ; Math # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+FF3C ; Math # Po FULLWIDTH REVERSE SOLIDUS
+FF3E ; Math # Sk FULLWIDTH CIRCUMFLEX ACCENT
+FF5C ; Math # Sm FULLWIDTH VERTICAL LINE
+FF5E ; Math # Sm FULLWIDTH TILDE
+FFE2 ; Math # Sm FULLWIDTH NOT SIGN
+FFE9..FFEC ; Math # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+1D400..1D454 ; Math # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; Math # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Math # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Math # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Math # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Math # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; Math # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Math # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Math # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; Math # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Math # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Math # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Math # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; Math # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Math # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Math # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Math # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Math # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; Math # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; Math # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C1 ; Math # Sm MATHEMATICAL BOLD NABLA
+1D6C2..1D6DA ; Math # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DB ; Math # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+1D6DC..1D6FA ; Math # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FB ; Math # Sm MATHEMATICAL ITALIC NABLA
+1D6FC..1D714 ; Math # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D715 ; Math # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+1D716..1D734 ; Math # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D735 ; Math # Sm MATHEMATICAL BOLD ITALIC NABLA
+1D736..1D74E ; Math # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D74F ; Math # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+1D750..1D76E ; Math # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D76F ; Math # Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+1D770..1D788 ; Math # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D789 ; Math # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+1D78A..1D7A8 ; Math # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7A9 ; Math # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+1D7AA..1D7C2 ; Math # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C3 ; Math # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+1D7C4..1D7CB ; Math # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; Math # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1EE00..1EE03 ; Math # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; Math # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; Math # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; Math # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; Math # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; Math # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; Math # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; Math # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; Math # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; Math # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; Math # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; Math # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; Math # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; Math # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; Math # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; Math # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; Math # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; Math # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; Math # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; Math # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; Math # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; Math # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; Math # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; Math # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; Math # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; Math # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; Math # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; Math # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; Math # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; Math # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; Math # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+1EEF0..1EEF1 ; Math # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+
+# Total code points: 2310
+
+# ================================================
+
+# Derived Property: Alphabetic
+# Generated from: Uppercase + Lowercase + Lt + Lm + Lo + Nl + Other_Alphabetic
+
+0041..005A ; Alphabetic # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; Alphabetic # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; Alphabetic # Lo FEMININE ORDINAL INDICATOR
+00B5 ; Alphabetic # L& MICRO SIGN
+00BA ; Alphabetic # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; Alphabetic # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; Alphabetic # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; Alphabetic # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; Alphabetic # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; Alphabetic # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; Alphabetic # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; Alphabetic # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; Alphabetic # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; Alphabetic # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; Alphabetic # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; Alphabetic # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; Alphabetic # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; Alphabetic # Lm MODIFIER LETTER VOICING
+02EE ; Alphabetic # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+0345 ; Alphabetic # Mn COMBINING GREEK YPOGEGRAMMENI
+0370..0373 ; Alphabetic # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; Alphabetic # Lm GREEK NUMERAL SIGN
+0376..0377 ; Alphabetic # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; Alphabetic # Lm GREEK YPOGEGRAMMENI
+037B..037D ; Alphabetic # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; Alphabetic # L& GREEK CAPITAL LETTER YOT
+0386 ; Alphabetic # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Alphabetic # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Alphabetic # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; Alphabetic # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; Alphabetic # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; Alphabetic # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; Alphabetic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; Alphabetic # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; Alphabetic # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0561..0587 ; Alphabetic # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+05B0..05BD ; Alphabetic # Mn [14] HEBREW POINT SHEVA..HEBREW POINT METEG
+05BF ; Alphabetic # Mn HEBREW POINT RAFE
+05C1..05C2 ; Alphabetic # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Alphabetic # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Alphabetic # Mn HEBREW POINT QAMATS QATAN
+05D0..05EA ; Alphabetic # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; Alphabetic # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0610..061A ; Alphabetic # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+0620..063F ; Alphabetic # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; Alphabetic # Lm ARABIC TATWEEL
+0641..064A ; Alphabetic # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+064B..0657 ; Alphabetic # Mn [13] ARABIC FATHATAN..ARABIC INVERTED DAMMA
+0659..065F ; Alphabetic # Mn [7] ARABIC ZWARAKAY..ARABIC WAVY HAMZA BELOW
+066E..066F ; Alphabetic # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0670 ; Alphabetic # Mn ARABIC LETTER SUPERSCRIPT ALEF
+0671..06D3 ; Alphabetic # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; Alphabetic # Lo ARABIC LETTER AE
+06D6..06DC ; Alphabetic # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06E1..06E4 ; Alphabetic # Mn [4] ARABIC SMALL HIGH DOTLESS HEAD OF KHAH..ARABIC SMALL HIGH MADDA
+06E5..06E6 ; Alphabetic # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E7..06E8 ; Alphabetic # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06ED ; Alphabetic # Mn ARABIC SMALL LOW MEEM
+06EE..06EF ; Alphabetic # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06FA..06FC ; Alphabetic # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; Alphabetic # Lo ARABIC LETTER HEH WITH INVERTED V
+0710 ; Alphabetic # Lo SYRIAC LETTER ALAPH
+0711 ; Alphabetic # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0712..072F ; Alphabetic # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+0730..073F ; Alphabetic # Mn [16] SYRIAC PTHAHA ABOVE..SYRIAC RWAHA
+074D..07A5 ; Alphabetic # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07A6..07B0 ; Alphabetic # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07B1 ; Alphabetic # Lo THAANA LETTER NAA
+07CA..07EA ; Alphabetic # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; Alphabetic # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; Alphabetic # Lm NKO LAJANYALAN
+0800..0815 ; Alphabetic # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+0816..0817 ; Alphabetic # Mn [2] SAMARITAN MARK IN..SAMARITAN MARK IN-ALAF
+081A ; Alphabetic # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+081B..0823 ; Alphabetic # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0824 ; Alphabetic # Lm SAMARITAN MODIFIER LETTER SHORT A
+0825..0827 ; Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0828 ; Alphabetic # Lm SAMARITAN MODIFIER LETTER I
+0829..082C ; Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN
+0840..0858 ; Alphabetic # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+08A0..08B4 ; Alphabetic # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; Alphabetic # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+08D4..08DF ; Alphabetic # Mn [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA
+08E3..08E9 ; Alphabetic # Mn [7] ARABIC TURNED DAMMA BELOW..ARABIC CURLY KASRATAN
+08F0..0902 ; Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA
+0903 ; Alphabetic # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; Alphabetic # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093A ; Alphabetic # Mn DEVANAGARI VOWEL SIGN OE
+093B ; Alphabetic # Mc DEVANAGARI VOWEL SIGN OOE
+093D ; Alphabetic # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; Alphabetic # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; Alphabetic # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; Alphabetic # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094E..094F ; Alphabetic # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+0950 ; Alphabetic # Lo DEVANAGARI OM
+0955..0957 ; Alphabetic # Mn [3] DEVANAGARI VOWEL SIGN CANDRA LONG E..DEVANAGARI VOWEL SIGN UUE
+0958..0961 ; Alphabetic # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0962..0963 ; Alphabetic # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0971 ; Alphabetic # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; Alphabetic # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0981 ; Alphabetic # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; Alphabetic # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; Alphabetic # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; Alphabetic # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; Alphabetic # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; Alphabetic # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; Alphabetic # Lo BENGALI LETTER LA
+09B6..09B9 ; Alphabetic # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; Alphabetic # Lo BENGALI SIGN AVAGRAHA
+09BE..09C0 ; Alphabetic # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; Alphabetic # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; Alphabetic # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; Alphabetic # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CE ; Alphabetic # Lo BENGALI LETTER KHANDA TA
+09D7 ; Alphabetic # Mc BENGALI AU LENGTH MARK
+09DC..09DD ; Alphabetic # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; Alphabetic # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E2..09E3 ; Alphabetic # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09F0..09F1 ; Alphabetic # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A01..0A02 ; Alphabetic # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; Alphabetic # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; Alphabetic # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; Alphabetic # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; Alphabetic # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; Alphabetic # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; Alphabetic # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; Alphabetic # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; Alphabetic # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3E..0A40 ; Alphabetic # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; Alphabetic # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Alphabetic # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4C ; Alphabetic # Mn [2] GURMUKHI VOWEL SIGN OO..GURMUKHI VOWEL SIGN AU
+0A51 ; Alphabetic # Mn GURMUKHI SIGN UDAAT
+0A59..0A5C ; Alphabetic # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; Alphabetic # Lo GURMUKHI LETTER FA
+0A70..0A71 ; Alphabetic # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A72..0A74 ; Alphabetic # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A75 ; Alphabetic # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; Alphabetic # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; Alphabetic # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; Alphabetic # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; Alphabetic # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; Alphabetic # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; Alphabetic # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; Alphabetic # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; Alphabetic # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; Alphabetic # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; Alphabetic # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; Alphabetic # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Alphabetic # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; Alphabetic # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; Alphabetic # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0AD0 ; Alphabetic # Lo GUJARATI OM
+0AE0..0AE1 ; Alphabetic # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE2..0AE3 ; Alphabetic # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AF9 ; Alphabetic # Lo GUJARATI LETTER ZHA
+0B01 ; Alphabetic # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; Alphabetic # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; Alphabetic # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; Alphabetic # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; Alphabetic # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; Alphabetic # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; Alphabetic # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; Alphabetic # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; Alphabetic # Lo ORIYA SIGN AVAGRAHA
+0B3E ; Alphabetic # Mc ORIYA VOWEL SIGN AA
+0B3F ; Alphabetic # Mn ORIYA VOWEL SIGN I
+0B40 ; Alphabetic # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; Alphabetic # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; Alphabetic # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; Alphabetic # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B56 ; Alphabetic # Mn ORIYA AI LENGTH MARK
+0B57 ; Alphabetic # Mc ORIYA AU LENGTH MARK
+0B5C..0B5D ; Alphabetic # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; Alphabetic # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B62..0B63 ; Alphabetic # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B71 ; Alphabetic # Lo ORIYA LETTER WA
+0B82 ; Alphabetic # Mn TAMIL SIGN ANUSVARA
+0B83 ; Alphabetic # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; Alphabetic # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; Alphabetic # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; Alphabetic # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; Alphabetic # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; Alphabetic # Lo TAMIL LETTER JA
+0B9E..0B9F ; Alphabetic # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; Alphabetic # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; Alphabetic # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; Alphabetic # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBE..0BBF ; Alphabetic # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; Alphabetic # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; Alphabetic # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; Alphabetic # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; Alphabetic # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BD0 ; Alphabetic # Lo TAMIL OM
+0BD7 ; Alphabetic # Mc TAMIL AU LENGTH MARK
+0C00 ; Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C01..0C03 ; Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; Alphabetic # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; Alphabetic # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; Alphabetic # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; Alphabetic # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; Alphabetic # Lo TELUGU SIGN AVAGRAHA
+0C3E..0C40 ; Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; Alphabetic # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4C ; Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU
+0C55..0C56 ; Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C58..0C5A ; Alphabetic # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; Alphabetic # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C62..0C63 ; Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C80 ; Alphabetic # Lo KANNADA SIGN SPACING CANDRABINDU
+0C81 ; Alphabetic # Mn KANNADA SIGN CANDRABINDU
+0C82..0C83 ; Alphabetic # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; Alphabetic # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; Alphabetic # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; Alphabetic # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; Alphabetic # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; Alphabetic # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; Alphabetic # Lo KANNADA SIGN AVAGRAHA
+0CBE ; Alphabetic # Mc KANNADA VOWEL SIGN AA
+0CBF ; Alphabetic # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; Alphabetic # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; Alphabetic # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; Alphabetic # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; Alphabetic # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC ; Alphabetic # Mn KANNADA VOWEL SIGN AU
+0CD5..0CD6 ; Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CDE ; Alphabetic # Lo KANNADA LETTER FA
+0CE0..0CE1 ; Alphabetic # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE2..0CE3 ; Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CF1..0CF2 ; Alphabetic # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D01 ; Alphabetic # Mn MALAYALAM SIGN CANDRABINDU
+0D02..0D03 ; Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; Alphabetic # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; Alphabetic # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; Alphabetic # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; Alphabetic # Lo MALAYALAM SIGN AVAGRAHA
+0D3E..0D40 ; Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; Alphabetic # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; Alphabetic # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4E ; Alphabetic # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; Alphabetic # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D57 ; Alphabetic # Mc MALAYALAM AU LENGTH MARK
+0D5F..0D61 ; Alphabetic # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D62..0D63 ; Alphabetic # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D7A..0D7F ; Alphabetic # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D82..0D83 ; Alphabetic # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; Alphabetic # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; Alphabetic # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; Alphabetic # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; Alphabetic # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; Alphabetic # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DCF..0DD1 ; Alphabetic # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; Alphabetic # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Alphabetic # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; Alphabetic # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DF2..0DF3 ; Alphabetic # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0E01..0E30 ; Alphabetic # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E31 ; Alphabetic # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; Alphabetic # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E3A ; Alphabetic # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E40..0E45 ; Alphabetic # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; Alphabetic # Lm THAI CHARACTER MAIYAMOK
+0E4D ; Alphabetic # Mn THAI CHARACTER NIKHAHIT
+0E81..0E82 ; Alphabetic # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; Alphabetic # Lo LAO LETTER KHO TAM
+0E87..0E88 ; Alphabetic # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; Alphabetic # Lo LAO LETTER SO TAM
+0E8D ; Alphabetic # Lo LAO LETTER NYO
+0E94..0E97 ; Alphabetic # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; Alphabetic # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; Alphabetic # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; Alphabetic # Lo LAO LETTER LO LOOT
+0EA7 ; Alphabetic # Lo LAO LETTER WO
+0EAA..0EAB ; Alphabetic # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; Alphabetic # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB1 ; Alphabetic # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; Alphabetic # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB9 ; Alphabetic # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Alphabetic # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EBD ; Alphabetic # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; Alphabetic # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; Alphabetic # Lm LAO KO LA
+0ECD ; Alphabetic # Mn LAO NIGGAHITA
+0EDC..0EDF ; Alphabetic # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; Alphabetic # Lo TIBETAN SYLLABLE OM
+0F40..0F47 ; Alphabetic # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; Alphabetic # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F71..0F7E ; Alphabetic # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F7F ; Alphabetic # Mc TIBETAN SIGN RNAM BCAD
+0F80..0F81 ; Alphabetic # Mn [2] TIBETAN VOWEL SIGN REVERSED I..TIBETAN VOWEL SIGN REVERSED II
+0F88..0F8C ; Alphabetic # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+0F8D..0F97 ; Alphabetic # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Alphabetic # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+1000..102A ; Alphabetic # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; Alphabetic # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; Alphabetic # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; Alphabetic # Mc MYANMAR VOWEL SIGN E
+1032..1036 ; Alphabetic # Mn [5] MYANMAR VOWEL SIGN AI..MYANMAR SIGN ANUSVARA
+1038 ; Alphabetic # Mc MYANMAR SIGN VISARGA
+103B..103C ; Alphabetic # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; Alphabetic # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+103F ; Alphabetic # Lo MYANMAR LETTER GREAT SA
+1050..1055 ; Alphabetic # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; Alphabetic # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; Alphabetic # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105A..105D ; Alphabetic # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+105E..1060 ; Alphabetic # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1061 ; Alphabetic # Lo MYANMAR LETTER SGAW KAREN SHA
+1062 ; Alphabetic # Mc MYANMAR VOWEL SIGN SGAW KAREN EU
+1065..1066 ; Alphabetic # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..1068 ; Alphabetic # Mc [2] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR VOWEL SIGN WESTERN PWO KAREN UE
+106E..1070 ; Alphabetic # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1071..1074 ; Alphabetic # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1075..1081 ; Alphabetic # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1082 ; Alphabetic # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; Alphabetic # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; Alphabetic # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+108E ; Alphabetic # Lo MYANMAR LETTER RUMAI PALAUNG FA
+109C ; Alphabetic # Mc MYANMAR VOWEL SIGN AITON A
+109D ; Alphabetic # Mn MYANMAR VOWEL SIGN AITON AI
+10A0..10C5 ; Alphabetic # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Alphabetic # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Alphabetic # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; Alphabetic # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; Alphabetic # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; Alphabetic # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; Alphabetic # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; Alphabetic # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; Alphabetic # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; Alphabetic # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; Alphabetic # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; Alphabetic # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; Alphabetic # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; Alphabetic # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+135F ; Alphabetic # Mn ETHIOPIC COMBINING GEMINATION MARK
+1380..138F ; Alphabetic # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; Alphabetic # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; Alphabetic # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; Alphabetic # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; Alphabetic # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; Alphabetic # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; Alphabetic # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; Alphabetic # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; Alphabetic # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; Alphabetic # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; Alphabetic # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1712..1713 ; Alphabetic # Mn [2] TAGALOG VOWEL SIGN I..TAGALOG VOWEL SIGN U
+1720..1731 ; Alphabetic # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1732..1733 ; Alphabetic # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+1740..1751 ; Alphabetic # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1752..1753 ; Alphabetic # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1760..176C ; Alphabetic # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; Alphabetic # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1772..1773 ; Alphabetic # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+1780..17B3 ; Alphabetic # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B6 ; Alphabetic # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; Alphabetic # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; Alphabetic # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; Alphabetic # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; Alphabetic # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17D7 ; Alphabetic # Lm KHMER SIGN LEK TOO
+17DC ; Alphabetic # Lo KHMER SIGN AVAKRAHASANYA
+1820..1842 ; Alphabetic # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; Alphabetic # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; Alphabetic # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; Alphabetic # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1885..1886 ; Alphabetic # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1887..18A8 ; Alphabetic # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18A9 ; Alphabetic # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+18AA ; Alphabetic # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; Alphabetic # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; Alphabetic # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1920..1922 ; Alphabetic # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; Alphabetic # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; Alphabetic # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; Alphabetic # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; Alphabetic # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; Alphabetic # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; Alphabetic # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1950..196D ; Alphabetic # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; Alphabetic # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; Alphabetic # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; Alphabetic # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+1A00..1A16 ; Alphabetic # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A17..1A18 ; Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A19..1A1A ; Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+1A1B ; Alphabetic # Mn BUGINESE VOWEL SIGN AE
+1A20..1A54 ; Alphabetic # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1A55 ; Alphabetic # Mc TAI THAM CONSONANT SIGN MEDIAL RA
+1A56 ; Alphabetic # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A57 ; Alphabetic # Mc TAI THAM CONSONANT SIGN LA TANG LAI
+1A58..1A5E ; Alphabetic # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A61 ; Alphabetic # Mc TAI THAM VOWEL SIGN A
+1A62 ; Alphabetic # Mn TAI THAM VOWEL SIGN MAI SAT
+1A63..1A64 ; Alphabetic # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+1A65..1A6C ; Alphabetic # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A6D..1A72 ; Alphabetic # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+1A73..1A74 ; Alphabetic # Mn [2] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN MAI KANG
+1AA7 ; Alphabetic # Lm TAI THAM SIGN MAI YAMOK
+1B00..1B03 ; Alphabetic # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; Alphabetic # Mc BALINESE SIGN BISAH
+1B05..1B33 ; Alphabetic # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B35 ; Alphabetic # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; Alphabetic # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; Alphabetic # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; Alphabetic # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; Alphabetic # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; Alphabetic # Mn BALINESE VOWEL SIGN PEPET
+1B43 ; Alphabetic # Mc BALINESE VOWEL SIGN PEPET TEDUNG
+1B45..1B4B ; Alphabetic # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B80..1B81 ; Alphabetic # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; Alphabetic # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; Alphabetic # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; Alphabetic # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; Alphabetic # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; Alphabetic # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; Alphabetic # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAC..1BAD ; Alphabetic # Mn [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BAE..1BAF ; Alphabetic # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BBA..1BE5 ; Alphabetic # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1BE7 ; Alphabetic # Mc BATAK VOWEL SIGN E
+1BE8..1BE9 ; Alphabetic # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BEA..1BEC ; Alphabetic # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+1BED ; Alphabetic # Mn BATAK VOWEL SIGN KARO O
+1BEE ; Alphabetic # Mc BATAK VOWEL SIGN U
+1BEF..1BF1 ; Alphabetic # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1C00..1C23 ; Alphabetic # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; Alphabetic # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; Alphabetic # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; Alphabetic # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C4D..1C4F ; Alphabetic # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C5A..1C77 ; Alphabetic # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; Alphabetic # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; Alphabetic # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CE9..1CEC ; Alphabetic # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CEE..1CF1 ; Alphabetic # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF2..1CF3 ; Alphabetic # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF5..1CF6 ; Alphabetic # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1D00..1D2B ; Alphabetic # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; Alphabetic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; Alphabetic # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; Alphabetic # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; Alphabetic # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; Alphabetic # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1DE7..1DF4 ; Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS
+1E00..1F15 ; Alphabetic # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; Alphabetic # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; Alphabetic # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; Alphabetic # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Alphabetic # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; Alphabetic # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Alphabetic # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Alphabetic # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; Alphabetic # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Alphabetic # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; Alphabetic # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; Alphabetic # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Alphabetic # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; Alphabetic # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; Alphabetic # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; Alphabetic # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; Alphabetic # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; Alphabetic # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; Alphabetic # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2071 ; Alphabetic # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Alphabetic # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; Alphabetic # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+2102 ; Alphabetic # L& DOUBLE-STRUCK CAPITAL C
+2107 ; Alphabetic # L& EULER CONSTANT
+210A..2113 ; Alphabetic # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; Alphabetic # L& DOUBLE-STRUCK CAPITAL N
+2119..211D ; Alphabetic # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; Alphabetic # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; Alphabetic # L& OHM SIGN
+2128 ; Alphabetic # L& BLACK-LETTER CAPITAL Z
+212A..212D ; Alphabetic # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212F..2134 ; Alphabetic # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; Alphabetic # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; Alphabetic # L& INFORMATION SOURCE
+213C..213F ; Alphabetic # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; Alphabetic # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; Alphabetic # L& TURNED SMALL F
+2160..2182 ; Alphabetic # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; Alphabetic # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; Alphabetic # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+24B6..24E9 ; Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C00..2C2E ; Alphabetic # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; Alphabetic # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; Alphabetic # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; Alphabetic # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; Alphabetic # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; Alphabetic # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; Alphabetic # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Alphabetic # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Alphabetic # L& GEORGIAN SMALL LETTER YN
+2D2D ; Alphabetic # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; Alphabetic # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; Alphabetic # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D80..2D96 ; Alphabetic # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2DE0..2DFF ; Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+2E2F ; Alphabetic # Lm VERTICAL TILDE
+3005 ; Alphabetic # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; Alphabetic # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; Alphabetic # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; Alphabetic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3031..3035 ; Alphabetic # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3038..303A ; Alphabetic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; Alphabetic # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; Alphabetic # Lo MASU MARK
+3041..3096 ; Alphabetic # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309D..309E ; Alphabetic # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; Alphabetic # Lo HIRAGANA DIGRAPH YORI
+30A1..30FA ; Alphabetic # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; Alphabetic # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; Alphabetic # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; Alphabetic # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; Alphabetic # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BA ; Alphabetic # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31F0..31FF ; Alphabetic # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; Alphabetic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FD5 ; Alphabetic # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; Alphabetic # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; Alphabetic # Lm YI SYLLABLE WU
+A016..A48C ; Alphabetic # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; Alphabetic # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; Alphabetic # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; Alphabetic # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; Alphabetic # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; Alphabetic # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A62A..A62B ; Alphabetic # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; Alphabetic # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; Alphabetic # Lo CYRILLIC LETTER MULTIOCULAR O
+A674..A67B ; Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA
+A67F ; Alphabetic # Lm CYRILLIC PAYEROK
+A680..A69B ; Alphabetic # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; Alphabetic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A69E..A69F ; Alphabetic # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6A0..A6E5 ; Alphabetic # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; Alphabetic # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A717..A71F ; Alphabetic # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A722..A76F ; Alphabetic # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; Alphabetic # Lm MODIFIER LETTER US
+A771..A787 ; Alphabetic # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; Alphabetic # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A78B..A78E ; Alphabetic # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; Alphabetic # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; Alphabetic # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; Alphabetic # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; Alphabetic # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; Alphabetic # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; Alphabetic # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; Alphabetic # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; Alphabetic # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; Alphabetic # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; Alphabetic # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; Alphabetic # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; Alphabetic # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; Alphabetic # Mc SYLOTI NAGRI VOWEL SIGN OO
+A840..A873 ; Alphabetic # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A880..A881 ; Alphabetic # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; Alphabetic # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; Alphabetic # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8C5 ; Alphabetic # Mn SAURASHTRA SIGN CANDRABINDU
+A8F2..A8F7 ; Alphabetic # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; Alphabetic # Lo DEVANAGARI HEADSTROKE
+A8FD ; Alphabetic # Lo DEVANAGARI JAIN OM
+A90A..A925 ; Alphabetic # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A926..A92A ; Alphabetic # Mn [5] KAYAH LI VOWEL UE..KAYAH LI VOWEL O
+A930..A946 ; Alphabetic # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A947..A951 ; Alphabetic # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952 ; Alphabetic # Mc REJANG CONSONANT SIGN H
+A960..A97C ; Alphabetic # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A980..A982 ; Alphabetic # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A983 ; Alphabetic # Mc JAVANESE SIGN WIGNYAN
+A984..A9B2 ; Alphabetic # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9B4..A9B5 ; Alphabetic # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+A9B6..A9B9 ; Alphabetic # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BA..A9BB ; Alphabetic # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+A9BC ; Alphabetic # Mn JAVANESE VOWEL SIGN PEPET
+A9BD..A9BF ; Alphabetic # Mc [3] JAVANESE CONSONANT SIGN KERET..JAVANESE CONSONANT SIGN CAKRA
+A9CF ; Alphabetic # Lm JAVANESE PANGRANGKEP
+A9E0..A9E4 ; Alphabetic # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E6 ; Alphabetic # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; Alphabetic # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9FA..A9FE ; Alphabetic # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; Alphabetic # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA29..AA2E ; Alphabetic # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; Alphabetic # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; Alphabetic # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; Alphabetic # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; Alphabetic # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA40..AA42 ; Alphabetic # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA43 ; Alphabetic # Mn CHAM CONSONANT SIGN FINAL NG
+AA44..AA4B ; Alphabetic # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4C ; Alphabetic # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; Alphabetic # Mc CHAM CONSONANT SIGN FINAL H
+AA60..AA6F ; Alphabetic # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; Alphabetic # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; Alphabetic # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA7A ; Alphabetic # Lo MYANMAR LETTER AITON RA
+AA7E..AAAF ; Alphabetic # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB0 ; Alphabetic # Mn TAI VIET MAI KANG
+AAB1 ; Alphabetic # Lo TAI VIET VOWEL AA
+AAB2..AAB4 ; Alphabetic # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB5..AAB6 ; Alphabetic # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB7..AAB8 ; Alphabetic # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AAB9..AABD ; Alphabetic # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AABE ; Alphabetic # Mn TAI VIET VOWEL AM
+AAC0 ; Alphabetic # Lo TAI VIET TONE MAI NUENG
+AAC2 ; Alphabetic # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; Alphabetic # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; Alphabetic # Lm TAI VIET SYMBOL SAM
+AAE0..AAEA ; Alphabetic # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAEB ; Alphabetic # Mc MEETEI MAYEK VOWEL SIGN II
+AAEC..AAED ; Alphabetic # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAEE..AAEF ; Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+AAF2 ; Alphabetic # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; Alphabetic # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AAF5 ; Alphabetic # Mc MEETEI MAYEK VOWEL SIGN VISARGA
+AB01..AB06 ; Alphabetic # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; Alphabetic # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; Alphabetic # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; Alphabetic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; Alphabetic # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; Alphabetic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; Alphabetic # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; Alphabetic # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; Alphabetic # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ABE3..ABE4 ; Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ABE5 ; Alphabetic # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE6..ABE7 ; Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ABE8 ; Alphabetic # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABE9..ABEA ; Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+AC00..D7A3 ; Alphabetic # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; Alphabetic # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; Alphabetic # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; Alphabetic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; Alphabetic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; Alphabetic # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Alphabetic # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; Alphabetic # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1E ; Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FB1F..FB28 ; Alphabetic # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; Alphabetic # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; Alphabetic # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; Alphabetic # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; Alphabetic # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; Alphabetic # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; Alphabetic # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; Alphabetic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; Alphabetic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; Alphabetic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; Alphabetic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FE70..FE74 ; Alphabetic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; Alphabetic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF21..FF3A ; Alphabetic # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; Alphabetic # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF66..FF6F ; Alphabetic # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; Alphabetic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; Alphabetic # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FF9E..FF9F ; Alphabetic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFA0..FFBE ; Alphabetic # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; Alphabetic # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; Alphabetic # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; Alphabetic # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; Alphabetic # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; Alphabetic # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; Alphabetic # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; Alphabetic # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; Alphabetic # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; Alphabetic # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; Alphabetic # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; Alphabetic # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; Alphabetic # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10280..1029C ; Alphabetic # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; Alphabetic # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031F ; Alphabetic # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10330..10340 ; Alphabetic # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; Alphabetic # Nl GOTHIC LETTER NINETY
+10342..10349 ; Alphabetic # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; Alphabetic # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; Alphabetic # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10376..1037A ; Alphabetic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10380..1039D ; Alphabetic # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; Alphabetic # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; Alphabetic # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; Alphabetic # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; Alphabetic # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; Alphabetic # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104B0..104D3 ; Alphabetic # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; Alphabetic # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; Alphabetic # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; Alphabetic # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10600..10736 ; Alphabetic # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; Alphabetic # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; Alphabetic # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; Alphabetic # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; Alphabetic # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; Alphabetic # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; Alphabetic # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; Alphabetic # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; Alphabetic # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; Alphabetic # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; Alphabetic # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; Alphabetic # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; Alphabetic # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; Alphabetic # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; Alphabetic # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; Alphabetic # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; Alphabetic # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; Alphabetic # Lo KHAROSHTHI LETTER A
+10A01..10A03 ; Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A10..10A13 ; Alphabetic # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; Alphabetic # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; Alphabetic # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A60..10A7C ; Alphabetic # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; Alphabetic # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; Alphabetic # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; Alphabetic # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10B00..10B35 ; Alphabetic # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; Alphabetic # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; Alphabetic # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; Alphabetic # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; Alphabetic # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; Alphabetic # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; Alphabetic # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+11000 ; Alphabetic # Mc BRAHMI SIGN CANDRABINDU
+11001 ; Alphabetic # Mn BRAHMI SIGN ANUSVARA
+11002 ; Alphabetic # Mc BRAHMI SIGN VISARGA
+11003..11037 ; Alphabetic # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11038..11045 ; Alphabetic # Mn [14] BRAHMI VOWEL SIGN AA..BRAHMI VOWEL SIGN AU
+11082 ; Alphabetic # Mc KAITHI SIGN VISARGA
+11083..110AF ; Alphabetic # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110B0..110B2 ; Alphabetic # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+110B3..110B6 ; Alphabetic # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B7..110B8 ; Alphabetic # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+110D0..110E8 ; Alphabetic # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+11100..11102 ; Alphabetic # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11103..11126 ; Alphabetic # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11127..1112B ; Alphabetic # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112C ; Alphabetic # Mc CHAKMA VOWEL SIGN E
+1112D..11132 ; Alphabetic # Mn [6] CHAKMA VOWEL SIGN AI..CHAKMA AU MARK
+11150..11172 ; Alphabetic # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11176 ; Alphabetic # Lo MAHAJANI LIGATURE SHRI
+11180..11181 ; Alphabetic # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+11182 ; Alphabetic # Mc SHARADA SIGN VISARGA
+11183..111B2 ; Alphabetic # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111B3..111B5 ; Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+111B6..111BE ; Alphabetic # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111BF ; Alphabetic # Mc SHARADA VOWEL SIGN AU
+111C1..111C4 ; Alphabetic # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111DA ; Alphabetic # Lo SHARADA EKAM
+111DC ; Alphabetic # Lo SHARADA HEADSTROKE
+11200..11211 ; Alphabetic # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; Alphabetic # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+1122C..1122E ; Alphabetic # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+1122F..11231 ; Alphabetic # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11232..11233 ; Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+11234 ; Alphabetic # Mn KHOJKI SIGN ANUSVARA
+11237 ; Alphabetic # Mn KHOJKI SIGN SHADDA
+1123E ; Alphabetic # Mn KHOJKI SIGN SUKUN
+11280..11286 ; Alphabetic # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; Alphabetic # Lo MULTANI LETTER GHA
+1128A..1128D ; Alphabetic # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; Alphabetic # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; Alphabetic # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; Alphabetic # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+112DF ; Alphabetic # Mn KHUDAWADI SIGN ANUSVARA
+112E0..112E2 ; Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+112E3..112E8 ; Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU
+11300..11301 ; Alphabetic # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+11302..11303 ; Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+11305..1130C ; Alphabetic # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; Alphabetic # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; Alphabetic # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; Alphabetic # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; Alphabetic # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; Alphabetic # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133D ; Alphabetic # Lo GRANTHA SIGN AVAGRAHA
+1133E..1133F ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+11340 ; Alphabetic # Mn GRANTHA VOWEL SIGN II
+11341..11344 ; Alphabetic # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+11347..11348 ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+1134B..1134C ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU
+11350 ; Alphabetic # Lo GRANTHA OM
+11357 ; Alphabetic # Mc GRANTHA AU LENGTH MARK
+1135D..11361 ; Alphabetic # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11362..11363 ; Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+11400..11434 ; Alphabetic # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11435..11437 ; Alphabetic # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+11438..1143F ; Alphabetic # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11440..11441 ; Alphabetic # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+11443..11444 ; Alphabetic # Mn [2] NEWA SIGN CANDRABINDU..NEWA SIGN ANUSVARA
+11445 ; Alphabetic # Mc NEWA SIGN VISARGA
+11447..1144A ; Alphabetic # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+11480..114AF ; Alphabetic # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114B0..114B2 ; Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+114B3..114B8 ; Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114B9 ; Alphabetic # Mc TIRHUTA VOWEL SIGN E
+114BA ; Alphabetic # Mn TIRHUTA VOWEL SIGN SHORT E
+114BB..114BE ; Alphabetic # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+114BF..114C0 ; Alphabetic # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C1 ; Alphabetic # Mc TIRHUTA SIGN VISARGA
+114C4..114C5 ; Alphabetic # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; Alphabetic # Lo TIRHUTA OM
+11580..115AE ; Alphabetic # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115AF..115B1 ; Alphabetic # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+115B2..115B5 ; Alphabetic # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115B8..115BB ; Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+115BC..115BD ; Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BE ; Alphabetic # Mc SIDDHAM SIGN VISARGA
+115D8..115DB ; Alphabetic # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+115DC..115DD ; Alphabetic # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11600..1162F ; Alphabetic # Lo [48] MODI LETTER A..MODI LETTER LLA
+11630..11632 ; Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+11633..1163A ; Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163B..1163C ; Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+1163D ; Alphabetic # Mn MODI SIGN ANUSVARA
+1163E ; Alphabetic # Mc MODI SIGN VISARGA
+11640 ; Alphabetic # Mn MODI SIGN ARDHACANDRA
+11644 ; Alphabetic # Lo MODI SIGN HUVA
+11680..116AA ; Alphabetic # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+116AB ; Alphabetic # Mn TAKRI SIGN ANUSVARA
+116AC ; Alphabetic # Mc TAKRI SIGN VISARGA
+116AD ; Alphabetic # Mn TAKRI VOWEL SIGN AA
+116AE..116AF ; Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+116B0..116B5 ; Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+11700..11719 ; Alphabetic # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+1171D..1171F ; Alphabetic # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11720..11721 ; Alphabetic # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+11722..11725 ; Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11726 ; Alphabetic # Mc AHOM VOWEL SIGN E
+11727..1172A ; Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM
+118A0..118DF ; Alphabetic # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118FF ; Alphabetic # Lo WARANG CITI OM
+11AC0..11AF8 ; Alphabetic # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; Alphabetic # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; Alphabetic # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C2F ; Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA
+11C30..11C36 ; Alphabetic # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; Alphabetic # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3E ; Alphabetic # Mc BHAIKSUKI SIGN VISARGA
+11C40 ; Alphabetic # Lo BHAIKSUKI SIGN AVAGRAHA
+11C72..11C8F ; Alphabetic # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+11C92..11CA7 ; Alphabetic # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CA9 ; Alphabetic # Mc MARCHEN SUBJOINED LETTER YA
+11CAA..11CB0 ; Alphabetic # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB1 ; Alphabetic # Mc MARCHEN VOWEL SIGN I
+11CB2..11CB3 ; Alphabetic # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB4 ; Alphabetic # Mc MARCHEN VOWEL SIGN O
+11CB5..11CB6 ; Alphabetic # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+12000..12399 ; Alphabetic # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; Alphabetic # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; Alphabetic # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; Alphabetic # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; Alphabetic # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; Alphabetic # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; Alphabetic # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16AD0..16AED ; Alphabetic # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16B00..16B2F ; Alphabetic # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B30..16B36 ; Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16B40..16B43 ; Alphabetic # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B63..16B77 ; Alphabetic # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; Alphabetic # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; Alphabetic # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; Alphabetic # Lo MIAO LETTER NASALIZATION
+16F51..16F7E ; Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
+16F93..16F9F ; Alphabetic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; Alphabetic # Lm TANGUT ITERATION MARK
+17000..187EC ; Alphabetic # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; Alphabetic # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; Alphabetic # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; Alphabetic # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; Alphabetic # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; Alphabetic # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; Alphabetic # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1BC9E ; Alphabetic # Mn DUPLOYAN DOUBLE MARK
+1D400..1D454 ; Alphabetic # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; Alphabetic # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Alphabetic # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Alphabetic # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Alphabetic # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Alphabetic # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; Alphabetic # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Alphabetic # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Alphabetic # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; Alphabetic # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Alphabetic # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Alphabetic # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Alphabetic # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; Alphabetic # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Alphabetic # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Alphabetic # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Alphabetic # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Alphabetic # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; Alphabetic # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; Alphabetic # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; Alphabetic # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; Alphabetic # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; Alphabetic # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; Alphabetic # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; Alphabetic # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; Alphabetic # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; Alphabetic # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; Alphabetic # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; Alphabetic # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; Alphabetic # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1E000..1E006 ; Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; Alphabetic # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; Alphabetic # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; Alphabetic # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E800..1E8C4 ; Alphabetic # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E900..1E943 ; Alphabetic # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E947 ; Alphabetic # Mn ADLAM HAMZA
+1EE00..1EE03 ; Alphabetic # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; Alphabetic # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; Alphabetic # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; Alphabetic # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; Alphabetic # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; Alphabetic # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; Alphabetic # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; Alphabetic # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; Alphabetic # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; Alphabetic # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; Alphabetic # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; Alphabetic # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; Alphabetic # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; Alphabetic # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; Alphabetic # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; Alphabetic # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; Alphabetic # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; Alphabetic # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; Alphabetic # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; Alphabetic # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; Alphabetic # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; Alphabetic # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; Alphabetic # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; Alphabetic # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+1F130..1F149 ; Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
+1F150..1F169 ; Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+1F170..1F189 ; Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
+20000..2A6D6 ; Alphabetic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; Alphabetic # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; Alphabetic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; Alphabetic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; Alphabetic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 118240
+
+# ================================================
+
+# Derived Property: Lowercase
+# Generated from: Ll + Other_Lowercase
+
+0061..007A ; Lowercase # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; Lowercase # Lo FEMININE ORDINAL INDICATOR
+00B5 ; Lowercase # L& MICRO SIGN
+00BA ; Lowercase # Lo MASCULINE ORDINAL INDICATOR
+00DF..00F6 ; Lowercase # L& [24] LATIN SMALL LETTER SHARP S..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..00FF ; Lowercase # L& [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS
+0101 ; Lowercase # L& LATIN SMALL LETTER A WITH MACRON
+0103 ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE
+0105 ; Lowercase # L& LATIN SMALL LETTER A WITH OGONEK
+0107 ; Lowercase # L& LATIN SMALL LETTER C WITH ACUTE
+0109 ; Lowercase # L& LATIN SMALL LETTER C WITH CIRCUMFLEX
+010B ; Lowercase # L& LATIN SMALL LETTER C WITH DOT ABOVE
+010D ; Lowercase # L& LATIN SMALL LETTER C WITH CARON
+010F ; Lowercase # L& LATIN SMALL LETTER D WITH CARON
+0111 ; Lowercase # L& LATIN SMALL LETTER D WITH STROKE
+0113 ; Lowercase # L& LATIN SMALL LETTER E WITH MACRON
+0115 ; Lowercase # L& LATIN SMALL LETTER E WITH BREVE
+0117 ; Lowercase # L& LATIN SMALL LETTER E WITH DOT ABOVE
+0119 ; Lowercase # L& LATIN SMALL LETTER E WITH OGONEK
+011B ; Lowercase # L& LATIN SMALL LETTER E WITH CARON
+011D ; Lowercase # L& LATIN SMALL LETTER G WITH CIRCUMFLEX
+011F ; Lowercase # L& LATIN SMALL LETTER G WITH BREVE
+0121 ; Lowercase # L& LATIN SMALL LETTER G WITH DOT ABOVE
+0123 ; Lowercase # L& LATIN SMALL LETTER G WITH CEDILLA
+0125 ; Lowercase # L& LATIN SMALL LETTER H WITH CIRCUMFLEX
+0127 ; Lowercase # L& LATIN SMALL LETTER H WITH STROKE
+0129 ; Lowercase # L& LATIN SMALL LETTER I WITH TILDE
+012B ; Lowercase # L& LATIN SMALL LETTER I WITH MACRON
+012D ; Lowercase # L& LATIN SMALL LETTER I WITH BREVE
+012F ; Lowercase # L& LATIN SMALL LETTER I WITH OGONEK
+0131 ; Lowercase # L& LATIN SMALL LETTER DOTLESS I
+0133 ; Lowercase # L& LATIN SMALL LIGATURE IJ
+0135 ; Lowercase # L& LATIN SMALL LETTER J WITH CIRCUMFLEX
+0137..0138 ; Lowercase # L& [2] LATIN SMALL LETTER K WITH CEDILLA..LATIN SMALL LETTER KRA
+013A ; Lowercase # L& LATIN SMALL LETTER L WITH ACUTE
+013C ; Lowercase # L& LATIN SMALL LETTER L WITH CEDILLA
+013E ; Lowercase # L& LATIN SMALL LETTER L WITH CARON
+0140 ; Lowercase # L& LATIN SMALL LETTER L WITH MIDDLE DOT
+0142 ; Lowercase # L& LATIN SMALL LETTER L WITH STROKE
+0144 ; Lowercase # L& LATIN SMALL LETTER N WITH ACUTE
+0146 ; Lowercase # L& LATIN SMALL LETTER N WITH CEDILLA
+0148..0149 ; Lowercase # L& [2] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014B ; Lowercase # L& LATIN SMALL LETTER ENG
+014D ; Lowercase # L& LATIN SMALL LETTER O WITH MACRON
+014F ; Lowercase # L& LATIN SMALL LETTER O WITH BREVE
+0151 ; Lowercase # L& LATIN SMALL LETTER O WITH DOUBLE ACUTE
+0153 ; Lowercase # L& LATIN SMALL LIGATURE OE
+0155 ; Lowercase # L& LATIN SMALL LETTER R WITH ACUTE
+0157 ; Lowercase # L& LATIN SMALL LETTER R WITH CEDILLA
+0159 ; Lowercase # L& LATIN SMALL LETTER R WITH CARON
+015B ; Lowercase # L& LATIN SMALL LETTER S WITH ACUTE
+015D ; Lowercase # L& LATIN SMALL LETTER S WITH CIRCUMFLEX
+015F ; Lowercase # L& LATIN SMALL LETTER S WITH CEDILLA
+0161 ; Lowercase # L& LATIN SMALL LETTER S WITH CARON
+0163 ; Lowercase # L& LATIN SMALL LETTER T WITH CEDILLA
+0165 ; Lowercase # L& LATIN SMALL LETTER T WITH CARON
+0167 ; Lowercase # L& LATIN SMALL LETTER T WITH STROKE
+0169 ; Lowercase # L& LATIN SMALL LETTER U WITH TILDE
+016B ; Lowercase # L& LATIN SMALL LETTER U WITH MACRON
+016D ; Lowercase # L& LATIN SMALL LETTER U WITH BREVE
+016F ; Lowercase # L& LATIN SMALL LETTER U WITH RING ABOVE
+0171 ; Lowercase # L& LATIN SMALL LETTER U WITH DOUBLE ACUTE
+0173 ; Lowercase # L& LATIN SMALL LETTER U WITH OGONEK
+0175 ; Lowercase # L& LATIN SMALL LETTER W WITH CIRCUMFLEX
+0177 ; Lowercase # L& LATIN SMALL LETTER Y WITH CIRCUMFLEX
+017A ; Lowercase # L& LATIN SMALL LETTER Z WITH ACUTE
+017C ; Lowercase # L& LATIN SMALL LETTER Z WITH DOT ABOVE
+017E..0180 ; Lowercase # L& [3] LATIN SMALL LETTER Z WITH CARON..LATIN SMALL LETTER B WITH STROKE
+0183 ; Lowercase # L& LATIN SMALL LETTER B WITH TOPBAR
+0185 ; Lowercase # L& LATIN SMALL LETTER TONE SIX
+0188 ; Lowercase # L& LATIN SMALL LETTER C WITH HOOK
+018C..018D ; Lowercase # L& [2] LATIN SMALL LETTER D WITH TOPBAR..LATIN SMALL LETTER TURNED DELTA
+0192 ; Lowercase # L& LATIN SMALL LETTER F WITH HOOK
+0195 ; Lowercase # L& LATIN SMALL LETTER HV
+0199..019B ; Lowercase # L& [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE
+019E ; Lowercase # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG
+01A1 ; Lowercase # L& LATIN SMALL LETTER O WITH HORN
+01A3 ; Lowercase # L& LATIN SMALL LETTER OI
+01A5 ; Lowercase # L& LATIN SMALL LETTER P WITH HOOK
+01A8 ; Lowercase # L& LATIN SMALL LETTER TONE TWO
+01AA..01AB ; Lowercase # L& [2] LATIN LETTER REVERSED ESH LOOP..LATIN SMALL LETTER T WITH PALATAL HOOK
+01AD ; Lowercase # L& LATIN SMALL LETTER T WITH HOOK
+01B0 ; Lowercase # L& LATIN SMALL LETTER U WITH HORN
+01B4 ; Lowercase # L& LATIN SMALL LETTER Y WITH HOOK
+01B6 ; Lowercase # L& LATIN SMALL LETTER Z WITH STROKE
+01B9..01BA ; Lowercase # L& [2] LATIN SMALL LETTER EZH REVERSED..LATIN SMALL LETTER EZH WITH TAIL
+01BD..01BF ; Lowercase # L& [3] LATIN SMALL LETTER TONE FIVE..LATIN LETTER WYNN
+01C6 ; Lowercase # L& LATIN SMALL LETTER DZ WITH CARON
+01C9 ; Lowercase # L& LATIN SMALL LETTER LJ
+01CC ; Lowercase # L& LATIN SMALL LETTER NJ
+01CE ; Lowercase # L& LATIN SMALL LETTER A WITH CARON
+01D0 ; Lowercase # L& LATIN SMALL LETTER I WITH CARON
+01D2 ; Lowercase # L& LATIN SMALL LETTER O WITH CARON
+01D4 ; Lowercase # L& LATIN SMALL LETTER U WITH CARON
+01D6 ; Lowercase # L& LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+01D8 ; Lowercase # L& LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+01DA ; Lowercase # L& LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+01DC..01DD ; Lowercase # L& [2] LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E
+01DF ; Lowercase # L& LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+01E1 ; Lowercase # L& LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+01E3 ; Lowercase # L& LATIN SMALL LETTER AE WITH MACRON
+01E5 ; Lowercase # L& LATIN SMALL LETTER G WITH STROKE
+01E7 ; Lowercase # L& LATIN SMALL LETTER G WITH CARON
+01E9 ; Lowercase # L& LATIN SMALL LETTER K WITH CARON
+01EB ; Lowercase # L& LATIN SMALL LETTER O WITH OGONEK
+01ED ; Lowercase # L& LATIN SMALL LETTER O WITH OGONEK AND MACRON
+01EF..01F0 ; Lowercase # L& [2] LATIN SMALL LETTER EZH WITH CARON..LATIN SMALL LETTER J WITH CARON
+01F3 ; Lowercase # L& LATIN SMALL LETTER DZ
+01F5 ; Lowercase # L& LATIN SMALL LETTER G WITH ACUTE
+01F9 ; Lowercase # L& LATIN SMALL LETTER N WITH GRAVE
+01FB ; Lowercase # L& LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+01FD ; Lowercase # L& LATIN SMALL LETTER AE WITH ACUTE
+01FF ; Lowercase # L& LATIN SMALL LETTER O WITH STROKE AND ACUTE
+0201 ; Lowercase # L& LATIN SMALL LETTER A WITH DOUBLE GRAVE
+0203 ; Lowercase # L& LATIN SMALL LETTER A WITH INVERTED BREVE
+0205 ; Lowercase # L& LATIN SMALL LETTER E WITH DOUBLE GRAVE
+0207 ; Lowercase # L& LATIN SMALL LETTER E WITH INVERTED BREVE
+0209 ; Lowercase # L& LATIN SMALL LETTER I WITH DOUBLE GRAVE
+020B ; Lowercase # L& LATIN SMALL LETTER I WITH INVERTED BREVE
+020D ; Lowercase # L& LATIN SMALL LETTER O WITH DOUBLE GRAVE
+020F ; Lowercase # L& LATIN SMALL LETTER O WITH INVERTED BREVE
+0211 ; Lowercase # L& LATIN SMALL LETTER R WITH DOUBLE GRAVE
+0213 ; Lowercase # L& LATIN SMALL LETTER R WITH INVERTED BREVE
+0215 ; Lowercase # L& LATIN SMALL LETTER U WITH DOUBLE GRAVE
+0217 ; Lowercase # L& LATIN SMALL LETTER U WITH INVERTED BREVE
+0219 ; Lowercase # L& LATIN SMALL LETTER S WITH COMMA BELOW
+021B ; Lowercase # L& LATIN SMALL LETTER T WITH COMMA BELOW
+021D ; Lowercase # L& LATIN SMALL LETTER YOGH
+021F ; Lowercase # L& LATIN SMALL LETTER H WITH CARON
+0221 ; Lowercase # L& LATIN SMALL LETTER D WITH CURL
+0223 ; Lowercase # L& LATIN SMALL LETTER OU
+0225 ; Lowercase # L& LATIN SMALL LETTER Z WITH HOOK
+0227 ; Lowercase # L& LATIN SMALL LETTER A WITH DOT ABOVE
+0229 ; Lowercase # L& LATIN SMALL LETTER E WITH CEDILLA
+022B ; Lowercase # L& LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+022D ; Lowercase # L& LATIN SMALL LETTER O WITH TILDE AND MACRON
+022F ; Lowercase # L& LATIN SMALL LETTER O WITH DOT ABOVE
+0231 ; Lowercase # L& LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+0233..0239 ; Lowercase # L& [7] LATIN SMALL LETTER Y WITH MACRON..LATIN SMALL LETTER QP DIGRAPH
+023C ; Lowercase # L& LATIN SMALL LETTER C WITH STROKE
+023F..0240 ; Lowercase # L& [2] LATIN SMALL LETTER S WITH SWASH TAIL..LATIN SMALL LETTER Z WITH SWASH TAIL
+0242 ; Lowercase # L& LATIN SMALL LETTER GLOTTAL STOP
+0247 ; Lowercase # L& LATIN SMALL LETTER E WITH STROKE
+0249 ; Lowercase # L& LATIN SMALL LETTER J WITH STROKE
+024B ; Lowercase # L& LATIN SMALL LETTER Q WITH HOOK TAIL
+024D ; Lowercase # L& LATIN SMALL LETTER R WITH STROKE
+024F..0293 ; Lowercase # L& [69] LATIN SMALL LETTER Y WITH STROKE..LATIN SMALL LETTER EZH WITH CURL
+0295..02AF ; Lowercase # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02B8 ; Lowercase # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y
+02C0..02C1 ; Lowercase # Lm [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP
+02E0..02E4 ; Lowercase # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+0345 ; Lowercase # Mn COMBINING GREEK YPOGEGRAMMENI
+0371 ; Lowercase # L& GREEK SMALL LETTER HETA
+0373 ; Lowercase # L& GREEK SMALL LETTER ARCHAIC SAMPI
+0377 ; Lowercase # L& GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; Lowercase # Lm GREEK YPOGEGRAMMENI
+037B..037D ; Lowercase # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0390 ; Lowercase # L& GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+03AC..03CE ; Lowercase # L& [35] GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER OMEGA WITH TONOS
+03D0..03D1 ; Lowercase # L& [2] GREEK BETA SYMBOL..GREEK THETA SYMBOL
+03D5..03D7 ; Lowercase # L& [3] GREEK PHI SYMBOL..GREEK KAI SYMBOL
+03D9 ; Lowercase # L& GREEK SMALL LETTER ARCHAIC KOPPA
+03DB ; Lowercase # L& GREEK SMALL LETTER STIGMA
+03DD ; Lowercase # L& GREEK SMALL LETTER DIGAMMA
+03DF ; Lowercase # L& GREEK SMALL LETTER KOPPA
+03E1 ; Lowercase # L& GREEK SMALL LETTER SAMPI
+03E3 ; Lowercase # L& COPTIC SMALL LETTER SHEI
+03E5 ; Lowercase # L& COPTIC SMALL LETTER FEI
+03E7 ; Lowercase # L& COPTIC SMALL LETTER KHEI
+03E9 ; Lowercase # L& COPTIC SMALL LETTER HORI
+03EB ; Lowercase # L& COPTIC SMALL LETTER GANGIA
+03ED ; Lowercase # L& COPTIC SMALL LETTER SHIMA
+03EF..03F3 ; Lowercase # L& [5] COPTIC SMALL LETTER DEI..GREEK LETTER YOT
+03F5 ; Lowercase # L& GREEK LUNATE EPSILON SYMBOL
+03F8 ; Lowercase # L& GREEK SMALL LETTER SHO
+03FB..03FC ; Lowercase # L& [2] GREEK SMALL LETTER SAN..GREEK RHO WITH STROKE SYMBOL
+0430..045F ; Lowercase # L& [48] CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER DZHE
+0461 ; Lowercase # L& CYRILLIC SMALL LETTER OMEGA
+0463 ; Lowercase # L& CYRILLIC SMALL LETTER YAT
+0465 ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED E
+0467 ; Lowercase # L& CYRILLIC SMALL LETTER LITTLE YUS
+0469 ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
+046B ; Lowercase # L& CYRILLIC SMALL LETTER BIG YUS
+046D ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED BIG YUS
+046F ; Lowercase # L& CYRILLIC SMALL LETTER KSI
+0471 ; Lowercase # L& CYRILLIC SMALL LETTER PSI
+0473 ; Lowercase # L& CYRILLIC SMALL LETTER FITA
+0475 ; Lowercase # L& CYRILLIC SMALL LETTER IZHITSA
+0477 ; Lowercase # L& CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0479 ; Lowercase # L& CYRILLIC SMALL LETTER UK
+047B ; Lowercase # L& CYRILLIC SMALL LETTER ROUND OMEGA
+047D ; Lowercase # L& CYRILLIC SMALL LETTER OMEGA WITH TITLO
+047F ; Lowercase # L& CYRILLIC SMALL LETTER OT
+0481 ; Lowercase # L& CYRILLIC SMALL LETTER KOPPA
+048B ; Lowercase # L& CYRILLIC SMALL LETTER SHORT I WITH TAIL
+048D ; Lowercase # L& CYRILLIC SMALL LETTER SEMISOFT SIGN
+048F ; Lowercase # L& CYRILLIC SMALL LETTER ER WITH TICK
+0491 ; Lowercase # L& CYRILLIC SMALL LETTER GHE WITH UPTURN
+0493 ; Lowercase # L& CYRILLIC SMALL LETTER GHE WITH STROKE
+0495 ; Lowercase # L& CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
+0497 ; Lowercase # L& CYRILLIC SMALL LETTER ZHE WITH DESCENDER
+0499 ; Lowercase # L& CYRILLIC SMALL LETTER ZE WITH DESCENDER
+049B ; Lowercase # L& CYRILLIC SMALL LETTER KA WITH DESCENDER
+049D ; Lowercase # L& CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
+049F ; Lowercase # L& CYRILLIC SMALL LETTER KA WITH STROKE
+04A1 ; Lowercase # L& CYRILLIC SMALL LETTER BASHKIR KA
+04A3 ; Lowercase # L& CYRILLIC SMALL LETTER EN WITH DESCENDER
+04A5 ; Lowercase # L& CYRILLIC SMALL LIGATURE EN GHE
+04A7 ; Lowercase # L& CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
+04A9 ; Lowercase # L& CYRILLIC SMALL LETTER ABKHASIAN HA
+04AB ; Lowercase # L& CYRILLIC SMALL LETTER ES WITH DESCENDER
+04AD ; Lowercase # L& CYRILLIC SMALL LETTER TE WITH DESCENDER
+04AF ; Lowercase # L& CYRILLIC SMALL LETTER STRAIGHT U
+04B1 ; Lowercase # L& CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+04B3 ; Lowercase # L& CYRILLIC SMALL LETTER HA WITH DESCENDER
+04B5 ; Lowercase # L& CYRILLIC SMALL LIGATURE TE TSE
+04B7 ; Lowercase # L& CYRILLIC SMALL LETTER CHE WITH DESCENDER
+04B9 ; Lowercase # L& CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
+04BB ; Lowercase # L& CYRILLIC SMALL LETTER SHHA
+04BD ; Lowercase # L& CYRILLIC SMALL LETTER ABKHASIAN CHE
+04BF ; Lowercase # L& CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
+04C2 ; Lowercase # L& CYRILLIC SMALL LETTER ZHE WITH BREVE
+04C4 ; Lowercase # L& CYRILLIC SMALL LETTER KA WITH HOOK
+04C6 ; Lowercase # L& CYRILLIC SMALL LETTER EL WITH TAIL
+04C8 ; Lowercase # L& CYRILLIC SMALL LETTER EN WITH HOOK
+04CA ; Lowercase # L& CYRILLIC SMALL LETTER EN WITH TAIL
+04CC ; Lowercase # L& CYRILLIC SMALL LETTER KHAKASSIAN CHE
+04CE..04CF ; Lowercase # L& [2] CYRILLIC SMALL LETTER EM WITH TAIL..CYRILLIC SMALL LETTER PALOCHKA
+04D1 ; Lowercase # L& CYRILLIC SMALL LETTER A WITH BREVE
+04D3 ; Lowercase # L& CYRILLIC SMALL LETTER A WITH DIAERESIS
+04D5 ; Lowercase # L& CYRILLIC SMALL LIGATURE A IE
+04D7 ; Lowercase # L& CYRILLIC SMALL LETTER IE WITH BREVE
+04D9 ; Lowercase # L& CYRILLIC SMALL LETTER SCHWA
+04DB ; Lowercase # L& CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
+04DD ; Lowercase # L& CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
+04DF ; Lowercase # L& CYRILLIC SMALL LETTER ZE WITH DIAERESIS
+04E1 ; Lowercase # L& CYRILLIC SMALL LETTER ABKHASIAN DZE
+04E3 ; Lowercase # L& CYRILLIC SMALL LETTER I WITH MACRON
+04E5 ; Lowercase # L& CYRILLIC SMALL LETTER I WITH DIAERESIS
+04E7 ; Lowercase # L& CYRILLIC SMALL LETTER O WITH DIAERESIS
+04E9 ; Lowercase # L& CYRILLIC SMALL LETTER BARRED O
+04EB ; Lowercase # L& CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
+04ED ; Lowercase # L& CYRILLIC SMALL LETTER E WITH DIAERESIS
+04EF ; Lowercase # L& CYRILLIC SMALL LETTER U WITH MACRON
+04F1 ; Lowercase # L& CYRILLIC SMALL LETTER U WITH DIAERESIS
+04F3 ; Lowercase # L& CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
+04F5 ; Lowercase # L& CYRILLIC SMALL LETTER CHE WITH DIAERESIS
+04F7 ; Lowercase # L& CYRILLIC SMALL LETTER GHE WITH DESCENDER
+04F9 ; Lowercase # L& CYRILLIC SMALL LETTER YERU WITH DIAERESIS
+04FB ; Lowercase # L& CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
+04FD ; Lowercase # L& CYRILLIC SMALL LETTER HA WITH HOOK
+04FF ; Lowercase # L& CYRILLIC SMALL LETTER HA WITH STROKE
+0501 ; Lowercase # L& CYRILLIC SMALL LETTER KOMI DE
+0503 ; Lowercase # L& CYRILLIC SMALL LETTER KOMI DJE
+0505 ; Lowercase # L& CYRILLIC SMALL LETTER KOMI ZJE
+0507 ; Lowercase # L& CYRILLIC SMALL LETTER KOMI DZJE
+0509 ; Lowercase # L& CYRILLIC SMALL LETTER KOMI LJE
+050B ; Lowercase # L& CYRILLIC SMALL LETTER KOMI NJE
+050D ; Lowercase # L& CYRILLIC SMALL LETTER KOMI SJE
+050F ; Lowercase # L& CYRILLIC SMALL LETTER KOMI TJE
+0511 ; Lowercase # L& CYRILLIC SMALL LETTER REVERSED ZE
+0513 ; Lowercase # L& CYRILLIC SMALL LETTER EL WITH HOOK
+0515 ; Lowercase # L& CYRILLIC SMALL LETTER LHA
+0517 ; Lowercase # L& CYRILLIC SMALL LETTER RHA
+0519 ; Lowercase # L& CYRILLIC SMALL LETTER YAE
+051B ; Lowercase # L& CYRILLIC SMALL LETTER QA
+051D ; Lowercase # L& CYRILLIC SMALL LETTER WE
+051F ; Lowercase # L& CYRILLIC SMALL LETTER ALEUT KA
+0521 ; Lowercase # L& CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK
+0523 ; Lowercase # L& CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+0525 ; Lowercase # L& CYRILLIC SMALL LETTER PE WITH DESCENDER
+0527 ; Lowercase # L& CYRILLIC SMALL LETTER SHHA WITH DESCENDER
+0529 ; Lowercase # L& CYRILLIC SMALL LETTER EN WITH LEFT HOOK
+052B ; Lowercase # L& CYRILLIC SMALL LETTER DZZHE
+052D ; Lowercase # L& CYRILLIC SMALL LETTER DCHE
+052F ; Lowercase # L& CYRILLIC SMALL LETTER EL WITH DESCENDER
+0561..0587 ; Lowercase # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+13F8..13FD ; Lowercase # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Lowercase # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1D00..1D2B ; Lowercase # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; Lowercase # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; Lowercase # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; Lowercase # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; Lowercase # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; Lowercase # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E01 ; Lowercase # L& LATIN SMALL LETTER A WITH RING BELOW
+1E03 ; Lowercase # L& LATIN SMALL LETTER B WITH DOT ABOVE
+1E05 ; Lowercase # L& LATIN SMALL LETTER B WITH DOT BELOW
+1E07 ; Lowercase # L& LATIN SMALL LETTER B WITH LINE BELOW
+1E09 ; Lowercase # L& LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+1E0B ; Lowercase # L& LATIN SMALL LETTER D WITH DOT ABOVE
+1E0D ; Lowercase # L& LATIN SMALL LETTER D WITH DOT BELOW
+1E0F ; Lowercase # L& LATIN SMALL LETTER D WITH LINE BELOW
+1E11 ; Lowercase # L& LATIN SMALL LETTER D WITH CEDILLA
+1E13 ; Lowercase # L& LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+1E15 ; Lowercase # L& LATIN SMALL LETTER E WITH MACRON AND GRAVE
+1E17 ; Lowercase # L& LATIN SMALL LETTER E WITH MACRON AND ACUTE
+1E19 ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+1E1B ; Lowercase # L& LATIN SMALL LETTER E WITH TILDE BELOW
+1E1D ; Lowercase # L& LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+1E1F ; Lowercase # L& LATIN SMALL LETTER F WITH DOT ABOVE
+1E21 ; Lowercase # L& LATIN SMALL LETTER G WITH MACRON
+1E23 ; Lowercase # L& LATIN SMALL LETTER H WITH DOT ABOVE
+1E25 ; Lowercase # L& LATIN SMALL LETTER H WITH DOT BELOW
+1E27 ; Lowercase # L& LATIN SMALL LETTER H WITH DIAERESIS
+1E29 ; Lowercase # L& LATIN SMALL LETTER H WITH CEDILLA
+1E2B ; Lowercase # L& LATIN SMALL LETTER H WITH BREVE BELOW
+1E2D ; Lowercase # L& LATIN SMALL LETTER I WITH TILDE BELOW
+1E2F ; Lowercase # L& LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+1E31 ; Lowercase # L& LATIN SMALL LETTER K WITH ACUTE
+1E33 ; Lowercase # L& LATIN SMALL LETTER K WITH DOT BELOW
+1E35 ; Lowercase # L& LATIN SMALL LETTER K WITH LINE BELOW
+1E37 ; Lowercase # L& LATIN SMALL LETTER L WITH DOT BELOW
+1E39 ; Lowercase # L& LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+1E3B ; Lowercase # L& LATIN SMALL LETTER L WITH LINE BELOW
+1E3D ; Lowercase # L& LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+1E3F ; Lowercase # L& LATIN SMALL LETTER M WITH ACUTE
+1E41 ; Lowercase # L& LATIN SMALL LETTER M WITH DOT ABOVE
+1E43 ; Lowercase # L& LATIN SMALL LETTER M WITH DOT BELOW
+1E45 ; Lowercase # L& LATIN SMALL LETTER N WITH DOT ABOVE
+1E47 ; Lowercase # L& LATIN SMALL LETTER N WITH DOT BELOW
+1E49 ; Lowercase # L& LATIN SMALL LETTER N WITH LINE BELOW
+1E4B ; Lowercase # L& LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+1E4D ; Lowercase # L& LATIN SMALL LETTER O WITH TILDE AND ACUTE
+1E4F ; Lowercase # L& LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+1E51 ; Lowercase # L& LATIN SMALL LETTER O WITH MACRON AND GRAVE
+1E53 ; Lowercase # L& LATIN SMALL LETTER O WITH MACRON AND ACUTE
+1E55 ; Lowercase # L& LATIN SMALL LETTER P WITH ACUTE
+1E57 ; Lowercase # L& LATIN SMALL LETTER P WITH DOT ABOVE
+1E59 ; Lowercase # L& LATIN SMALL LETTER R WITH DOT ABOVE
+1E5B ; Lowercase # L& LATIN SMALL LETTER R WITH DOT BELOW
+1E5D ; Lowercase # L& LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+1E5F ; Lowercase # L& LATIN SMALL LETTER R WITH LINE BELOW
+1E61 ; Lowercase # L& LATIN SMALL LETTER S WITH DOT ABOVE
+1E63 ; Lowercase # L& LATIN SMALL LETTER S WITH DOT BELOW
+1E65 ; Lowercase # L& LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+1E67 ; Lowercase # L& LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+1E69 ; Lowercase # L& LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6B ; Lowercase # L& LATIN SMALL LETTER T WITH DOT ABOVE
+1E6D ; Lowercase # L& LATIN SMALL LETTER T WITH DOT BELOW
+1E6F ; Lowercase # L& LATIN SMALL LETTER T WITH LINE BELOW
+1E71 ; Lowercase # L& LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+1E73 ; Lowercase # L& LATIN SMALL LETTER U WITH DIAERESIS BELOW
+1E75 ; Lowercase # L& LATIN SMALL LETTER U WITH TILDE BELOW
+1E77 ; Lowercase # L& LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+1E79 ; Lowercase # L& LATIN SMALL LETTER U WITH TILDE AND ACUTE
+1E7B ; Lowercase # L& LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+1E7D ; Lowercase # L& LATIN SMALL LETTER V WITH TILDE
+1E7F ; Lowercase # L& LATIN SMALL LETTER V WITH DOT BELOW
+1E81 ; Lowercase # L& LATIN SMALL LETTER W WITH GRAVE
+1E83 ; Lowercase # L& LATIN SMALL LETTER W WITH ACUTE
+1E85 ; Lowercase # L& LATIN SMALL LETTER W WITH DIAERESIS
+1E87 ; Lowercase # L& LATIN SMALL LETTER W WITH DOT ABOVE
+1E89 ; Lowercase # L& LATIN SMALL LETTER W WITH DOT BELOW
+1E8B ; Lowercase # L& LATIN SMALL LETTER X WITH DOT ABOVE
+1E8D ; Lowercase # L& LATIN SMALL LETTER X WITH DIAERESIS
+1E8F ; Lowercase # L& LATIN SMALL LETTER Y WITH DOT ABOVE
+1E91 ; Lowercase # L& LATIN SMALL LETTER Z WITH CIRCUMFLEX
+1E93 ; Lowercase # L& LATIN SMALL LETTER Z WITH DOT BELOW
+1E95..1E9D ; Lowercase # L& [9] LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER LONG S WITH HIGH STROKE
+1E9F ; Lowercase # L& LATIN SMALL LETTER DELTA
+1EA1 ; Lowercase # L& LATIN SMALL LETTER A WITH DOT BELOW
+1EA3 ; Lowercase # L& LATIN SMALL LETTER A WITH HOOK ABOVE
+1EA5 ; Lowercase # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA7 ; Lowercase # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA9 ; Lowercase # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAB ; Lowercase # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAD ; Lowercase # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAF ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE AND ACUTE
+1EB1 ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE AND GRAVE
+1EB3 ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+1EB5 ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE AND TILDE
+1EB7 ; Lowercase # L& LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+1EB9 ; Lowercase # L& LATIN SMALL LETTER E WITH DOT BELOW
+1EBB ; Lowercase # L& LATIN SMALL LETTER E WITH HOOK ABOVE
+1EBD ; Lowercase # L& LATIN SMALL LETTER E WITH TILDE
+1EBF ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC1 ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC3 ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC5 ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC7 ; Lowercase # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC9 ; Lowercase # L& LATIN SMALL LETTER I WITH HOOK ABOVE
+1ECB ; Lowercase # L& LATIN SMALL LETTER I WITH DOT BELOW
+1ECD ; Lowercase # L& LATIN SMALL LETTER O WITH DOT BELOW
+1ECF ; Lowercase # L& LATIN SMALL LETTER O WITH HOOK ABOVE
+1ED1 ; Lowercase # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED3 ; Lowercase # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED5 ; Lowercase # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED7 ; Lowercase # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED9 ; Lowercase # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDB ; Lowercase # L& LATIN SMALL LETTER O WITH HORN AND ACUTE
+1EDD ; Lowercase # L& LATIN SMALL LETTER O WITH HORN AND GRAVE
+1EDF ; Lowercase # L& LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+1EE1 ; Lowercase # L& LATIN SMALL LETTER O WITH HORN AND TILDE
+1EE3 ; Lowercase # L& LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+1EE5 ; Lowercase # L& LATIN SMALL LETTER U WITH DOT BELOW
+1EE7 ; Lowercase # L& LATIN SMALL LETTER U WITH HOOK ABOVE
+1EE9 ; Lowercase # L& LATIN SMALL LETTER U WITH HORN AND ACUTE
+1EEB ; Lowercase # L& LATIN SMALL LETTER U WITH HORN AND GRAVE
+1EED ; Lowercase # L& LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+1EEF ; Lowercase # L& LATIN SMALL LETTER U WITH HORN AND TILDE
+1EF1 ; Lowercase # L& LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+1EF3 ; Lowercase # L& LATIN SMALL LETTER Y WITH GRAVE
+1EF5 ; Lowercase # L& LATIN SMALL LETTER Y WITH DOT BELOW
+1EF7 ; Lowercase # L& LATIN SMALL LETTER Y WITH HOOK ABOVE
+1EF9 ; Lowercase # L& LATIN SMALL LETTER Y WITH TILDE
+1EFB ; Lowercase # L& LATIN SMALL LETTER MIDDLE-WELSH LL
+1EFD ; Lowercase # L& LATIN SMALL LETTER MIDDLE-WELSH V
+1EFF..1F07 ; Lowercase # L& [9] LATIN SMALL LETTER Y WITH LOOP..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F10..1F15 ; Lowercase # L& [6] GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F27 ; Lowercase # L& [8] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
+1F30..1F37 ; Lowercase # L& [8] GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F40..1F45 ; Lowercase # L& [6] GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Lowercase # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F60..1F67 ; Lowercase # L& [8] GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F70..1F7D ; Lowercase # L& [14] GREEK SMALL LETTER ALPHA WITH VARIA..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1F87 ; Lowercase # L& [8] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F90..1F97 ; Lowercase # L& [8] GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA0..1FA7 ; Lowercase # L& [8] GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FB0..1FB4 ; Lowercase # L& [5] GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FB7 ; Lowercase # L& [2] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FBE ; Lowercase # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Lowercase # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FC7 ; Lowercase # L& [2] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FD0..1FD3 ; Lowercase # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FD7 ; Lowercase # L& [2] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FE0..1FE7 ; Lowercase # L& [8] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FF2..1FF4 ; Lowercase # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FF7 ; Lowercase # L& [2] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+2071 ; Lowercase # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Lowercase # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; Lowercase # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+210A ; Lowercase # L& SCRIPT SMALL G
+210E..210F ; Lowercase # L& [2] PLANCK CONSTANT..PLANCK CONSTANT OVER TWO PI
+2113 ; Lowercase # L& SCRIPT SMALL L
+212F ; Lowercase # L& SCRIPT SMALL E
+2134 ; Lowercase # L& SCRIPT SMALL O
+2139 ; Lowercase # L& INFORMATION SOURCE
+213C..213D ; Lowercase # L& [2] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK SMALL GAMMA
+2146..2149 ; Lowercase # L& [4] DOUBLE-STRUCK ITALIC SMALL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; Lowercase # L& TURNED SMALL F
+2170..217F ; Lowercase # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
+2184 ; Lowercase # L& LATIN SMALL LETTER REVERSED C
+24D0..24E9 ; Lowercase # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C30..2C5E ; Lowercase # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C61 ; Lowercase # L& LATIN SMALL LETTER L WITH DOUBLE BAR
+2C65..2C66 ; Lowercase # L& [2] LATIN SMALL LETTER A WITH STROKE..LATIN SMALL LETTER T WITH DIAGONAL STROKE
+2C68 ; Lowercase # L& LATIN SMALL LETTER H WITH DESCENDER
+2C6A ; Lowercase # L& LATIN SMALL LETTER K WITH DESCENDER
+2C6C ; Lowercase # L& LATIN SMALL LETTER Z WITH DESCENDER
+2C71 ; Lowercase # L& LATIN SMALL LETTER V WITH RIGHT HOOK
+2C73..2C74 ; Lowercase # L& [2] LATIN SMALL LETTER W WITH HOOK..LATIN SMALL LETTER V WITH CURL
+2C76..2C7B ; Lowercase # L& [6] LATIN SMALL LETTER HALF H..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C81 ; Lowercase # L& COPTIC SMALL LETTER ALFA
+2C83 ; Lowercase # L& COPTIC SMALL LETTER VIDA
+2C85 ; Lowercase # L& COPTIC SMALL LETTER GAMMA
+2C87 ; Lowercase # L& COPTIC SMALL LETTER DALDA
+2C89 ; Lowercase # L& COPTIC SMALL LETTER EIE
+2C8B ; Lowercase # L& COPTIC SMALL LETTER SOU
+2C8D ; Lowercase # L& COPTIC SMALL LETTER ZATA
+2C8F ; Lowercase # L& COPTIC SMALL LETTER HATE
+2C91 ; Lowercase # L& COPTIC SMALL LETTER THETHE
+2C93 ; Lowercase # L& COPTIC SMALL LETTER IAUDA
+2C95 ; Lowercase # L& COPTIC SMALL LETTER KAPA
+2C97 ; Lowercase # L& COPTIC SMALL LETTER LAULA
+2C99 ; Lowercase # L& COPTIC SMALL LETTER MI
+2C9B ; Lowercase # L& COPTIC SMALL LETTER NI
+2C9D ; Lowercase # L& COPTIC SMALL LETTER KSI
+2C9F ; Lowercase # L& COPTIC SMALL LETTER O
+2CA1 ; Lowercase # L& COPTIC SMALL LETTER PI
+2CA3 ; Lowercase # L& COPTIC SMALL LETTER RO
+2CA5 ; Lowercase # L& COPTIC SMALL LETTER SIMA
+2CA7 ; Lowercase # L& COPTIC SMALL LETTER TAU
+2CA9 ; Lowercase # L& COPTIC SMALL LETTER UA
+2CAB ; Lowercase # L& COPTIC SMALL LETTER FI
+2CAD ; Lowercase # L& COPTIC SMALL LETTER KHI
+2CAF ; Lowercase # L& COPTIC SMALL LETTER PSI
+2CB1 ; Lowercase # L& COPTIC SMALL LETTER OOU
+2CB3 ; Lowercase # L& COPTIC SMALL LETTER DIALECT-P ALEF
+2CB5 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC AIN
+2CB7 ; Lowercase # L& COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
+2CB9 ; Lowercase # L& COPTIC SMALL LETTER DIALECT-P KAPA
+2CBB ; Lowercase # L& COPTIC SMALL LETTER DIALECT-P NI
+2CBD ; Lowercase # L& COPTIC SMALL LETTER CRYPTOGRAMMIC NI
+2CBF ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC OOU
+2CC1 ; Lowercase # L& COPTIC SMALL LETTER SAMPI
+2CC3 ; Lowercase # L& COPTIC SMALL LETTER CROSSED SHEI
+2CC5 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC SHEI
+2CC7 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC ESH
+2CC9 ; Lowercase # L& COPTIC SMALL LETTER AKHMIMIC KHEI
+2CCB ; Lowercase # L& COPTIC SMALL LETTER DIALECT-P HORI
+2CCD ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC HORI
+2CCF ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC HA
+2CD1 ; Lowercase # L& COPTIC SMALL LETTER L-SHAPED HA
+2CD3 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC HEI
+2CD5 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC HAT
+2CD7 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC GANGIA
+2CD9 ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC DJA
+2CDB ; Lowercase # L& COPTIC SMALL LETTER OLD COPTIC SHIMA
+2CDD ; Lowercase # L& COPTIC SMALL LETTER OLD NUBIAN SHIMA
+2CDF ; Lowercase # L& COPTIC SMALL LETTER OLD NUBIAN NGI
+2CE1 ; Lowercase # L& COPTIC SMALL LETTER OLD NUBIAN NYI
+2CE3..2CE4 ; Lowercase # L& [2] COPTIC SMALL LETTER OLD NUBIAN WAU..COPTIC SYMBOL KAI
+2CEC ; Lowercase # L& COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI
+2CEE ; Lowercase # L& COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF3 ; Lowercase # L& COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Lowercase # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Lowercase # L& GEORGIAN SMALL LETTER YN
+2D2D ; Lowercase # L& GEORGIAN SMALL LETTER AEN
+A641 ; Lowercase # L& CYRILLIC SMALL LETTER ZEMLYA
+A643 ; Lowercase # L& CYRILLIC SMALL LETTER DZELO
+A645 ; Lowercase # L& CYRILLIC SMALL LETTER REVERSED DZE
+A647 ; Lowercase # L& CYRILLIC SMALL LETTER IOTA
+A649 ; Lowercase # L& CYRILLIC SMALL LETTER DJERV
+A64B ; Lowercase # L& CYRILLIC SMALL LETTER MONOGRAPH UK
+A64D ; Lowercase # L& CYRILLIC SMALL LETTER BROAD OMEGA
+A64F ; Lowercase # L& CYRILLIC SMALL LETTER NEUTRAL YER
+A651 ; Lowercase # L& CYRILLIC SMALL LETTER YERU WITH BACK YER
+A653 ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED YAT
+A655 ; Lowercase # L& CYRILLIC SMALL LETTER REVERSED YU
+A657 ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED A
+A659 ; Lowercase # L& CYRILLIC SMALL LETTER CLOSED LITTLE YUS
+A65B ; Lowercase # L& CYRILLIC SMALL LETTER BLENDED YUS
+A65D ; Lowercase # L& CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS
+A65F ; Lowercase # L& CYRILLIC SMALL LETTER YN
+A661 ; Lowercase # L& CYRILLIC SMALL LETTER REVERSED TSE
+A663 ; Lowercase # L& CYRILLIC SMALL LETTER SOFT DE
+A665 ; Lowercase # L& CYRILLIC SMALL LETTER SOFT EL
+A667 ; Lowercase # L& CYRILLIC SMALL LETTER SOFT EM
+A669 ; Lowercase # L& CYRILLIC SMALL LETTER MONOCULAR O
+A66B ; Lowercase # L& CYRILLIC SMALL LETTER BINOCULAR O
+A66D ; Lowercase # L& CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A681 ; Lowercase # L& CYRILLIC SMALL LETTER DWE
+A683 ; Lowercase # L& CYRILLIC SMALL LETTER DZWE
+A685 ; Lowercase # L& CYRILLIC SMALL LETTER ZHWE
+A687 ; Lowercase # L& CYRILLIC SMALL LETTER CCHE
+A689 ; Lowercase # L& CYRILLIC SMALL LETTER DZZE
+A68B ; Lowercase # L& CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK
+A68D ; Lowercase # L& CYRILLIC SMALL LETTER TWE
+A68F ; Lowercase # L& CYRILLIC SMALL LETTER TSWE
+A691 ; Lowercase # L& CYRILLIC SMALL LETTER TSSE
+A693 ; Lowercase # L& CYRILLIC SMALL LETTER TCHE
+A695 ; Lowercase # L& CYRILLIC SMALL LETTER HWE
+A697 ; Lowercase # L& CYRILLIC SMALL LETTER SHWE
+A699 ; Lowercase # L& CYRILLIC SMALL LETTER DOUBLE O
+A69B ; Lowercase # L& CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A723 ; Lowercase # L& LATIN SMALL LETTER EGYPTOLOGICAL ALEF
+A725 ; Lowercase # L& LATIN SMALL LETTER EGYPTOLOGICAL AIN
+A727 ; Lowercase # L& LATIN SMALL LETTER HENG
+A729 ; Lowercase # L& LATIN SMALL LETTER TZ
+A72B ; Lowercase # L& LATIN SMALL LETTER TRESILLO
+A72D ; Lowercase # L& LATIN SMALL LETTER CUATRILLO
+A72F..A731 ; Lowercase # L& [3] LATIN SMALL LETTER CUATRILLO WITH COMMA..LATIN LETTER SMALL CAPITAL S
+A733 ; Lowercase # L& LATIN SMALL LETTER AA
+A735 ; Lowercase # L& LATIN SMALL LETTER AO
+A737 ; Lowercase # L& LATIN SMALL LETTER AU
+A739 ; Lowercase # L& LATIN SMALL LETTER AV
+A73B ; Lowercase # L& LATIN SMALL LETTER AV WITH HORIZONTAL BAR
+A73D ; Lowercase # L& LATIN SMALL LETTER AY
+A73F ; Lowercase # L& LATIN SMALL LETTER REVERSED C WITH DOT
+A741 ; Lowercase # L& LATIN SMALL LETTER K WITH STROKE
+A743 ; Lowercase # L& LATIN SMALL LETTER K WITH DIAGONAL STROKE
+A745 ; Lowercase # L& LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE
+A747 ; Lowercase # L& LATIN SMALL LETTER BROKEN L
+A749 ; Lowercase # L& LATIN SMALL LETTER L WITH HIGH STROKE
+A74B ; Lowercase # L& LATIN SMALL LETTER O WITH LONG STROKE OVERLAY
+A74D ; Lowercase # L& LATIN SMALL LETTER O WITH LOOP
+A74F ; Lowercase # L& LATIN SMALL LETTER OO
+A751 ; Lowercase # L& LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER
+A753 ; Lowercase # L& LATIN SMALL LETTER P WITH FLOURISH
+A755 ; Lowercase # L& LATIN SMALL LETTER P WITH SQUIRREL TAIL
+A757 ; Lowercase # L& LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER
+A759 ; Lowercase # L& LATIN SMALL LETTER Q WITH DIAGONAL STROKE
+A75B ; Lowercase # L& LATIN SMALL LETTER R ROTUNDA
+A75D ; Lowercase # L& LATIN SMALL LETTER RUM ROTUNDA
+A75F ; Lowercase # L& LATIN SMALL LETTER V WITH DIAGONAL STROKE
+A761 ; Lowercase # L& LATIN SMALL LETTER VY
+A763 ; Lowercase # L& LATIN SMALL LETTER VISIGOTHIC Z
+A765 ; Lowercase # L& LATIN SMALL LETTER THORN WITH STROKE
+A767 ; Lowercase # L& LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER
+A769 ; Lowercase # L& LATIN SMALL LETTER VEND
+A76B ; Lowercase # L& LATIN SMALL LETTER ET
+A76D ; Lowercase # L& LATIN SMALL LETTER IS
+A76F ; Lowercase # L& LATIN SMALL LETTER CON
+A770 ; Lowercase # Lm MODIFIER LETTER US
+A771..A778 ; Lowercase # L& [8] LATIN SMALL LETTER DUM..LATIN SMALL LETTER UM
+A77A ; Lowercase # L& LATIN SMALL LETTER INSULAR D
+A77C ; Lowercase # L& LATIN SMALL LETTER INSULAR F
+A77F ; Lowercase # L& LATIN SMALL LETTER TURNED INSULAR G
+A781 ; Lowercase # L& LATIN SMALL LETTER TURNED L
+A783 ; Lowercase # L& LATIN SMALL LETTER INSULAR R
+A785 ; Lowercase # L& LATIN SMALL LETTER INSULAR S
+A787 ; Lowercase # L& LATIN SMALL LETTER INSULAR T
+A78C ; Lowercase # L& LATIN SMALL LETTER SALTILLO
+A78E ; Lowercase # L& LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A791 ; Lowercase # L& LATIN SMALL LETTER N WITH DESCENDER
+A793..A795 ; Lowercase # L& [3] LATIN SMALL LETTER C WITH BAR..LATIN SMALL LETTER H WITH PALATAL HOOK
+A797 ; Lowercase # L& LATIN SMALL LETTER B WITH FLOURISH
+A799 ; Lowercase # L& LATIN SMALL LETTER F WITH STROKE
+A79B ; Lowercase # L& LATIN SMALL LETTER VOLAPUK AE
+A79D ; Lowercase # L& LATIN SMALL LETTER VOLAPUK OE
+A79F ; Lowercase # L& LATIN SMALL LETTER VOLAPUK UE
+A7A1 ; Lowercase # L& LATIN SMALL LETTER G WITH OBLIQUE STROKE
+A7A3 ; Lowercase # L& LATIN SMALL LETTER K WITH OBLIQUE STROKE
+A7A5 ; Lowercase # L& LATIN SMALL LETTER N WITH OBLIQUE STROKE
+A7A7 ; Lowercase # L& LATIN SMALL LETTER R WITH OBLIQUE STROKE
+A7A9 ; Lowercase # L& LATIN SMALL LETTER S WITH OBLIQUE STROKE
+A7B5 ; Lowercase # L& LATIN SMALL LETTER BETA
+A7B7 ; Lowercase # L& LATIN SMALL LETTER OMEGA
+A7F8..A7F9 ; Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; Lowercase # L& LATIN LETTER SMALL CAPITAL TURNED M
+AB30..AB5A ; Lowercase # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; Lowercase # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; Lowercase # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Lowercase # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Lowercase # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF41..FF5A ; Lowercase # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10428..1044F ; Lowercase # L& [40] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER EW
+104D8..104FB ; Lowercase # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10CC0..10CF2 ; Lowercase # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+118C0..118DF ; Lowercase # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+1D41A..1D433 ; Lowercase # L& [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z
+1D44E..1D454 ; Lowercase # L& [7] MATHEMATICAL ITALIC SMALL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D467 ; Lowercase # L& [18] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL ITALIC SMALL Z
+1D482..1D49B ; Lowercase # L& [26] MATHEMATICAL BOLD ITALIC SMALL A..MATHEMATICAL BOLD ITALIC SMALL Z
+1D4B6..1D4B9 ; Lowercase # L& [4] MATHEMATICAL SCRIPT SMALL A..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Lowercase # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Lowercase # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D4CF ; Lowercase # L& [11] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL SCRIPT SMALL Z
+1D4EA..1D503 ; Lowercase # L& [26] MATHEMATICAL BOLD SCRIPT SMALL A..MATHEMATICAL BOLD SCRIPT SMALL Z
+1D51E..1D537 ; Lowercase # L& [26] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL FRAKTUR SMALL Z
+1D552..1D56B ; Lowercase # L& [26] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL DOUBLE-STRUCK SMALL Z
+1D586..1D59F ; Lowercase # L& [26] MATHEMATICAL BOLD FRAKTUR SMALL A..MATHEMATICAL BOLD FRAKTUR SMALL Z
+1D5BA..1D5D3 ; Lowercase # L& [26] MATHEMATICAL SANS-SERIF SMALL A..MATHEMATICAL SANS-SERIF SMALL Z
+1D5EE..1D607 ; Lowercase # L& [26] MATHEMATICAL SANS-SERIF BOLD SMALL A..MATHEMATICAL SANS-SERIF BOLD SMALL Z
+1D622..1D63B ; Lowercase # L& [26] MATHEMATICAL SANS-SERIF ITALIC SMALL A..MATHEMATICAL SANS-SERIF ITALIC SMALL Z
+1D656..1D66F ; Lowercase # L& [26] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z
+1D68A..1D6A5 ; Lowercase # L& [28] MATHEMATICAL MONOSPACE SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6C2..1D6DA ; Lowercase # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6E1 ; Lowercase # L& [6] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL BOLD PI SYMBOL
+1D6FC..1D714 ; Lowercase # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D71B ; Lowercase # L& [6] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL ITALIC PI SYMBOL
+1D736..1D74E ; Lowercase # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D755 ; Lowercase # L& [6] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC PI SYMBOL
+1D770..1D788 ; Lowercase # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D78F ; Lowercase # L& [6] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD PI SYMBOL
+1D7AA..1D7C2 ; Lowercase # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7C9 ; Lowercase # L& [6] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL
+1D7CB ; Lowercase # L& MATHEMATICAL BOLD SMALL DIGAMMA
+1E922..1E943 ; Lowercase # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
+
+# Total code points: 2252
+
+# ================================================
+
+# Derived Property: Uppercase
+# Generated from: Lu + Other_Uppercase
+
+0041..005A ; Uppercase # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+00C0..00D6 ; Uppercase # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00DE ; Uppercase # L& [7] LATIN CAPITAL LETTER O WITH STROKE..LATIN CAPITAL LETTER THORN
+0100 ; Uppercase # L& LATIN CAPITAL LETTER A WITH MACRON
+0102 ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE
+0104 ; Uppercase # L& LATIN CAPITAL LETTER A WITH OGONEK
+0106 ; Uppercase # L& LATIN CAPITAL LETTER C WITH ACUTE
+0108 ; Uppercase # L& LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A ; Uppercase # L& LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C ; Uppercase # L& LATIN CAPITAL LETTER C WITH CARON
+010E ; Uppercase # L& LATIN CAPITAL LETTER D WITH CARON
+0110 ; Uppercase # L& LATIN CAPITAL LETTER D WITH STROKE
+0112 ; Uppercase # L& LATIN CAPITAL LETTER E WITH MACRON
+0114 ; Uppercase # L& LATIN CAPITAL LETTER E WITH BREVE
+0116 ; Uppercase # L& LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118 ; Uppercase # L& LATIN CAPITAL LETTER E WITH OGONEK
+011A ; Uppercase # L& LATIN CAPITAL LETTER E WITH CARON
+011C ; Uppercase # L& LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E ; Uppercase # L& LATIN CAPITAL LETTER G WITH BREVE
+0120 ; Uppercase # L& LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122 ; Uppercase # L& LATIN CAPITAL LETTER G WITH CEDILLA
+0124 ; Uppercase # L& LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126 ; Uppercase # L& LATIN CAPITAL LETTER H WITH STROKE
+0128 ; Uppercase # L& LATIN CAPITAL LETTER I WITH TILDE
+012A ; Uppercase # L& LATIN CAPITAL LETTER I WITH MACRON
+012C ; Uppercase # L& LATIN CAPITAL LETTER I WITH BREVE
+012E ; Uppercase # L& LATIN CAPITAL LETTER I WITH OGONEK
+0130 ; Uppercase # L& LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132 ; Uppercase # L& LATIN CAPITAL LIGATURE IJ
+0134 ; Uppercase # L& LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136 ; Uppercase # L& LATIN CAPITAL LETTER K WITH CEDILLA
+0139 ; Uppercase # L& LATIN CAPITAL LETTER L WITH ACUTE
+013B ; Uppercase # L& LATIN CAPITAL LETTER L WITH CEDILLA
+013D ; Uppercase # L& LATIN CAPITAL LETTER L WITH CARON
+013F ; Uppercase # L& LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141 ; Uppercase # L& LATIN CAPITAL LETTER L WITH STROKE
+0143 ; Uppercase # L& LATIN CAPITAL LETTER N WITH ACUTE
+0145 ; Uppercase # L& LATIN CAPITAL LETTER N WITH CEDILLA
+0147 ; Uppercase # L& LATIN CAPITAL LETTER N WITH CARON
+014A ; Uppercase # L& LATIN CAPITAL LETTER ENG
+014C ; Uppercase # L& LATIN CAPITAL LETTER O WITH MACRON
+014E ; Uppercase # L& LATIN CAPITAL LETTER O WITH BREVE
+0150 ; Uppercase # L& LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152 ; Uppercase # L& LATIN CAPITAL LIGATURE OE
+0154 ; Uppercase # L& LATIN CAPITAL LETTER R WITH ACUTE
+0156 ; Uppercase # L& LATIN CAPITAL LETTER R WITH CEDILLA
+0158 ; Uppercase # L& LATIN CAPITAL LETTER R WITH CARON
+015A ; Uppercase # L& LATIN CAPITAL LETTER S WITH ACUTE
+015C ; Uppercase # L& LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E ; Uppercase # L& LATIN CAPITAL LETTER S WITH CEDILLA
+0160 ; Uppercase # L& LATIN CAPITAL LETTER S WITH CARON
+0162 ; Uppercase # L& LATIN CAPITAL LETTER T WITH CEDILLA
+0164 ; Uppercase # L& LATIN CAPITAL LETTER T WITH CARON
+0166 ; Uppercase # L& LATIN CAPITAL LETTER T WITH STROKE
+0168 ; Uppercase # L& LATIN CAPITAL LETTER U WITH TILDE
+016A ; Uppercase # L& LATIN CAPITAL LETTER U WITH MACRON
+016C ; Uppercase # L& LATIN CAPITAL LETTER U WITH BREVE
+016E ; Uppercase # L& LATIN CAPITAL LETTER U WITH RING ABOVE
+0170 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172 ; Uppercase # L& LATIN CAPITAL LETTER U WITH OGONEK
+0174 ; Uppercase # L& LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178..0179 ; Uppercase # L& [2] LATIN CAPITAL LETTER Y WITH DIAERESIS..LATIN CAPITAL LETTER Z WITH ACUTE
+017B ; Uppercase # L& LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D ; Uppercase # L& LATIN CAPITAL LETTER Z WITH CARON
+0181..0182 ; Uppercase # L& [2] LATIN CAPITAL LETTER B WITH HOOK..LATIN CAPITAL LETTER B WITH TOPBAR
+0184 ; Uppercase # L& LATIN CAPITAL LETTER TONE SIX
+0186..0187 ; Uppercase # L& [2] LATIN CAPITAL LETTER OPEN O..LATIN CAPITAL LETTER C WITH HOOK
+0189..018B ; Uppercase # L& [3] LATIN CAPITAL LETTER AFRICAN D..LATIN CAPITAL LETTER D WITH TOPBAR
+018E..0191 ; Uppercase # L& [4] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER F WITH HOOK
+0193..0194 ; Uppercase # L& [2] LATIN CAPITAL LETTER G WITH HOOK..LATIN CAPITAL LETTER GAMMA
+0196..0198 ; Uppercase # L& [3] LATIN CAPITAL LETTER IOTA..LATIN CAPITAL LETTER K WITH HOOK
+019C..019D ; Uppercase # L& [2] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F..01A0 ; Uppercase # L& [2] LATIN CAPITAL LETTER O WITH MIDDLE TILDE..LATIN CAPITAL LETTER O WITH HORN
+01A2 ; Uppercase # L& LATIN CAPITAL LETTER OI
+01A4 ; Uppercase # L& LATIN CAPITAL LETTER P WITH HOOK
+01A6..01A7 ; Uppercase # L& [2] LATIN LETTER YR..LATIN CAPITAL LETTER TONE TWO
+01A9 ; Uppercase # L& LATIN CAPITAL LETTER ESH
+01AC ; Uppercase # L& LATIN CAPITAL LETTER T WITH HOOK
+01AE..01AF ; Uppercase # L& [2] LATIN CAPITAL LETTER T WITH RETROFLEX HOOK..LATIN CAPITAL LETTER U WITH HORN
+01B1..01B3 ; Uppercase # L& [3] LATIN CAPITAL LETTER UPSILON..LATIN CAPITAL LETTER Y WITH HOOK
+01B5 ; Uppercase # L& LATIN CAPITAL LETTER Z WITH STROKE
+01B7..01B8 ; Uppercase # L& [2] LATIN CAPITAL LETTER EZH..LATIN CAPITAL LETTER EZH REVERSED
+01BC ; Uppercase # L& LATIN CAPITAL LETTER TONE FIVE
+01C4 ; Uppercase # L& LATIN CAPITAL LETTER DZ WITH CARON
+01C7 ; Uppercase # L& LATIN CAPITAL LETTER LJ
+01CA ; Uppercase # L& LATIN CAPITAL LETTER NJ
+01CD ; Uppercase # L& LATIN CAPITAL LETTER A WITH CARON
+01CF ; Uppercase # L& LATIN CAPITAL LETTER I WITH CARON
+01D1 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CARON
+01D3 ; Uppercase # L& LATIN CAPITAL LETTER U WITH CARON
+01D5 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB ; Uppercase # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE ; Uppercase # L& LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0 ; Uppercase # L& LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2 ; Uppercase # L& LATIN CAPITAL LETTER AE WITH MACRON
+01E4 ; Uppercase # L& LATIN CAPITAL LETTER G WITH STROKE
+01E6 ; Uppercase # L& LATIN CAPITAL LETTER G WITH CARON
+01E8 ; Uppercase # L& LATIN CAPITAL LETTER K WITH CARON
+01EA ; Uppercase # L& LATIN CAPITAL LETTER O WITH OGONEK
+01EC ; Uppercase # L& LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE ; Uppercase # L& LATIN CAPITAL LETTER EZH WITH CARON
+01F1 ; Uppercase # L& LATIN CAPITAL LETTER DZ
+01F4 ; Uppercase # L& LATIN CAPITAL LETTER G WITH ACUTE
+01F6..01F8 ; Uppercase # L& [3] LATIN CAPITAL LETTER HWAIR..LATIN CAPITAL LETTER N WITH GRAVE
+01FA ; Uppercase # L& LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC ; Uppercase # L& LATIN CAPITAL LETTER AE WITH ACUTE
+01FE ; Uppercase # L& LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200 ; Uppercase # L& LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202 ; Uppercase # L& LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204 ; Uppercase # L& LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206 ; Uppercase # L& LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208 ; Uppercase # L& LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A ; Uppercase # L& LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C ; Uppercase # L& LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E ; Uppercase # L& LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210 ; Uppercase # L& LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212 ; Uppercase # L& LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216 ; Uppercase # L& LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218 ; Uppercase # L& LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A ; Uppercase # L& LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C ; Uppercase # L& LATIN CAPITAL LETTER YOGH
+021E ; Uppercase # L& LATIN CAPITAL LETTER H WITH CARON
+0220 ; Uppercase # L& LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222 ; Uppercase # L& LATIN CAPITAL LETTER OU
+0224 ; Uppercase # L& LATIN CAPITAL LETTER Z WITH HOOK
+0226 ; Uppercase # L& LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CEDILLA
+022A ; Uppercase # L& LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C ; Uppercase # L& LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E ; Uppercase # L& LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230 ; Uppercase # L& LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH MACRON
+023A..023B ; Uppercase # L& [2] LATIN CAPITAL LETTER A WITH STROKE..LATIN CAPITAL LETTER C WITH STROKE
+023D..023E ; Uppercase # L& [2] LATIN CAPITAL LETTER L WITH BAR..LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+0241 ; Uppercase # L& LATIN CAPITAL LETTER GLOTTAL STOP
+0243..0246 ; Uppercase # L& [4] LATIN CAPITAL LETTER B WITH STROKE..LATIN CAPITAL LETTER E WITH STROKE
+0248 ; Uppercase # L& LATIN CAPITAL LETTER J WITH STROKE
+024A ; Uppercase # L& LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+024C ; Uppercase # L& LATIN CAPITAL LETTER R WITH STROKE
+024E ; Uppercase # L& LATIN CAPITAL LETTER Y WITH STROKE
+0370 ; Uppercase # L& GREEK CAPITAL LETTER HETA
+0372 ; Uppercase # L& GREEK CAPITAL LETTER ARCHAIC SAMPI
+0376 ; Uppercase # L& GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+037F ; Uppercase # L& GREEK CAPITAL LETTER YOT
+0386 ; Uppercase # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Uppercase # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Uppercase # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..038F ; Uppercase # L& [2] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER OMEGA WITH TONOS
+0391..03A1 ; Uppercase # L& [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+03A3..03AB ; Uppercase # L& [9] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03CF ; Uppercase # L& GREEK CAPITAL KAI SYMBOL
+03D2..03D4 ; Uppercase # L& [3] GREEK UPSILON WITH HOOK SYMBOL..GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL
+03D8 ; Uppercase # L& GREEK LETTER ARCHAIC KOPPA
+03DA ; Uppercase # L& GREEK LETTER STIGMA
+03DC ; Uppercase # L& GREEK LETTER DIGAMMA
+03DE ; Uppercase # L& GREEK LETTER KOPPA
+03E0 ; Uppercase # L& GREEK LETTER SAMPI
+03E2 ; Uppercase # L& COPTIC CAPITAL LETTER SHEI
+03E4 ; Uppercase # L& COPTIC CAPITAL LETTER FEI
+03E6 ; Uppercase # L& COPTIC CAPITAL LETTER KHEI
+03E8 ; Uppercase # L& COPTIC CAPITAL LETTER HORI
+03EA ; Uppercase # L& COPTIC CAPITAL LETTER GANGIA
+03EC ; Uppercase # L& COPTIC CAPITAL LETTER SHIMA
+03EE ; Uppercase # L& COPTIC CAPITAL LETTER DEI
+03F4 ; Uppercase # L& GREEK CAPITAL THETA SYMBOL
+03F7 ; Uppercase # L& GREEK CAPITAL LETTER SHO
+03F9..03FA ; Uppercase # L& [2] GREEK CAPITAL LUNATE SIGMA SYMBOL..GREEK CAPITAL LETTER SAN
+03FD..042F ; Uppercase # L& [51] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..CYRILLIC CAPITAL LETTER YA
+0460 ; Uppercase # L& CYRILLIC CAPITAL LETTER OMEGA
+0462 ; Uppercase # L& CYRILLIC CAPITAL LETTER YAT
+0464 ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED E
+0466 ; Uppercase # L& CYRILLIC CAPITAL LETTER LITTLE YUS
+0468 ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A ; Uppercase # L& CYRILLIC CAPITAL LETTER BIG YUS
+046C ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E ; Uppercase # L& CYRILLIC CAPITAL LETTER KSI
+0470 ; Uppercase # L& CYRILLIC CAPITAL LETTER PSI
+0472 ; Uppercase # L& CYRILLIC CAPITAL LETTER FITA
+0474 ; Uppercase # L& CYRILLIC CAPITAL LETTER IZHITSA
+0476 ; Uppercase # L& CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478 ; Uppercase # L& CYRILLIC CAPITAL LETTER UK
+047A ; Uppercase # L& CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C ; Uppercase # L& CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E ; Uppercase # L& CYRILLIC CAPITAL LETTER OT
+0480 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOPPA
+048A ; Uppercase # L& CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C ; Uppercase # L& CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E ; Uppercase # L& CYRILLIC CAPITAL LETTER ER WITH TICK
+0490 ; Uppercase # L& CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492 ; Uppercase # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494 ; Uppercase # L& CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496 ; Uppercase # L& CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498 ; Uppercase # L& CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A ; Uppercase # L& CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C ; Uppercase # L& CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E ; Uppercase # L& CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0 ; Uppercase # L& CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2 ; Uppercase # L& CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4 ; Uppercase # L& CYRILLIC CAPITAL LIGATURE EN GHE
+04A6 ; Uppercase # L& CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8 ; Uppercase # L& CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA ; Uppercase # L& CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC ; Uppercase # L& CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE ; Uppercase # L& CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0 ; Uppercase # L& CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2 ; Uppercase # L& CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4 ; Uppercase # L& CYRILLIC CAPITAL LIGATURE TE TSE
+04B6 ; Uppercase # L& CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8 ; Uppercase # L& CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA ; Uppercase # L& CYRILLIC CAPITAL LETTER SHHA
+04BC ; Uppercase # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE ; Uppercase # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C0..04C1 ; Uppercase # L& [2] CYRILLIC LETTER PALOCHKA..CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3 ; Uppercase # L& CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5 ; Uppercase # L& CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7 ; Uppercase # L& CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9 ; Uppercase # L& CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB ; Uppercase # L& CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD ; Uppercase # L& CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0 ; Uppercase # L& CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2 ; Uppercase # L& CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4 ; Uppercase # L& CYRILLIC CAPITAL LIGATURE A IE
+04D6 ; Uppercase # L& CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8 ; Uppercase # L& CYRILLIC CAPITAL LETTER SCHWA
+04DA ; Uppercase # L& CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC ; Uppercase # L& CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE ; Uppercase # L& CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0 ; Uppercase # L& CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2 ; Uppercase # L& CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4 ; Uppercase # L& CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6 ; Uppercase # L& CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8 ; Uppercase # L& CYRILLIC CAPITAL LETTER BARRED O
+04EA ; Uppercase # L& CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC ; Uppercase # L& CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE ; Uppercase # L& CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0 ; Uppercase # L& CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2 ; Uppercase # L& CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4 ; Uppercase # L& CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6 ; Uppercase # L& CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8 ; Uppercase # L& CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+04FA ; Uppercase # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+04FC ; Uppercase # L& CYRILLIC CAPITAL LETTER HA WITH HOOK
+04FE ; Uppercase # L& CYRILLIC CAPITAL LETTER HA WITH STROKE
+0500 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI DE
+0502 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI DJE
+0504 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI ZJE
+0506 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI DZJE
+0508 ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI LJE
+050A ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI NJE
+050C ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI SJE
+050E ; Uppercase # L& CYRILLIC CAPITAL LETTER KOMI TJE
+0510 ; Uppercase # L& CYRILLIC CAPITAL LETTER REVERSED ZE
+0512 ; Uppercase # L& CYRILLIC CAPITAL LETTER EL WITH HOOK
+0514 ; Uppercase # L& CYRILLIC CAPITAL LETTER LHA
+0516 ; Uppercase # L& CYRILLIC CAPITAL LETTER RHA
+0518 ; Uppercase # L& CYRILLIC CAPITAL LETTER YAE
+051A ; Uppercase # L& CYRILLIC CAPITAL LETTER QA
+051C ; Uppercase # L& CYRILLIC CAPITAL LETTER WE
+051E ; Uppercase # L& CYRILLIC CAPITAL LETTER ALEUT KA
+0520 ; Uppercase # L& CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
+0522 ; Uppercase # L& CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
+0524 ; Uppercase # L& CYRILLIC CAPITAL LETTER PE WITH DESCENDER
+0526 ; Uppercase # L& CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER
+0528 ; Uppercase # L& CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK
+052A ; Uppercase # L& CYRILLIC CAPITAL LETTER DZZHE
+052C ; Uppercase # L& CYRILLIC CAPITAL LETTER DCHE
+052E ; Uppercase # L& CYRILLIC CAPITAL LETTER EL WITH DESCENDER
+0531..0556 ; Uppercase # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+10A0..10C5 ; Uppercase # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Uppercase # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Uppercase # L& GEORGIAN CAPITAL LETTER AEN
+13A0..13F5 ; Uppercase # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+1E00 ; Uppercase # L& LATIN CAPITAL LETTER A WITH RING BELOW
+1E02 ; Uppercase # L& LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04 ; Uppercase # L& LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06 ; Uppercase # L& LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08 ; Uppercase # L& LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A ; Uppercase # L& LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C ; Uppercase # L& LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E ; Uppercase # L& LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10 ; Uppercase # L& LATIN CAPITAL LETTER D WITH CEDILLA
+1E12 ; Uppercase # L& LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14 ; Uppercase # L& LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16 ; Uppercase # L& LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A ; Uppercase # L& LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C ; Uppercase # L& LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E ; Uppercase # L& LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20 ; Uppercase # L& LATIN CAPITAL LETTER G WITH MACRON
+1E22 ; Uppercase # L& LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24 ; Uppercase # L& LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26 ; Uppercase # L& LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28 ; Uppercase # L& LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A ; Uppercase # L& LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C ; Uppercase # L& LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E ; Uppercase # L& LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30 ; Uppercase # L& LATIN CAPITAL LETTER K WITH ACUTE
+1E32 ; Uppercase # L& LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34 ; Uppercase # L& LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36 ; Uppercase # L& LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38 ; Uppercase # L& LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A ; Uppercase # L& LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C ; Uppercase # L& LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E ; Uppercase # L& LATIN CAPITAL LETTER M WITH ACUTE
+1E40 ; Uppercase # L& LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42 ; Uppercase # L& LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44 ; Uppercase # L& LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46 ; Uppercase # L& LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48 ; Uppercase # L& LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A ; Uppercase # L& LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C ; Uppercase # L& LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E ; Uppercase # L& LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50 ; Uppercase # L& LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52 ; Uppercase # L& LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54 ; Uppercase # L& LATIN CAPITAL LETTER P WITH ACUTE
+1E56 ; Uppercase # L& LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58 ; Uppercase # L& LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A ; Uppercase # L& LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C ; Uppercase # L& LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E ; Uppercase # L& LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60 ; Uppercase # L& LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62 ; Uppercase # L& LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64 ; Uppercase # L& LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66 ; Uppercase # L& LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68 ; Uppercase # L& LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A ; Uppercase # L& LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C ; Uppercase # L& LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E ; Uppercase # L& LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70 ; Uppercase # L& LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74 ; Uppercase # L& LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76 ; Uppercase # L& LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78 ; Uppercase # L& LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A ; Uppercase # L& LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C ; Uppercase # L& LATIN CAPITAL LETTER V WITH TILDE
+1E7E ; Uppercase # L& LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80 ; Uppercase # L& LATIN CAPITAL LETTER W WITH GRAVE
+1E82 ; Uppercase # L& LATIN CAPITAL LETTER W WITH ACUTE
+1E84 ; Uppercase # L& LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86 ; Uppercase # L& LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88 ; Uppercase # L& LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A ; Uppercase # L& LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C ; Uppercase # L& LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E ; Uppercase # L& LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90 ; Uppercase # L& LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92 ; Uppercase # L& LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94 ; Uppercase # L& LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E9E ; Uppercase # L& LATIN CAPITAL LETTER SHARP S
+1EA0 ; Uppercase # L& LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2 ; Uppercase # L& LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4 ; Uppercase # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6 ; Uppercase # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8 ; Uppercase # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA ; Uppercase # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC ; Uppercase # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0 ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2 ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4 ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6 ; Uppercase # L& LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8 ; Uppercase # L& LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA ; Uppercase # L& LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC ; Uppercase # L& LATIN CAPITAL LETTER E WITH TILDE
+1EBE ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6 ; Uppercase # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8 ; Uppercase # L& LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA ; Uppercase # L& LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC ; Uppercase # L& LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE ; Uppercase # L& LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8 ; Uppercase # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA ; Uppercase # L& LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC ; Uppercase # L& LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE ; Uppercase # L& LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0 ; Uppercase # L& LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2 ; Uppercase # L& LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4 ; Uppercase # L& LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6 ; Uppercase # L& LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8 ; Uppercase # L& LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA ; Uppercase # L& LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC ; Uppercase # L& LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE ; Uppercase # L& LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0 ; Uppercase # L& LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8 ; Uppercase # L& LATIN CAPITAL LETTER Y WITH TILDE
+1EFA ; Uppercase # L& LATIN CAPITAL LETTER MIDDLE-WELSH LL
+1EFC ; Uppercase # L& LATIN CAPITAL LETTER MIDDLE-WELSH V
+1EFE ; Uppercase # L& LATIN CAPITAL LETTER Y WITH LOOP
+1F08..1F0F ; Uppercase # L& [8] GREEK CAPITAL LETTER ALPHA WITH PSILI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18..1F1D ; Uppercase # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28..1F2F ; Uppercase # L& [8] GREEK CAPITAL LETTER ETA WITH PSILI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38..1F3F ; Uppercase # L& [8] GREEK CAPITAL LETTER IOTA WITH PSILI..GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48..1F4D ; Uppercase # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F59 ; Uppercase # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Uppercase # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Uppercase # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F ; Uppercase # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68..1F6F ; Uppercase # L& [8] GREEK CAPITAL LETTER OMEGA WITH PSILI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1FB8..1FBB ; Uppercase # L& [4] GREEK CAPITAL LETTER ALPHA WITH VRACHY..GREEK CAPITAL LETTER ALPHA WITH OXIA
+1FC8..1FCB ; Uppercase # L& [4] GREEK CAPITAL LETTER EPSILON WITH VARIA..GREEK CAPITAL LETTER ETA WITH OXIA
+1FD8..1FDB ; Uppercase # L& [4] GREEK CAPITAL LETTER IOTA WITH VRACHY..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE8..1FEC ; Uppercase # L& [5] GREEK CAPITAL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF8..1FFB ; Uppercase # L& [4] GREEK CAPITAL LETTER OMICRON WITH VARIA..GREEK CAPITAL LETTER OMEGA WITH OXIA
+2102 ; Uppercase # L& DOUBLE-STRUCK CAPITAL C
+2107 ; Uppercase # L& EULER CONSTANT
+210B..210D ; Uppercase # L& [3] SCRIPT CAPITAL H..DOUBLE-STRUCK CAPITAL H
+2110..2112 ; Uppercase # L& [3] SCRIPT CAPITAL I..SCRIPT CAPITAL L
+2115 ; Uppercase # L& DOUBLE-STRUCK CAPITAL N
+2119..211D ; Uppercase # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; Uppercase # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; Uppercase # L& OHM SIGN
+2128 ; Uppercase # L& BLACK-LETTER CAPITAL Z
+212A..212D ; Uppercase # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+2130..2133 ; Uppercase # L& [4] SCRIPT CAPITAL E..SCRIPT CAPITAL M
+213E..213F ; Uppercase # L& [2] DOUBLE-STRUCK CAPITAL GAMMA..DOUBLE-STRUCK CAPITAL PI
+2145 ; Uppercase # L& DOUBLE-STRUCK ITALIC CAPITAL D
+2160..216F ; Uppercase # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND
+2183 ; Uppercase # L& ROMAN NUMERAL REVERSED ONE HUNDRED
+24B6..24CF ; Uppercase # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z
+2C00..2C2E ; Uppercase # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C60 ; Uppercase # L& LATIN CAPITAL LETTER L WITH DOUBLE BAR
+2C62..2C64 ; Uppercase # L& [3] LATIN CAPITAL LETTER L WITH MIDDLE TILDE..LATIN CAPITAL LETTER R WITH TAIL
+2C67 ; Uppercase # L& LATIN CAPITAL LETTER H WITH DESCENDER
+2C69 ; Uppercase # L& LATIN CAPITAL LETTER K WITH DESCENDER
+2C6B ; Uppercase # L& LATIN CAPITAL LETTER Z WITH DESCENDER
+2C6D..2C70 ; Uppercase # L& [4] LATIN CAPITAL LETTER ALPHA..LATIN CAPITAL LETTER TURNED ALPHA
+2C72 ; Uppercase # L& LATIN CAPITAL LETTER W WITH HOOK
+2C75 ; Uppercase # L& LATIN CAPITAL LETTER HALF H
+2C7E..2C80 ; Uppercase # L& [3] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC CAPITAL LETTER ALFA
+2C82 ; Uppercase # L& COPTIC CAPITAL LETTER VIDA
+2C84 ; Uppercase # L& COPTIC CAPITAL LETTER GAMMA
+2C86 ; Uppercase # L& COPTIC CAPITAL LETTER DALDA
+2C88 ; Uppercase # L& COPTIC CAPITAL LETTER EIE
+2C8A ; Uppercase # L& COPTIC CAPITAL LETTER SOU
+2C8C ; Uppercase # L& COPTIC CAPITAL LETTER ZATA
+2C8E ; Uppercase # L& COPTIC CAPITAL LETTER HATE
+2C90 ; Uppercase # L& COPTIC CAPITAL LETTER THETHE
+2C92 ; Uppercase # L& COPTIC CAPITAL LETTER IAUDA
+2C94 ; Uppercase # L& COPTIC CAPITAL LETTER KAPA
+2C96 ; Uppercase # L& COPTIC CAPITAL LETTER LAULA
+2C98 ; Uppercase # L& COPTIC CAPITAL LETTER MI
+2C9A ; Uppercase # L& COPTIC CAPITAL LETTER NI
+2C9C ; Uppercase # L& COPTIC CAPITAL LETTER KSI
+2C9E ; Uppercase # L& COPTIC CAPITAL LETTER O
+2CA0 ; Uppercase # L& COPTIC CAPITAL LETTER PI
+2CA2 ; Uppercase # L& COPTIC CAPITAL LETTER RO
+2CA4 ; Uppercase # L& COPTIC CAPITAL LETTER SIMA
+2CA6 ; Uppercase # L& COPTIC CAPITAL LETTER TAU
+2CA8 ; Uppercase # L& COPTIC CAPITAL LETTER UA
+2CAA ; Uppercase # L& COPTIC CAPITAL LETTER FI
+2CAC ; Uppercase # L& COPTIC CAPITAL LETTER KHI
+2CAE ; Uppercase # L& COPTIC CAPITAL LETTER PSI
+2CB0 ; Uppercase # L& COPTIC CAPITAL LETTER OOU
+2CB2 ; Uppercase # L& COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6 ; Uppercase # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8 ; Uppercase # L& COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA ; Uppercase # L& COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC ; Uppercase # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0 ; Uppercase # L& COPTIC CAPITAL LETTER SAMPI
+2CC2 ; Uppercase # L& COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8 ; Uppercase # L& COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA ; Uppercase # L& COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0 ; Uppercase # L& COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8 ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA ; Uppercase # L& COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC ; Uppercase # L& COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE ; Uppercase # L& COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0 ; Uppercase # L& COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2 ; Uppercase # L& COPTIC CAPITAL LETTER OLD NUBIAN WAU
+2CEB ; Uppercase # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI
+2CED ; Uppercase # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA
+2CF2 ; Uppercase # L& COPTIC CAPITAL LETTER BOHAIRIC KHEI
+A640 ; Uppercase # L& CYRILLIC CAPITAL LETTER ZEMLYA
+A642 ; Uppercase # L& CYRILLIC CAPITAL LETTER DZELO
+A644 ; Uppercase # L& CYRILLIC CAPITAL LETTER REVERSED DZE
+A646 ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTA
+A648 ; Uppercase # L& CYRILLIC CAPITAL LETTER DJERV
+A64A ; Uppercase # L& CYRILLIC CAPITAL LETTER MONOGRAPH UK
+A64C ; Uppercase # L& CYRILLIC CAPITAL LETTER BROAD OMEGA
+A64E ; Uppercase # L& CYRILLIC CAPITAL LETTER NEUTRAL YER
+A650 ; Uppercase # L& CYRILLIC CAPITAL LETTER YERU WITH BACK YER
+A652 ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED YAT
+A654 ; Uppercase # L& CYRILLIC CAPITAL LETTER REVERSED YU
+A656 ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED A
+A658 ; Uppercase # L& CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
+A65A ; Uppercase # L& CYRILLIC CAPITAL LETTER BLENDED YUS
+A65C ; Uppercase # L& CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
+A65E ; Uppercase # L& CYRILLIC CAPITAL LETTER YN
+A660 ; Uppercase # L& CYRILLIC CAPITAL LETTER REVERSED TSE
+A662 ; Uppercase # L& CYRILLIC CAPITAL LETTER SOFT DE
+A664 ; Uppercase # L& CYRILLIC CAPITAL LETTER SOFT EL
+A666 ; Uppercase # L& CYRILLIC CAPITAL LETTER SOFT EM
+A668 ; Uppercase # L& CYRILLIC CAPITAL LETTER MONOCULAR O
+A66A ; Uppercase # L& CYRILLIC CAPITAL LETTER BINOCULAR O
+A66C ; Uppercase # L& CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
+A680 ; Uppercase # L& CYRILLIC CAPITAL LETTER DWE
+A682 ; Uppercase # L& CYRILLIC CAPITAL LETTER DZWE
+A684 ; Uppercase # L& CYRILLIC CAPITAL LETTER ZHWE
+A686 ; Uppercase # L& CYRILLIC CAPITAL LETTER CCHE
+A688 ; Uppercase # L& CYRILLIC CAPITAL LETTER DZZE
+A68A ; Uppercase # L& CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
+A68C ; Uppercase # L& CYRILLIC CAPITAL LETTER TWE
+A68E ; Uppercase # L& CYRILLIC CAPITAL LETTER TSWE
+A690 ; Uppercase # L& CYRILLIC CAPITAL LETTER TSSE
+A692 ; Uppercase # L& CYRILLIC CAPITAL LETTER TCHE
+A694 ; Uppercase # L& CYRILLIC CAPITAL LETTER HWE
+A696 ; Uppercase # L& CYRILLIC CAPITAL LETTER SHWE
+A698 ; Uppercase # L& CYRILLIC CAPITAL LETTER DOUBLE O
+A69A ; Uppercase # L& CYRILLIC CAPITAL LETTER CROSSED O
+A722 ; Uppercase # L& LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
+A724 ; Uppercase # L& LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
+A726 ; Uppercase # L& LATIN CAPITAL LETTER HENG
+A728 ; Uppercase # L& LATIN CAPITAL LETTER TZ
+A72A ; Uppercase # L& LATIN CAPITAL LETTER TRESILLO
+A72C ; Uppercase # L& LATIN CAPITAL LETTER CUATRILLO
+A72E ; Uppercase # L& LATIN CAPITAL LETTER CUATRILLO WITH COMMA
+A732 ; Uppercase # L& LATIN CAPITAL LETTER AA
+A734 ; Uppercase # L& LATIN CAPITAL LETTER AO
+A736 ; Uppercase # L& LATIN CAPITAL LETTER AU
+A738 ; Uppercase # L& LATIN CAPITAL LETTER AV
+A73A ; Uppercase # L& LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+A73C ; Uppercase # L& LATIN CAPITAL LETTER AY
+A73E ; Uppercase # L& LATIN CAPITAL LETTER REVERSED C WITH DOT
+A740 ; Uppercase # L& LATIN CAPITAL LETTER K WITH STROKE
+A742 ; Uppercase # L& LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+A744 ; Uppercase # L& LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+A746 ; Uppercase # L& LATIN CAPITAL LETTER BROKEN L
+A748 ; Uppercase # L& LATIN CAPITAL LETTER L WITH HIGH STROKE
+A74A ; Uppercase # L& LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+A74C ; Uppercase # L& LATIN CAPITAL LETTER O WITH LOOP
+A74E ; Uppercase # L& LATIN CAPITAL LETTER OO
+A750 ; Uppercase # L& LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+A752 ; Uppercase # L& LATIN CAPITAL LETTER P WITH FLOURISH
+A754 ; Uppercase # L& LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+A756 ; Uppercase # L& LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+A758 ; Uppercase # L& LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+A75A ; Uppercase # L& LATIN CAPITAL LETTER R ROTUNDA
+A75C ; Uppercase # L& LATIN CAPITAL LETTER RUM ROTUNDA
+A75E ; Uppercase # L& LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+A760 ; Uppercase # L& LATIN CAPITAL LETTER VY
+A762 ; Uppercase # L& LATIN CAPITAL LETTER VISIGOTHIC Z
+A764 ; Uppercase # L& LATIN CAPITAL LETTER THORN WITH STROKE
+A766 ; Uppercase # L& LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
+A768 ; Uppercase # L& LATIN CAPITAL LETTER VEND
+A76A ; Uppercase # L& LATIN CAPITAL LETTER ET
+A76C ; Uppercase # L& LATIN CAPITAL LETTER IS
+A76E ; Uppercase # L& LATIN CAPITAL LETTER CON
+A779 ; Uppercase # L& LATIN CAPITAL LETTER INSULAR D
+A77B ; Uppercase # L& LATIN CAPITAL LETTER INSULAR F
+A77D..A77E ; Uppercase # L& [2] LATIN CAPITAL LETTER INSULAR G..LATIN CAPITAL LETTER TURNED INSULAR G
+A780 ; Uppercase # L& LATIN CAPITAL LETTER TURNED L
+A782 ; Uppercase # L& LATIN CAPITAL LETTER INSULAR R
+A784 ; Uppercase # L& LATIN CAPITAL LETTER INSULAR S
+A786 ; Uppercase # L& LATIN CAPITAL LETTER INSULAR T
+A78B ; Uppercase # L& LATIN CAPITAL LETTER SALTILLO
+A78D ; Uppercase # L& LATIN CAPITAL LETTER TURNED H
+A790 ; Uppercase # L& LATIN CAPITAL LETTER N WITH DESCENDER
+A792 ; Uppercase # L& LATIN CAPITAL LETTER C WITH BAR
+A796 ; Uppercase # L& LATIN CAPITAL LETTER B WITH FLOURISH
+A798 ; Uppercase # L& LATIN CAPITAL LETTER F WITH STROKE
+A79A ; Uppercase # L& LATIN CAPITAL LETTER VOLAPUK AE
+A79C ; Uppercase # L& LATIN CAPITAL LETTER VOLAPUK OE
+A79E ; Uppercase # L& LATIN CAPITAL LETTER VOLAPUK UE
+A7A0 ; Uppercase # L& LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
+A7A2 ; Uppercase # L& LATIN CAPITAL LETTER K WITH OBLIQUE STROKE
+A7A4 ; Uppercase # L& LATIN CAPITAL LETTER N WITH OBLIQUE STROKE
+A7A6 ; Uppercase # L& LATIN CAPITAL LETTER R WITH OBLIQUE STROKE
+A7A8 ; Uppercase # L& LATIN CAPITAL LETTER S WITH OBLIQUE STROKE
+A7AA..A7AE ; Uppercase # L& [5] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B4 ; Uppercase # L& [5] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER BETA
+A7B6 ; Uppercase # L& LATIN CAPITAL LETTER OMEGA
+FF21..FF3A ; Uppercase # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+10400..10427 ; Uppercase # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW
+104B0..104D3 ; Uppercase # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+10C80..10CB2 ; Uppercase # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+118A0..118BF ; Uppercase # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO
+1D400..1D419 ; Uppercase # L& [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z
+1D434..1D44D ; Uppercase # L& [26] MATHEMATICAL ITALIC CAPITAL A..MATHEMATICAL ITALIC CAPITAL Z
+1D468..1D481 ; Uppercase # L& [26] MATHEMATICAL BOLD ITALIC CAPITAL A..MATHEMATICAL BOLD ITALIC CAPITAL Z
+1D49C ; Uppercase # L& MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Uppercase # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Uppercase # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Uppercase # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Uppercase # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B5 ; Uppercase # L& [8] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT CAPITAL Z
+1D4D0..1D4E9 ; Uppercase # L& [26] MATHEMATICAL BOLD SCRIPT CAPITAL A..MATHEMATICAL BOLD SCRIPT CAPITAL Z
+1D504..1D505 ; Uppercase # L& [2] MATHEMATICAL FRAKTUR CAPITAL A..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Uppercase # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Uppercase # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Uppercase # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D538..1D539 ; Uppercase # L& [2] MATHEMATICAL DOUBLE-STRUCK CAPITAL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Uppercase # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Uppercase # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Uppercase # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Uppercase # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D56C..1D585 ; Uppercase # L& [26] MATHEMATICAL BOLD FRAKTUR CAPITAL A..MATHEMATICAL BOLD FRAKTUR CAPITAL Z
+1D5A0..1D5B9 ; Uppercase # L& [26] MATHEMATICAL SANS-SERIF CAPITAL A..MATHEMATICAL SANS-SERIF CAPITAL Z
+1D5D4..1D5ED ; Uppercase # L& [26] MATHEMATICAL SANS-SERIF BOLD CAPITAL A..MATHEMATICAL SANS-SERIF BOLD CAPITAL Z
+1D608..1D621 ; Uppercase # L& [26] MATHEMATICAL SANS-SERIF ITALIC CAPITAL A..MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z
+1D63C..1D655 ; Uppercase # L& [26] MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z
+1D670..1D689 ; Uppercase # L& [26] MATHEMATICAL MONOSPACE CAPITAL A..MATHEMATICAL MONOSPACE CAPITAL Z
+1D6A8..1D6C0 ; Uppercase # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6E2..1D6FA ; Uppercase # L& [25] MATHEMATICAL ITALIC CAPITAL ALPHA..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D71C..1D734 ; Uppercase # L& [25] MATHEMATICAL BOLD ITALIC CAPITAL ALPHA..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D756..1D76E ; Uppercase # L& [25] MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D790..1D7A8 ; Uppercase # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7CA ; Uppercase # L& MATHEMATICAL BOLD CAPITAL DIGAMMA
+1E900..1E921 ; Uppercase # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
+1F130..1F149 ; Uppercase # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
+1F150..1F169 ; Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+1F170..1F189 ; Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
+
+# Total code points: 1822
+
+# ================================================
+
+# Derived Property: Cased (Cased)
+# As defined by Unicode Standard Definition D135
+# C has the Lowercase or Uppercase property or has a General_Category value of Titlecase_Letter.
+
+0041..005A ; Cased # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; Cased # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; Cased # Lo FEMININE ORDINAL INDICATOR
+00B5 ; Cased # L& MICRO SIGN
+00BA ; Cased # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; Cased # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; Cased # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; Cased # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BC..01BF ; Cased # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C4..0293 ; Cased # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0295..02AF ; Cased # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02B8 ; Cased # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y
+02C0..02C1 ; Cased # Lm [2] MODIFIER LETTER GLOTTAL STOP..MODIFIER LETTER REVERSED GLOTTAL STOP
+02E0..02E4 ; Cased # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+0345 ; Cased # Mn COMBINING GREEK YPOGEGRAMMENI
+0370..0373 ; Cased # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0376..0377 ; Cased # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; Cased # Lm GREEK YPOGEGRAMMENI
+037B..037D ; Cased # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; Cased # L& GREEK CAPITAL LETTER YOT
+0386 ; Cased # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Cased # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Cased # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; Cased # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; Cased # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; Cased # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; Cased # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; Cased # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0561..0587 ; Cased # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+10A0..10C5 ; Cased # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Cased # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Cased # L& GEORGIAN CAPITAL LETTER AEN
+13A0..13F5 ; Cased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; Cased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Cased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1D00..1D2B ; Cased # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; Cased # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; Cased # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; Cased # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; Cased # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; Cased # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; Cased # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; Cased # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; Cased # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; Cased # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Cased # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; Cased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Cased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Cased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; Cased # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Cased # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; Cased # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; Cased # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Cased # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; Cased # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; Cased # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; Cased # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; Cased # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; Cased # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; Cased # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2071 ; Cased # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Cased # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; Cased # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+2102 ; Cased # L& DOUBLE-STRUCK CAPITAL C
+2107 ; Cased # L& EULER CONSTANT
+210A..2113 ; Cased # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; Cased # L& DOUBLE-STRUCK CAPITAL N
+2119..211D ; Cased # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; Cased # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; Cased # L& OHM SIGN
+2128 ; Cased # L& BLACK-LETTER CAPITAL Z
+212A..212D ; Cased # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212F..2134 ; Cased # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2139 ; Cased # L& INFORMATION SOURCE
+213C..213F ; Cased # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; Cased # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; Cased # L& TURNED SMALL F
+2160..217F ; Cased # Nl [32] ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
+2183..2184 ; Cased # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+24B6..24E9 ; Cased # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C00..2C2E ; Cased # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; Cased # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; Cased # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; Cased # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; Cased # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; Cased # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; Cased # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Cased # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Cased # L& GEORGIAN SMALL LETTER YN
+2D2D ; Cased # L& GEORGIAN SMALL LETTER AEN
+A640..A66D ; Cased # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A680..A69B ; Cased # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; Cased # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A722..A76F ; Cased # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; Cased # Lm MODIFIER LETTER US
+A771..A787 ; Cased # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A78B..A78E ; Cased # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A790..A7AE ; Cased # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; Cased # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F8..A7F9 ; Cased # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; Cased # L& LATIN LETTER SMALL CAPITAL TURNED M
+AB30..AB5A ; Cased # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; Cased # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; Cased # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; Cased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Cased # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Cased # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF21..FF3A ; Cased # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; Cased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10400..1044F ; Cased # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+104B0..104D3 ; Cased # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; Cased # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10C80..10CB2 ; Cased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; Cased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+118A0..118DF ; Cased # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+1D400..1D454 ; Cased # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; Cased # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Cased # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Cased # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Cased # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Cased # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; Cased # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Cased # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Cased # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; Cased # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Cased # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Cased # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Cased # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; Cased # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Cased # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Cased # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Cased # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Cased # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; Cased # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; Cased # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; Cased # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; Cased # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; Cased # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; Cased # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; Cased # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; Cased # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; Cased # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; Cased # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; Cased # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; Cased # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1E900..1E943 ; Cased # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1F130..1F149 ; Cased # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
+1F150..1F169 ; Cased # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
+1F170..1F189 ; Cased # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
+
+# Total code points: 4105
+
+# ================================================
+
+# Derived Property: Case_Ignorable (CI)
+# As defined by Unicode Standard Definition D136
+# C is defined to be case-ignorable if
+# Word_Break(C) = MidLetter or MidNumLet or Single_Quote, or
+# General_Category(C) = Nonspacing_Mark (Mn), Enclosing_Mark (Me), Format (Cf), Modifier_Letter (Lm), or Modifier_Symbol (Sk).
+
+0027 ; Case_Ignorable # Po APOSTROPHE
+002E ; Case_Ignorable # Po FULL STOP
+003A ; Case_Ignorable # Po COLON
+005E ; Case_Ignorable # Sk CIRCUMFLEX ACCENT
+0060 ; Case_Ignorable # Sk GRAVE ACCENT
+00A8 ; Case_Ignorable # Sk DIAERESIS
+00AD ; Case_Ignorable # Cf SOFT HYPHEN
+00AF ; Case_Ignorable # Sk MACRON
+00B4 ; Case_Ignorable # Sk ACUTE ACCENT
+00B7 ; Case_Ignorable # Po MIDDLE DOT
+00B8 ; Case_Ignorable # Sk CEDILLA
+02B0..02C1 ; Case_Ignorable # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C2..02C5 ; Case_Ignorable # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02C6..02D1 ; Case_Ignorable # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02D2..02DF ; Case_Ignorable # Sk [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT
+02E0..02E4 ; Case_Ignorable # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02E5..02EB ; Case_Ignorable # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02EC ; Case_Ignorable # Lm MODIFIER LETTER VOICING
+02ED ; Case_Ignorable # Sk MODIFIER LETTER UNASPIRATED
+02EE ; Case_Ignorable # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+02EF..02FF ; Case_Ignorable # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+0300..036F ; Case_Ignorable # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0374 ; Case_Ignorable # Lm GREEK NUMERAL SIGN
+0375 ; Case_Ignorable # Sk GREEK LOWER NUMERAL SIGN
+037A ; Case_Ignorable # Lm GREEK YPOGEGRAMMENI
+0384..0385 ; Case_Ignorable # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+0387 ; Case_Ignorable # Po GREEK ANO TELEIA
+0483..0487 ; Case_Ignorable # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0488..0489 ; Case_Ignorable # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+0559 ; Case_Ignorable # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0591..05BD ; Case_Ignorable # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; Case_Ignorable # Mn HEBREW POINT RAFE
+05C1..05C2 ; Case_Ignorable # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Case_Ignorable # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Case_Ignorable # Mn HEBREW POINT QAMATS QATAN
+05F4 ; Case_Ignorable # Po HEBREW PUNCTUATION GERSHAYIM
+0600..0605 ; Case_Ignorable # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE
+0610..061A ; Case_Ignorable # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+061C ; Case_Ignorable # Cf ARABIC LETTER MARK
+0640 ; Case_Ignorable # Lm ARABIC TATWEEL
+064B..065F ; Case_Ignorable # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+0670 ; Case_Ignorable # Mn ARABIC LETTER SUPERSCRIPT ALEF
+06D6..06DC ; Case_Ignorable # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DD ; Case_Ignorable # Cf ARABIC END OF AYAH
+06DF..06E4 ; Case_Ignorable # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E5..06E6 ; Case_Ignorable # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E7..06E8 ; Case_Ignorable # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; Case_Ignorable # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+070F ; Case_Ignorable # Cf SYRIAC ABBREVIATION MARK
+0711 ; Case_Ignorable # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0730..074A ; Case_Ignorable # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+07A6..07B0 ; Case_Ignorable # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07EB..07F3 ; Case_Ignorable # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07F4..07F5 ; Case_Ignorable # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; Case_Ignorable # Lm NKO LAJANYALAN
+0816..0819 ; Case_Ignorable # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+081A ; Case_Ignorable # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+081B..0823 ; Case_Ignorable # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0824 ; Case_Ignorable # Lm SAMARITAN MODIFIER LETTER SHORT A
+0825..0827 ; Case_Ignorable # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0828 ; Case_Ignorable # Lm SAMARITAN MODIFIER LETTER I
+0829..082D ; Case_Ignorable # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+0859..085B ; Case_Ignorable # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+08D4..08E1 ; Case_Ignorable # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08E2 ; Case_Ignorable # Cf ARABIC DISPUTED END OF AYAH
+08E3..0902 ; Case_Ignorable # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+093A ; Case_Ignorable # Mn DEVANAGARI VOWEL SIGN OE
+093C ; Case_Ignorable # Mn DEVANAGARI SIGN NUKTA
+0941..0948 ; Case_Ignorable # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+094D ; Case_Ignorable # Mn DEVANAGARI SIGN VIRAMA
+0951..0957 ; Case_Ignorable # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+0962..0963 ; Case_Ignorable # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0971 ; Case_Ignorable # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0981 ; Case_Ignorable # Mn BENGALI SIGN CANDRABINDU
+09BC ; Case_Ignorable # Mn BENGALI SIGN NUKTA
+09C1..09C4 ; Case_Ignorable # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09CD ; Case_Ignorable # Mn BENGALI SIGN VIRAMA
+09E2..09E3 ; Case_Ignorable # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+0A01..0A02 ; Case_Ignorable # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A3C ; Case_Ignorable # Mn GURMUKHI SIGN NUKTA
+0A41..0A42 ; Case_Ignorable # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Case_Ignorable # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Case_Ignorable # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Case_Ignorable # Mn GURMUKHI SIGN UDAAT
+0A70..0A71 ; Case_Ignorable # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A75 ; Case_Ignorable # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; Case_Ignorable # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0ABC ; Case_Ignorable # Mn GUJARATI SIGN NUKTA
+0AC1..0AC5 ; Case_Ignorable # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Case_Ignorable # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0ACD ; Case_Ignorable # Mn GUJARATI SIGN VIRAMA
+0AE2..0AE3 ; Case_Ignorable # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0B01 ; Case_Ignorable # Mn ORIYA SIGN CANDRABINDU
+0B3C ; Case_Ignorable # Mn ORIYA SIGN NUKTA
+0B3F ; Case_Ignorable # Mn ORIYA VOWEL SIGN I
+0B41..0B44 ; Case_Ignorable # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B4D ; Case_Ignorable # Mn ORIYA SIGN VIRAMA
+0B56 ; Case_Ignorable # Mn ORIYA AI LENGTH MARK
+0B62..0B63 ; Case_Ignorable # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B82 ; Case_Ignorable # Mn TAMIL SIGN ANUSVARA
+0BC0 ; Case_Ignorable # Mn TAMIL VOWEL SIGN II
+0BCD ; Case_Ignorable # Mn TAMIL SIGN VIRAMA
+0C00 ; Case_Ignorable # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C3E..0C40 ; Case_Ignorable # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C46..0C48 ; Case_Ignorable # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Case_Ignorable # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Case_Ignorable # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C62..0C63 ; Case_Ignorable # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C81 ; Case_Ignorable # Mn KANNADA SIGN CANDRABINDU
+0CBC ; Case_Ignorable # Mn KANNADA SIGN NUKTA
+0CBF ; Case_Ignorable # Mn KANNADA VOWEL SIGN I
+0CC6 ; Case_Ignorable # Mn KANNADA VOWEL SIGN E
+0CCC..0CCD ; Case_Ignorable # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CE2..0CE3 ; Case_Ignorable # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0D01 ; Case_Ignorable # Mn MALAYALAM SIGN CANDRABINDU
+0D41..0D44 ; Case_Ignorable # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D4D ; Case_Ignorable # Mn MALAYALAM SIGN VIRAMA
+0D62..0D63 ; Case_Ignorable # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0DCA ; Case_Ignorable # Mn SINHALA SIGN AL-LAKUNA
+0DD2..0DD4 ; Case_Ignorable # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Case_Ignorable # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0E31 ; Case_Ignorable # Mn THAI CHARACTER MAI HAN-AKAT
+0E34..0E3A ; Case_Ignorable # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E46 ; Case_Ignorable # Lm THAI CHARACTER MAIYAMOK
+0E47..0E4E ; Case_Ignorable # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0EB1 ; Case_Ignorable # Mn LAO VOWEL SIGN MAI KAN
+0EB4..0EB9 ; Case_Ignorable # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Case_Ignorable # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EC6 ; Case_Ignorable # Lm LAO KO LA
+0EC8..0ECD ; Case_Ignorable # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0F18..0F19 ; Case_Ignorable # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; Case_Ignorable # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; Case_Ignorable # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; Case_Ignorable # Mn TIBETAN MARK TSA -PHRU
+0F71..0F7E ; Case_Ignorable # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F80..0F84 ; Case_Ignorable # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; Case_Ignorable # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F8D..0F97 ; Case_Ignorable # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Case_Ignorable # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; Case_Ignorable # Mn TIBETAN SYMBOL PADMA GDAN
+102D..1030 ; Case_Ignorable # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1032..1037 ; Case_Ignorable # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1039..103A ; Case_Ignorable # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103D..103E ; Case_Ignorable # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+1058..1059 ; Case_Ignorable # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105E..1060 ; Case_Ignorable # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1071..1074 ; Case_Ignorable # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1082 ; Case_Ignorable # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1085..1086 ; Case_Ignorable # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+108D ; Case_Ignorable # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+109D ; Case_Ignorable # Mn MYANMAR VOWEL SIGN AITON AI
+10FC ; Case_Ignorable # Lm MODIFIER LETTER GEORGIAN NAR
+135D..135F ; Case_Ignorable # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+1712..1714 ; Case_Ignorable # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1732..1734 ; Case_Ignorable # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1752..1753 ; Case_Ignorable # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1772..1773 ; Case_Ignorable # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+17B4..17B5 ; Case_Ignorable # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B7..17BD ; Case_Ignorable # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17C6 ; Case_Ignorable # Mn KHMER SIGN NIKAHIT
+17C9..17D3 ; Case_Ignorable # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17D7 ; Case_Ignorable # Lm KHMER SIGN LEK TOO
+17DD ; Case_Ignorable # Mn KHMER SIGN ATTHACAN
+180B..180D ; Case_Ignorable # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180E ; Case_Ignorable # Cf MONGOLIAN VOWEL SEPARATOR
+1843 ; Case_Ignorable # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1885..1886 ; Case_Ignorable # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+18A9 ; Case_Ignorable # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+1920..1922 ; Case_Ignorable # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1927..1928 ; Case_Ignorable # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1932 ; Case_Ignorable # Mn LIMBU SMALL LETTER ANUSVARA
+1939..193B ; Case_Ignorable # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1A17..1A18 ; Case_Ignorable # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A1B ; Case_Ignorable # Mn BUGINESE VOWEL SIGN AE
+1A56 ; Case_Ignorable # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A58..1A5E ; Case_Ignorable # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A60 ; Case_Ignorable # Mn TAI THAM SIGN SAKOT
+1A62 ; Case_Ignorable # Mn TAI THAM VOWEL SIGN MAI SAT
+1A65..1A6C ; Case_Ignorable # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A73..1A7C ; Case_Ignorable # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F ; Case_Ignorable # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+1AA7 ; Case_Ignorable # Lm TAI THAM SIGN MAI YAMOK
+1AB0..1ABD ; Case_Ignorable # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+1ABE ; Case_Ignorable # Me COMBINING PARENTHESES OVERLAY
+1B00..1B03 ; Case_Ignorable # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B34 ; Case_Ignorable # Mn BALINESE SIGN REREKAN
+1B36..1B3A ; Case_Ignorable # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3C ; Case_Ignorable # Mn BALINESE VOWEL SIGN LA LENGA
+1B42 ; Case_Ignorable # Mn BALINESE VOWEL SIGN PEPET
+1B6B..1B73 ; Case_Ignorable # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; Case_Ignorable # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1BA2..1BA5 ; Case_Ignorable # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA8..1BA9 ; Case_Ignorable # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAB..1BAD ; Case_Ignorable # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BE6 ; Case_Ignorable # Mn BATAK SIGN TOMPI
+1BE8..1BE9 ; Case_Ignorable # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BED ; Case_Ignorable # Mn BATAK VOWEL SIGN KARO O
+1BEF..1BF1 ; Case_Ignorable # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1C2C..1C33 ; Case_Ignorable # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C36..1C37 ; Case_Ignorable # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1C78..1C7D ; Case_Ignorable # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1CD0..1CD2 ; Case_Ignorable # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+1CD4..1CE0 ; Case_Ignorable # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+1CE2..1CE8 ; Case_Ignorable # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+1CED ; Case_Ignorable # Mn VEDIC SIGN TIRYAK
+1CF4 ; Case_Ignorable # Mn VEDIC TONE CANDRA ABOVE
+1CF8..1CF9 ; Case_Ignorable # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+1D2C..1D6A ; Case_Ignorable # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D78 ; Case_Ignorable # Lm MODIFIER LETTER CYRILLIC EN
+1D9B..1DBF ; Case_Ignorable # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1DC0..1DF5 ; Case_Ignorable # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
+1DFB..1DFF ; Case_Ignorable # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+1FBD ; Case_Ignorable # Sk GREEK KORONIS
+1FBF..1FC1 ; Case_Ignorable # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+1FCD..1FCF ; Case_Ignorable # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+1FDD..1FDF ; Case_Ignorable # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+1FED..1FEF ; Case_Ignorable # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+1FFD..1FFE ; Case_Ignorable # Sk [2] GREEK OXIA..GREEK DASIA
+200B..200F ; Case_Ignorable # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+2018 ; Case_Ignorable # Pi LEFT SINGLE QUOTATION MARK
+2019 ; Case_Ignorable # Pf RIGHT SINGLE QUOTATION MARK
+2024 ; Case_Ignorable # Po ONE DOT LEADER
+2027 ; Case_Ignorable # Po HYPHENATION POINT
+202A..202E ; Case_Ignorable # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+2060..2064 ; Case_Ignorable # Cf [5] WORD JOINER..INVISIBLE PLUS
+2066..206F ; Case_Ignorable # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+2071 ; Case_Ignorable # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Case_Ignorable # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; Case_Ignorable # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+20D0..20DC ; Case_Ignorable # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20DD..20E0 ; Case_Ignorable # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E1 ; Case_Ignorable # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E2..20E4 ; Case_Ignorable # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+20E5..20F0 ; Case_Ignorable # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2C7C..2C7D ; Case_Ignorable # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2CEF..2CF1 ; Case_Ignorable # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+2D6F ; Case_Ignorable # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D7F ; Case_Ignorable # Mn TIFINAGH CONSONANT JOINER
+2DE0..2DFF ; Case_Ignorable # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+2E2F ; Case_Ignorable # Lm VERTICAL TILDE
+3005 ; Case_Ignorable # Lm IDEOGRAPHIC ITERATION MARK
+302A..302D ; Case_Ignorable # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+3031..3035 ; Case_Ignorable # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+303B ; Case_Ignorable # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+3099..309A ; Case_Ignorable # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309B..309C ; Case_Ignorable # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; Case_Ignorable # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+30FC..30FE ; Case_Ignorable # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+A015 ; Case_Ignorable # Lm YI SYLLABLE WU
+A4F8..A4FD ; Case_Ignorable # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A60C ; Case_Ignorable # Lm VAI SYLLABLE LENGTHENER
+A66F ; Case_Ignorable # Mn COMBINING CYRILLIC VZMET
+A670..A672 ; Case_Ignorable # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A674..A67D ; Case_Ignorable # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+A67F ; Case_Ignorable # Lm CYRILLIC PAYEROK
+A69C..A69D ; Case_Ignorable # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A69E..A69F ; Case_Ignorable # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6F0..A6F1 ; Case_Ignorable # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+A700..A716 ; Case_Ignorable # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A717..A71F ; Case_Ignorable # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A720..A721 ; Case_Ignorable # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A770 ; Case_Ignorable # Lm MODIFIER LETTER US
+A788 ; Case_Ignorable # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A789..A78A ; Case_Ignorable # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+A7F8..A7F9 ; Case_Ignorable # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A802 ; Case_Ignorable # Mn SYLOTI NAGRI SIGN DVISVARA
+A806 ; Case_Ignorable # Mn SYLOTI NAGRI SIGN HASANTA
+A80B ; Case_Ignorable # Mn SYLOTI NAGRI SIGN ANUSVARA
+A825..A826 ; Case_Ignorable # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A8C4..A8C5 ; Case_Ignorable # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+A8E0..A8F1 ; Case_Ignorable # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A926..A92D ; Case_Ignorable # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A947..A951 ; Case_Ignorable # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A980..A982 ; Case_Ignorable # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A9B3 ; Case_Ignorable # Mn JAVANESE SIGN CECAK TELU
+A9B6..A9B9 ; Case_Ignorable # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BC ; Case_Ignorable # Mn JAVANESE VOWEL SIGN PEPET
+A9CF ; Case_Ignorable # Lm JAVANESE PANGRANGKEP
+A9E5 ; Case_Ignorable # Mn MYANMAR SIGN SHAN SAW
+A9E6 ; Case_Ignorable # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+AA29..AA2E ; Case_Ignorable # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA31..AA32 ; Case_Ignorable # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA35..AA36 ; Case_Ignorable # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA43 ; Case_Ignorable # Mn CHAM CONSONANT SIGN FINAL NG
+AA4C ; Case_Ignorable # Mn CHAM CONSONANT SIGN FINAL M
+AA70 ; Case_Ignorable # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA7C ; Case_Ignorable # Mn MYANMAR SIGN TAI LAING TONE-2
+AAB0 ; Case_Ignorable # Mn TAI VIET MAI KANG
+AAB2..AAB4 ; Case_Ignorable # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB7..AAB8 ; Case_Ignorable # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AABE..AABF ; Case_Ignorable # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+AAC1 ; Case_Ignorable # Mn TAI VIET TONE MAI THO
+AADD ; Case_Ignorable # Lm TAI VIET SYMBOL SAM
+AAEC..AAED ; Case_Ignorable # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAF3..AAF4 ; Case_Ignorable # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AAF6 ; Case_Ignorable # Mn MEETEI MAYEK VIRAMA
+AB5B ; Case_Ignorable # Sk MODIFIER BREVE WITH INVERTED BREVE
+AB5C..AB5F ; Case_Ignorable # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+ABE5 ; Case_Ignorable # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE8 ; Case_Ignorable # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABED ; Case_Ignorable # Mn MEETEI MAYEK APUN IYEK
+FB1E ; Case_Ignorable # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FBB2..FBC1 ; Case_Ignorable # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW
+FE00..FE0F ; Case_Ignorable # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE13 ; Case_Ignorable # Po PRESENTATION FORM FOR VERTICAL COLON
+FE20..FE2F ; Case_Ignorable # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+FE52 ; Case_Ignorable # Po SMALL FULL STOP
+FE55 ; Case_Ignorable # Po SMALL COLON
+FEFF ; Case_Ignorable # Cf ZERO WIDTH NO-BREAK SPACE
+FF07 ; Case_Ignorable # Po FULLWIDTH APOSTROPHE
+FF0E ; Case_Ignorable # Po FULLWIDTH FULL STOP
+FF1A ; Case_Ignorable # Po FULLWIDTH COLON
+FF3E ; Case_Ignorable # Sk FULLWIDTH CIRCUMFLEX ACCENT
+FF40 ; Case_Ignorable # Sk FULLWIDTH GRAVE ACCENT
+FF70 ; Case_Ignorable # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF9E..FF9F ; Case_Ignorable # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFE3 ; Case_Ignorable # Sk FULLWIDTH MACRON
+FFF9..FFFB ; Case_Ignorable # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+101FD ; Case_Ignorable # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+102E0 ; Case_Ignorable # Mn COPTIC EPACT THOUSANDS MARK
+10376..1037A ; Case_Ignorable # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10A01..10A03 ; Case_Ignorable # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Case_Ignorable # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Case_Ignorable # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A38..10A3A ; Case_Ignorable # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Case_Ignorable # Mn KHAROSHTHI VIRAMA
+10AE5..10AE6 ; Case_Ignorable # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+11001 ; Case_Ignorable # Mn BRAHMI SIGN ANUSVARA
+11038..11046 ; Case_Ignorable # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+1107F..11081 ; Case_Ignorable # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+110B3..110B6 ; Case_Ignorable # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B9..110BA ; Case_Ignorable # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+110BD ; Case_Ignorable # Cf KAITHI NUMBER SIGN
+11100..11102 ; Case_Ignorable # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11127..1112B ; Case_Ignorable # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112D..11134 ; Case_Ignorable # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+11173 ; Case_Ignorable # Mn MAHAJANI SIGN NUKTA
+11180..11181 ; Case_Ignorable # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+111B6..111BE ; Case_Ignorable # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111CA..111CC ; Case_Ignorable # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+1122F..11231 ; Case_Ignorable # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11234 ; Case_Ignorable # Mn KHOJKI SIGN ANUSVARA
+11236..11237 ; Case_Ignorable # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+1123E ; Case_Ignorable # Mn KHOJKI SIGN SUKUN
+112DF ; Case_Ignorable # Mn KHUDAWADI SIGN ANUSVARA
+112E3..112EA ; Case_Ignorable # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+11300..11301 ; Case_Ignorable # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+1133C ; Case_Ignorable # Mn GRANTHA SIGN NUKTA
+11340 ; Case_Ignorable # Mn GRANTHA VOWEL SIGN II
+11366..1136C ; Case_Ignorable # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+11370..11374 ; Case_Ignorable # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+11438..1143F ; Case_Ignorable # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11442..11444 ; Case_Ignorable # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+11446 ; Case_Ignorable # Mn NEWA SIGN NUKTA
+114B3..114B8 ; Case_Ignorable # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114BA ; Case_Ignorable # Mn TIRHUTA VOWEL SIGN SHORT E
+114BF..114C0 ; Case_Ignorable # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C2..114C3 ; Case_Ignorable # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+115B2..115B5 ; Case_Ignorable # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115BC..115BD ; Case_Ignorable # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BF..115C0 ; Case_Ignorable # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+115DC..115DD ; Case_Ignorable # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11633..1163A ; Case_Ignorable # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163D ; Case_Ignorable # Mn MODI SIGN ANUSVARA
+1163F..11640 ; Case_Ignorable # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+116AB ; Case_Ignorable # Mn TAKRI SIGN ANUSVARA
+116AD ; Case_Ignorable # Mn TAKRI VOWEL SIGN AA
+116B0..116B5 ; Case_Ignorable # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+116B7 ; Case_Ignorable # Mn TAKRI SIGN NUKTA
+1171D..1171F ; Case_Ignorable # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11722..11725 ; Case_Ignorable # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11727..1172B ; Case_Ignorable # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+11C30..11C36 ; Case_Ignorable # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; Case_Ignorable # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3F ; Case_Ignorable # Mn BHAIKSUKI SIGN VIRAMA
+11C92..11CA7 ; Case_Ignorable # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CAA..11CB0 ; Case_Ignorable # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB2..11CB3 ; Case_Ignorable # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB5..11CB6 ; Case_Ignorable # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+16AF0..16AF4 ; Case_Ignorable # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+16B30..16B36 ; Case_Ignorable # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16B40..16B43 ; Case_Ignorable # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16F8F..16F92 ; Case_Ignorable # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+16F93..16F9F ; Case_Ignorable # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; Case_Ignorable # Lm TANGUT ITERATION MARK
+1BC9D..1BC9E ; Case_Ignorable # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1BCA0..1BCA3 ; Case_Ignorable # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+1D167..1D169 ; Case_Ignorable # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D173..1D17A ; Case_Ignorable # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+1D17B..1D182 ; Case_Ignorable # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Case_Ignorable # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Case_Ignorable # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; Case_Ignorable # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1DA00..1DA36 ; Case_Ignorable # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+1DA3B..1DA6C ; Case_Ignorable # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+1DA75 ; Case_Ignorable # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+1DA84 ; Case_Ignorable # Mn SIGNWRITING LOCATION HEAD NECK
+1DA9B..1DA9F ; Case_Ignorable # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+1DAA1..1DAAF ; Case_Ignorable # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+1E000..1E006 ; Case_Ignorable # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; Case_Ignorable # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; Case_Ignorable # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; Case_Ignorable # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; Case_Ignorable # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E8D0..1E8D6 ; Case_Ignorable # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+1E944..1E94A ; Case_Ignorable # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1F3FB..1F3FF ; Case_Ignorable # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+E0001 ; Case_Ignorable # Cf LANGUAGE TAG
+E0020..E007F ; Case_Ignorable # Cf [96] TAG SPACE..CANCEL TAG
+E0100..E01EF ; Case_Ignorable # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 2240
+
+# ================================================
+
+# Derived Property: Changes_When_Lowercased (CWL)
+# Characters whose normalized forms are not stable under a toLowercase mapping.
+# For more information, see D139 in Section 3.13, "Default Case Algorithms".
+# Changes_When_Lowercased(X) is true when toLowercase(toNFD(X)) != toNFD(X)
+
+0041..005A ; Changes_When_Lowercased # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+00C0..00D6 ; Changes_When_Lowercased # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00DE ; Changes_When_Lowercased # L& [7] LATIN CAPITAL LETTER O WITH STROKE..LATIN CAPITAL LETTER THORN
+0100 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH MACRON
+0102 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE
+0104 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH OGONEK
+0106 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH ACUTE
+0108 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH CARON
+010E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH CARON
+0110 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH STROKE
+0112 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH MACRON
+0114 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH BREVE
+0116 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH OGONEK
+011A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CARON
+011C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH BREVE
+0120 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH CEDILLA
+0124 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH STROKE
+0128 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH TILDE
+012A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH MACRON
+012C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH BREVE
+012E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH OGONEK
+0130 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132 ; Changes_When_Lowercased # L& LATIN CAPITAL LIGATURE IJ
+0134 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH CEDILLA
+0139 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH ACUTE
+013B ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH CEDILLA
+013D ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH CARON
+013F ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH STROKE
+0143 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH ACUTE
+0145 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH CEDILLA
+0147 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH CARON
+014A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ENG
+014C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH MACRON
+014E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH BREVE
+0150 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152 ; Changes_When_Lowercased # L& LATIN CAPITAL LIGATURE OE
+0154 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH ACUTE
+0156 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH CEDILLA
+0158 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH CARON
+015A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH ACUTE
+015C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH CEDILLA
+0160 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH CARON
+0162 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH CEDILLA
+0164 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH CARON
+0166 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH STROKE
+0168 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH TILDE
+016A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH MACRON
+016C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH BREVE
+016E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH RING ABOVE
+0170 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH OGONEK
+0174 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178..0179 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER Y WITH DIAERESIS..LATIN CAPITAL LETTER Z WITH ACUTE
+017B ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH CARON
+0181..0182 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER B WITH HOOK..LATIN CAPITAL LETTER B WITH TOPBAR
+0184 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TONE SIX
+0186..0187 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER OPEN O..LATIN CAPITAL LETTER C WITH HOOK
+0189..018B ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER AFRICAN D..LATIN CAPITAL LETTER D WITH TOPBAR
+018E..0191 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER F WITH HOOK
+0193..0194 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER G WITH HOOK..LATIN CAPITAL LETTER GAMMA
+0196..0198 ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER IOTA..LATIN CAPITAL LETTER K WITH HOOK
+019C..019D ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F..01A0 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER O WITH MIDDLE TILDE..LATIN CAPITAL LETTER O WITH HORN
+01A2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OI
+01A4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH HOOK
+01A6..01A7 ; Changes_When_Lowercased # L& [2] LATIN LETTER YR..LATIN CAPITAL LETTER TONE TWO
+01A9 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ESH
+01AC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH HOOK
+01AE..01AF ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER T WITH RETROFLEX HOOK..LATIN CAPITAL LETTER U WITH HORN
+01B1..01B3 ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER UPSILON..LATIN CAPITAL LETTER Y WITH HOOK
+01B5 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH STROKE
+01B7..01B8 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER EZH..LATIN CAPITAL LETTER EZH REVERSED
+01BC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TONE FIVE
+01C4..01C5 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C7..01C8 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER LJ..LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CA..01CB ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER NJ..LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01CD ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CARON
+01CF ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH CARON
+01D1 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CARON
+01D3 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH CARON
+01D5 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AE WITH MACRON
+01E4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH STROKE
+01E6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH CARON
+01E8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH CARON
+01EA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH OGONEK
+01EC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER EZH WITH CARON
+01F1..01F2 ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER DZ..LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+01F4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH ACUTE
+01F6..01F8 ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER HWAIR..LATIN CAPITAL LETTER N WITH GRAVE
+01FA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AE WITH ACUTE
+01FE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER YOGH
+021E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH CARON
+0220 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OU
+0224 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH HOOK
+0226 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CEDILLA
+022A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH MACRON
+023A..023B ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER A WITH STROKE..LATIN CAPITAL LETTER C WITH STROKE
+023D..023E ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER L WITH BAR..LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+0241 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER GLOTTAL STOP
+0243..0246 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER B WITH STROKE..LATIN CAPITAL LETTER E WITH STROKE
+0248 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER J WITH STROKE
+024A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+024C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH STROKE
+024E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH STROKE
+0370 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER HETA
+0372 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER ARCHAIC SAMPI
+0376 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+037F ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER YOT
+0386 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Changes_When_Lowercased # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..038F ; Changes_When_Lowercased # L& [2] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER OMEGA WITH TONOS
+0391..03A1 ; Changes_When_Lowercased # L& [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+03A3..03AB ; Changes_When_Lowercased # L& [9] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03CF ; Changes_When_Lowercased # L& GREEK CAPITAL KAI SYMBOL
+03D8 ; Changes_When_Lowercased # L& GREEK LETTER ARCHAIC KOPPA
+03DA ; Changes_When_Lowercased # L& GREEK LETTER STIGMA
+03DC ; Changes_When_Lowercased # L& GREEK LETTER DIGAMMA
+03DE ; Changes_When_Lowercased # L& GREEK LETTER KOPPA
+03E0 ; Changes_When_Lowercased # L& GREEK LETTER SAMPI
+03E2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER SHEI
+03E4 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER FEI
+03E6 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER KHEI
+03E8 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER HORI
+03EA ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER GANGIA
+03EC ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER SHIMA
+03EE ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DEI
+03F4 ; Changes_When_Lowercased # L& GREEK CAPITAL THETA SYMBOL
+03F7 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER SHO
+03F9..03FA ; Changes_When_Lowercased # L& [2] GREEK CAPITAL LUNATE SIGMA SYMBOL..GREEK CAPITAL LETTER SAN
+03FD..042F ; Changes_When_Lowercased # L& [51] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..CYRILLIC CAPITAL LETTER YA
+0460 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER OMEGA
+0462 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER YAT
+0464 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED E
+0466 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER LITTLE YUS
+0468 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BIG YUS
+046C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KSI
+0470 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER PSI
+0472 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER FITA
+0474 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IZHITSA
+0476 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER UK
+047A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER OT
+0480 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOPPA
+048A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ER WITH TICK
+0490 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LIGATURE EN GHE
+04A6 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LIGATURE TE TSE
+04B6 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SHHA
+04BC ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C0..04C1 ; Changes_When_Lowercased # L& [2] CYRILLIC LETTER PALOCHKA..CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LIGATURE A IE
+04D6 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SCHWA
+04DA ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BARRED O
+04EA ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+04FA ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+04FC ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER HA WITH HOOK
+04FE ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER HA WITH STROKE
+0500 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI DE
+0502 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI DJE
+0504 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI ZJE
+0506 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI DZJE
+0508 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI LJE
+050A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI NJE
+050C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI SJE
+050E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER KOMI TJE
+0510 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER REVERSED ZE
+0512 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EL WITH HOOK
+0514 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER LHA
+0516 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER RHA
+0518 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER YAE
+051A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER QA
+051C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER WE
+051E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ALEUT KA
+0520 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
+0522 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
+0524 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER PE WITH DESCENDER
+0526 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER
+0528 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK
+052A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DZZHE
+052C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DCHE
+052E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER EL WITH DESCENDER
+0531..0556 ; Changes_When_Lowercased # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+10A0..10C5 ; Changes_When_Lowercased # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Changes_When_Lowercased # L& GEORGIAN CAPITAL LETTER AEN
+13A0..13F5 ; Changes_When_Lowercased # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+1E00 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH RING BELOW
+1E02 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH CEDILLA
+1E12 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH MACRON
+1E22 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH ACUTE
+1E32 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER M WITH ACUTE
+1E40 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH ACUTE
+1E56 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER V WITH TILDE
+1E7E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH GRAVE
+1E82 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH ACUTE
+1E84 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E9E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SHARP S
+1EA0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH TILDE
+1EBE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH TILDE
+1EFA ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER MIDDLE-WELSH LL
+1EFC ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER MIDDLE-WELSH V
+1EFE ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Y WITH LOOP
+1F08..1F0F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER ALPHA WITH PSILI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18..1F1D ; Changes_When_Lowercased # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28..1F2F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER ETA WITH PSILI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38..1F3F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER IOTA WITH PSILI..GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48..1F4D ; Changes_When_Lowercased # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F59 ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F ; Changes_When_Lowercased # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68..1F6F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER OMEGA WITH PSILI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F88..1F8F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F98..1F9F ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FA8..1FAF ; Changes_When_Lowercased # L& [8] GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FB8..1FBC ; Changes_When_Lowercased # L& [5] GREEK CAPITAL LETTER ALPHA WITH VRACHY..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FC8..1FCC ; Changes_When_Lowercased # L& [5] GREEK CAPITAL LETTER EPSILON WITH VARIA..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD8..1FDB ; Changes_When_Lowercased # L& [4] GREEK CAPITAL LETTER IOTA WITH VRACHY..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE8..1FEC ; Changes_When_Lowercased # L& [5] GREEK CAPITAL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF8..1FFC ; Changes_When_Lowercased # L& [5] GREEK CAPITAL LETTER OMICRON WITH VARIA..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126 ; Changes_When_Lowercased # L& OHM SIGN
+212A..212B ; Changes_When_Lowercased # L& [2] KELVIN SIGN..ANGSTROM SIGN
+2132 ; Changes_When_Lowercased # L& TURNED CAPITAL F
+2160..216F ; Changes_When_Lowercased # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND
+2183 ; Changes_When_Lowercased # L& ROMAN NUMERAL REVERSED ONE HUNDRED
+24B6..24CF ; Changes_When_Lowercased # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z
+2C00..2C2E ; Changes_When_Lowercased # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C60 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH DOUBLE BAR
+2C62..2C64 ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER L WITH MIDDLE TILDE..LATIN CAPITAL LETTER R WITH TAIL
+2C67 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER H WITH DESCENDER
+2C69 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH DESCENDER
+2C6B ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Z WITH DESCENDER
+2C6D..2C70 ; Changes_When_Lowercased # L& [4] LATIN CAPITAL LETTER ALPHA..LATIN CAPITAL LETTER TURNED ALPHA
+2C72 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER W WITH HOOK
+2C75 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER HALF H
+2C7E..2C80 ; Changes_When_Lowercased # L& [3] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC CAPITAL LETTER ALFA
+2C82 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER VIDA
+2C84 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER GAMMA
+2C86 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DALDA
+2C88 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER EIE
+2C8A ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER SOU
+2C8C ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER ZATA
+2C8E ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER HATE
+2C90 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER THETHE
+2C92 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER IAUDA
+2C94 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER KAPA
+2C96 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER LAULA
+2C98 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER MI
+2C9A ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER NI
+2C9C ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER KSI
+2C9E ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER O
+2CA0 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER PI
+2CA2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER RO
+2CA4 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER SIMA
+2CA6 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER TAU
+2CA8 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER UA
+2CAA ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER FI
+2CAC ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER KHI
+2CAE ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER PSI
+2CB0 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OOU
+2CB2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER SAMPI
+2CC2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER OLD NUBIAN WAU
+2CEB ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI
+2CED ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA
+2CF2 ; Changes_When_Lowercased # L& COPTIC CAPITAL LETTER BOHAIRIC KHEI
+A640 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZEMLYA
+A642 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DZELO
+A644 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER REVERSED DZE
+A646 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTA
+A648 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DJERV
+A64A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER MONOGRAPH UK
+A64C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BROAD OMEGA
+A64E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER NEUTRAL YER
+A650 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER YERU WITH BACK YER
+A652 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED YAT
+A654 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER REVERSED YU
+A656 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED A
+A658 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
+A65A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BLENDED YUS
+A65C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
+A65E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER YN
+A660 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER REVERSED TSE
+A662 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SOFT DE
+A664 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SOFT EL
+A666 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SOFT EM
+A668 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER MONOCULAR O
+A66A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER BINOCULAR O
+A66C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
+A680 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DWE
+A682 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DZWE
+A684 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER ZHWE
+A686 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CCHE
+A688 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DZZE
+A68A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
+A68C ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TWE
+A68E ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TSWE
+A690 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TSSE
+A692 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER TCHE
+A694 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER HWE
+A696 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER SHWE
+A698 ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER DOUBLE O
+A69A ; Changes_When_Lowercased # L& CYRILLIC CAPITAL LETTER CROSSED O
+A722 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
+A724 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
+A726 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER HENG
+A728 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TZ
+A72A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TRESILLO
+A72C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CUATRILLO
+A72E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CUATRILLO WITH COMMA
+A732 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AA
+A734 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AO
+A736 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AU
+A738 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AV
+A73A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+A73C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER AY
+A73E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER REVERSED C WITH DOT
+A740 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH STROKE
+A742 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+A744 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+A746 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER BROKEN L
+A748 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER L WITH HIGH STROKE
+A74A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+A74C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER O WITH LOOP
+A74E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OO
+A750 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+A752 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH FLOURISH
+A754 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+A756 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+A758 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+A75A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R ROTUNDA
+A75C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER RUM ROTUNDA
+A75E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+A760 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VY
+A762 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VISIGOTHIC Z
+A764 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER THORN WITH STROKE
+A766 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
+A768 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VEND
+A76A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER ET
+A76C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER IS
+A76E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER CON
+A779 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER INSULAR D
+A77B ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER INSULAR F
+A77D..A77E ; Changes_When_Lowercased # L& [2] LATIN CAPITAL LETTER INSULAR G..LATIN CAPITAL LETTER TURNED INSULAR G
+A780 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TURNED L
+A782 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER INSULAR R
+A784 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER INSULAR S
+A786 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER INSULAR T
+A78B ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER SALTILLO
+A78D ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER TURNED H
+A790 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH DESCENDER
+A792 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER C WITH BAR
+A796 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER B WITH FLOURISH
+A798 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER F WITH STROKE
+A79A ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VOLAPUK AE
+A79C ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VOLAPUK OE
+A79E ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER VOLAPUK UE
+A7A0 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
+A7A2 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER K WITH OBLIQUE STROKE
+A7A4 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER N WITH OBLIQUE STROKE
+A7A6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER R WITH OBLIQUE STROKE
+A7A8 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER S WITH OBLIQUE STROKE
+A7AA..A7AE ; Changes_When_Lowercased # L& [5] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B4 ; Changes_When_Lowercased # L& [5] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER BETA
+A7B6 ; Changes_When_Lowercased # L& LATIN CAPITAL LETTER OMEGA
+FF21..FF3A ; Changes_When_Lowercased # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+10400..10427 ; Changes_When_Lowercased # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW
+104B0..104D3 ; Changes_When_Lowercased # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+10C80..10CB2 ; Changes_When_Lowercased # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+118A0..118BF ; Changes_When_Lowercased # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO
+1E900..1E921 ; Changes_When_Lowercased # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
+
+# Total code points: 1304
+
+# ================================================
+
+# Derived Property: Changes_When_Uppercased (CWU)
+# Characters whose normalized forms are not stable under a toUppercase mapping.
+# For more information, see D140 in Section 3.13, "Default Case Algorithms".
+# Changes_When_Uppercased(X) is true when toUppercase(toNFD(X)) != toNFD(X)
+
+0061..007A ; Changes_When_Uppercased # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00B5 ; Changes_When_Uppercased # L& MICRO SIGN
+00DF..00F6 ; Changes_When_Uppercased # L& [24] LATIN SMALL LETTER SHARP S..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..00FF ; Changes_When_Uppercased # L& [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS
+0101 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH MACRON
+0103 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE
+0105 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH OGONEK
+0107 ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH ACUTE
+0109 ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH CIRCUMFLEX
+010B ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH DOT ABOVE
+010D ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH CARON
+010F ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH CARON
+0111 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH STROKE
+0113 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH MACRON
+0115 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH BREVE
+0117 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH DOT ABOVE
+0119 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH OGONEK
+011B ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CARON
+011D ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH CIRCUMFLEX
+011F ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH BREVE
+0121 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH DOT ABOVE
+0123 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH CEDILLA
+0125 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH CIRCUMFLEX
+0127 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH STROKE
+0129 ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH TILDE
+012B ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH MACRON
+012D ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH BREVE
+012F ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH OGONEK
+0131 ; Changes_When_Uppercased # L& LATIN SMALL LETTER DOTLESS I
+0133 ; Changes_When_Uppercased # L& LATIN SMALL LIGATURE IJ
+0135 ; Changes_When_Uppercased # L& LATIN SMALL LETTER J WITH CIRCUMFLEX
+0137 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH CEDILLA
+013A ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH ACUTE
+013C ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH CEDILLA
+013E ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH CARON
+0140 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH MIDDLE DOT
+0142 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH STROKE
+0144 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH ACUTE
+0146 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH CEDILLA
+0148..0149 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014B ; Changes_When_Uppercased # L& LATIN SMALL LETTER ENG
+014D ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH MACRON
+014F ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH BREVE
+0151 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DOUBLE ACUTE
+0153 ; Changes_When_Uppercased # L& LATIN SMALL LIGATURE OE
+0155 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH ACUTE
+0157 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH CEDILLA
+0159 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH CARON
+015B ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH ACUTE
+015D ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH CIRCUMFLEX
+015F ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH CEDILLA
+0161 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH CARON
+0163 ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH CEDILLA
+0165 ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH CARON
+0167 ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH STROKE
+0169 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH TILDE
+016B ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH MACRON
+016D ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH BREVE
+016F ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH RING ABOVE
+0171 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DOUBLE ACUTE
+0173 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH OGONEK
+0175 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH CIRCUMFLEX
+0177 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH CIRCUMFLEX
+017A ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH ACUTE
+017C ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH DOT ABOVE
+017E..0180 ; Changes_When_Uppercased # L& [3] LATIN SMALL LETTER Z WITH CARON..LATIN SMALL LETTER B WITH STROKE
+0183 ; Changes_When_Uppercased # L& LATIN SMALL LETTER B WITH TOPBAR
+0185 ; Changes_When_Uppercased # L& LATIN SMALL LETTER TONE SIX
+0188 ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH HOOK
+018C ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH TOPBAR
+0192 ; Changes_When_Uppercased # L& LATIN SMALL LETTER F WITH HOOK
+0195 ; Changes_When_Uppercased # L& LATIN SMALL LETTER HV
+0199..019A ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR
+019E ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG
+01A1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN
+01A3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OI
+01A5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH HOOK
+01A8 ; Changes_When_Uppercased # L& LATIN SMALL LETTER TONE TWO
+01AD ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH HOOK
+01B0 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN
+01B4 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH HOOK
+01B6 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH STROKE
+01B9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER EZH REVERSED
+01BD ; Changes_When_Uppercased # L& LATIN SMALL LETTER TONE FIVE
+01BF ; Changes_When_Uppercased # L& LATIN LETTER WYNN
+01C5..01C6 ; Changes_When_Uppercased # L& [2] LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON..LATIN SMALL LETTER DZ WITH CARON
+01C8..01C9 ; Changes_When_Uppercased # L& [2] LATIN CAPITAL LETTER L WITH SMALL LETTER J..LATIN SMALL LETTER LJ
+01CB..01CC ; Changes_When_Uppercased # L& [2] LATIN CAPITAL LETTER N WITH SMALL LETTER J..LATIN SMALL LETTER NJ
+01CE ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CARON
+01D0 ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH CARON
+01D2 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CARON
+01D4 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH CARON
+01D6 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+01D8 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+01DA ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+01DC..01DD ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E
+01DF ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+01E1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+01E3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER AE WITH MACRON
+01E5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH STROKE
+01E7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH CARON
+01E9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH CARON
+01EB ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH OGONEK
+01ED ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH OGONEK AND MACRON
+01EF..01F0 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER EZH WITH CARON..LATIN SMALL LETTER J WITH CARON
+01F2..01F3 ; Changes_When_Uppercased # L& [2] LATIN CAPITAL LETTER D WITH SMALL LETTER Z..LATIN SMALL LETTER DZ
+01F5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH ACUTE
+01F9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH GRAVE
+01FB ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+01FD ; Changes_When_Uppercased # L& LATIN SMALL LETTER AE WITH ACUTE
+01FF ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH STROKE AND ACUTE
+0201 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH DOUBLE GRAVE
+0203 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH INVERTED BREVE
+0205 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH DOUBLE GRAVE
+0207 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH INVERTED BREVE
+0209 ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH DOUBLE GRAVE
+020B ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH INVERTED BREVE
+020D ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DOUBLE GRAVE
+020F ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH INVERTED BREVE
+0211 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH DOUBLE GRAVE
+0213 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH INVERTED BREVE
+0215 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DOUBLE GRAVE
+0217 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH INVERTED BREVE
+0219 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH COMMA BELOW
+021B ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH COMMA BELOW
+021D ; Changes_When_Uppercased # L& LATIN SMALL LETTER YOGH
+021F ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH CARON
+0223 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OU
+0225 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH HOOK
+0227 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH DOT ABOVE
+0229 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CEDILLA
+022B ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+022D ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH TILDE AND MACRON
+022F ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DOT ABOVE
+0231 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+0233 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH MACRON
+023C ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH STROKE
+023F..0240 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER S WITH SWASH TAIL..LATIN SMALL LETTER Z WITH SWASH TAIL
+0242 ; Changes_When_Uppercased # L& LATIN SMALL LETTER GLOTTAL STOP
+0247 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH STROKE
+0249 ; Changes_When_Uppercased # L& LATIN SMALL LETTER J WITH STROKE
+024B ; Changes_When_Uppercased # L& LATIN SMALL LETTER Q WITH HOOK TAIL
+024D ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH STROKE
+024F..0254 ; Changes_When_Uppercased # L& [6] LATIN SMALL LETTER Y WITH STROKE..LATIN SMALL LETTER OPEN O
+0256..0257 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER D WITH TAIL..LATIN SMALL LETTER D WITH HOOK
+0259 ; Changes_When_Uppercased # L& LATIN SMALL LETTER SCHWA
+025B..025C ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E
+0260..0261 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G
+0263 ; Changes_When_Uppercased # L& LATIN SMALL LETTER GAMMA
+0265..0266 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK
+0268..026C ; Changes_When_Uppercased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT
+026F ; Changes_When_Uppercased # L& LATIN SMALL LETTER TURNED M
+0271..0272 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK
+0275 ; Changes_When_Uppercased # L& LATIN SMALL LETTER BARRED O
+027D ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH TAIL
+0280 ; Changes_When_Uppercased # L& LATIN LETTER SMALL CAPITAL R
+0283 ; Changes_When_Uppercased # L& LATIN SMALL LETTER ESH
+0287..028C ; Changes_When_Uppercased # L& [6] LATIN SMALL LETTER TURNED T..LATIN SMALL LETTER TURNED V
+0292 ; Changes_When_Uppercased # L& LATIN SMALL LETTER EZH
+029D..029E ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER J WITH CROSSED-TAIL..LATIN SMALL LETTER TURNED K
+0345 ; Changes_When_Uppercased # Mn COMBINING GREEK YPOGEGRAMMENI
+0371 ; Changes_When_Uppercased # L& GREEK SMALL LETTER HETA
+0373 ; Changes_When_Uppercased # L& GREEK SMALL LETTER ARCHAIC SAMPI
+0377 ; Changes_When_Uppercased # L& GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; Changes_When_Uppercased # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0390 ; Changes_When_Uppercased # L& GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+03AC..03CE ; Changes_When_Uppercased # L& [35] GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER OMEGA WITH TONOS
+03D0..03D1 ; Changes_When_Uppercased # L& [2] GREEK BETA SYMBOL..GREEK THETA SYMBOL
+03D5..03D7 ; Changes_When_Uppercased # L& [3] GREEK PHI SYMBOL..GREEK KAI SYMBOL
+03D9 ; Changes_When_Uppercased # L& GREEK SMALL LETTER ARCHAIC KOPPA
+03DB ; Changes_When_Uppercased # L& GREEK SMALL LETTER STIGMA
+03DD ; Changes_When_Uppercased # L& GREEK SMALL LETTER DIGAMMA
+03DF ; Changes_When_Uppercased # L& GREEK SMALL LETTER KOPPA
+03E1 ; Changes_When_Uppercased # L& GREEK SMALL LETTER SAMPI
+03E3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER SHEI
+03E5 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER FEI
+03E7 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER KHEI
+03E9 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER HORI
+03EB ; Changes_When_Uppercased # L& COPTIC SMALL LETTER GANGIA
+03ED ; Changes_When_Uppercased # L& COPTIC SMALL LETTER SHIMA
+03EF..03F3 ; Changes_When_Uppercased # L& [5] COPTIC SMALL LETTER DEI..GREEK LETTER YOT
+03F5 ; Changes_When_Uppercased # L& GREEK LUNATE EPSILON SYMBOL
+03F8 ; Changes_When_Uppercased # L& GREEK SMALL LETTER SHO
+03FB ; Changes_When_Uppercased # L& GREEK SMALL LETTER SAN
+0430..045F ; Changes_When_Uppercased # L& [48] CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER DZHE
+0461 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER OMEGA
+0463 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER YAT
+0465 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED E
+0467 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER LITTLE YUS
+0469 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
+046B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BIG YUS
+046D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED BIG YUS
+046F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KSI
+0471 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER PSI
+0473 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER FITA
+0475 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IZHITSA
+0477 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0479 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER UK
+047B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ROUND OMEGA
+047D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER OMEGA WITH TITLO
+047F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER OT
+0481 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOPPA
+048B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SHORT I WITH TAIL
+048D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SEMISOFT SIGN
+048F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ER WITH TICK
+0491 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER GHE WITH UPTURN
+0493 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER GHE WITH STROKE
+0495 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
+0497 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZHE WITH DESCENDER
+0499 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZE WITH DESCENDER
+049B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KA WITH DESCENDER
+049D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
+049F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KA WITH STROKE
+04A1 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BASHKIR KA
+04A3 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EN WITH DESCENDER
+04A5 ; Changes_When_Uppercased # L& CYRILLIC SMALL LIGATURE EN GHE
+04A7 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
+04A9 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ABKHASIAN HA
+04AB ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ES WITH DESCENDER
+04AD ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TE WITH DESCENDER
+04AF ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER STRAIGHT U
+04B1 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+04B3 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER HA WITH DESCENDER
+04B5 ; Changes_When_Uppercased # L& CYRILLIC SMALL LIGATURE TE TSE
+04B7 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CHE WITH DESCENDER
+04B9 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
+04BB ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SHHA
+04BD ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ABKHASIAN CHE
+04BF ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
+04C2 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZHE WITH BREVE
+04C4 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KA WITH HOOK
+04C6 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EL WITH TAIL
+04C8 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EN WITH HOOK
+04CA ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EN WITH TAIL
+04CC ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KHAKASSIAN CHE
+04CE..04CF ; Changes_When_Uppercased # L& [2] CYRILLIC SMALL LETTER EM WITH TAIL..CYRILLIC SMALL LETTER PALOCHKA
+04D1 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER A WITH BREVE
+04D3 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER A WITH DIAERESIS
+04D5 ; Changes_When_Uppercased # L& CYRILLIC SMALL LIGATURE A IE
+04D7 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IE WITH BREVE
+04D9 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SCHWA
+04DB ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
+04DD ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
+04DF ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZE WITH DIAERESIS
+04E1 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ABKHASIAN DZE
+04E3 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER I WITH MACRON
+04E5 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER I WITH DIAERESIS
+04E7 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER O WITH DIAERESIS
+04E9 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BARRED O
+04EB ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
+04ED ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER E WITH DIAERESIS
+04EF ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER U WITH MACRON
+04F1 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER U WITH DIAERESIS
+04F3 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
+04F5 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CHE WITH DIAERESIS
+04F7 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER GHE WITH DESCENDER
+04F9 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER YERU WITH DIAERESIS
+04FB ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
+04FD ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER HA WITH HOOK
+04FF ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER HA WITH STROKE
+0501 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI DE
+0503 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI DJE
+0505 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI ZJE
+0507 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI DZJE
+0509 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI LJE
+050B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI NJE
+050D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI SJE
+050F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER KOMI TJE
+0511 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER REVERSED ZE
+0513 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EL WITH HOOK
+0515 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER LHA
+0517 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER RHA
+0519 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER YAE
+051B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER QA
+051D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER WE
+051F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ALEUT KA
+0521 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK
+0523 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+0525 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER PE WITH DESCENDER
+0527 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SHHA WITH DESCENDER
+0529 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EN WITH LEFT HOOK
+052B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DZZHE
+052D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DCHE
+052F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER EL WITH DESCENDER
+0561..0587 ; Changes_When_Uppercased # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+13F8..13FD ; Changes_When_Uppercased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Changes_When_Uppercased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1D79 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR G
+1D7D ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH STROKE
+1E01 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH RING BELOW
+1E03 ; Changes_When_Uppercased # L& LATIN SMALL LETTER B WITH DOT ABOVE
+1E05 ; Changes_When_Uppercased # L& LATIN SMALL LETTER B WITH DOT BELOW
+1E07 ; Changes_When_Uppercased # L& LATIN SMALL LETTER B WITH LINE BELOW
+1E09 ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+1E0B ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH DOT ABOVE
+1E0D ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH DOT BELOW
+1E0F ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH LINE BELOW
+1E11 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH CEDILLA
+1E13 ; Changes_When_Uppercased # L& LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+1E15 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH MACRON AND GRAVE
+1E17 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH MACRON AND ACUTE
+1E19 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+1E1B ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH TILDE BELOW
+1E1D ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+1E1F ; Changes_When_Uppercased # L& LATIN SMALL LETTER F WITH DOT ABOVE
+1E21 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH MACRON
+1E23 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH DOT ABOVE
+1E25 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH DOT BELOW
+1E27 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH DIAERESIS
+1E29 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH CEDILLA
+1E2B ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH BREVE BELOW
+1E2D ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH TILDE BELOW
+1E2F ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+1E31 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH ACUTE
+1E33 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH DOT BELOW
+1E35 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH LINE BELOW
+1E37 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH DOT BELOW
+1E39 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+1E3B ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH LINE BELOW
+1E3D ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+1E3F ; Changes_When_Uppercased # L& LATIN SMALL LETTER M WITH ACUTE
+1E41 ; Changes_When_Uppercased # L& LATIN SMALL LETTER M WITH DOT ABOVE
+1E43 ; Changes_When_Uppercased # L& LATIN SMALL LETTER M WITH DOT BELOW
+1E45 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH DOT ABOVE
+1E47 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH DOT BELOW
+1E49 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH LINE BELOW
+1E4B ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+1E4D ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH TILDE AND ACUTE
+1E4F ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+1E51 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH MACRON AND GRAVE
+1E53 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH MACRON AND ACUTE
+1E55 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH ACUTE
+1E57 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH DOT ABOVE
+1E59 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH DOT ABOVE
+1E5B ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH DOT BELOW
+1E5D ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+1E5F ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH LINE BELOW
+1E61 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DOT ABOVE
+1E63 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DOT BELOW
+1E65 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+1E67 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+1E69 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6B ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH DOT ABOVE
+1E6D ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH DOT BELOW
+1E6F ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH LINE BELOW
+1E71 ; Changes_When_Uppercased # L& LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+1E73 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DIAERESIS BELOW
+1E75 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH TILDE BELOW
+1E77 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+1E79 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH TILDE AND ACUTE
+1E7B ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+1E7D ; Changes_When_Uppercased # L& LATIN SMALL LETTER V WITH TILDE
+1E7F ; Changes_When_Uppercased # L& LATIN SMALL LETTER V WITH DOT BELOW
+1E81 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH GRAVE
+1E83 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH ACUTE
+1E85 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH DIAERESIS
+1E87 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH DOT ABOVE
+1E89 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH DOT BELOW
+1E8B ; Changes_When_Uppercased # L& LATIN SMALL LETTER X WITH DOT ABOVE
+1E8D ; Changes_When_Uppercased # L& LATIN SMALL LETTER X WITH DIAERESIS
+1E8F ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH DOT ABOVE
+1E91 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH CIRCUMFLEX
+1E93 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH DOT BELOW
+1E95..1E9B ; Changes_When_Uppercased # L& [7] LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1EA1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH DOT BELOW
+1EA3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH HOOK ABOVE
+1EA5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAB ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAD ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAF ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE AND ACUTE
+1EB1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE AND GRAVE
+1EB3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+1EB5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE AND TILDE
+1EB7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+1EB9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH DOT BELOW
+1EBB ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH HOOK ABOVE
+1EBD ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH TILDE
+1EBF ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH HOOK ABOVE
+1ECB ; Changes_When_Uppercased # L& LATIN SMALL LETTER I WITH DOT BELOW
+1ECD ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH DOT BELOW
+1ECF ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HOOK ABOVE
+1ED1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDB ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN AND ACUTE
+1EDD ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN AND GRAVE
+1EDF ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+1EE1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN AND TILDE
+1EE3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+1EE5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH DOT BELOW
+1EE7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HOOK ABOVE
+1EE9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN AND ACUTE
+1EEB ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN AND GRAVE
+1EED ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+1EEF ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN AND TILDE
+1EF1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+1EF3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH GRAVE
+1EF5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH DOT BELOW
+1EF7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH HOOK ABOVE
+1EF9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Y WITH TILDE
+1EFB ; Changes_When_Uppercased # L& LATIN SMALL LETTER MIDDLE-WELSH LL
+1EFD ; Changes_When_Uppercased # L& LATIN SMALL LETTER MIDDLE-WELSH V
+1EFF..1F07 ; Changes_When_Uppercased # L& [9] LATIN SMALL LETTER Y WITH LOOP..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F10..1F15 ; Changes_When_Uppercased # L& [6] GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F27 ; Changes_When_Uppercased # L& [8] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
+1F30..1F37 ; Changes_When_Uppercased # L& [8] GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F40..1F45 ; Changes_When_Uppercased # L& [6] GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Changes_When_Uppercased # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F60..1F67 ; Changes_When_Uppercased # L& [8] GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F70..1F7D ; Changes_When_Uppercased # L& [14] GREEK SMALL LETTER ALPHA WITH VARIA..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Changes_When_Uppercased # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FB7 ; Changes_When_Uppercased # L& [2] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FBC ; Changes_When_Uppercased # L& GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; Changes_When_Uppercased # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Changes_When_Uppercased # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FC7 ; Changes_When_Uppercased # L& [2] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FCC ; Changes_When_Uppercased # L& GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; Changes_When_Uppercased # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FD7 ; Changes_When_Uppercased # L& [2] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FE0..1FE7 ; Changes_When_Uppercased # L& [8] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FF2..1FF4 ; Changes_When_Uppercased # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FF7 ; Changes_When_Uppercased # L& [2] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FFC ; Changes_When_Uppercased # L& GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+214E ; Changes_When_Uppercased # L& TURNED SMALL F
+2170..217F ; Changes_When_Uppercased # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
+2184 ; Changes_When_Uppercased # L& LATIN SMALL LETTER REVERSED C
+24D0..24E9 ; Changes_When_Uppercased # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C30..2C5E ; Changes_When_Uppercased # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C61 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH DOUBLE BAR
+2C65..2C66 ; Changes_When_Uppercased # L& [2] LATIN SMALL LETTER A WITH STROKE..LATIN SMALL LETTER T WITH DIAGONAL STROKE
+2C68 ; Changes_When_Uppercased # L& LATIN SMALL LETTER H WITH DESCENDER
+2C6A ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH DESCENDER
+2C6C ; Changes_When_Uppercased # L& LATIN SMALL LETTER Z WITH DESCENDER
+2C73 ; Changes_When_Uppercased # L& LATIN SMALL LETTER W WITH HOOK
+2C76 ; Changes_When_Uppercased # L& LATIN SMALL LETTER HALF H
+2C81 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER ALFA
+2C83 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER VIDA
+2C85 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER GAMMA
+2C87 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER DALDA
+2C89 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER EIE
+2C8B ; Changes_When_Uppercased # L& COPTIC SMALL LETTER SOU
+2C8D ; Changes_When_Uppercased # L& COPTIC SMALL LETTER ZATA
+2C8F ; Changes_When_Uppercased # L& COPTIC SMALL LETTER HATE
+2C91 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER THETHE
+2C93 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER IAUDA
+2C95 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER KAPA
+2C97 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER LAULA
+2C99 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER MI
+2C9B ; Changes_When_Uppercased # L& COPTIC SMALL LETTER NI
+2C9D ; Changes_When_Uppercased # L& COPTIC SMALL LETTER KSI
+2C9F ; Changes_When_Uppercased # L& COPTIC SMALL LETTER O
+2CA1 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER PI
+2CA3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER RO
+2CA5 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER SIMA
+2CA7 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER TAU
+2CA9 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER UA
+2CAB ; Changes_When_Uppercased # L& COPTIC SMALL LETTER FI
+2CAD ; Changes_When_Uppercased # L& COPTIC SMALL LETTER KHI
+2CAF ; Changes_When_Uppercased # L& COPTIC SMALL LETTER PSI
+2CB1 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OOU
+2CB3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER DIALECT-P ALEF
+2CB5 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC AIN
+2CB7 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
+2CB9 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER DIALECT-P KAPA
+2CBB ; Changes_When_Uppercased # L& COPTIC SMALL LETTER DIALECT-P NI
+2CBD ; Changes_When_Uppercased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC NI
+2CBF ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC OOU
+2CC1 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER SAMPI
+2CC3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER CROSSED SHEI
+2CC5 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC SHEI
+2CC7 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC ESH
+2CC9 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER AKHMIMIC KHEI
+2CCB ; Changes_When_Uppercased # L& COPTIC SMALL LETTER DIALECT-P HORI
+2CCD ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC HORI
+2CCF ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC HA
+2CD1 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER L-SHAPED HA
+2CD3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC HEI
+2CD5 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC HAT
+2CD7 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC GANGIA
+2CD9 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC DJA
+2CDB ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD COPTIC SHIMA
+2CDD ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD NUBIAN SHIMA
+2CDF ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD NUBIAN NGI
+2CE1 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD NUBIAN NYI
+2CE3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER OLD NUBIAN WAU
+2CEC ; Changes_When_Uppercased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI
+2CEE ; Changes_When_Uppercased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF3 ; Changes_When_Uppercased # L& COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Changes_When_Uppercased # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Changes_When_Uppercased # L& GEORGIAN SMALL LETTER YN
+2D2D ; Changes_When_Uppercased # L& GEORGIAN SMALL LETTER AEN
+A641 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZEMLYA
+A643 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DZELO
+A645 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER REVERSED DZE
+A647 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTA
+A649 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DJERV
+A64B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER MONOGRAPH UK
+A64D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BROAD OMEGA
+A64F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER NEUTRAL YER
+A651 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER YERU WITH BACK YER
+A653 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED YAT
+A655 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER REVERSED YU
+A657 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED A
+A659 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CLOSED LITTLE YUS
+A65B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BLENDED YUS
+A65D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS
+A65F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER YN
+A661 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER REVERSED TSE
+A663 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SOFT DE
+A665 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SOFT EL
+A667 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SOFT EM
+A669 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER MONOCULAR O
+A66B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER BINOCULAR O
+A66D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A681 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DWE
+A683 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DZWE
+A685 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER ZHWE
+A687 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CCHE
+A689 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DZZE
+A68B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK
+A68D ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TWE
+A68F ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TSWE
+A691 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TSSE
+A693 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER TCHE
+A695 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER HWE
+A697 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER SHWE
+A699 ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER DOUBLE O
+A69B ; Changes_When_Uppercased # L& CYRILLIC SMALL LETTER CROSSED O
+A723 ; Changes_When_Uppercased # L& LATIN SMALL LETTER EGYPTOLOGICAL ALEF
+A725 ; Changes_When_Uppercased # L& LATIN SMALL LETTER EGYPTOLOGICAL AIN
+A727 ; Changes_When_Uppercased # L& LATIN SMALL LETTER HENG
+A729 ; Changes_When_Uppercased # L& LATIN SMALL LETTER TZ
+A72B ; Changes_When_Uppercased # L& LATIN SMALL LETTER TRESILLO
+A72D ; Changes_When_Uppercased # L& LATIN SMALL LETTER CUATRILLO
+A72F ; Changes_When_Uppercased # L& LATIN SMALL LETTER CUATRILLO WITH COMMA
+A733 ; Changes_When_Uppercased # L& LATIN SMALL LETTER AA
+A735 ; Changes_When_Uppercased # L& LATIN SMALL LETTER AO
+A737 ; Changes_When_Uppercased # L& LATIN SMALL LETTER AU
+A739 ; Changes_When_Uppercased # L& LATIN SMALL LETTER AV
+A73B ; Changes_When_Uppercased # L& LATIN SMALL LETTER AV WITH HORIZONTAL BAR
+A73D ; Changes_When_Uppercased # L& LATIN SMALL LETTER AY
+A73F ; Changes_When_Uppercased # L& LATIN SMALL LETTER REVERSED C WITH DOT
+A741 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH STROKE
+A743 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH DIAGONAL STROKE
+A745 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE
+A747 ; Changes_When_Uppercased # L& LATIN SMALL LETTER BROKEN L
+A749 ; Changes_When_Uppercased # L& LATIN SMALL LETTER L WITH HIGH STROKE
+A74B ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH LONG STROKE OVERLAY
+A74D ; Changes_When_Uppercased # L& LATIN SMALL LETTER O WITH LOOP
+A74F ; Changes_When_Uppercased # L& LATIN SMALL LETTER OO
+A751 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER
+A753 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH FLOURISH
+A755 ; Changes_When_Uppercased # L& LATIN SMALL LETTER P WITH SQUIRREL TAIL
+A757 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER
+A759 ; Changes_When_Uppercased # L& LATIN SMALL LETTER Q WITH DIAGONAL STROKE
+A75B ; Changes_When_Uppercased # L& LATIN SMALL LETTER R ROTUNDA
+A75D ; Changes_When_Uppercased # L& LATIN SMALL LETTER RUM ROTUNDA
+A75F ; Changes_When_Uppercased # L& LATIN SMALL LETTER V WITH DIAGONAL STROKE
+A761 ; Changes_When_Uppercased # L& LATIN SMALL LETTER VY
+A763 ; Changes_When_Uppercased # L& LATIN SMALL LETTER VISIGOTHIC Z
+A765 ; Changes_When_Uppercased # L& LATIN SMALL LETTER THORN WITH STROKE
+A767 ; Changes_When_Uppercased # L& LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER
+A769 ; Changes_When_Uppercased # L& LATIN SMALL LETTER VEND
+A76B ; Changes_When_Uppercased # L& LATIN SMALL LETTER ET
+A76D ; Changes_When_Uppercased # L& LATIN SMALL LETTER IS
+A76F ; Changes_When_Uppercased # L& LATIN SMALL LETTER CON
+A77A ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR D
+A77C ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR F
+A77F ; Changes_When_Uppercased # L& LATIN SMALL LETTER TURNED INSULAR G
+A781 ; Changes_When_Uppercased # L& LATIN SMALL LETTER TURNED L
+A783 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR R
+A785 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR S
+A787 ; Changes_When_Uppercased # L& LATIN SMALL LETTER INSULAR T
+A78C ; Changes_When_Uppercased # L& LATIN SMALL LETTER SALTILLO
+A791 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH DESCENDER
+A793 ; Changes_When_Uppercased # L& LATIN SMALL LETTER C WITH BAR
+A797 ; Changes_When_Uppercased # L& LATIN SMALL LETTER B WITH FLOURISH
+A799 ; Changes_When_Uppercased # L& LATIN SMALL LETTER F WITH STROKE
+A79B ; Changes_When_Uppercased # L& LATIN SMALL LETTER VOLAPUK AE
+A79D ; Changes_When_Uppercased # L& LATIN SMALL LETTER VOLAPUK OE
+A79F ; Changes_When_Uppercased # L& LATIN SMALL LETTER VOLAPUK UE
+A7A1 ; Changes_When_Uppercased # L& LATIN SMALL LETTER G WITH OBLIQUE STROKE
+A7A3 ; Changes_When_Uppercased # L& LATIN SMALL LETTER K WITH OBLIQUE STROKE
+A7A5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER N WITH OBLIQUE STROKE
+A7A7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER R WITH OBLIQUE STROKE
+A7A9 ; Changes_When_Uppercased # L& LATIN SMALL LETTER S WITH OBLIQUE STROKE
+A7B5 ; Changes_When_Uppercased # L& LATIN SMALL LETTER BETA
+A7B7 ; Changes_When_Uppercased # L& LATIN SMALL LETTER OMEGA
+AB53 ; Changes_When_Uppercased # L& LATIN SMALL LETTER CHI
+AB70..ABBF ; Changes_When_Uppercased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Changes_When_Uppercased # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Changes_When_Uppercased # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF41..FF5A ; Changes_When_Uppercased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10428..1044F ; Changes_When_Uppercased # L& [40] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER EW
+104D8..104FB ; Changes_When_Uppercased # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10CC0..10CF2 ; Changes_When_Uppercased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+118C0..118DF ; Changes_When_Uppercased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+1E922..1E943 ; Changes_When_Uppercased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
+
+# Total code points: 1396
+
+# ================================================
+
+# Derived Property: Changes_When_Titlecased (CWT)
+# Characters whose normalized forms are not stable under a toTitlecase mapping.
+# For more information, see D141 in Section 3.13, "Default Case Algorithms".
+# Changes_When_Titlecased(X) is true when toTitlecase(toNFD(X)) != toNFD(X)
+
+0061..007A ; Changes_When_Titlecased # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00B5 ; Changes_When_Titlecased # L& MICRO SIGN
+00DF..00F6 ; Changes_When_Titlecased # L& [24] LATIN SMALL LETTER SHARP S..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..00FF ; Changes_When_Titlecased # L& [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS
+0101 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH MACRON
+0103 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE
+0105 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH OGONEK
+0107 ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH ACUTE
+0109 ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH CIRCUMFLEX
+010B ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH DOT ABOVE
+010D ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH CARON
+010F ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH CARON
+0111 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH STROKE
+0113 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH MACRON
+0115 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH BREVE
+0117 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH DOT ABOVE
+0119 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH OGONEK
+011B ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CARON
+011D ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH CIRCUMFLEX
+011F ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH BREVE
+0121 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH DOT ABOVE
+0123 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH CEDILLA
+0125 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH CIRCUMFLEX
+0127 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH STROKE
+0129 ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH TILDE
+012B ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH MACRON
+012D ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH BREVE
+012F ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH OGONEK
+0131 ; Changes_When_Titlecased # L& LATIN SMALL LETTER DOTLESS I
+0133 ; Changes_When_Titlecased # L& LATIN SMALL LIGATURE IJ
+0135 ; Changes_When_Titlecased # L& LATIN SMALL LETTER J WITH CIRCUMFLEX
+0137 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH CEDILLA
+013A ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH ACUTE
+013C ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH CEDILLA
+013E ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH CARON
+0140 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH MIDDLE DOT
+0142 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH STROKE
+0144 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH ACUTE
+0146 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH CEDILLA
+0148..0149 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014B ; Changes_When_Titlecased # L& LATIN SMALL LETTER ENG
+014D ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH MACRON
+014F ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH BREVE
+0151 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DOUBLE ACUTE
+0153 ; Changes_When_Titlecased # L& LATIN SMALL LIGATURE OE
+0155 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH ACUTE
+0157 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH CEDILLA
+0159 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH CARON
+015B ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH ACUTE
+015D ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH CIRCUMFLEX
+015F ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH CEDILLA
+0161 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH CARON
+0163 ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH CEDILLA
+0165 ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH CARON
+0167 ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH STROKE
+0169 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH TILDE
+016B ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH MACRON
+016D ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH BREVE
+016F ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH RING ABOVE
+0171 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DOUBLE ACUTE
+0173 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH OGONEK
+0175 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH CIRCUMFLEX
+0177 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH CIRCUMFLEX
+017A ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH ACUTE
+017C ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH DOT ABOVE
+017E..0180 ; Changes_When_Titlecased # L& [3] LATIN SMALL LETTER Z WITH CARON..LATIN SMALL LETTER B WITH STROKE
+0183 ; Changes_When_Titlecased # L& LATIN SMALL LETTER B WITH TOPBAR
+0185 ; Changes_When_Titlecased # L& LATIN SMALL LETTER TONE SIX
+0188 ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH HOOK
+018C ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH TOPBAR
+0192 ; Changes_When_Titlecased # L& LATIN SMALL LETTER F WITH HOOK
+0195 ; Changes_When_Titlecased # L& LATIN SMALL LETTER HV
+0199..019A ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER L WITH BAR
+019E ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH LONG RIGHT LEG
+01A1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN
+01A3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OI
+01A5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH HOOK
+01A8 ; Changes_When_Titlecased # L& LATIN SMALL LETTER TONE TWO
+01AD ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH HOOK
+01B0 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN
+01B4 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH HOOK
+01B6 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH STROKE
+01B9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER EZH REVERSED
+01BD ; Changes_When_Titlecased # L& LATIN SMALL LETTER TONE FIVE
+01BF ; Changes_When_Titlecased # L& LATIN LETTER WYNN
+01C4 ; Changes_When_Titlecased # L& LATIN CAPITAL LETTER DZ WITH CARON
+01C6..01C7 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER DZ WITH CARON..LATIN CAPITAL LETTER LJ
+01C9..01CA ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER LJ..LATIN CAPITAL LETTER NJ
+01CC ; Changes_When_Titlecased # L& LATIN SMALL LETTER NJ
+01CE ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CARON
+01D0 ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH CARON
+01D2 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CARON
+01D4 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH CARON
+01D6 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+01D8 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+01DA ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+01DC..01DD ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E
+01DF ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+01E1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+01E3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER AE WITH MACRON
+01E5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH STROKE
+01E7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH CARON
+01E9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH CARON
+01EB ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH OGONEK
+01ED ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH OGONEK AND MACRON
+01EF..01F1 ; Changes_When_Titlecased # L& [3] LATIN SMALL LETTER EZH WITH CARON..LATIN CAPITAL LETTER DZ
+01F3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER DZ
+01F5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH ACUTE
+01F9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH GRAVE
+01FB ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+01FD ; Changes_When_Titlecased # L& LATIN SMALL LETTER AE WITH ACUTE
+01FF ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH STROKE AND ACUTE
+0201 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH DOUBLE GRAVE
+0203 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH INVERTED BREVE
+0205 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH DOUBLE GRAVE
+0207 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH INVERTED BREVE
+0209 ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH DOUBLE GRAVE
+020B ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH INVERTED BREVE
+020D ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DOUBLE GRAVE
+020F ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH INVERTED BREVE
+0211 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH DOUBLE GRAVE
+0213 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH INVERTED BREVE
+0215 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DOUBLE GRAVE
+0217 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH INVERTED BREVE
+0219 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH COMMA BELOW
+021B ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH COMMA BELOW
+021D ; Changes_When_Titlecased # L& LATIN SMALL LETTER YOGH
+021F ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH CARON
+0223 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OU
+0225 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH HOOK
+0227 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH DOT ABOVE
+0229 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CEDILLA
+022B ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+022D ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH TILDE AND MACRON
+022F ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DOT ABOVE
+0231 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+0233 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH MACRON
+023C ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH STROKE
+023F..0240 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER S WITH SWASH TAIL..LATIN SMALL LETTER Z WITH SWASH TAIL
+0242 ; Changes_When_Titlecased # L& LATIN SMALL LETTER GLOTTAL STOP
+0247 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH STROKE
+0249 ; Changes_When_Titlecased # L& LATIN SMALL LETTER J WITH STROKE
+024B ; Changes_When_Titlecased # L& LATIN SMALL LETTER Q WITH HOOK TAIL
+024D ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH STROKE
+024F..0254 ; Changes_When_Titlecased # L& [6] LATIN SMALL LETTER Y WITH STROKE..LATIN SMALL LETTER OPEN O
+0256..0257 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER D WITH TAIL..LATIN SMALL LETTER D WITH HOOK
+0259 ; Changes_When_Titlecased # L& LATIN SMALL LETTER SCHWA
+025B..025C ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E
+0260..0261 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G
+0263 ; Changes_When_Titlecased # L& LATIN SMALL LETTER GAMMA
+0265..0266 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK
+0268..026C ; Changes_When_Titlecased # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT
+026F ; Changes_When_Titlecased # L& LATIN SMALL LETTER TURNED M
+0271..0272 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK
+0275 ; Changes_When_Titlecased # L& LATIN SMALL LETTER BARRED O
+027D ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH TAIL
+0280 ; Changes_When_Titlecased # L& LATIN LETTER SMALL CAPITAL R
+0283 ; Changes_When_Titlecased # L& LATIN SMALL LETTER ESH
+0287..028C ; Changes_When_Titlecased # L& [6] LATIN SMALL LETTER TURNED T..LATIN SMALL LETTER TURNED V
+0292 ; Changes_When_Titlecased # L& LATIN SMALL LETTER EZH
+029D..029E ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER J WITH CROSSED-TAIL..LATIN SMALL LETTER TURNED K
+0345 ; Changes_When_Titlecased # Mn COMBINING GREEK YPOGEGRAMMENI
+0371 ; Changes_When_Titlecased # L& GREEK SMALL LETTER HETA
+0373 ; Changes_When_Titlecased # L& GREEK SMALL LETTER ARCHAIC SAMPI
+0377 ; Changes_When_Titlecased # L& GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; Changes_When_Titlecased # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0390 ; Changes_When_Titlecased # L& GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+03AC..03CE ; Changes_When_Titlecased # L& [35] GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER OMEGA WITH TONOS
+03D0..03D1 ; Changes_When_Titlecased # L& [2] GREEK BETA SYMBOL..GREEK THETA SYMBOL
+03D5..03D7 ; Changes_When_Titlecased # L& [3] GREEK PHI SYMBOL..GREEK KAI SYMBOL
+03D9 ; Changes_When_Titlecased # L& GREEK SMALL LETTER ARCHAIC KOPPA
+03DB ; Changes_When_Titlecased # L& GREEK SMALL LETTER STIGMA
+03DD ; Changes_When_Titlecased # L& GREEK SMALL LETTER DIGAMMA
+03DF ; Changes_When_Titlecased # L& GREEK SMALL LETTER KOPPA
+03E1 ; Changes_When_Titlecased # L& GREEK SMALL LETTER SAMPI
+03E3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER SHEI
+03E5 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER FEI
+03E7 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER KHEI
+03E9 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER HORI
+03EB ; Changes_When_Titlecased # L& COPTIC SMALL LETTER GANGIA
+03ED ; Changes_When_Titlecased # L& COPTIC SMALL LETTER SHIMA
+03EF..03F3 ; Changes_When_Titlecased # L& [5] COPTIC SMALL LETTER DEI..GREEK LETTER YOT
+03F5 ; Changes_When_Titlecased # L& GREEK LUNATE EPSILON SYMBOL
+03F8 ; Changes_When_Titlecased # L& GREEK SMALL LETTER SHO
+03FB ; Changes_When_Titlecased # L& GREEK SMALL LETTER SAN
+0430..045F ; Changes_When_Titlecased # L& [48] CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER DZHE
+0461 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER OMEGA
+0463 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER YAT
+0465 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED E
+0467 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER LITTLE YUS
+0469 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
+046B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BIG YUS
+046D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED BIG YUS
+046F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KSI
+0471 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER PSI
+0473 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER FITA
+0475 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IZHITSA
+0477 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0479 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER UK
+047B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ROUND OMEGA
+047D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER OMEGA WITH TITLO
+047F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER OT
+0481 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOPPA
+048B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SHORT I WITH TAIL
+048D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SEMISOFT SIGN
+048F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ER WITH TICK
+0491 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER GHE WITH UPTURN
+0493 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER GHE WITH STROKE
+0495 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
+0497 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZHE WITH DESCENDER
+0499 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZE WITH DESCENDER
+049B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KA WITH DESCENDER
+049D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
+049F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KA WITH STROKE
+04A1 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BASHKIR KA
+04A3 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EN WITH DESCENDER
+04A5 ; Changes_When_Titlecased # L& CYRILLIC SMALL LIGATURE EN GHE
+04A7 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
+04A9 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ABKHASIAN HA
+04AB ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ES WITH DESCENDER
+04AD ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TE WITH DESCENDER
+04AF ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER STRAIGHT U
+04B1 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+04B3 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER HA WITH DESCENDER
+04B5 ; Changes_When_Titlecased # L& CYRILLIC SMALL LIGATURE TE TSE
+04B7 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CHE WITH DESCENDER
+04B9 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
+04BB ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SHHA
+04BD ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ABKHASIAN CHE
+04BF ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
+04C2 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZHE WITH BREVE
+04C4 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KA WITH HOOK
+04C6 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EL WITH TAIL
+04C8 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EN WITH HOOK
+04CA ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EN WITH TAIL
+04CC ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KHAKASSIAN CHE
+04CE..04CF ; Changes_When_Titlecased # L& [2] CYRILLIC SMALL LETTER EM WITH TAIL..CYRILLIC SMALL LETTER PALOCHKA
+04D1 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER A WITH BREVE
+04D3 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER A WITH DIAERESIS
+04D5 ; Changes_When_Titlecased # L& CYRILLIC SMALL LIGATURE A IE
+04D7 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IE WITH BREVE
+04D9 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SCHWA
+04DB ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
+04DD ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
+04DF ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZE WITH DIAERESIS
+04E1 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ABKHASIAN DZE
+04E3 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER I WITH MACRON
+04E5 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER I WITH DIAERESIS
+04E7 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER O WITH DIAERESIS
+04E9 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BARRED O
+04EB ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
+04ED ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER E WITH DIAERESIS
+04EF ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER U WITH MACRON
+04F1 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER U WITH DIAERESIS
+04F3 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
+04F5 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CHE WITH DIAERESIS
+04F7 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER GHE WITH DESCENDER
+04F9 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER YERU WITH DIAERESIS
+04FB ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
+04FD ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER HA WITH HOOK
+04FF ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER HA WITH STROKE
+0501 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI DE
+0503 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI DJE
+0505 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI ZJE
+0507 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI DZJE
+0509 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI LJE
+050B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI NJE
+050D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI SJE
+050F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER KOMI TJE
+0511 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER REVERSED ZE
+0513 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EL WITH HOOK
+0515 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER LHA
+0517 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER RHA
+0519 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER YAE
+051B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER QA
+051D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER WE
+051F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ALEUT KA
+0521 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK
+0523 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+0525 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER PE WITH DESCENDER
+0527 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SHHA WITH DESCENDER
+0529 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EN WITH LEFT HOOK
+052B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DZZHE
+052D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DCHE
+052F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER EL WITH DESCENDER
+0561..0587 ; Changes_When_Titlecased # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+13F8..13FD ; Changes_When_Titlecased # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Changes_When_Titlecased # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1D79 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR G
+1D7D ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH STROKE
+1E01 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH RING BELOW
+1E03 ; Changes_When_Titlecased # L& LATIN SMALL LETTER B WITH DOT ABOVE
+1E05 ; Changes_When_Titlecased # L& LATIN SMALL LETTER B WITH DOT BELOW
+1E07 ; Changes_When_Titlecased # L& LATIN SMALL LETTER B WITH LINE BELOW
+1E09 ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+1E0B ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH DOT ABOVE
+1E0D ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH DOT BELOW
+1E0F ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH LINE BELOW
+1E11 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH CEDILLA
+1E13 ; Changes_When_Titlecased # L& LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+1E15 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH MACRON AND GRAVE
+1E17 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH MACRON AND ACUTE
+1E19 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+1E1B ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH TILDE BELOW
+1E1D ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+1E1F ; Changes_When_Titlecased # L& LATIN SMALL LETTER F WITH DOT ABOVE
+1E21 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH MACRON
+1E23 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH DOT ABOVE
+1E25 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH DOT BELOW
+1E27 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH DIAERESIS
+1E29 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH CEDILLA
+1E2B ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH BREVE BELOW
+1E2D ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH TILDE BELOW
+1E2F ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+1E31 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH ACUTE
+1E33 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH DOT BELOW
+1E35 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH LINE BELOW
+1E37 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH DOT BELOW
+1E39 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+1E3B ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH LINE BELOW
+1E3D ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+1E3F ; Changes_When_Titlecased # L& LATIN SMALL LETTER M WITH ACUTE
+1E41 ; Changes_When_Titlecased # L& LATIN SMALL LETTER M WITH DOT ABOVE
+1E43 ; Changes_When_Titlecased # L& LATIN SMALL LETTER M WITH DOT BELOW
+1E45 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH DOT ABOVE
+1E47 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH DOT BELOW
+1E49 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH LINE BELOW
+1E4B ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+1E4D ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH TILDE AND ACUTE
+1E4F ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+1E51 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH MACRON AND GRAVE
+1E53 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH MACRON AND ACUTE
+1E55 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH ACUTE
+1E57 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH DOT ABOVE
+1E59 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH DOT ABOVE
+1E5B ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH DOT BELOW
+1E5D ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+1E5F ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH LINE BELOW
+1E61 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DOT ABOVE
+1E63 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DOT BELOW
+1E65 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+1E67 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+1E69 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6B ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH DOT ABOVE
+1E6D ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH DOT BELOW
+1E6F ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH LINE BELOW
+1E71 ; Changes_When_Titlecased # L& LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+1E73 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DIAERESIS BELOW
+1E75 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH TILDE BELOW
+1E77 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+1E79 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH TILDE AND ACUTE
+1E7B ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+1E7D ; Changes_When_Titlecased # L& LATIN SMALL LETTER V WITH TILDE
+1E7F ; Changes_When_Titlecased # L& LATIN SMALL LETTER V WITH DOT BELOW
+1E81 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH GRAVE
+1E83 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH ACUTE
+1E85 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH DIAERESIS
+1E87 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH DOT ABOVE
+1E89 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH DOT BELOW
+1E8B ; Changes_When_Titlecased # L& LATIN SMALL LETTER X WITH DOT ABOVE
+1E8D ; Changes_When_Titlecased # L& LATIN SMALL LETTER X WITH DIAERESIS
+1E8F ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH DOT ABOVE
+1E91 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH CIRCUMFLEX
+1E93 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH DOT BELOW
+1E95..1E9B ; Changes_When_Titlecased # L& [7] LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1EA1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH DOT BELOW
+1EA3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH HOOK ABOVE
+1EA5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAB ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAD ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAF ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE AND ACUTE
+1EB1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE AND GRAVE
+1EB3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+1EB5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE AND TILDE
+1EB7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+1EB9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH DOT BELOW
+1EBB ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH HOOK ABOVE
+1EBD ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH TILDE
+1EBF ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH HOOK ABOVE
+1ECB ; Changes_When_Titlecased # L& LATIN SMALL LETTER I WITH DOT BELOW
+1ECD ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH DOT BELOW
+1ECF ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HOOK ABOVE
+1ED1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDB ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN AND ACUTE
+1EDD ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN AND GRAVE
+1EDF ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+1EE1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN AND TILDE
+1EE3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+1EE5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH DOT BELOW
+1EE7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HOOK ABOVE
+1EE9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN AND ACUTE
+1EEB ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN AND GRAVE
+1EED ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+1EEF ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN AND TILDE
+1EF1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+1EF3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH GRAVE
+1EF5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH DOT BELOW
+1EF7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH HOOK ABOVE
+1EF9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Y WITH TILDE
+1EFB ; Changes_When_Titlecased # L& LATIN SMALL LETTER MIDDLE-WELSH LL
+1EFD ; Changes_When_Titlecased # L& LATIN SMALL LETTER MIDDLE-WELSH V
+1EFF..1F07 ; Changes_When_Titlecased # L& [9] LATIN SMALL LETTER Y WITH LOOP..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F10..1F15 ; Changes_When_Titlecased # L& [6] GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F27 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
+1F30..1F37 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F40..1F45 ; Changes_When_Titlecased # L& [6] GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F60..1F67 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F70..1F7D ; Changes_When_Titlecased # L& [14] GREEK SMALL LETTER ALPHA WITH VARIA..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1F87 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F90..1F97 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA0..1FA7 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FB0..1FB4 ; Changes_When_Titlecased # L& [5] GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FB7 ; Changes_When_Titlecased # L& [2] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FBE ; Changes_When_Titlecased # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Changes_When_Titlecased # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FC7 ; Changes_When_Titlecased # L& [2] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FD0..1FD3 ; Changes_When_Titlecased # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FD7 ; Changes_When_Titlecased # L& [2] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FE0..1FE7 ; Changes_When_Titlecased # L& [8] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FF2..1FF4 ; Changes_When_Titlecased # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FF7 ; Changes_When_Titlecased # L& [2] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+214E ; Changes_When_Titlecased # L& TURNED SMALL F
+2170..217F ; Changes_When_Titlecased # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
+2184 ; Changes_When_Titlecased # L& LATIN SMALL LETTER REVERSED C
+24D0..24E9 ; Changes_When_Titlecased # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C30..2C5E ; Changes_When_Titlecased # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C61 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH DOUBLE BAR
+2C65..2C66 ; Changes_When_Titlecased # L& [2] LATIN SMALL LETTER A WITH STROKE..LATIN SMALL LETTER T WITH DIAGONAL STROKE
+2C68 ; Changes_When_Titlecased # L& LATIN SMALL LETTER H WITH DESCENDER
+2C6A ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH DESCENDER
+2C6C ; Changes_When_Titlecased # L& LATIN SMALL LETTER Z WITH DESCENDER
+2C73 ; Changes_When_Titlecased # L& LATIN SMALL LETTER W WITH HOOK
+2C76 ; Changes_When_Titlecased # L& LATIN SMALL LETTER HALF H
+2C81 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER ALFA
+2C83 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER VIDA
+2C85 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER GAMMA
+2C87 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER DALDA
+2C89 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER EIE
+2C8B ; Changes_When_Titlecased # L& COPTIC SMALL LETTER SOU
+2C8D ; Changes_When_Titlecased # L& COPTIC SMALL LETTER ZATA
+2C8F ; Changes_When_Titlecased # L& COPTIC SMALL LETTER HATE
+2C91 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER THETHE
+2C93 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER IAUDA
+2C95 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER KAPA
+2C97 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER LAULA
+2C99 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER MI
+2C9B ; Changes_When_Titlecased # L& COPTIC SMALL LETTER NI
+2C9D ; Changes_When_Titlecased # L& COPTIC SMALL LETTER KSI
+2C9F ; Changes_When_Titlecased # L& COPTIC SMALL LETTER O
+2CA1 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER PI
+2CA3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER RO
+2CA5 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER SIMA
+2CA7 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER TAU
+2CA9 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER UA
+2CAB ; Changes_When_Titlecased # L& COPTIC SMALL LETTER FI
+2CAD ; Changes_When_Titlecased # L& COPTIC SMALL LETTER KHI
+2CAF ; Changes_When_Titlecased # L& COPTIC SMALL LETTER PSI
+2CB1 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OOU
+2CB3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER DIALECT-P ALEF
+2CB5 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC AIN
+2CB7 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
+2CB9 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER DIALECT-P KAPA
+2CBB ; Changes_When_Titlecased # L& COPTIC SMALL LETTER DIALECT-P NI
+2CBD ; Changes_When_Titlecased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC NI
+2CBF ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC OOU
+2CC1 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER SAMPI
+2CC3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER CROSSED SHEI
+2CC5 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC SHEI
+2CC7 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC ESH
+2CC9 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER AKHMIMIC KHEI
+2CCB ; Changes_When_Titlecased # L& COPTIC SMALL LETTER DIALECT-P HORI
+2CCD ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC HORI
+2CCF ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC HA
+2CD1 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER L-SHAPED HA
+2CD3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC HEI
+2CD5 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC HAT
+2CD7 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC GANGIA
+2CD9 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC DJA
+2CDB ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD COPTIC SHIMA
+2CDD ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD NUBIAN SHIMA
+2CDF ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD NUBIAN NGI
+2CE1 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD NUBIAN NYI
+2CE3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER OLD NUBIAN WAU
+2CEC ; Changes_When_Titlecased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI
+2CEE ; Changes_When_Titlecased # L& COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF3 ; Changes_When_Titlecased # L& COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Changes_When_Titlecased # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Changes_When_Titlecased # L& GEORGIAN SMALL LETTER YN
+2D2D ; Changes_When_Titlecased # L& GEORGIAN SMALL LETTER AEN
+A641 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZEMLYA
+A643 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DZELO
+A645 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER REVERSED DZE
+A647 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTA
+A649 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DJERV
+A64B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER MONOGRAPH UK
+A64D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BROAD OMEGA
+A64F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER NEUTRAL YER
+A651 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER YERU WITH BACK YER
+A653 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED YAT
+A655 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER REVERSED YU
+A657 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED A
+A659 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CLOSED LITTLE YUS
+A65B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BLENDED YUS
+A65D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS
+A65F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER YN
+A661 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER REVERSED TSE
+A663 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SOFT DE
+A665 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SOFT EL
+A667 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SOFT EM
+A669 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER MONOCULAR O
+A66B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER BINOCULAR O
+A66D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A681 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DWE
+A683 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DZWE
+A685 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER ZHWE
+A687 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CCHE
+A689 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DZZE
+A68B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK
+A68D ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TWE
+A68F ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TSWE
+A691 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TSSE
+A693 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER TCHE
+A695 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER HWE
+A697 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER SHWE
+A699 ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER DOUBLE O
+A69B ; Changes_When_Titlecased # L& CYRILLIC SMALL LETTER CROSSED O
+A723 ; Changes_When_Titlecased # L& LATIN SMALL LETTER EGYPTOLOGICAL ALEF
+A725 ; Changes_When_Titlecased # L& LATIN SMALL LETTER EGYPTOLOGICAL AIN
+A727 ; Changes_When_Titlecased # L& LATIN SMALL LETTER HENG
+A729 ; Changes_When_Titlecased # L& LATIN SMALL LETTER TZ
+A72B ; Changes_When_Titlecased # L& LATIN SMALL LETTER TRESILLO
+A72D ; Changes_When_Titlecased # L& LATIN SMALL LETTER CUATRILLO
+A72F ; Changes_When_Titlecased # L& LATIN SMALL LETTER CUATRILLO WITH COMMA
+A733 ; Changes_When_Titlecased # L& LATIN SMALL LETTER AA
+A735 ; Changes_When_Titlecased # L& LATIN SMALL LETTER AO
+A737 ; Changes_When_Titlecased # L& LATIN SMALL LETTER AU
+A739 ; Changes_When_Titlecased # L& LATIN SMALL LETTER AV
+A73B ; Changes_When_Titlecased # L& LATIN SMALL LETTER AV WITH HORIZONTAL BAR
+A73D ; Changes_When_Titlecased # L& LATIN SMALL LETTER AY
+A73F ; Changes_When_Titlecased # L& LATIN SMALL LETTER REVERSED C WITH DOT
+A741 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH STROKE
+A743 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH DIAGONAL STROKE
+A745 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE
+A747 ; Changes_When_Titlecased # L& LATIN SMALL LETTER BROKEN L
+A749 ; Changes_When_Titlecased # L& LATIN SMALL LETTER L WITH HIGH STROKE
+A74B ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH LONG STROKE OVERLAY
+A74D ; Changes_When_Titlecased # L& LATIN SMALL LETTER O WITH LOOP
+A74F ; Changes_When_Titlecased # L& LATIN SMALL LETTER OO
+A751 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER
+A753 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH FLOURISH
+A755 ; Changes_When_Titlecased # L& LATIN SMALL LETTER P WITH SQUIRREL TAIL
+A757 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER
+A759 ; Changes_When_Titlecased # L& LATIN SMALL LETTER Q WITH DIAGONAL STROKE
+A75B ; Changes_When_Titlecased # L& LATIN SMALL LETTER R ROTUNDA
+A75D ; Changes_When_Titlecased # L& LATIN SMALL LETTER RUM ROTUNDA
+A75F ; Changes_When_Titlecased # L& LATIN SMALL LETTER V WITH DIAGONAL STROKE
+A761 ; Changes_When_Titlecased # L& LATIN SMALL LETTER VY
+A763 ; Changes_When_Titlecased # L& LATIN SMALL LETTER VISIGOTHIC Z
+A765 ; Changes_When_Titlecased # L& LATIN SMALL LETTER THORN WITH STROKE
+A767 ; Changes_When_Titlecased # L& LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER
+A769 ; Changes_When_Titlecased # L& LATIN SMALL LETTER VEND
+A76B ; Changes_When_Titlecased # L& LATIN SMALL LETTER ET
+A76D ; Changes_When_Titlecased # L& LATIN SMALL LETTER IS
+A76F ; Changes_When_Titlecased # L& LATIN SMALL LETTER CON
+A77A ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR D
+A77C ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR F
+A77F ; Changes_When_Titlecased # L& LATIN SMALL LETTER TURNED INSULAR G
+A781 ; Changes_When_Titlecased # L& LATIN SMALL LETTER TURNED L
+A783 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR R
+A785 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR S
+A787 ; Changes_When_Titlecased # L& LATIN SMALL LETTER INSULAR T
+A78C ; Changes_When_Titlecased # L& LATIN SMALL LETTER SALTILLO
+A791 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH DESCENDER
+A793 ; Changes_When_Titlecased # L& LATIN SMALL LETTER C WITH BAR
+A797 ; Changes_When_Titlecased # L& LATIN SMALL LETTER B WITH FLOURISH
+A799 ; Changes_When_Titlecased # L& LATIN SMALL LETTER F WITH STROKE
+A79B ; Changes_When_Titlecased # L& LATIN SMALL LETTER VOLAPUK AE
+A79D ; Changes_When_Titlecased # L& LATIN SMALL LETTER VOLAPUK OE
+A79F ; Changes_When_Titlecased # L& LATIN SMALL LETTER VOLAPUK UE
+A7A1 ; Changes_When_Titlecased # L& LATIN SMALL LETTER G WITH OBLIQUE STROKE
+A7A3 ; Changes_When_Titlecased # L& LATIN SMALL LETTER K WITH OBLIQUE STROKE
+A7A5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER N WITH OBLIQUE STROKE
+A7A7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER R WITH OBLIQUE STROKE
+A7A9 ; Changes_When_Titlecased # L& LATIN SMALL LETTER S WITH OBLIQUE STROKE
+A7B5 ; Changes_When_Titlecased # L& LATIN SMALL LETTER BETA
+A7B7 ; Changes_When_Titlecased # L& LATIN SMALL LETTER OMEGA
+AB53 ; Changes_When_Titlecased # L& LATIN SMALL LETTER CHI
+AB70..ABBF ; Changes_When_Titlecased # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Changes_When_Titlecased # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Changes_When_Titlecased # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF41..FF5A ; Changes_When_Titlecased # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10428..1044F ; Changes_When_Titlecased # L& [40] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER EW
+104D8..104FB ; Changes_When_Titlecased # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10CC0..10CF2 ; Changes_When_Titlecased # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+118C0..118DF ; Changes_When_Titlecased # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+1E922..1E943 ; Changes_When_Titlecased # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
+
+# Total code points: 1369
+
+# ================================================
+
+# Derived Property: Changes_When_Casefolded (CWCF)
+# Characters whose normalized forms are not stable under case folding.
+# For more information, see D142 in Section 3.13, "Default Case Algorithms".
+# Changes_When_Casefolded(X) is true when toCasefold(toNFD(X)) != toNFD(X)
+
+0041..005A ; Changes_When_Casefolded # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+00B5 ; Changes_When_Casefolded # L& MICRO SIGN
+00C0..00D6 ; Changes_When_Casefolded # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00DF ; Changes_When_Casefolded # L& [8] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER SHARP S
+0100 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH MACRON
+0102 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE
+0104 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH OGONEK
+0106 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH ACUTE
+0108 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH CARON
+010E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH CARON
+0110 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH STROKE
+0112 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH MACRON
+0114 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH BREVE
+0116 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH OGONEK
+011A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CARON
+011C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH BREVE
+0120 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH CEDILLA
+0124 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH STROKE
+0128 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH TILDE
+012A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH MACRON
+012C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH BREVE
+012E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH OGONEK
+0130 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132 ; Changes_When_Casefolded # L& LATIN CAPITAL LIGATURE IJ
+0134 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH CEDILLA
+0139 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH ACUTE
+013B ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH CEDILLA
+013D ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH CARON
+013F ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH STROKE
+0143 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH ACUTE
+0145 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH CEDILLA
+0147 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH CARON
+0149..014A ; Changes_When_Casefolded # L& [2] LATIN SMALL LETTER N PRECEDED BY APOSTROPHE..LATIN CAPITAL LETTER ENG
+014C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH MACRON
+014E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH BREVE
+0150 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152 ; Changes_When_Casefolded # L& LATIN CAPITAL LIGATURE OE
+0154 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH ACUTE
+0156 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH CEDILLA
+0158 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH CARON
+015A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH ACUTE
+015C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH CEDILLA
+0160 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH CARON
+0162 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH CEDILLA
+0164 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH CARON
+0166 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH STROKE
+0168 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH TILDE
+016A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH MACRON
+016C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH BREVE
+016E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH RING ABOVE
+0170 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH OGONEK
+0174 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178..0179 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER Y WITH DIAERESIS..LATIN CAPITAL LETTER Z WITH ACUTE
+017B ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH CARON
+017F ; Changes_When_Casefolded # L& LATIN SMALL LETTER LONG S
+0181..0182 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER B WITH HOOK..LATIN CAPITAL LETTER B WITH TOPBAR
+0184 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TONE SIX
+0186..0187 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER OPEN O..LATIN CAPITAL LETTER C WITH HOOK
+0189..018B ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER AFRICAN D..LATIN CAPITAL LETTER D WITH TOPBAR
+018E..0191 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER F WITH HOOK
+0193..0194 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER G WITH HOOK..LATIN CAPITAL LETTER GAMMA
+0196..0198 ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER IOTA..LATIN CAPITAL LETTER K WITH HOOK
+019C..019D ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F..01A0 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER O WITH MIDDLE TILDE..LATIN CAPITAL LETTER O WITH HORN
+01A2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OI
+01A4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH HOOK
+01A6..01A7 ; Changes_When_Casefolded # L& [2] LATIN LETTER YR..LATIN CAPITAL LETTER TONE TWO
+01A9 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER ESH
+01AC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH HOOK
+01AE..01AF ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER T WITH RETROFLEX HOOK..LATIN CAPITAL LETTER U WITH HORN
+01B1..01B3 ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER UPSILON..LATIN CAPITAL LETTER Y WITH HOOK
+01B5 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH STROKE
+01B7..01B8 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER EZH..LATIN CAPITAL LETTER EZH REVERSED
+01BC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TONE FIVE
+01C4..01C5 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C7..01C8 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER LJ..LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CA..01CB ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER NJ..LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01CD ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CARON
+01CF ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH CARON
+01D1 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CARON
+01D3 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH CARON
+01D5 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AE WITH MACRON
+01E4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH STROKE
+01E6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH CARON
+01E8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH CARON
+01EA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH OGONEK
+01EC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER EZH WITH CARON
+01F1..01F2 ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER DZ..LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+01F4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH ACUTE
+01F6..01F8 ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER HWAIR..LATIN CAPITAL LETTER N WITH GRAVE
+01FA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AE WITH ACUTE
+01FE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER YOGH
+021E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH CARON
+0220 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OU
+0224 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH HOOK
+0226 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CEDILLA
+022A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH MACRON
+023A..023B ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER A WITH STROKE..LATIN CAPITAL LETTER C WITH STROKE
+023D..023E ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER L WITH BAR..LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+0241 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER GLOTTAL STOP
+0243..0246 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER B WITH STROKE..LATIN CAPITAL LETTER E WITH STROKE
+0248 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER J WITH STROKE
+024A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+024C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH STROKE
+024E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH STROKE
+0345 ; Changes_When_Casefolded # Mn COMBINING GREEK YPOGEGRAMMENI
+0370 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER HETA
+0372 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER ARCHAIC SAMPI
+0376 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+037F ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER YOT
+0386 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Changes_When_Casefolded # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..038F ; Changes_When_Casefolded # L& [2] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER OMEGA WITH TONOS
+0391..03A1 ; Changes_When_Casefolded # L& [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+03A3..03AB ; Changes_When_Casefolded # L& [9] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03C2 ; Changes_When_Casefolded # L& GREEK SMALL LETTER FINAL SIGMA
+03CF..03D1 ; Changes_When_Casefolded # L& [3] GREEK CAPITAL KAI SYMBOL..GREEK THETA SYMBOL
+03D5..03D6 ; Changes_When_Casefolded # L& [2] GREEK PHI SYMBOL..GREEK PI SYMBOL
+03D8 ; Changes_When_Casefolded # L& GREEK LETTER ARCHAIC KOPPA
+03DA ; Changes_When_Casefolded # L& GREEK LETTER STIGMA
+03DC ; Changes_When_Casefolded # L& GREEK LETTER DIGAMMA
+03DE ; Changes_When_Casefolded # L& GREEK LETTER KOPPA
+03E0 ; Changes_When_Casefolded # L& GREEK LETTER SAMPI
+03E2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER SHEI
+03E4 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER FEI
+03E6 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER KHEI
+03E8 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER HORI
+03EA ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER GANGIA
+03EC ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER SHIMA
+03EE ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DEI
+03F0..03F1 ; Changes_When_Casefolded # L& [2] GREEK KAPPA SYMBOL..GREEK RHO SYMBOL
+03F4..03F5 ; Changes_When_Casefolded # L& [2] GREEK CAPITAL THETA SYMBOL..GREEK LUNATE EPSILON SYMBOL
+03F7 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER SHO
+03F9..03FA ; Changes_When_Casefolded # L& [2] GREEK CAPITAL LUNATE SIGMA SYMBOL..GREEK CAPITAL LETTER SAN
+03FD..042F ; Changes_When_Casefolded # L& [51] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..CYRILLIC CAPITAL LETTER YA
+0460 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER OMEGA
+0462 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER YAT
+0464 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED E
+0466 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER LITTLE YUS
+0468 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BIG YUS
+046C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KSI
+0470 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER PSI
+0472 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER FITA
+0474 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IZHITSA
+0476 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER UK
+047A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER OT
+0480 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOPPA
+048A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ER WITH TICK
+0490 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LIGATURE EN GHE
+04A6 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LIGATURE TE TSE
+04B6 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SHHA
+04BC ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C0..04C1 ; Changes_When_Casefolded # L& [2] CYRILLIC LETTER PALOCHKA..CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LIGATURE A IE
+04D6 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SCHWA
+04DA ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BARRED O
+04EA ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+04FA ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+04FC ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER HA WITH HOOK
+04FE ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER HA WITH STROKE
+0500 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI DE
+0502 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI DJE
+0504 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI ZJE
+0506 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI DZJE
+0508 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI LJE
+050A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI NJE
+050C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI SJE
+050E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER KOMI TJE
+0510 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER REVERSED ZE
+0512 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EL WITH HOOK
+0514 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER LHA
+0516 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER RHA
+0518 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER YAE
+051A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER QA
+051C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER WE
+051E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ALEUT KA
+0520 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
+0522 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
+0524 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER PE WITH DESCENDER
+0526 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER
+0528 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK
+052A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DZZHE
+052C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DCHE
+052E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER EL WITH DESCENDER
+0531..0556 ; Changes_When_Casefolded # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0587 ; Changes_When_Casefolded # L& ARMENIAN SMALL LIGATURE ECH YIWN
+10A0..10C5 ; Changes_When_Casefolded # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Changes_When_Casefolded # L& GEORGIAN CAPITAL LETTER AEN
+13F8..13FD ; Changes_When_Casefolded # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Changes_When_Casefolded # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1E00 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH RING BELOW
+1E02 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH CEDILLA
+1E12 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH MACRON
+1E22 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH ACUTE
+1E32 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER M WITH ACUTE
+1E40 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH ACUTE
+1E56 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER V WITH TILDE
+1E7E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH GRAVE
+1E82 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH ACUTE
+1E84 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E9A..1E9B ; Changes_When_Casefolded # L& [2] LATIN SMALL LETTER A WITH RIGHT HALF RING..LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1E9E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SHARP S
+1EA0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH TILDE
+1EBE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH TILDE
+1EFA ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER MIDDLE-WELSH LL
+1EFC ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER MIDDLE-WELSH V
+1EFE ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Y WITH LOOP
+1F08..1F0F ; Changes_When_Casefolded # L& [8] GREEK CAPITAL LETTER ALPHA WITH PSILI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18..1F1D ; Changes_When_Casefolded # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28..1F2F ; Changes_When_Casefolded # L& [8] GREEK CAPITAL LETTER ETA WITH PSILI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38..1F3F ; Changes_When_Casefolded # L& [8] GREEK CAPITAL LETTER IOTA WITH PSILI..GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48..1F4D ; Changes_When_Casefolded # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F59 ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F ; Changes_When_Casefolded # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68..1F6F ; Changes_When_Casefolded # L& [8] GREEK CAPITAL LETTER OMEGA WITH PSILI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F80..1FAF ; Changes_When_Casefolded # L& [48] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FB2..1FB4 ; Changes_When_Casefolded # L& [3] GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB7..1FBC ; Changes_When_Casefolded # L& [6] GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FC2..1FC4 ; Changes_When_Casefolded # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC7..1FCC ; Changes_When_Casefolded # L& [6] GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD8..1FDB ; Changes_When_Casefolded # L& [4] GREEK CAPITAL LETTER IOTA WITH VRACHY..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE8..1FEC ; Changes_When_Casefolded # L& [5] GREEK CAPITAL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; Changes_When_Casefolded # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF7..1FFC ; Changes_When_Casefolded # L& [6] GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126 ; Changes_When_Casefolded # L& OHM SIGN
+212A..212B ; Changes_When_Casefolded # L& [2] KELVIN SIGN..ANGSTROM SIGN
+2132 ; Changes_When_Casefolded # L& TURNED CAPITAL F
+2160..216F ; Changes_When_Casefolded # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND
+2183 ; Changes_When_Casefolded # L& ROMAN NUMERAL REVERSED ONE HUNDRED
+24B6..24CF ; Changes_When_Casefolded # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z
+2C00..2C2E ; Changes_When_Casefolded # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C60 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH DOUBLE BAR
+2C62..2C64 ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER L WITH MIDDLE TILDE..LATIN CAPITAL LETTER R WITH TAIL
+2C67 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER H WITH DESCENDER
+2C69 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH DESCENDER
+2C6B ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Z WITH DESCENDER
+2C6D..2C70 ; Changes_When_Casefolded # L& [4] LATIN CAPITAL LETTER ALPHA..LATIN CAPITAL LETTER TURNED ALPHA
+2C72 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER W WITH HOOK
+2C75 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER HALF H
+2C7E..2C80 ; Changes_When_Casefolded # L& [3] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC CAPITAL LETTER ALFA
+2C82 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER VIDA
+2C84 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER GAMMA
+2C86 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DALDA
+2C88 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER EIE
+2C8A ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER SOU
+2C8C ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER ZATA
+2C8E ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER HATE
+2C90 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER THETHE
+2C92 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER IAUDA
+2C94 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER KAPA
+2C96 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER LAULA
+2C98 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER MI
+2C9A ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER NI
+2C9C ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER KSI
+2C9E ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER O
+2CA0 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER PI
+2CA2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER RO
+2CA4 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER SIMA
+2CA6 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER TAU
+2CA8 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER UA
+2CAA ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER FI
+2CAC ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER KHI
+2CAE ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER PSI
+2CB0 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OOU
+2CB2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER SAMPI
+2CC2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER OLD NUBIAN WAU
+2CEB ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI
+2CED ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA
+2CF2 ; Changes_When_Casefolded # L& COPTIC CAPITAL LETTER BOHAIRIC KHEI
+A640 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZEMLYA
+A642 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DZELO
+A644 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER REVERSED DZE
+A646 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTA
+A648 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DJERV
+A64A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER MONOGRAPH UK
+A64C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BROAD OMEGA
+A64E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER NEUTRAL YER
+A650 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER YERU WITH BACK YER
+A652 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED YAT
+A654 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER REVERSED YU
+A656 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED A
+A658 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
+A65A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BLENDED YUS
+A65C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
+A65E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER YN
+A660 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER REVERSED TSE
+A662 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SOFT DE
+A664 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SOFT EL
+A666 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SOFT EM
+A668 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER MONOCULAR O
+A66A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER BINOCULAR O
+A66C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
+A680 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DWE
+A682 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DZWE
+A684 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER ZHWE
+A686 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CCHE
+A688 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DZZE
+A68A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
+A68C ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TWE
+A68E ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TSWE
+A690 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TSSE
+A692 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER TCHE
+A694 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER HWE
+A696 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER SHWE
+A698 ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER DOUBLE O
+A69A ; Changes_When_Casefolded # L& CYRILLIC CAPITAL LETTER CROSSED O
+A722 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
+A724 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
+A726 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER HENG
+A728 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TZ
+A72A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TRESILLO
+A72C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CUATRILLO
+A72E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CUATRILLO WITH COMMA
+A732 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AA
+A734 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AO
+A736 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AU
+A738 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AV
+A73A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+A73C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER AY
+A73E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER REVERSED C WITH DOT
+A740 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH STROKE
+A742 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+A744 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+A746 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER BROKEN L
+A748 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER L WITH HIGH STROKE
+A74A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+A74C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER O WITH LOOP
+A74E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OO
+A750 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+A752 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH FLOURISH
+A754 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+A756 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+A758 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+A75A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R ROTUNDA
+A75C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER RUM ROTUNDA
+A75E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+A760 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VY
+A762 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VISIGOTHIC Z
+A764 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER THORN WITH STROKE
+A766 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
+A768 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VEND
+A76A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER ET
+A76C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER IS
+A76E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER CON
+A779 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER INSULAR D
+A77B ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER INSULAR F
+A77D..A77E ; Changes_When_Casefolded # L& [2] LATIN CAPITAL LETTER INSULAR G..LATIN CAPITAL LETTER TURNED INSULAR G
+A780 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TURNED L
+A782 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER INSULAR R
+A784 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER INSULAR S
+A786 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER INSULAR T
+A78B ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER SALTILLO
+A78D ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER TURNED H
+A790 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH DESCENDER
+A792 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER C WITH BAR
+A796 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER B WITH FLOURISH
+A798 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER F WITH STROKE
+A79A ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VOLAPUK AE
+A79C ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VOLAPUK OE
+A79E ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER VOLAPUK UE
+A7A0 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
+A7A2 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER K WITH OBLIQUE STROKE
+A7A4 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER N WITH OBLIQUE STROKE
+A7A6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER R WITH OBLIQUE STROKE
+A7A8 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER S WITH OBLIQUE STROKE
+A7AA..A7AE ; Changes_When_Casefolded # L& [5] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B4 ; Changes_When_Casefolded # L& [5] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER BETA
+A7B6 ; Changes_When_Casefolded # L& LATIN CAPITAL LETTER OMEGA
+AB70..ABBF ; Changes_When_Casefolded # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Changes_When_Casefolded # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Changes_When_Casefolded # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF21..FF3A ; Changes_When_Casefolded # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+10400..10427 ; Changes_When_Casefolded # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW
+104B0..104D3 ; Changes_When_Casefolded # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+10C80..10CB2 ; Changes_When_Casefolded # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+118A0..118BF ; Changes_When_Casefolded # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO
+1E900..1E921 ; Changes_When_Casefolded # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
+
+# Total code points: 1377
+
+# ================================================
+
+# Derived Property: Changes_When_Casemapped (CWCM)
+# Characters whose normalized forms are not stable under case mapping.
+# For more information, see D143 in Section 3.13, "Default Case Algorithms".
+# Changes_When_Casemapped(X) is true when CWL(X), or CWT(X), or CWU(X)
+
+0041..005A ; Changes_When_Casemapped # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; Changes_When_Casemapped # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00B5 ; Changes_When_Casemapped # L& MICRO SIGN
+00C0..00D6 ; Changes_When_Casemapped # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; Changes_When_Casemapped # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..0137 ; Changes_When_Casemapped # L& [64] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER K WITH CEDILLA
+0139..018C ; Changes_When_Casemapped # L& [84] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER D WITH TOPBAR
+018E..019A ; Changes_When_Casemapped # L& [13] LATIN CAPITAL LETTER REVERSED E..LATIN SMALL LETTER L WITH BAR
+019C..01A9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER ESH
+01AC..01B9 ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER T WITH HOOK..LATIN SMALL LETTER EZH REVERSED
+01BC..01BD ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER TONE FIVE..LATIN SMALL LETTER TONE FIVE
+01BF ; Changes_When_Casemapped # L& LATIN LETTER WYNN
+01C4..0220 ; Changes_When_Casemapped # L& [93] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222..0233 ; Changes_When_Casemapped # L& [18] LATIN CAPITAL LETTER OU..LATIN SMALL LETTER Y WITH MACRON
+023A..0254 ; Changes_When_Casemapped # L& [27] LATIN CAPITAL LETTER A WITH STROKE..LATIN SMALL LETTER OPEN O
+0256..0257 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER D WITH TAIL..LATIN SMALL LETTER D WITH HOOK
+0259 ; Changes_When_Casemapped # L& LATIN SMALL LETTER SCHWA
+025B..025C ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER OPEN E..LATIN SMALL LETTER REVERSED OPEN E
+0260..0261 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER G WITH HOOK..LATIN SMALL LETTER SCRIPT G
+0263 ; Changes_When_Casemapped # L& LATIN SMALL LETTER GAMMA
+0265..0266 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER TURNED H..LATIN SMALL LETTER H WITH HOOK
+0268..026C ; Changes_When_Casemapped # L& [5] LATIN SMALL LETTER I WITH STROKE..LATIN SMALL LETTER L WITH BELT
+026F ; Changes_When_Casemapped # L& LATIN SMALL LETTER TURNED M
+0271..0272 ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER M WITH HOOK..LATIN SMALL LETTER N WITH LEFT HOOK
+0275 ; Changes_When_Casemapped # L& LATIN SMALL LETTER BARRED O
+027D ; Changes_When_Casemapped # L& LATIN SMALL LETTER R WITH TAIL
+0280 ; Changes_When_Casemapped # L& LATIN LETTER SMALL CAPITAL R
+0283 ; Changes_When_Casemapped # L& LATIN SMALL LETTER ESH
+0287..028C ; Changes_When_Casemapped # L& [6] LATIN SMALL LETTER TURNED T..LATIN SMALL LETTER TURNED V
+0292 ; Changes_When_Casemapped # L& LATIN SMALL LETTER EZH
+029D..029E ; Changes_When_Casemapped # L& [2] LATIN SMALL LETTER J WITH CROSSED-TAIL..LATIN SMALL LETTER TURNED K
+0345 ; Changes_When_Casemapped # Mn COMBINING GREEK YPOGEGRAMMENI
+0370..0373 ; Changes_When_Casemapped # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0376..0377 ; Changes_When_Casemapped # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; Changes_When_Casemapped # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER YOT
+0386 ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Changes_When_Casemapped # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; Changes_When_Casemapped # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03D1 ; Changes_When_Casemapped # L& [47] GREEK CAPITAL LETTER SIGMA..GREEK THETA SYMBOL
+03D5..03F5 ; Changes_When_Casemapped # L& [33] GREEK PHI SYMBOL..GREEK LUNATE EPSILON SYMBOL
+03F7..03FB ; Changes_When_Casemapped # L& [5] GREEK CAPITAL LETTER SHO..GREEK SMALL LETTER SAN
+03FD..0481 ; Changes_When_Casemapped # L& [133] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; Changes_When_Casemapped # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; Changes_When_Casemapped # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0561..0587 ; Changes_When_Casemapped # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+10A0..10C5 ; Changes_When_Casemapped # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Changes_When_Casemapped # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Changes_When_Casemapped # L& GEORGIAN CAPITAL LETTER AEN
+13A0..13F5 ; Changes_When_Casemapped # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; Changes_When_Casemapped # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1C80..1C88 ; Changes_When_Casemapped # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1D79 ; Changes_When_Casemapped # L& LATIN SMALL LETTER INSULAR G
+1D7D ; Changes_When_Casemapped # L& LATIN SMALL LETTER P WITH STROKE
+1E00..1E9B ; Changes_When_Casemapped # L& [156] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1E9E ; Changes_When_Casemapped # L& LATIN CAPITAL LETTER SHARP S
+1EA0..1F15 ; Changes_When_Casemapped # L& [118] LATIN CAPITAL LETTER A WITH DOT BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; Changes_When_Casemapped # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; Changes_When_Casemapped # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; Changes_When_Casemapped # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Changes_When_Casemapped # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Changes_When_Casemapped # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; Changes_When_Casemapped # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Changes_When_Casemapped # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; Changes_When_Casemapped # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; Changes_When_Casemapped # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Changes_When_Casemapped # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; Changes_When_Casemapped # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; Changes_When_Casemapped # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; Changes_When_Casemapped # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; Changes_When_Casemapped # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; Changes_When_Casemapped # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; Changes_When_Casemapped # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126 ; Changes_When_Casemapped # L& OHM SIGN
+212A..212B ; Changes_When_Casemapped # L& [2] KELVIN SIGN..ANGSTROM SIGN
+2132 ; Changes_When_Casemapped # L& TURNED CAPITAL F
+214E ; Changes_When_Casemapped # L& TURNED SMALL F
+2160..217F ; Changes_When_Casemapped # Nl [32] ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
+2183..2184 ; Changes_When_Casemapped # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+24B6..24E9 ; Changes_When_Casemapped # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2C00..2C2E ; Changes_When_Casemapped # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; Changes_When_Casemapped # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C70 ; Changes_When_Casemapped # L& [17] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN CAPITAL LETTER TURNED ALPHA
+2C72..2C73 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER W WITH HOOK..LATIN SMALL LETTER W WITH HOOK
+2C75..2C76 ; Changes_When_Casemapped # L& [2] LATIN CAPITAL LETTER HALF H..LATIN SMALL LETTER HALF H
+2C7E..2CE3 ; Changes_When_Casemapped # L& [102] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SMALL LETTER OLD NUBIAN WAU
+2CEB..2CEE ; Changes_When_Casemapped # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; Changes_When_Casemapped # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; Changes_When_Casemapped # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Changes_When_Casemapped # L& GEORGIAN SMALL LETTER YN
+2D2D ; Changes_When_Casemapped # L& GEORGIAN SMALL LETTER AEN
+A640..A66D ; Changes_When_Casemapped # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A680..A69B ; Changes_When_Casemapped # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A722..A72F ; Changes_When_Casemapped # L& [14] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CUATRILLO WITH COMMA
+A732..A76F ; Changes_When_Casemapped # L& [62] LATIN CAPITAL LETTER AA..LATIN SMALL LETTER CON
+A779..A787 ; Changes_When_Casemapped # L& [15] LATIN CAPITAL LETTER INSULAR D..LATIN SMALL LETTER INSULAR T
+A78B..A78D ; Changes_When_Casemapped # L& [3] LATIN CAPITAL LETTER SALTILLO..LATIN CAPITAL LETTER TURNED H
+A790..A793 ; Changes_When_Casemapped # L& [4] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH BAR
+A796..A7AE ; Changes_When_Casemapped # L& [25] LATIN CAPITAL LETTER B WITH FLOURISH..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; Changes_When_Casemapped # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+AB53 ; Changes_When_Casemapped # L& LATIN SMALL LETTER CHI
+AB70..ABBF ; Changes_When_Casemapped # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+FB00..FB06 ; Changes_When_Casemapped # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Changes_When_Casemapped # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF21..FF3A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; Changes_When_Casemapped # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10400..1044F ; Changes_When_Casemapped # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+104B0..104D3 ; Changes_When_Casemapped # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; Changes_When_Casemapped # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10C80..10CB2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; Changes_When_Casemapped # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+118A0..118DF ; Changes_When_Casemapped # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+1E900..1E943 ; Changes_When_Casemapped # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+
+# Total code points: 2669
+
+# ================================================
+
+# Derived Property: ID_Start
+# Characters that can start an identifier.
+# Generated from:
+# Lu + Ll + Lt + Lm + Lo + Nl
+# + Other_ID_Start
+# - Pattern_Syntax
+# - Pattern_White_Space
+# NOTE: See UAX #31 for more information
+
+0041..005A ; ID_Start # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; ID_Start # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; ID_Start # Lo FEMININE ORDINAL INDICATOR
+00B5 ; ID_Start # L& MICRO SIGN
+00BA ; ID_Start # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; ID_Start # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; ID_Start # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; ID_Start # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; ID_Start # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; ID_Start # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; ID_Start # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; ID_Start # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; ID_Start # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; ID_Start # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; ID_Start # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; ID_Start # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; ID_Start # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; ID_Start # Lm MODIFIER LETTER VOICING
+02EE ; ID_Start # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+0370..0373 ; ID_Start # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; ID_Start # Lm GREEK NUMERAL SIGN
+0376..0377 ; ID_Start # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; ID_Start # Lm GREEK YPOGEGRAMMENI
+037B..037D ; ID_Start # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; ID_Start # L& GREEK CAPITAL LETTER YOT
+0386 ; ID_Start # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; ID_Start # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; ID_Start # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; ID_Start # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; ID_Start # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; ID_Start # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; ID_Start # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; ID_Start # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; ID_Start # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0561..0587 ; ID_Start # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+05D0..05EA ; ID_Start # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; ID_Start # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0620..063F ; ID_Start # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; ID_Start # Lm ARABIC TATWEEL
+0641..064A ; ID_Start # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+066E..066F ; ID_Start # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; ID_Start # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; ID_Start # Lo ARABIC LETTER AE
+06E5..06E6 ; ID_Start # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06EE..06EF ; ID_Start # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06FA..06FC ; ID_Start # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; ID_Start # Lo ARABIC LETTER HEH WITH INVERTED V
+0710 ; ID_Start # Lo SYRIAC LETTER ALAPH
+0712..072F ; ID_Start # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; ID_Start # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07B1 ; ID_Start # Lo THAANA LETTER NAA
+07CA..07EA ; ID_Start # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; ID_Start # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; ID_Start # Lm NKO LAJANYALAN
+0800..0815 ; ID_Start # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+081A ; ID_Start # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+0824 ; ID_Start # Lm SAMARITAN MODIFIER LETTER SHORT A
+0828 ; ID_Start # Lm SAMARITAN MODIFIER LETTER I
+0840..0858 ; ID_Start # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+08A0..08B4 ; ID_Start # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; ID_Start # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+0904..0939 ; ID_Start # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093D ; ID_Start # Lo DEVANAGARI SIGN AVAGRAHA
+0950 ; ID_Start # Lo DEVANAGARI OM
+0958..0961 ; ID_Start # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0971 ; ID_Start # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; ID_Start # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0985..098C ; ID_Start # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; ID_Start # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; ID_Start # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; ID_Start # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; ID_Start # Lo BENGALI LETTER LA
+09B6..09B9 ; ID_Start # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; ID_Start # Lo BENGALI SIGN AVAGRAHA
+09CE ; ID_Start # Lo BENGALI LETTER KHANDA TA
+09DC..09DD ; ID_Start # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; ID_Start # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09F0..09F1 ; ID_Start # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A05..0A0A ; ID_Start # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; ID_Start # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; ID_Start # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; ID_Start # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; ID_Start # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; ID_Start # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; ID_Start # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A59..0A5C ; ID_Start # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; ID_Start # Lo GURMUKHI LETTER FA
+0A72..0A74 ; ID_Start # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A85..0A8D ; ID_Start # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; ID_Start # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; ID_Start # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; ID_Start # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; ID_Start # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; ID_Start # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; ID_Start # Lo GUJARATI SIGN AVAGRAHA
+0AD0 ; ID_Start # Lo GUJARATI OM
+0AE0..0AE1 ; ID_Start # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AF9 ; ID_Start # Lo GUJARATI LETTER ZHA
+0B05..0B0C ; ID_Start # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; ID_Start # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; ID_Start # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; ID_Start # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; ID_Start # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; ID_Start # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; ID_Start # Lo ORIYA SIGN AVAGRAHA
+0B5C..0B5D ; ID_Start # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; ID_Start # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B71 ; ID_Start # Lo ORIYA LETTER WA
+0B83 ; ID_Start # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; ID_Start # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; ID_Start # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; ID_Start # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; ID_Start # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; ID_Start # Lo TAMIL LETTER JA
+0B9E..0B9F ; ID_Start # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; ID_Start # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; ID_Start # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; ID_Start # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BD0 ; ID_Start # Lo TAMIL OM
+0C05..0C0C ; ID_Start # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; ID_Start # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; ID_Start # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; ID_Start # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; ID_Start # Lo TELUGU SIGN AVAGRAHA
+0C58..0C5A ; ID_Start # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; ID_Start # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C80 ; ID_Start # Lo KANNADA SIGN SPACING CANDRABINDU
+0C85..0C8C ; ID_Start # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; ID_Start # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; ID_Start # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; ID_Start # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; ID_Start # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; ID_Start # Lo KANNADA SIGN AVAGRAHA
+0CDE ; ID_Start # Lo KANNADA LETTER FA
+0CE0..0CE1 ; ID_Start # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CF1..0CF2 ; ID_Start # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D05..0D0C ; ID_Start # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; ID_Start # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; ID_Start # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; ID_Start # Lo MALAYALAM SIGN AVAGRAHA
+0D4E ; ID_Start # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; ID_Start # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D5F..0D61 ; ID_Start # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D7A..0D7F ; ID_Start # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D85..0D96 ; ID_Start # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; ID_Start # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; ID_Start # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; ID_Start # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; ID_Start # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0E01..0E30 ; ID_Start # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E32..0E33 ; ID_Start # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E40..0E45 ; ID_Start # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; ID_Start # Lm THAI CHARACTER MAIYAMOK
+0E81..0E82 ; ID_Start # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; ID_Start # Lo LAO LETTER KHO TAM
+0E87..0E88 ; ID_Start # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; ID_Start # Lo LAO LETTER SO TAM
+0E8D ; ID_Start # Lo LAO LETTER NYO
+0E94..0E97 ; ID_Start # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; ID_Start # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; ID_Start # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; ID_Start # Lo LAO LETTER LO LOOT
+0EA7 ; ID_Start # Lo LAO LETTER WO
+0EAA..0EAB ; ID_Start # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; ID_Start # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB2..0EB3 ; ID_Start # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EBD ; ID_Start # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; ID_Start # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; ID_Start # Lm LAO KO LA
+0EDC..0EDF ; ID_Start # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; ID_Start # Lo TIBETAN SYLLABLE OM
+0F40..0F47 ; ID_Start # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; ID_Start # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F88..0F8C ; ID_Start # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+1000..102A ; ID_Start # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+103F ; ID_Start # Lo MYANMAR LETTER GREAT SA
+1050..1055 ; ID_Start # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+105A..105D ; ID_Start # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+1061 ; ID_Start # Lo MYANMAR LETTER SGAW KAREN SHA
+1065..1066 ; ID_Start # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+106E..1070 ; ID_Start # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1075..1081 ; ID_Start # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+108E ; ID_Start # Lo MYANMAR LETTER RUMAI PALAUNG FA
+10A0..10C5 ; ID_Start # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; ID_Start # L& GEORGIAN CAPITAL LETTER YN
+10CD ; ID_Start # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; ID_Start # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; ID_Start # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; ID_Start # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; ID_Start # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; ID_Start # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; ID_Start # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; ID_Start # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; ID_Start # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; ID_Start # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; ID_Start # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; ID_Start # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; ID_Start # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; ID_Start # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; ID_Start # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; ID_Start # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; ID_Start # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; ID_Start # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1380..138F ; ID_Start # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; ID_Start # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; ID_Start # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; ID_Start # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; ID_Start # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; ID_Start # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; ID_Start # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; ID_Start # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; ID_Start # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; ID_Start # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; ID_Start # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1720..1731 ; ID_Start # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1740..1751 ; ID_Start # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1760..176C ; ID_Start # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; ID_Start # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1780..17B3 ; ID_Start # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17D7 ; ID_Start # Lm KHMER SIGN LEK TOO
+17DC ; ID_Start # Lo KHMER SIGN AVAKRAHASANYA
+1820..1842 ; ID_Start # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; ID_Start # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; ID_Start # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; ID_Start # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1885..1886 ; ID_Start # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1887..18A8 ; ID_Start # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; ID_Start # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; ID_Start # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; ID_Start # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1950..196D ; ID_Start # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; ID_Start # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; ID_Start # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; ID_Start # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+1A00..1A16 ; ID_Start # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A20..1A54 ; ID_Start # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1AA7 ; ID_Start # Lm TAI THAM SIGN MAI YAMOK
+1B05..1B33 ; ID_Start # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B45..1B4B ; ID_Start # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B83..1BA0 ; ID_Start # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BAE..1BAF ; ID_Start # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BBA..1BE5 ; ID_Start # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1C00..1C23 ; ID_Start # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C4D..1C4F ; ID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C5A..1C77 ; ID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; ID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; ID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CE9..1CEC ; ID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CEE..1CF1 ; ID_Start # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF5..1CF6 ; ID_Start # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1D00..1D2B ; ID_Start # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; ID_Start # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; ID_Start # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; ID_Start # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; ID_Start # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; ID_Start # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; ID_Start # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; ID_Start # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; ID_Start # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; ID_Start # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; ID_Start # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; ID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; ID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; ID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; ID_Start # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; ID_Start # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; ID_Start # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; ID_Start # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; ID_Start # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; ID_Start # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; ID_Start # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; ID_Start # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; ID_Start # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; ID_Start # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; ID_Start # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2071 ; ID_Start # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; ID_Start # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; ID_Start # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+2102 ; ID_Start # L& DOUBLE-STRUCK CAPITAL C
+2107 ; ID_Start # L& EULER CONSTANT
+210A..2113 ; ID_Start # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; ID_Start # L& DOUBLE-STRUCK CAPITAL N
+2118 ; ID_Start # Sm SCRIPT CAPITAL P
+2119..211D ; ID_Start # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; ID_Start # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; ID_Start # L& OHM SIGN
+2128 ; ID_Start # L& BLACK-LETTER CAPITAL Z
+212A..212D ; ID_Start # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; ID_Start # So ESTIMATED SYMBOL
+212F..2134 ; ID_Start # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; ID_Start # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; ID_Start # L& INFORMATION SOURCE
+213C..213F ; ID_Start # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; ID_Start # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; ID_Start # L& TURNED SMALL F
+2160..2182 ; ID_Start # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; ID_Start # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; ID_Start # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2C00..2C2E ; ID_Start # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; ID_Start # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; ID_Start # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; ID_Start # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; ID_Start # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; ID_Start # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; ID_Start # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; ID_Start # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; ID_Start # L& GEORGIAN SMALL LETTER YN
+2D2D ; ID_Start # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; ID_Start # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; ID_Start # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D80..2D96 ; ID_Start # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; ID_Start # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; ID_Start # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; ID_Start # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; ID_Start # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+3005 ; ID_Start # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; ID_Start # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; ID_Start # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; ID_Start # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3031..3035 ; ID_Start # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3038..303A ; ID_Start # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; ID_Start # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; ID_Start # Lo MASU MARK
+3041..3096 ; ID_Start # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309B..309C ; ID_Start # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; ID_Start # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; ID_Start # Lo HIRAGANA DIGRAPH YORI
+30A1..30FA ; ID_Start # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; ID_Start # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; ID_Start # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; ID_Start # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; ID_Start # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BA ; ID_Start # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31F0..31FF ; ID_Start # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; ID_Start # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FD5 ; ID_Start # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; ID_Start # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; ID_Start # Lm YI SYLLABLE WU
+A016..A48C ; ID_Start # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; ID_Start # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; ID_Start # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; ID_Start # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; ID_Start # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; ID_Start # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A62A..A62B ; ID_Start # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; ID_Start # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; ID_Start # Lo CYRILLIC LETTER MULTIOCULAR O
+A67F ; ID_Start # Lm CYRILLIC PAYEROK
+A680..A69B ; ID_Start # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; ID_Start # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A6A0..A6E5 ; ID_Start # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; ID_Start # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A717..A71F ; ID_Start # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A722..A76F ; ID_Start # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; ID_Start # Lm MODIFIER LETTER US
+A771..A787 ; ID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; ID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A78B..A78E ; ID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; ID_Start # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; ID_Start # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; ID_Start # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; ID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; ID_Start # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; ID_Start # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; ID_Start # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; ID_Start # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; ID_Start # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; ID_Start # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A840..A873 ; ID_Start # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A882..A8B3 ; ID_Start # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8F2..A8F7 ; ID_Start # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; ID_Start # Lo DEVANAGARI HEADSTROKE
+A8FD ; ID_Start # Lo DEVANAGARI JAIN OM
+A90A..A925 ; ID_Start # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A930..A946 ; ID_Start # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A960..A97C ; ID_Start # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A984..A9B2 ; ID_Start # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9CF ; ID_Start # Lm JAVANESE PANGRANGKEP
+A9E0..A9E4 ; ID_Start # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E6 ; ID_Start # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; ID_Start # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9FA..A9FE ; ID_Start # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; ID_Start # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA40..AA42 ; ID_Start # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA44..AA4B ; ID_Start # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA60..AA6F ; ID_Start # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; ID_Start # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; ID_Start # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA7A ; ID_Start # Lo MYANMAR LETTER AITON RA
+AA7E..AAAF ; ID_Start # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB1 ; ID_Start # Lo TAI VIET VOWEL AA
+AAB5..AAB6 ; ID_Start # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB9..AABD ; ID_Start # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AAC0 ; ID_Start # Lo TAI VIET TONE MAI NUENG
+AAC2 ; ID_Start # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; ID_Start # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; ID_Start # Lm TAI VIET SYMBOL SAM
+AAE0..AAEA ; ID_Start # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAF2 ; ID_Start # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; ID_Start # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AB01..AB06 ; ID_Start # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; ID_Start # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; ID_Start # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; ID_Start # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; ID_Start # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; ID_Start # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; ID_Start # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; ID_Start # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; ID_Start # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; ID_Start # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+AC00..D7A3 ; ID_Start # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; ID_Start # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; ID_Start # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; ID_Start # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; ID_Start # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; ID_Start # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; ID_Start # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; ID_Start # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; ID_Start # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; ID_Start # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; ID_Start # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; ID_Start # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; ID_Start # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; ID_Start # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; ID_Start # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; ID_Start # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; ID_Start # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; ID_Start # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; ID_Start # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FE70..FE74 ; ID_Start # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; ID_Start # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF21..FF3A ; ID_Start # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; ID_Start # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF66..FF6F ; ID_Start # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; ID_Start # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; ID_Start # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FF9E..FF9F ; ID_Start # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFA0..FFBE ; ID_Start # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; ID_Start # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; ID_Start # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; ID_Start # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; ID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; ID_Start # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; ID_Start # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; ID_Start # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; ID_Start # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; ID_Start # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; ID_Start # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; ID_Start # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; ID_Start # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10280..1029C ; ID_Start # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; ID_Start # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031F ; ID_Start # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10330..10340 ; ID_Start # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; ID_Start # Nl GOTHIC LETTER NINETY
+10342..10349 ; ID_Start # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; ID_Start # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; ID_Start # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10380..1039D ; ID_Start # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; ID_Start # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; ID_Start # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; ID_Start # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; ID_Start # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; ID_Start # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104B0..104D3 ; ID_Start # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; ID_Start # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; ID_Start # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; ID_Start # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10600..10736 ; ID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; ID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; ID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; ID_Start # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; ID_Start # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; ID_Start # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; ID_Start # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; ID_Start # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; ID_Start # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; ID_Start # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; ID_Start # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; ID_Start # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; ID_Start # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; ID_Start # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; ID_Start # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; ID_Start # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; ID_Start # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; ID_Start # Lo KHAROSHTHI LETTER A
+10A10..10A13 ; ID_Start # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; ID_Start # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; ID_Start # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A60..10A7C ; ID_Start # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; ID_Start # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; ID_Start # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; ID_Start # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10B00..10B35 ; ID_Start # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; ID_Start # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; ID_Start # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; ID_Start # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; ID_Start # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; ID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; ID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+11003..11037 ; ID_Start # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11083..110AF ; ID_Start # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110D0..110E8 ; ID_Start # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+11103..11126 ; ID_Start # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11150..11172 ; ID_Start # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11176 ; ID_Start # Lo MAHAJANI LIGATURE SHRI
+11183..111B2 ; ID_Start # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111C1..111C4 ; ID_Start # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111DA ; ID_Start # Lo SHARADA EKAM
+111DC ; ID_Start # Lo SHARADA HEADSTROKE
+11200..11211 ; ID_Start # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; ID_Start # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+11280..11286 ; ID_Start # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; ID_Start # Lo MULTANI LETTER GHA
+1128A..1128D ; ID_Start # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; ID_Start # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; ID_Start # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; ID_Start # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+11305..1130C ; ID_Start # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; ID_Start # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; ID_Start # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; ID_Start # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; ID_Start # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; ID_Start # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133D ; ID_Start # Lo GRANTHA SIGN AVAGRAHA
+11350 ; ID_Start # Lo GRANTHA OM
+1135D..11361 ; ID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11400..11434 ; ID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11447..1144A ; ID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+11480..114AF ; ID_Start # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114C4..114C5 ; ID_Start # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; ID_Start # Lo TIRHUTA OM
+11580..115AE ; ID_Start # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115D8..115DB ; ID_Start # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+11600..1162F ; ID_Start # Lo [48] MODI LETTER A..MODI LETTER LLA
+11644 ; ID_Start # Lo MODI SIGN HUVA
+11680..116AA ; ID_Start # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+11700..11719 ; ID_Start # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+118A0..118DF ; ID_Start # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118FF ; ID_Start # Lo WARANG CITI OM
+11AC0..11AF8 ; ID_Start # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; ID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; ID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C40 ; ID_Start # Lo BHAIKSUKI SIGN AVAGRAHA
+11C72..11C8F ; ID_Start # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+12000..12399 ; ID_Start # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; ID_Start # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; ID_Start # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; ID_Start # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; ID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; ID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; ID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16AD0..16AED ; ID_Start # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16B00..16B2F ; ID_Start # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B40..16B43 ; ID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B63..16B77 ; ID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; ID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; ID_Start # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; ID_Start # Lo MIAO LETTER NASALIZATION
+16F93..16F9F ; ID_Start # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; ID_Start # Lm TANGUT ITERATION MARK
+17000..187EC ; ID_Start # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; ID_Start # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; ID_Start # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; ID_Start # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; ID_Start # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; ID_Start # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; ID_Start # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1D400..1D454 ; ID_Start # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; ID_Start # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; ID_Start # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; ID_Start # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; ID_Start # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; ID_Start # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; ID_Start # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; ID_Start # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; ID_Start # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; ID_Start # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; ID_Start # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; ID_Start # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; ID_Start # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; ID_Start # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; ID_Start # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; ID_Start # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; ID_Start # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; ID_Start # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; ID_Start # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; ID_Start # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; ID_Start # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; ID_Start # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; ID_Start # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; ID_Start # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; ID_Start # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; ID_Start # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; ID_Start # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; ID_Start # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; ID_Start # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; ID_Start # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1E800..1E8C4 ; ID_Start # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E900..1E943 ; ID_Start # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1EE00..1EE03 ; ID_Start # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; ID_Start # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; ID_Start # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; ID_Start # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; ID_Start # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; ID_Start # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; ID_Start # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; ID_Start # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; ID_Start # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; ID_Start # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; ID_Start # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; ID_Start # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; ID_Start # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; ID_Start # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; ID_Start # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; ID_Start # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; ID_Start # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; ID_Start # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; ID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; ID_Start # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; ID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; ID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; ID_Start # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; ID_Start # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; ID_Start # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; ID_Start # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; ID_Start # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; ID_Start # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+20000..2A6D6 ; ID_Start # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; ID_Start # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; ID_Start # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; ID_Start # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; ID_Start # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 117007
+
+# ================================================
+
+# Derived Property: ID_Continue
+# Characters that can continue an identifier.
+# Generated from:
+# ID_Start
+# + Mn + Mc + Nd + Pc
+# + Other_ID_Continue
+# - Pattern_Syntax
+# - Pattern_White_Space
+# NOTE: See UAX #31 for more information
+
+0030..0039 ; ID_Continue # Nd [10] DIGIT ZERO..DIGIT NINE
+0041..005A ; ID_Continue # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+005F ; ID_Continue # Pc LOW LINE
+0061..007A ; ID_Continue # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; ID_Continue # Lo FEMININE ORDINAL INDICATOR
+00B5 ; ID_Continue # L& MICRO SIGN
+00B7 ; ID_Continue # Po MIDDLE DOT
+00BA ; ID_Continue # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; ID_Continue # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; ID_Continue # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; ID_Continue # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; ID_Continue # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; ID_Continue # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; ID_Continue # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; ID_Continue # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; ID_Continue # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; ID_Continue # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; ID_Continue # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; ID_Continue # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; ID_Continue # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; ID_Continue # Lm MODIFIER LETTER VOICING
+02EE ; ID_Continue # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+0300..036F ; ID_Continue # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0370..0373 ; ID_Continue # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; ID_Continue # Lm GREEK NUMERAL SIGN
+0376..0377 ; ID_Continue # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; ID_Continue # Lm GREEK YPOGEGRAMMENI
+037B..037D ; ID_Continue # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; ID_Continue # L& GREEK CAPITAL LETTER YOT
+0386 ; ID_Continue # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0387 ; ID_Continue # Po GREEK ANO TELEIA
+0388..038A ; ID_Continue # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; ID_Continue # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; ID_Continue # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; ID_Continue # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; ID_Continue # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+0483..0487 ; ID_Continue # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+048A..052F ; ID_Continue # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; ID_Continue # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; ID_Continue # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0561..0587 ; ID_Continue # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+0591..05BD ; ID_Continue # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; ID_Continue # Mn HEBREW POINT RAFE
+05C1..05C2 ; ID_Continue # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; ID_Continue # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; ID_Continue # Mn HEBREW POINT QAMATS QATAN
+05D0..05EA ; ID_Continue # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; ID_Continue # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0610..061A ; ID_Continue # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+0620..063F ; ID_Continue # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; ID_Continue # Lm ARABIC TATWEEL
+0641..064A ; ID_Continue # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+064B..065F ; ID_Continue # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+0660..0669 ; ID_Continue # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+066E..066F ; ID_Continue # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0670 ; ID_Continue # Mn ARABIC LETTER SUPERSCRIPT ALEF
+0671..06D3 ; ID_Continue # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; ID_Continue # Lo ARABIC LETTER AE
+06D6..06DC ; ID_Continue # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E4 ; ID_Continue # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E5..06E6 ; ID_Continue # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E7..06E8 ; ID_Continue # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; ID_Continue # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+06EE..06EF ; ID_Continue # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06F0..06F9 ; ID_Continue # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+06FA..06FC ; ID_Continue # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; ID_Continue # Lo ARABIC LETTER HEH WITH INVERTED V
+0710 ; ID_Continue # Lo SYRIAC LETTER ALAPH
+0711 ; ID_Continue # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0712..072F ; ID_Continue # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+0730..074A ; ID_Continue # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+074D..07A5 ; ID_Continue # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07A6..07B0 ; ID_Continue # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07B1 ; ID_Continue # Lo THAANA LETTER NAA
+07C0..07C9 ; ID_Continue # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+07CA..07EA ; ID_Continue # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07EB..07F3 ; ID_Continue # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07F4..07F5 ; ID_Continue # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; ID_Continue # Lm NKO LAJANYALAN
+0800..0815 ; ID_Continue # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+0816..0819 ; ID_Continue # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+081A ; ID_Continue # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+081B..0823 ; ID_Continue # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0824 ; ID_Continue # Lm SAMARITAN MODIFIER LETTER SHORT A
+0825..0827 ; ID_Continue # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0828 ; ID_Continue # Lm SAMARITAN MODIFIER LETTER I
+0829..082D ; ID_Continue # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+0840..0858 ; ID_Continue # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+0859..085B ; ID_Continue # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+08A0..08B4 ; ID_Continue # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; ID_Continue # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+08D4..08E1 ; ID_Continue # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08E3..0902 ; ID_Continue # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+0903 ; ID_Continue # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; ID_Continue # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093A ; ID_Continue # Mn DEVANAGARI VOWEL SIGN OE
+093B ; ID_Continue # Mc DEVANAGARI VOWEL SIGN OOE
+093C ; ID_Continue # Mn DEVANAGARI SIGN NUKTA
+093D ; ID_Continue # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; ID_Continue # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; ID_Continue # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; ID_Continue # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094D ; ID_Continue # Mn DEVANAGARI SIGN VIRAMA
+094E..094F ; ID_Continue # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+0950 ; ID_Continue # Lo DEVANAGARI OM
+0951..0957 ; ID_Continue # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+0958..0961 ; ID_Continue # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0962..0963 ; ID_Continue # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0966..096F ; ID_Continue # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+0971 ; ID_Continue # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; ID_Continue # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0981 ; ID_Continue # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; ID_Continue # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; ID_Continue # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; ID_Continue # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; ID_Continue # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; ID_Continue # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; ID_Continue # Lo BENGALI LETTER LA
+09B6..09B9 ; ID_Continue # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BC ; ID_Continue # Mn BENGALI SIGN NUKTA
+09BD ; ID_Continue # Lo BENGALI SIGN AVAGRAHA
+09BE..09C0 ; ID_Continue # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; ID_Continue # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; ID_Continue # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; ID_Continue # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CD ; ID_Continue # Mn BENGALI SIGN VIRAMA
+09CE ; ID_Continue # Lo BENGALI LETTER KHANDA TA
+09D7 ; ID_Continue # Mc BENGALI AU LENGTH MARK
+09DC..09DD ; ID_Continue # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; ID_Continue # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E2..09E3 ; ID_Continue # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09E6..09EF ; ID_Continue # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+09F0..09F1 ; ID_Continue # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A01..0A02 ; ID_Continue # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; ID_Continue # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; ID_Continue # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; ID_Continue # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; ID_Continue # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; ID_Continue # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; ID_Continue # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; ID_Continue # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; ID_Continue # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3C ; ID_Continue # Mn GURMUKHI SIGN NUKTA
+0A3E..0A40 ; ID_Continue # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; ID_Continue # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; ID_Continue # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; ID_Continue # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; ID_Continue # Mn GURMUKHI SIGN UDAAT
+0A59..0A5C ; ID_Continue # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; ID_Continue # Lo GURMUKHI LETTER FA
+0A66..0A6F ; ID_Continue # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0A70..0A71 ; ID_Continue # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A72..0A74 ; ID_Continue # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A75 ; ID_Continue # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; ID_Continue # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; ID_Continue # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; ID_Continue # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; ID_Continue # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; ID_Continue # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; ID_Continue # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; ID_Continue # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; ID_Continue # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABC ; ID_Continue # Mn GUJARATI SIGN NUKTA
+0ABD ; ID_Continue # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; ID_Continue # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; ID_Continue # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; ID_Continue # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; ID_Continue # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; ID_Continue # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0ACD ; ID_Continue # Mn GUJARATI SIGN VIRAMA
+0AD0 ; ID_Continue # Lo GUJARATI OM
+0AE0..0AE1 ; ID_Continue # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE2..0AE3 ; ID_Continue # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AE6..0AEF ; ID_Continue # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0AF9 ; ID_Continue # Lo GUJARATI LETTER ZHA
+0B01 ; ID_Continue # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; ID_Continue # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; ID_Continue # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; ID_Continue # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; ID_Continue # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; ID_Continue # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; ID_Continue # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; ID_Continue # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3C ; ID_Continue # Mn ORIYA SIGN NUKTA
+0B3D ; ID_Continue # Lo ORIYA SIGN AVAGRAHA
+0B3E ; ID_Continue # Mc ORIYA VOWEL SIGN AA
+0B3F ; ID_Continue # Mn ORIYA VOWEL SIGN I
+0B40 ; ID_Continue # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; ID_Continue # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; ID_Continue # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; ID_Continue # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B4D ; ID_Continue # Mn ORIYA SIGN VIRAMA
+0B56 ; ID_Continue # Mn ORIYA AI LENGTH MARK
+0B57 ; ID_Continue # Mc ORIYA AU LENGTH MARK
+0B5C..0B5D ; ID_Continue # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; ID_Continue # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B62..0B63 ; ID_Continue # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B66..0B6F ; ID_Continue # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0B71 ; ID_Continue # Lo ORIYA LETTER WA
+0B82 ; ID_Continue # Mn TAMIL SIGN ANUSVARA
+0B83 ; ID_Continue # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; ID_Continue # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; ID_Continue # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; ID_Continue # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; ID_Continue # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; ID_Continue # Lo TAMIL LETTER JA
+0B9E..0B9F ; ID_Continue # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; ID_Continue # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; ID_Continue # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; ID_Continue # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBE..0BBF ; ID_Continue # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; ID_Continue # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; ID_Continue # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; ID_Continue # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; ID_Continue # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BCD ; ID_Continue # Mn TAMIL SIGN VIRAMA
+0BD0 ; ID_Continue # Lo TAMIL OM
+0BD7 ; ID_Continue # Mc TAMIL AU LENGTH MARK
+0BE6..0BEF ; ID_Continue # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0C00 ; ID_Continue # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C01..0C03 ; ID_Continue # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; ID_Continue # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; ID_Continue # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; ID_Continue # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; ID_Continue # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; ID_Continue # Lo TELUGU SIGN AVAGRAHA
+0C3E..0C40 ; ID_Continue # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; ID_Continue # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; ID_Continue # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; ID_Continue # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; ID_Continue # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C58..0C5A ; ID_Continue # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; ID_Continue # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C62..0C63 ; ID_Continue # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C66..0C6F ; ID_Continue # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0C80 ; ID_Continue # Lo KANNADA SIGN SPACING CANDRABINDU
+0C81 ; ID_Continue # Mn KANNADA SIGN CANDRABINDU
+0C82..0C83 ; ID_Continue # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; ID_Continue # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; ID_Continue # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; ID_Continue # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; ID_Continue # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; ID_Continue # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBC ; ID_Continue # Mn KANNADA SIGN NUKTA
+0CBD ; ID_Continue # Lo KANNADA SIGN AVAGRAHA
+0CBE ; ID_Continue # Mc KANNADA VOWEL SIGN AA
+0CBF ; ID_Continue # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; ID_Continue # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; ID_Continue # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; ID_Continue # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; ID_Continue # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC..0CCD ; ID_Continue # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; ID_Continue # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CDE ; ID_Continue # Lo KANNADA LETTER FA
+0CE0..0CE1 ; ID_Continue # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE2..0CE3 ; ID_Continue # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CE6..0CEF ; ID_Continue # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0CF1..0CF2 ; ID_Continue # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D01 ; ID_Continue # Mn MALAYALAM SIGN CANDRABINDU
+0D02..0D03 ; ID_Continue # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; ID_Continue # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; ID_Continue # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; ID_Continue # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; ID_Continue # Lo MALAYALAM SIGN AVAGRAHA
+0D3E..0D40 ; ID_Continue # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; ID_Continue # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; ID_Continue # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; ID_Continue # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4D ; ID_Continue # Mn MALAYALAM SIGN VIRAMA
+0D4E ; ID_Continue # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; ID_Continue # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D57 ; ID_Continue # Mc MALAYALAM AU LENGTH MARK
+0D5F..0D61 ; ID_Continue # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D62..0D63 ; ID_Continue # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D66..0D6F ; ID_Continue # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0D7A..0D7F ; ID_Continue # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D82..0D83 ; ID_Continue # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; ID_Continue # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; ID_Continue # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; ID_Continue # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; ID_Continue # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; ID_Continue # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DCA ; ID_Continue # Mn SINHALA SIGN AL-LAKUNA
+0DCF..0DD1 ; ID_Continue # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; ID_Continue # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; ID_Continue # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; ID_Continue # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DE6..0DEF ; ID_Continue # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+0DF2..0DF3 ; ID_Continue # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0E01..0E30 ; ID_Continue # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E31 ; ID_Continue # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; ID_Continue # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E3A ; ID_Continue # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E40..0E45 ; ID_Continue # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; ID_Continue # Lm THAI CHARACTER MAIYAMOK
+0E47..0E4E ; ID_Continue # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0E50..0E59 ; ID_Continue # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0E81..0E82 ; ID_Continue # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; ID_Continue # Lo LAO LETTER KHO TAM
+0E87..0E88 ; ID_Continue # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; ID_Continue # Lo LAO LETTER SO TAM
+0E8D ; ID_Continue # Lo LAO LETTER NYO
+0E94..0E97 ; ID_Continue # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; ID_Continue # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; ID_Continue # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; ID_Continue # Lo LAO LETTER LO LOOT
+0EA7 ; ID_Continue # Lo LAO LETTER WO
+0EAA..0EAB ; ID_Continue # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; ID_Continue # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB1 ; ID_Continue # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; ID_Continue # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB9 ; ID_Continue # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; ID_Continue # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EBD ; ID_Continue # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; ID_Continue # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; ID_Continue # Lm LAO KO LA
+0EC8..0ECD ; ID_Continue # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0ED0..0ED9 ; ID_Continue # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0EDC..0EDF ; ID_Continue # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; ID_Continue # Lo TIBETAN SYLLABLE OM
+0F18..0F19 ; ID_Continue # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F20..0F29 ; ID_Continue # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+0F35 ; ID_Continue # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; ID_Continue # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; ID_Continue # Mn TIBETAN MARK TSA -PHRU
+0F3E..0F3F ; ID_Continue # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F40..0F47 ; ID_Continue # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; ID_Continue # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F71..0F7E ; ID_Continue # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F7F ; ID_Continue # Mc TIBETAN SIGN RNAM BCAD
+0F80..0F84 ; ID_Continue # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; ID_Continue # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F88..0F8C ; ID_Continue # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+0F8D..0F97 ; ID_Continue # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; ID_Continue # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; ID_Continue # Mn TIBETAN SYMBOL PADMA GDAN
+1000..102A ; ID_Continue # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; ID_Continue # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; ID_Continue # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; ID_Continue # Mc MYANMAR VOWEL SIGN E
+1032..1037 ; ID_Continue # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1038 ; ID_Continue # Mc MYANMAR SIGN VISARGA
+1039..103A ; ID_Continue # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103B..103C ; ID_Continue # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; ID_Continue # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+103F ; ID_Continue # Lo MYANMAR LETTER GREAT SA
+1040..1049 ; ID_Continue # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+1050..1055 ; ID_Continue # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; ID_Continue # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; ID_Continue # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105A..105D ; ID_Continue # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+105E..1060 ; ID_Continue # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1061 ; ID_Continue # Lo MYANMAR LETTER SGAW KAREN SHA
+1062..1064 ; ID_Continue # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1065..1066 ; ID_Continue # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..106D ; ID_Continue # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+106E..1070 ; ID_Continue # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1071..1074 ; ID_Continue # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1075..1081 ; ID_Continue # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1082 ; ID_Continue # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; ID_Continue # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; ID_Continue # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+1087..108C ; ID_Continue # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108D ; ID_Continue # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+108E ; ID_Continue # Lo MYANMAR LETTER RUMAI PALAUNG FA
+108F ; ID_Continue # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+1090..1099 ; ID_Continue # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+109A..109C ; ID_Continue # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+109D ; ID_Continue # Mn MYANMAR VOWEL SIGN AITON AI
+10A0..10C5 ; ID_Continue # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; ID_Continue # L& GEORGIAN CAPITAL LETTER YN
+10CD ; ID_Continue # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; ID_Continue # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; ID_Continue # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; ID_Continue # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; ID_Continue # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; ID_Continue # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; ID_Continue # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; ID_Continue # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; ID_Continue # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; ID_Continue # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; ID_Continue # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; ID_Continue # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+135D..135F ; ID_Continue # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+1369..1371 ; ID_Continue # No [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE
+1380..138F ; ID_Continue # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; ID_Continue # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; ID_Continue # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; ID_Continue # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; ID_Continue # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; ID_Continue # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; ID_Continue # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; ID_Continue # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; ID_Continue # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; ID_Continue # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; ID_Continue # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1712..1714 ; ID_Continue # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1720..1731 ; ID_Continue # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1732..1734 ; ID_Continue # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1740..1751 ; ID_Continue # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1752..1753 ; ID_Continue # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1760..176C ; ID_Continue # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; ID_Continue # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1772..1773 ; ID_Continue # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+1780..17B3 ; ID_Continue # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B4..17B5 ; ID_Continue # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B6 ; ID_Continue # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; ID_Continue # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; ID_Continue # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; ID_Continue # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; ID_Continue # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17C9..17D3 ; ID_Continue # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17D7 ; ID_Continue # Lm KHMER SIGN LEK TOO
+17DC ; ID_Continue # Lo KHMER SIGN AVAKRAHASANYA
+17DD ; ID_Continue # Mn KHMER SIGN ATTHACAN
+17E0..17E9 ; ID_Continue # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+180B..180D ; ID_Continue # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+1810..1819 ; ID_Continue # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1820..1842 ; ID_Continue # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; ID_Continue # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; ID_Continue # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; ID_Continue # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1885..1886 ; ID_Continue # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1887..18A8 ; ID_Continue # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18A9 ; ID_Continue # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+18AA ; ID_Continue # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; ID_Continue # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; ID_Continue # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1920..1922 ; ID_Continue # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; ID_Continue # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; ID_Continue # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; ID_Continue # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; ID_Continue # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; ID_Continue # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; ID_Continue # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1939..193B ; ID_Continue # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1946..194F ; ID_Continue # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+1950..196D ; ID_Continue # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; ID_Continue # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; ID_Continue # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; ID_Continue # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+19D0..19D9 ; ID_Continue # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+19DA ; ID_Continue # No NEW TAI LUE THAM DIGIT ONE
+1A00..1A16 ; ID_Continue # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A17..1A18 ; ID_Continue # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A19..1A1A ; ID_Continue # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+1A1B ; ID_Continue # Mn BUGINESE VOWEL SIGN AE
+1A20..1A54 ; ID_Continue # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1A55 ; ID_Continue # Mc TAI THAM CONSONANT SIGN MEDIAL RA
+1A56 ; ID_Continue # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A57 ; ID_Continue # Mc TAI THAM CONSONANT SIGN LA TANG LAI
+1A58..1A5E ; ID_Continue # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A60 ; ID_Continue # Mn TAI THAM SIGN SAKOT
+1A61 ; ID_Continue # Mc TAI THAM VOWEL SIGN A
+1A62 ; ID_Continue # Mn TAI THAM VOWEL SIGN MAI SAT
+1A63..1A64 ; ID_Continue # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+1A65..1A6C ; ID_Continue # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A6D..1A72 ; ID_Continue # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+1A73..1A7C ; ID_Continue # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F ; ID_Continue # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+1A80..1A89 ; ID_Continue # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+1A90..1A99 ; ID_Continue # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+1AA7 ; ID_Continue # Lm TAI THAM SIGN MAI YAMOK
+1AB0..1ABD ; ID_Continue # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+1B00..1B03 ; ID_Continue # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; ID_Continue # Mc BALINESE SIGN BISAH
+1B05..1B33 ; ID_Continue # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B34 ; ID_Continue # Mn BALINESE SIGN REREKAN
+1B35 ; ID_Continue # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; ID_Continue # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; ID_Continue # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; ID_Continue # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; ID_Continue # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; ID_Continue # Mn BALINESE VOWEL SIGN PEPET
+1B43..1B44 ; ID_Continue # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B45..1B4B ; ID_Continue # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B50..1B59 ; ID_Continue # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1B6B..1B73 ; ID_Continue # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; ID_Continue # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; ID_Continue # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; ID_Continue # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; ID_Continue # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; ID_Continue # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; ID_Continue # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; ID_Continue # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAA ; ID_Continue # Mc SUNDANESE SIGN PAMAAEH
+1BAB..1BAD ; ID_Continue # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BAE..1BAF ; ID_Continue # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BB0..1BB9 ; ID_Continue # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1BBA..1BE5 ; ID_Continue # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1BE6 ; ID_Continue # Mn BATAK SIGN TOMPI
+1BE7 ; ID_Continue # Mc BATAK VOWEL SIGN E
+1BE8..1BE9 ; ID_Continue # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BEA..1BEC ; ID_Continue # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+1BED ; ID_Continue # Mn BATAK VOWEL SIGN KARO O
+1BEE ; ID_Continue # Mc BATAK VOWEL SIGN U
+1BEF..1BF1 ; ID_Continue # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1BF2..1BF3 ; ID_Continue # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+1C00..1C23 ; ID_Continue # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; ID_Continue # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; ID_Continue # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; ID_Continue # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C36..1C37 ; ID_Continue # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1C40..1C49 ; ID_Continue # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C4D..1C4F ; ID_Continue # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C50..1C59 ; ID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+1C5A..1C77 ; ID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; ID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; ID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CD0..1CD2 ; ID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+1CD4..1CE0 ; ID_Continue # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+1CE1 ; ID_Continue # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+1CE2..1CE8 ; ID_Continue # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+1CE9..1CEC ; ID_Continue # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CED ; ID_Continue # Mn VEDIC SIGN TIRYAK
+1CEE..1CF1 ; ID_Continue # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF2..1CF3 ; ID_Continue # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF4 ; ID_Continue # Mn VEDIC TONE CANDRA ABOVE
+1CF5..1CF6 ; ID_Continue # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1CF8..1CF9 ; ID_Continue # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+1D00..1D2B ; ID_Continue # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; ID_Continue # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; ID_Continue # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; ID_Continue # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; ID_Continue # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; ID_Continue # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1DC0..1DF5 ; ID_Continue # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
+1DFB..1DFF ; ID_Continue # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+1E00..1F15 ; ID_Continue # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; ID_Continue # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; ID_Continue # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; ID_Continue # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; ID_Continue # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; ID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; ID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; ID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; ID_Continue # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; ID_Continue # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; ID_Continue # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; ID_Continue # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; ID_Continue # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; ID_Continue # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; ID_Continue # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; ID_Continue # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; ID_Continue # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; ID_Continue # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; ID_Continue # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+203F..2040 ; ID_Continue # Pc [2] UNDERTIE..CHARACTER TIE
+2054 ; ID_Continue # Pc INVERTED UNDERTIE
+2071 ; ID_Continue # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; ID_Continue # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; ID_Continue # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+20D0..20DC ; ID_Continue # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20E1 ; ID_Continue # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E5..20F0 ; ID_Continue # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2102 ; ID_Continue # L& DOUBLE-STRUCK CAPITAL C
+2107 ; ID_Continue # L& EULER CONSTANT
+210A..2113 ; ID_Continue # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; ID_Continue # L& DOUBLE-STRUCK CAPITAL N
+2118 ; ID_Continue # Sm SCRIPT CAPITAL P
+2119..211D ; ID_Continue # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; ID_Continue # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; ID_Continue # L& OHM SIGN
+2128 ; ID_Continue # L& BLACK-LETTER CAPITAL Z
+212A..212D ; ID_Continue # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; ID_Continue # So ESTIMATED SYMBOL
+212F..2134 ; ID_Continue # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; ID_Continue # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; ID_Continue # L& INFORMATION SOURCE
+213C..213F ; ID_Continue # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; ID_Continue # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; ID_Continue # L& TURNED SMALL F
+2160..2182 ; ID_Continue # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; ID_Continue # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; ID_Continue # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2C00..2C2E ; ID_Continue # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; ID_Continue # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; ID_Continue # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; ID_Continue # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; ID_Continue # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; ID_Continue # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CEF..2CF1 ; ID_Continue # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+2CF2..2CF3 ; ID_Continue # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; ID_Continue # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; ID_Continue # L& GEORGIAN SMALL LETTER YN
+2D2D ; ID_Continue # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; ID_Continue # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; ID_Continue # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D7F ; ID_Continue # Mn TIFINAGH CONSONANT JOINER
+2D80..2D96 ; ID_Continue # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2DE0..2DFF ; ID_Continue # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+3005 ; ID_Continue # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; ID_Continue # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; ID_Continue # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; ID_Continue # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+302A..302D ; ID_Continue # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+302E..302F ; ID_Continue # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3031..3035 ; ID_Continue # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3038..303A ; ID_Continue # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; ID_Continue # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; ID_Continue # Lo MASU MARK
+3041..3096 ; ID_Continue # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+3099..309A ; ID_Continue # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309B..309C ; ID_Continue # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; ID_Continue # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; ID_Continue # Lo HIRAGANA DIGRAPH YORI
+30A1..30FA ; ID_Continue # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; ID_Continue # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; ID_Continue # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; ID_Continue # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; ID_Continue # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BA ; ID_Continue # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31F0..31FF ; ID_Continue # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; ID_Continue # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FD5 ; ID_Continue # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; ID_Continue # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; ID_Continue # Lm YI SYLLABLE WU
+A016..A48C ; ID_Continue # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; ID_Continue # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; ID_Continue # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; ID_Continue # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; ID_Continue # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; ID_Continue # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A620..A629 ; ID_Continue # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A62A..A62B ; ID_Continue # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; ID_Continue # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; ID_Continue # Lo CYRILLIC LETTER MULTIOCULAR O
+A66F ; ID_Continue # Mn COMBINING CYRILLIC VZMET
+A674..A67D ; ID_Continue # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+A67F ; ID_Continue # Lm CYRILLIC PAYEROK
+A680..A69B ; ID_Continue # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; ID_Continue # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A69E..A69F ; ID_Continue # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6A0..A6E5 ; ID_Continue # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; ID_Continue # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A6F0..A6F1 ; ID_Continue # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+A717..A71F ; ID_Continue # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A722..A76F ; ID_Continue # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; ID_Continue # Lm MODIFIER LETTER US
+A771..A787 ; ID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; ID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A78B..A78E ; ID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; ID_Continue # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; ID_Continue # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; ID_Continue # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; ID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; ID_Continue # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; ID_Continue # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; ID_Continue # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A802 ; ID_Continue # Mn SYLOTI NAGRI SIGN DVISVARA
+A803..A805 ; ID_Continue # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A806 ; ID_Continue # Mn SYLOTI NAGRI SIGN HASANTA
+A807..A80A ; ID_Continue # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80B ; ID_Continue # Mn SYLOTI NAGRI SIGN ANUSVARA
+A80C..A822 ; ID_Continue # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; ID_Continue # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; ID_Continue # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; ID_Continue # Mc SYLOTI NAGRI VOWEL SIGN OO
+A840..A873 ; ID_Continue # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A880..A881 ; ID_Continue # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; ID_Continue # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; ID_Continue # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8C4..A8C5 ; ID_Continue # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+A8D0..A8D9 ; ID_Continue # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A8E0..A8F1 ; ID_Continue # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A8F2..A8F7 ; ID_Continue # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; ID_Continue # Lo DEVANAGARI HEADSTROKE
+A8FD ; ID_Continue # Lo DEVANAGARI JAIN OM
+A900..A909 ; ID_Continue # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A90A..A925 ; ID_Continue # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A926..A92D ; ID_Continue # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A930..A946 ; ID_Continue # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A947..A951 ; ID_Continue # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952..A953 ; ID_Continue # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+A960..A97C ; ID_Continue # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A980..A982 ; ID_Continue # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A983 ; ID_Continue # Mc JAVANESE SIGN WIGNYAN
+A984..A9B2 ; ID_Continue # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9B3 ; ID_Continue # Mn JAVANESE SIGN CECAK TELU
+A9B4..A9B5 ; ID_Continue # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+A9B6..A9B9 ; ID_Continue # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BA..A9BB ; ID_Continue # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+A9BC ; ID_Continue # Mn JAVANESE VOWEL SIGN PEPET
+A9BD..A9C0 ; ID_Continue # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON
+A9CF ; ID_Continue # Lm JAVANESE PANGRANGKEP
+A9D0..A9D9 ; ID_Continue # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+A9E0..A9E4 ; ID_Continue # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E5 ; ID_Continue # Mn MYANMAR SIGN SHAN SAW
+A9E6 ; ID_Continue # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; ID_Continue # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9F0..A9F9 ; ID_Continue # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+A9FA..A9FE ; ID_Continue # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; ID_Continue # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA29..AA2E ; ID_Continue # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; ID_Continue # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; ID_Continue # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; ID_Continue # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; ID_Continue # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA40..AA42 ; ID_Continue # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA43 ; ID_Continue # Mn CHAM CONSONANT SIGN FINAL NG
+AA44..AA4B ; ID_Continue # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4C ; ID_Continue # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; ID_Continue # Mc CHAM CONSONANT SIGN FINAL H
+AA50..AA59 ; ID_Continue # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+AA60..AA6F ; ID_Continue # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; ID_Continue # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; ID_Continue # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA7A ; ID_Continue # Lo MYANMAR LETTER AITON RA
+AA7B ; ID_Continue # Mc MYANMAR SIGN PAO KAREN TONE
+AA7C ; ID_Continue # Mn MYANMAR SIGN TAI LAING TONE-2
+AA7D ; ID_Continue # Mc MYANMAR SIGN TAI LAING TONE-5
+AA7E..AAAF ; ID_Continue # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB0 ; ID_Continue # Mn TAI VIET MAI KANG
+AAB1 ; ID_Continue # Lo TAI VIET VOWEL AA
+AAB2..AAB4 ; ID_Continue # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB5..AAB6 ; ID_Continue # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB7..AAB8 ; ID_Continue # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AAB9..AABD ; ID_Continue # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AABE..AABF ; ID_Continue # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+AAC0 ; ID_Continue # Lo TAI VIET TONE MAI NUENG
+AAC1 ; ID_Continue # Mn TAI VIET TONE MAI THO
+AAC2 ; ID_Continue # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; ID_Continue # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; ID_Continue # Lm TAI VIET SYMBOL SAM
+AAE0..AAEA ; ID_Continue # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAEB ; ID_Continue # Mc MEETEI MAYEK VOWEL SIGN II
+AAEC..AAED ; ID_Continue # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAEE..AAEF ; ID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+AAF2 ; ID_Continue # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; ID_Continue # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AAF5 ; ID_Continue # Mc MEETEI MAYEK VOWEL SIGN VISARGA
+AAF6 ; ID_Continue # Mn MEETEI MAYEK VIRAMA
+AB01..AB06 ; ID_Continue # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; ID_Continue # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; ID_Continue # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; ID_Continue # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; ID_Continue # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; ID_Continue # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; ID_Continue # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; ID_Continue # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; ID_Continue # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ABE3..ABE4 ; ID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ABE5 ; ID_Continue # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE6..ABE7 ; ID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ABE8 ; ID_Continue # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABE9..ABEA ; ID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ABEC ; ID_Continue # Mc MEETEI MAYEK LUM IYEK
+ABED ; ID_Continue # Mn MEETEI MAYEK APUN IYEK
+ABF0..ABF9 ; ID_Continue # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+AC00..D7A3 ; ID_Continue # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; ID_Continue # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; ID_Continue # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; ID_Continue # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; ID_Continue # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; ID_Continue # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; ID_Continue # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; ID_Continue # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1E ; ID_Continue # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FB1F..FB28 ; ID_Continue # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; ID_Continue # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; ID_Continue # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; ID_Continue # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; ID_Continue # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; ID_Continue # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; ID_Continue # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; ID_Continue # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; ID_Continue # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; ID_Continue # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; ID_Continue # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FE00..FE0F ; ID_Continue # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE2F ; ID_Continue # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+FE33..FE34 ; ID_Continue # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE4D..FE4F ; ID_Continue # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FE70..FE74 ; ID_Continue # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; ID_Continue # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF10..FF19 ; ID_Continue # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+FF21..FF3A ; ID_Continue # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF3F ; ID_Continue # Pc FULLWIDTH LOW LINE
+FF41..FF5A ; ID_Continue # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF66..FF6F ; ID_Continue # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; ID_Continue # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; ID_Continue # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FF9E..FF9F ; ID_Continue # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFA0..FFBE ; ID_Continue # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; ID_Continue # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; ID_Continue # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; ID_Continue # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; ID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; ID_Continue # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; ID_Continue # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; ID_Continue # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; ID_Continue # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; ID_Continue # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; ID_Continue # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; ID_Continue # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; ID_Continue # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+101FD ; ID_Continue # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+10280..1029C ; ID_Continue # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; ID_Continue # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+102E0 ; ID_Continue # Mn COPTIC EPACT THOUSANDS MARK
+10300..1031F ; ID_Continue # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10330..10340 ; ID_Continue # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; ID_Continue # Nl GOTHIC LETTER NINETY
+10342..10349 ; ID_Continue # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; ID_Continue # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; ID_Continue # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10376..1037A ; ID_Continue # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10380..1039D ; ID_Continue # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; ID_Continue # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; ID_Continue # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; ID_Continue # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; ID_Continue # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; ID_Continue # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104A0..104A9 ; ID_Continue # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+104B0..104D3 ; ID_Continue # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; ID_Continue # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; ID_Continue # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; ID_Continue # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10600..10736 ; ID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; ID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; ID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; ID_Continue # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; ID_Continue # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; ID_Continue # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; ID_Continue # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; ID_Continue # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; ID_Continue # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; ID_Continue # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; ID_Continue # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; ID_Continue # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; ID_Continue # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; ID_Continue # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; ID_Continue # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; ID_Continue # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; ID_Continue # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; ID_Continue # Lo KHAROSHTHI LETTER A
+10A01..10A03 ; ID_Continue # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; ID_Continue # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; ID_Continue # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A10..10A13 ; ID_Continue # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; ID_Continue # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; ID_Continue # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A38..10A3A ; ID_Continue # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; ID_Continue # Mn KHAROSHTHI VIRAMA
+10A60..10A7C ; ID_Continue # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; ID_Continue # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; ID_Continue # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; ID_Continue # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10AE5..10AE6 ; ID_Continue # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10B00..10B35 ; ID_Continue # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; ID_Continue # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; ID_Continue # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; ID_Continue # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; ID_Continue # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; ID_Continue # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; ID_Continue # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+11000 ; ID_Continue # Mc BRAHMI SIGN CANDRABINDU
+11001 ; ID_Continue # Mn BRAHMI SIGN ANUSVARA
+11002 ; ID_Continue # Mc BRAHMI SIGN VISARGA
+11003..11037 ; ID_Continue # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11038..11046 ; ID_Continue # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+11066..1106F ; ID_Continue # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+1107F..11081 ; ID_Continue # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+11082 ; ID_Continue # Mc KAITHI SIGN VISARGA
+11083..110AF ; ID_Continue # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110B0..110B2 ; ID_Continue # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+110B3..110B6 ; ID_Continue # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B7..110B8 ; ID_Continue # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+110B9..110BA ; ID_Continue # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+110D0..110E8 ; ID_Continue # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+110F0..110F9 ; ID_Continue # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+11100..11102 ; ID_Continue # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11103..11126 ; ID_Continue # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11127..1112B ; ID_Continue # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112C ; ID_Continue # Mc CHAKMA VOWEL SIGN E
+1112D..11134 ; ID_Continue # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+11136..1113F ; ID_Continue # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+11150..11172 ; ID_Continue # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11173 ; ID_Continue # Mn MAHAJANI SIGN NUKTA
+11176 ; ID_Continue # Lo MAHAJANI LIGATURE SHRI
+11180..11181 ; ID_Continue # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+11182 ; ID_Continue # Mc SHARADA SIGN VISARGA
+11183..111B2 ; ID_Continue # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111B3..111B5 ; ID_Continue # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+111B6..111BE ; ID_Continue # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111BF..111C0 ; ID_Continue # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+111C1..111C4 ; ID_Continue # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111CA..111CC ; ID_Continue # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+111D0..111D9 ; ID_Continue # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+111DA ; ID_Continue # Lo SHARADA EKAM
+111DC ; ID_Continue # Lo SHARADA HEADSTROKE
+11200..11211 ; ID_Continue # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; ID_Continue # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+1122C..1122E ; ID_Continue # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+1122F..11231 ; ID_Continue # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11232..11233 ; ID_Continue # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+11234 ; ID_Continue # Mn KHOJKI SIGN ANUSVARA
+11235 ; ID_Continue # Mc KHOJKI SIGN VIRAMA
+11236..11237 ; ID_Continue # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+1123E ; ID_Continue # Mn KHOJKI SIGN SUKUN
+11280..11286 ; ID_Continue # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; ID_Continue # Lo MULTANI LETTER GHA
+1128A..1128D ; ID_Continue # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; ID_Continue # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; ID_Continue # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; ID_Continue # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+112DF ; ID_Continue # Mn KHUDAWADI SIGN ANUSVARA
+112E0..112E2 ; ID_Continue # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+112E3..112EA ; ID_Continue # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+112F0..112F9 ; ID_Continue # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+11300..11301 ; ID_Continue # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+11302..11303 ; ID_Continue # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+11305..1130C ; ID_Continue # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; ID_Continue # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; ID_Continue # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; ID_Continue # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; ID_Continue # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; ID_Continue # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133C ; ID_Continue # Mn GRANTHA SIGN NUKTA
+1133D ; ID_Continue # Lo GRANTHA SIGN AVAGRAHA
+1133E..1133F ; ID_Continue # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+11340 ; ID_Continue # Mn GRANTHA VOWEL SIGN II
+11341..11344 ; ID_Continue # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+11347..11348 ; ID_Continue # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+1134B..1134D ; ID_Continue # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+11350 ; ID_Continue # Lo GRANTHA OM
+11357 ; ID_Continue # Mc GRANTHA AU LENGTH MARK
+1135D..11361 ; ID_Continue # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11362..11363 ; ID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+11366..1136C ; ID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+11370..11374 ; ID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+11400..11434 ; ID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11435..11437 ; ID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+11438..1143F ; ID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11440..11441 ; ID_Continue # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+11442..11444 ; ID_Continue # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+11445 ; ID_Continue # Mc NEWA SIGN VISARGA
+11446 ; ID_Continue # Mn NEWA SIGN NUKTA
+11447..1144A ; ID_Continue # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+11450..11459 ; ID_Continue # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+11480..114AF ; ID_Continue # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114B0..114B2 ; ID_Continue # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+114B3..114B8 ; ID_Continue # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114B9 ; ID_Continue # Mc TIRHUTA VOWEL SIGN E
+114BA ; ID_Continue # Mn TIRHUTA VOWEL SIGN SHORT E
+114BB..114BE ; ID_Continue # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+114BF..114C0 ; ID_Continue # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C1 ; ID_Continue # Mc TIRHUTA SIGN VISARGA
+114C2..114C3 ; ID_Continue # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+114C4..114C5 ; ID_Continue # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; ID_Continue # Lo TIRHUTA OM
+114D0..114D9 ; ID_Continue # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+11580..115AE ; ID_Continue # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115AF..115B1 ; ID_Continue # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+115B2..115B5 ; ID_Continue # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115B8..115BB ; ID_Continue # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+115BC..115BD ; ID_Continue # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BE ; ID_Continue # Mc SIDDHAM SIGN VISARGA
+115BF..115C0 ; ID_Continue # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+115D8..115DB ; ID_Continue # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+115DC..115DD ; ID_Continue # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11600..1162F ; ID_Continue # Lo [48] MODI LETTER A..MODI LETTER LLA
+11630..11632 ; ID_Continue # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+11633..1163A ; ID_Continue # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163B..1163C ; ID_Continue # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+1163D ; ID_Continue # Mn MODI SIGN ANUSVARA
+1163E ; ID_Continue # Mc MODI SIGN VISARGA
+1163F..11640 ; ID_Continue # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+11644 ; ID_Continue # Lo MODI SIGN HUVA
+11650..11659 ; ID_Continue # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+11680..116AA ; ID_Continue # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+116AB ; ID_Continue # Mn TAKRI SIGN ANUSVARA
+116AC ; ID_Continue # Mc TAKRI SIGN VISARGA
+116AD ; ID_Continue # Mn TAKRI VOWEL SIGN AA
+116AE..116AF ; ID_Continue # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+116B0..116B5 ; ID_Continue # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+116B6 ; ID_Continue # Mc TAKRI SIGN VIRAMA
+116B7 ; ID_Continue # Mn TAKRI SIGN NUKTA
+116C0..116C9 ; ID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+11700..11719 ; ID_Continue # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+1171D..1171F ; ID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11720..11721 ; ID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+11722..11725 ; ID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11726 ; ID_Continue # Mc AHOM VOWEL SIGN E
+11727..1172B ; ID_Continue # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+11730..11739 ; ID_Continue # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+118A0..118DF ; ID_Continue # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118E0..118E9 ; ID_Continue # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+118FF ; ID_Continue # Lo WARANG CITI OM
+11AC0..11AF8 ; ID_Continue # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; ID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; ID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C2F ; ID_Continue # Mc BHAIKSUKI VOWEL SIGN AA
+11C30..11C36 ; ID_Continue # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; ID_Continue # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3E ; ID_Continue # Mc BHAIKSUKI SIGN VISARGA
+11C3F ; ID_Continue # Mn BHAIKSUKI SIGN VIRAMA
+11C40 ; ID_Continue # Lo BHAIKSUKI SIGN AVAGRAHA
+11C50..11C59 ; ID_Continue # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+11C72..11C8F ; ID_Continue # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+11C92..11CA7 ; ID_Continue # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CA9 ; ID_Continue # Mc MARCHEN SUBJOINED LETTER YA
+11CAA..11CB0 ; ID_Continue # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB1 ; ID_Continue # Mc MARCHEN VOWEL SIGN I
+11CB2..11CB3 ; ID_Continue # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB4 ; ID_Continue # Mc MARCHEN VOWEL SIGN O
+11CB5..11CB6 ; ID_Continue # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+12000..12399 ; ID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; ID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; ID_Continue # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; ID_Continue # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; ID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; ID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; ID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16A60..16A69 ; ID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+16AD0..16AED ; ID_Continue # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16AF0..16AF4 ; ID_Continue # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+16B00..16B2F ; ID_Continue # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B30..16B36 ; ID_Continue # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16B40..16B43 ; ID_Continue # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B50..16B59 ; ID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+16B63..16B77 ; ID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; ID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; ID_Continue # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; ID_Continue # Lo MIAO LETTER NASALIZATION
+16F51..16F7E ; ID_Continue # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
+16F8F..16F92 ; ID_Continue # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+16F93..16F9F ; ID_Continue # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; ID_Continue # Lm TANGUT ITERATION MARK
+17000..187EC ; ID_Continue # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; ID_Continue # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; ID_Continue # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; ID_Continue # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; ID_Continue # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; ID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; ID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1BC9D..1BC9E ; ID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1D165..1D166 ; ID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D167..1D169 ; ID_Continue # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D16D..1D172 ; ID_Continue # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+1D17B..1D182 ; ID_Continue # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; ID_Continue # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; ID_Continue # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; ID_Continue # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1D400..1D454 ; ID_Continue # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; ID_Continue # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; ID_Continue # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; ID_Continue # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; ID_Continue # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; ID_Continue # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; ID_Continue # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; ID_Continue # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; ID_Continue # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; ID_Continue # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; ID_Continue # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; ID_Continue # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; ID_Continue # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; ID_Continue # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; ID_Continue # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; ID_Continue # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; ID_Continue # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; ID_Continue # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; ID_Continue # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; ID_Continue # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; ID_Continue # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; ID_Continue # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; ID_Continue # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; ID_Continue # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; ID_Continue # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; ID_Continue # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; ID_Continue # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; ID_Continue # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; ID_Continue # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; ID_Continue # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; ID_Continue # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1DA00..1DA36 ; ID_Continue # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+1DA3B..1DA6C ; ID_Continue # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+1DA75 ; ID_Continue # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+1DA84 ; ID_Continue # Mn SIGNWRITING LOCATION HEAD NECK
+1DA9B..1DA9F ; ID_Continue # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+1DAA1..1DAAF ; ID_Continue # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+1E000..1E006 ; ID_Continue # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; ID_Continue # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; ID_Continue # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; ID_Continue # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; ID_Continue # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E800..1E8C4 ; ID_Continue # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E8D0..1E8D6 ; ID_Continue # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+1E900..1E943 ; ID_Continue # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E944..1E94A ; ID_Continue # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1E950..1E959 ; ID_Continue # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+1EE00..1EE03 ; ID_Continue # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; ID_Continue # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; ID_Continue # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; ID_Continue # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; ID_Continue # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; ID_Continue # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; ID_Continue # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; ID_Continue # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; ID_Continue # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; ID_Continue # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; ID_Continue # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; ID_Continue # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; ID_Continue # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; ID_Continue # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; ID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; ID_Continue # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; ID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; ID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; ID_Continue # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; ID_Continue # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; ID_Continue # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; ID_Continue # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; ID_Continue # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; ID_Continue # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+20000..2A6D6 ; ID_Continue # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; ID_Continue # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; ID_Continue # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; ID_Continue # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; ID_Continue # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+E0100..E01EF ; ID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 119691
+
+# ================================================
+
+# Derived Property: XID_Start
+# ID_Start modified for closure under NFKx
+# Modified as described in UAX #15
+# NOTE: Does NOT remove the non-NFKx characters.
+# Merely ensures that if isIdentifer(string) then isIdentifier(NFKx(string))
+# NOTE: See UAX #31 for more information
+
+0041..005A ; XID_Start # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; XID_Start # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; XID_Start # Lo FEMININE ORDINAL INDICATOR
+00B5 ; XID_Start # L& MICRO SIGN
+00BA ; XID_Start # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; XID_Start # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; XID_Start # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; XID_Start # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; XID_Start # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; XID_Start # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; XID_Start # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; XID_Start # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; XID_Start # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; XID_Start # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; XID_Start # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; XID_Start # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; XID_Start # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; XID_Start # Lm MODIFIER LETTER VOICING
+02EE ; XID_Start # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+0370..0373 ; XID_Start # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; XID_Start # Lm GREEK NUMERAL SIGN
+0376..0377 ; XID_Start # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; XID_Start # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; XID_Start # L& GREEK CAPITAL LETTER YOT
+0386 ; XID_Start # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; XID_Start # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; XID_Start # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; XID_Start # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; XID_Start # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; XID_Start # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+048A..052F ; XID_Start # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; XID_Start # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; XID_Start # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0561..0587 ; XID_Start # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+05D0..05EA ; XID_Start # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; XID_Start # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0620..063F ; XID_Start # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; XID_Start # Lm ARABIC TATWEEL
+0641..064A ; XID_Start # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+066E..066F ; XID_Start # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; XID_Start # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; XID_Start # Lo ARABIC LETTER AE
+06E5..06E6 ; XID_Start # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06EE..06EF ; XID_Start # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06FA..06FC ; XID_Start # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; XID_Start # Lo ARABIC LETTER HEH WITH INVERTED V
+0710 ; XID_Start # Lo SYRIAC LETTER ALAPH
+0712..072F ; XID_Start # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; XID_Start # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07B1 ; XID_Start # Lo THAANA LETTER NAA
+07CA..07EA ; XID_Start # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; XID_Start # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; XID_Start # Lm NKO LAJANYALAN
+0800..0815 ; XID_Start # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+081A ; XID_Start # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+0824 ; XID_Start # Lm SAMARITAN MODIFIER LETTER SHORT A
+0828 ; XID_Start # Lm SAMARITAN MODIFIER LETTER I
+0840..0858 ; XID_Start # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+08A0..08B4 ; XID_Start # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; XID_Start # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+0904..0939 ; XID_Start # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093D ; XID_Start # Lo DEVANAGARI SIGN AVAGRAHA
+0950 ; XID_Start # Lo DEVANAGARI OM
+0958..0961 ; XID_Start # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0971 ; XID_Start # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; XID_Start # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0985..098C ; XID_Start # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; XID_Start # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; XID_Start # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; XID_Start # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; XID_Start # Lo BENGALI LETTER LA
+09B6..09B9 ; XID_Start # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; XID_Start # Lo BENGALI SIGN AVAGRAHA
+09CE ; XID_Start # Lo BENGALI LETTER KHANDA TA
+09DC..09DD ; XID_Start # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; XID_Start # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09F0..09F1 ; XID_Start # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A05..0A0A ; XID_Start # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; XID_Start # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; XID_Start # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; XID_Start # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; XID_Start # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; XID_Start # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; XID_Start # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A59..0A5C ; XID_Start # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; XID_Start # Lo GURMUKHI LETTER FA
+0A72..0A74 ; XID_Start # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A85..0A8D ; XID_Start # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; XID_Start # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; XID_Start # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; XID_Start # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; XID_Start # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; XID_Start # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; XID_Start # Lo GUJARATI SIGN AVAGRAHA
+0AD0 ; XID_Start # Lo GUJARATI OM
+0AE0..0AE1 ; XID_Start # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AF9 ; XID_Start # Lo GUJARATI LETTER ZHA
+0B05..0B0C ; XID_Start # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; XID_Start # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; XID_Start # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; XID_Start # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; XID_Start # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; XID_Start # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; XID_Start # Lo ORIYA SIGN AVAGRAHA
+0B5C..0B5D ; XID_Start # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; XID_Start # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B71 ; XID_Start # Lo ORIYA LETTER WA
+0B83 ; XID_Start # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; XID_Start # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; XID_Start # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; XID_Start # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; XID_Start # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; XID_Start # Lo TAMIL LETTER JA
+0B9E..0B9F ; XID_Start # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; XID_Start # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; XID_Start # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; XID_Start # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BD0 ; XID_Start # Lo TAMIL OM
+0C05..0C0C ; XID_Start # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; XID_Start # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; XID_Start # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; XID_Start # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; XID_Start # Lo TELUGU SIGN AVAGRAHA
+0C58..0C5A ; XID_Start # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; XID_Start # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C80 ; XID_Start # Lo KANNADA SIGN SPACING CANDRABINDU
+0C85..0C8C ; XID_Start # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; XID_Start # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; XID_Start # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; XID_Start # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; XID_Start # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; XID_Start # Lo KANNADA SIGN AVAGRAHA
+0CDE ; XID_Start # Lo KANNADA LETTER FA
+0CE0..0CE1 ; XID_Start # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CF1..0CF2 ; XID_Start # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D05..0D0C ; XID_Start # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; XID_Start # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; XID_Start # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; XID_Start # Lo MALAYALAM SIGN AVAGRAHA
+0D4E ; XID_Start # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; XID_Start # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D5F..0D61 ; XID_Start # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D7A..0D7F ; XID_Start # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D85..0D96 ; XID_Start # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; XID_Start # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; XID_Start # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; XID_Start # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; XID_Start # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0E01..0E30 ; XID_Start # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E32 ; XID_Start # Lo THAI CHARACTER SARA AA
+0E40..0E45 ; XID_Start # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; XID_Start # Lm THAI CHARACTER MAIYAMOK
+0E81..0E82 ; XID_Start # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; XID_Start # Lo LAO LETTER KHO TAM
+0E87..0E88 ; XID_Start # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; XID_Start # Lo LAO LETTER SO TAM
+0E8D ; XID_Start # Lo LAO LETTER NYO
+0E94..0E97 ; XID_Start # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; XID_Start # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; XID_Start # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; XID_Start # Lo LAO LETTER LO LOOT
+0EA7 ; XID_Start # Lo LAO LETTER WO
+0EAA..0EAB ; XID_Start # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; XID_Start # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB2 ; XID_Start # Lo LAO VOWEL SIGN AA
+0EBD ; XID_Start # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; XID_Start # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; XID_Start # Lm LAO KO LA
+0EDC..0EDF ; XID_Start # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; XID_Start # Lo TIBETAN SYLLABLE OM
+0F40..0F47 ; XID_Start # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; XID_Start # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F88..0F8C ; XID_Start # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+1000..102A ; XID_Start # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+103F ; XID_Start # Lo MYANMAR LETTER GREAT SA
+1050..1055 ; XID_Start # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+105A..105D ; XID_Start # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+1061 ; XID_Start # Lo MYANMAR LETTER SGAW KAREN SHA
+1065..1066 ; XID_Start # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+106E..1070 ; XID_Start # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1075..1081 ; XID_Start # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+108E ; XID_Start # Lo MYANMAR LETTER RUMAI PALAUNG FA
+10A0..10C5 ; XID_Start # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; XID_Start # L& GEORGIAN CAPITAL LETTER YN
+10CD ; XID_Start # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; XID_Start # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; XID_Start # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; XID_Start # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; XID_Start # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; XID_Start # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; XID_Start # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; XID_Start # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; XID_Start # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; XID_Start # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; XID_Start # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; XID_Start # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; XID_Start # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; XID_Start # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; XID_Start # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; XID_Start # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; XID_Start # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; XID_Start # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1380..138F ; XID_Start # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; XID_Start # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; XID_Start # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; XID_Start # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; XID_Start # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; XID_Start # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; XID_Start # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; XID_Start # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; XID_Start # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; XID_Start # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; XID_Start # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1720..1731 ; XID_Start # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1740..1751 ; XID_Start # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1760..176C ; XID_Start # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; XID_Start # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1780..17B3 ; XID_Start # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17D7 ; XID_Start # Lm KHMER SIGN LEK TOO
+17DC ; XID_Start # Lo KHMER SIGN AVAKRAHASANYA
+1820..1842 ; XID_Start # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; XID_Start # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; XID_Start # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; XID_Start # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1885..1886 ; XID_Start # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1887..18A8 ; XID_Start # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; XID_Start # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; XID_Start # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; XID_Start # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1950..196D ; XID_Start # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; XID_Start # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; XID_Start # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; XID_Start # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+1A00..1A16 ; XID_Start # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A20..1A54 ; XID_Start # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1AA7 ; XID_Start # Lm TAI THAM SIGN MAI YAMOK
+1B05..1B33 ; XID_Start # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B45..1B4B ; XID_Start # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B83..1BA0 ; XID_Start # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BAE..1BAF ; XID_Start # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BBA..1BE5 ; XID_Start # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1C00..1C23 ; XID_Start # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C4D..1C4F ; XID_Start # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C5A..1C77 ; XID_Start # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; XID_Start # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; XID_Start # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CE9..1CEC ; XID_Start # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CEE..1CF1 ; XID_Start # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF5..1CF6 ; XID_Start # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1D00..1D2B ; XID_Start # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; XID_Start # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; XID_Start # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; XID_Start # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; XID_Start # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; XID_Start # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; XID_Start # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; XID_Start # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; XID_Start # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; XID_Start # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; XID_Start # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; XID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; XID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; XID_Start # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; XID_Start # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; XID_Start # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; XID_Start # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; XID_Start # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; XID_Start # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; XID_Start # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; XID_Start # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; XID_Start # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; XID_Start # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; XID_Start # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; XID_Start # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2071 ; XID_Start # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; XID_Start # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; XID_Start # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+2102 ; XID_Start # L& DOUBLE-STRUCK CAPITAL C
+2107 ; XID_Start # L& EULER CONSTANT
+210A..2113 ; XID_Start # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; XID_Start # L& DOUBLE-STRUCK CAPITAL N
+2118 ; XID_Start # Sm SCRIPT CAPITAL P
+2119..211D ; XID_Start # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; XID_Start # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; XID_Start # L& OHM SIGN
+2128 ; XID_Start # L& BLACK-LETTER CAPITAL Z
+212A..212D ; XID_Start # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; XID_Start # So ESTIMATED SYMBOL
+212F..2134 ; XID_Start # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; XID_Start # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; XID_Start # L& INFORMATION SOURCE
+213C..213F ; XID_Start # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; XID_Start # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; XID_Start # L& TURNED SMALL F
+2160..2182 ; XID_Start # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; XID_Start # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; XID_Start # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2C00..2C2E ; XID_Start # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; XID_Start # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; XID_Start # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; XID_Start # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; XID_Start # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; XID_Start # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; XID_Start # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; XID_Start # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; XID_Start # L& GEORGIAN SMALL LETTER YN
+2D2D ; XID_Start # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; XID_Start # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; XID_Start # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D80..2D96 ; XID_Start # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; XID_Start # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; XID_Start # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; XID_Start # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; XID_Start # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+3005 ; XID_Start # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; XID_Start # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; XID_Start # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; XID_Start # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3031..3035 ; XID_Start # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3038..303A ; XID_Start # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; XID_Start # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; XID_Start # Lo MASU MARK
+3041..3096 ; XID_Start # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309D..309E ; XID_Start # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; XID_Start # Lo HIRAGANA DIGRAPH YORI
+30A1..30FA ; XID_Start # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; XID_Start # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; XID_Start # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; XID_Start # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; XID_Start # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BA ; XID_Start # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31F0..31FF ; XID_Start # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; XID_Start # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FD5 ; XID_Start # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; XID_Start # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; XID_Start # Lm YI SYLLABLE WU
+A016..A48C ; XID_Start # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; XID_Start # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; XID_Start # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; XID_Start # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; XID_Start # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; XID_Start # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A62A..A62B ; XID_Start # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; XID_Start # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; XID_Start # Lo CYRILLIC LETTER MULTIOCULAR O
+A67F ; XID_Start # Lm CYRILLIC PAYEROK
+A680..A69B ; XID_Start # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; XID_Start # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A6A0..A6E5 ; XID_Start # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; XID_Start # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A717..A71F ; XID_Start # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A722..A76F ; XID_Start # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; XID_Start # Lm MODIFIER LETTER US
+A771..A787 ; XID_Start # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; XID_Start # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A78B..A78E ; XID_Start # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; XID_Start # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; XID_Start # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; XID_Start # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; XID_Start # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; XID_Start # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; XID_Start # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; XID_Start # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; XID_Start # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; XID_Start # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; XID_Start # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A840..A873 ; XID_Start # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A882..A8B3 ; XID_Start # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8F2..A8F7 ; XID_Start # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; XID_Start # Lo DEVANAGARI HEADSTROKE
+A8FD ; XID_Start # Lo DEVANAGARI JAIN OM
+A90A..A925 ; XID_Start # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A930..A946 ; XID_Start # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A960..A97C ; XID_Start # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A984..A9B2 ; XID_Start # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9CF ; XID_Start # Lm JAVANESE PANGRANGKEP
+A9E0..A9E4 ; XID_Start # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E6 ; XID_Start # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; XID_Start # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9FA..A9FE ; XID_Start # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; XID_Start # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA40..AA42 ; XID_Start # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA44..AA4B ; XID_Start # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA60..AA6F ; XID_Start # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; XID_Start # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; XID_Start # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA7A ; XID_Start # Lo MYANMAR LETTER AITON RA
+AA7E..AAAF ; XID_Start # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB1 ; XID_Start # Lo TAI VIET VOWEL AA
+AAB5..AAB6 ; XID_Start # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB9..AABD ; XID_Start # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AAC0 ; XID_Start # Lo TAI VIET TONE MAI NUENG
+AAC2 ; XID_Start # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; XID_Start # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; XID_Start # Lm TAI VIET SYMBOL SAM
+AAE0..AAEA ; XID_Start # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAF2 ; XID_Start # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; XID_Start # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AB01..AB06 ; XID_Start # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; XID_Start # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; XID_Start # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; XID_Start # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; XID_Start # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; XID_Start # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; XID_Start # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; XID_Start # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; XID_Start # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; XID_Start # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+AC00..D7A3 ; XID_Start # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; XID_Start # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; XID_Start # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; XID_Start # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; XID_Start # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; XID_Start # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; XID_Start # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; XID_Start # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; XID_Start # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; XID_Start # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; XID_Start # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; XID_Start # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; XID_Start # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; XID_Start # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; XID_Start # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FC5D ; XID_Start # Lo [139] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM
+FC64..FD3D ; XID_Start # Lo [218] ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; XID_Start # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; XID_Start # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDF9 ; XID_Start # Lo [10] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE SALLA ISOLATED FORM
+FE71 ; XID_Start # Lo ARABIC TATWEEL WITH FATHATAN ABOVE
+FE73 ; XID_Start # Lo ARABIC TAIL FRAGMENT
+FE77 ; XID_Start # Lo ARABIC FATHA MEDIAL FORM
+FE79 ; XID_Start # Lo ARABIC DAMMA MEDIAL FORM
+FE7B ; XID_Start # Lo ARABIC KASRA MEDIAL FORM
+FE7D ; XID_Start # Lo ARABIC SHADDA MEDIAL FORM
+FE7F..FEFC ; XID_Start # Lo [126] ARABIC SUKUN MEDIAL FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF21..FF3A ; XID_Start # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; XID_Start # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF66..FF6F ; XID_Start # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; XID_Start # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; XID_Start # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FFA0..FFBE ; XID_Start # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; XID_Start # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; XID_Start # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; XID_Start # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; XID_Start # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; XID_Start # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; XID_Start # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; XID_Start # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; XID_Start # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; XID_Start # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; XID_Start # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; XID_Start # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; XID_Start # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10280..1029C ; XID_Start # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; XID_Start # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031F ; XID_Start # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10330..10340 ; XID_Start # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; XID_Start # Nl GOTHIC LETTER NINETY
+10342..10349 ; XID_Start # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; XID_Start # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; XID_Start # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10380..1039D ; XID_Start # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; XID_Start # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; XID_Start # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; XID_Start # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; XID_Start # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; XID_Start # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104B0..104D3 ; XID_Start # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; XID_Start # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; XID_Start # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; XID_Start # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10600..10736 ; XID_Start # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; XID_Start # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; XID_Start # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; XID_Start # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; XID_Start # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; XID_Start # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; XID_Start # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; XID_Start # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; XID_Start # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; XID_Start # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; XID_Start # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; XID_Start # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; XID_Start # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; XID_Start # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; XID_Start # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; XID_Start # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; XID_Start # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; XID_Start # Lo KHAROSHTHI LETTER A
+10A10..10A13 ; XID_Start # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; XID_Start # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; XID_Start # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A60..10A7C ; XID_Start # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; XID_Start # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; XID_Start # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; XID_Start # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10B00..10B35 ; XID_Start # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; XID_Start # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; XID_Start # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; XID_Start # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; XID_Start # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; XID_Start # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; XID_Start # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+11003..11037 ; XID_Start # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11083..110AF ; XID_Start # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110D0..110E8 ; XID_Start # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+11103..11126 ; XID_Start # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11150..11172 ; XID_Start # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11176 ; XID_Start # Lo MAHAJANI LIGATURE SHRI
+11183..111B2 ; XID_Start # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111C1..111C4 ; XID_Start # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111DA ; XID_Start # Lo SHARADA EKAM
+111DC ; XID_Start # Lo SHARADA HEADSTROKE
+11200..11211 ; XID_Start # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; XID_Start # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+11280..11286 ; XID_Start # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; XID_Start # Lo MULTANI LETTER GHA
+1128A..1128D ; XID_Start # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; XID_Start # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; XID_Start # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; XID_Start # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+11305..1130C ; XID_Start # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; XID_Start # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; XID_Start # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; XID_Start # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; XID_Start # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; XID_Start # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133D ; XID_Start # Lo GRANTHA SIGN AVAGRAHA
+11350 ; XID_Start # Lo GRANTHA OM
+1135D..11361 ; XID_Start # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11400..11434 ; XID_Start # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11447..1144A ; XID_Start # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+11480..114AF ; XID_Start # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114C4..114C5 ; XID_Start # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; XID_Start # Lo TIRHUTA OM
+11580..115AE ; XID_Start # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115D8..115DB ; XID_Start # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+11600..1162F ; XID_Start # Lo [48] MODI LETTER A..MODI LETTER LLA
+11644 ; XID_Start # Lo MODI SIGN HUVA
+11680..116AA ; XID_Start # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+11700..11719 ; XID_Start # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+118A0..118DF ; XID_Start # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118FF ; XID_Start # Lo WARANG CITI OM
+11AC0..11AF8 ; XID_Start # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; XID_Start # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; XID_Start # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C40 ; XID_Start # Lo BHAIKSUKI SIGN AVAGRAHA
+11C72..11C8F ; XID_Start # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+12000..12399 ; XID_Start # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; XID_Start # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; XID_Start # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; XID_Start # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; XID_Start # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; XID_Start # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; XID_Start # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16AD0..16AED ; XID_Start # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16B00..16B2F ; XID_Start # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B40..16B43 ; XID_Start # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B63..16B77 ; XID_Start # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; XID_Start # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; XID_Start # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; XID_Start # Lo MIAO LETTER NASALIZATION
+16F93..16F9F ; XID_Start # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; XID_Start # Lm TANGUT ITERATION MARK
+17000..187EC ; XID_Start # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; XID_Start # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; XID_Start # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; XID_Start # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; XID_Start # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; XID_Start # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; XID_Start # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1D400..1D454 ; XID_Start # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; XID_Start # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; XID_Start # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; XID_Start # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; XID_Start # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; XID_Start # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; XID_Start # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; XID_Start # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; XID_Start # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; XID_Start # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; XID_Start # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; XID_Start # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; XID_Start # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; XID_Start # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; XID_Start # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; XID_Start # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; XID_Start # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; XID_Start # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; XID_Start # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; XID_Start # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; XID_Start # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; XID_Start # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; XID_Start # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; XID_Start # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; XID_Start # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; XID_Start # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; XID_Start # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; XID_Start # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; XID_Start # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; XID_Start # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1E800..1E8C4 ; XID_Start # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E900..1E943 ; XID_Start # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1EE00..1EE03 ; XID_Start # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; XID_Start # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; XID_Start # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; XID_Start # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; XID_Start # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; XID_Start # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; XID_Start # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; XID_Start # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; XID_Start # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; XID_Start # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; XID_Start # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; XID_Start # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; XID_Start # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; XID_Start # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; XID_Start # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; XID_Start # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; XID_Start # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; XID_Start # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; XID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; XID_Start # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; XID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; XID_Start # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; XID_Start # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; XID_Start # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; XID_Start # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; XID_Start # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; XID_Start # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; XID_Start # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+20000..2A6D6 ; XID_Start # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; XID_Start # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; XID_Start # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; XID_Start # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; XID_Start # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 116984
+
+# ================================================
+
+# Derived Property: XID_Continue
+# Mod_ID_Continue modified for closure under NFKx
+# Modified as described in UAX #15
+# NOTE: Does NOT remove the non-NFKx characters.
+# Merely ensures that if isIdentifer(string) then isIdentifier(NFKx(string))
+# NOTE: See UAX #31 for more information
+
+0030..0039 ; XID_Continue # Nd [10] DIGIT ZERO..DIGIT NINE
+0041..005A ; XID_Continue # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+005F ; XID_Continue # Pc LOW LINE
+0061..007A ; XID_Continue # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; XID_Continue # Lo FEMININE ORDINAL INDICATOR
+00B5 ; XID_Continue # L& MICRO SIGN
+00B7 ; XID_Continue # Po MIDDLE DOT
+00BA ; XID_Continue # Lo MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; XID_Continue # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; XID_Continue # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; XID_Continue # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; XID_Continue # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; XID_Continue # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; XID_Continue # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; XID_Continue # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; XID_Continue # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; XID_Continue # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; XID_Continue # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; XID_Continue # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; XID_Continue # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; XID_Continue # Lm MODIFIER LETTER VOICING
+02EE ; XID_Continue # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+0300..036F ; XID_Continue # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0370..0373 ; XID_Continue # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; XID_Continue # Lm GREEK NUMERAL SIGN
+0376..0377 ; XID_Continue # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; XID_Continue # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037F ; XID_Continue # L& GREEK CAPITAL LETTER YOT
+0386 ; XID_Continue # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0387 ; XID_Continue # Po GREEK ANO TELEIA
+0388..038A ; XID_Continue # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; XID_Continue # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; XID_Continue # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; XID_Continue # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F7..0481 ; XID_Continue # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+0483..0487 ; XID_Continue # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+048A..052F ; XID_Continue # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; XID_Continue # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; XID_Continue # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+0561..0587 ; XID_Continue # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+0591..05BD ; XID_Continue # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; XID_Continue # Mn HEBREW POINT RAFE
+05C1..05C2 ; XID_Continue # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; XID_Continue # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; XID_Continue # Mn HEBREW POINT QAMATS QATAN
+05D0..05EA ; XID_Continue # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; XID_Continue # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0610..061A ; XID_Continue # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+0620..063F ; XID_Continue # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; XID_Continue # Lm ARABIC TATWEEL
+0641..064A ; XID_Continue # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+064B..065F ; XID_Continue # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+0660..0669 ; XID_Continue # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+066E..066F ; XID_Continue # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0670 ; XID_Continue # Mn ARABIC LETTER SUPERSCRIPT ALEF
+0671..06D3 ; XID_Continue # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; XID_Continue # Lo ARABIC LETTER AE
+06D6..06DC ; XID_Continue # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E4 ; XID_Continue # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E5..06E6 ; XID_Continue # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E7..06E8 ; XID_Continue # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; XID_Continue # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+06EE..06EF ; XID_Continue # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06F0..06F9 ; XID_Continue # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+06FA..06FC ; XID_Continue # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; XID_Continue # Lo ARABIC LETTER HEH WITH INVERTED V
+0710 ; XID_Continue # Lo SYRIAC LETTER ALAPH
+0711 ; XID_Continue # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0712..072F ; XID_Continue # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+0730..074A ; XID_Continue # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+074D..07A5 ; XID_Continue # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07A6..07B0 ; XID_Continue # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07B1 ; XID_Continue # Lo THAANA LETTER NAA
+07C0..07C9 ; XID_Continue # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+07CA..07EA ; XID_Continue # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07EB..07F3 ; XID_Continue # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07F4..07F5 ; XID_Continue # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; XID_Continue # Lm NKO LAJANYALAN
+0800..0815 ; XID_Continue # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+0816..0819 ; XID_Continue # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+081A ; XID_Continue # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+081B..0823 ; XID_Continue # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0824 ; XID_Continue # Lm SAMARITAN MODIFIER LETTER SHORT A
+0825..0827 ; XID_Continue # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0828 ; XID_Continue # Lm SAMARITAN MODIFIER LETTER I
+0829..082D ; XID_Continue # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+0840..0858 ; XID_Continue # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+0859..085B ; XID_Continue # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+08A0..08B4 ; XID_Continue # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; XID_Continue # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+08D4..08E1 ; XID_Continue # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08E3..0902 ; XID_Continue # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+0903 ; XID_Continue # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; XID_Continue # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093A ; XID_Continue # Mn DEVANAGARI VOWEL SIGN OE
+093B ; XID_Continue # Mc DEVANAGARI VOWEL SIGN OOE
+093C ; XID_Continue # Mn DEVANAGARI SIGN NUKTA
+093D ; XID_Continue # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; XID_Continue # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; XID_Continue # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; XID_Continue # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094D ; XID_Continue # Mn DEVANAGARI SIGN VIRAMA
+094E..094F ; XID_Continue # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+0950 ; XID_Continue # Lo DEVANAGARI OM
+0951..0957 ; XID_Continue # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+0958..0961 ; XID_Continue # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0962..0963 ; XID_Continue # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0966..096F ; XID_Continue # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+0971 ; XID_Continue # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; XID_Continue # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0981 ; XID_Continue # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; XID_Continue # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; XID_Continue # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; XID_Continue # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; XID_Continue # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; XID_Continue # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; XID_Continue # Lo BENGALI LETTER LA
+09B6..09B9 ; XID_Continue # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BC ; XID_Continue # Mn BENGALI SIGN NUKTA
+09BD ; XID_Continue # Lo BENGALI SIGN AVAGRAHA
+09BE..09C0 ; XID_Continue # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; XID_Continue # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; XID_Continue # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; XID_Continue # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CD ; XID_Continue # Mn BENGALI SIGN VIRAMA
+09CE ; XID_Continue # Lo BENGALI LETTER KHANDA TA
+09D7 ; XID_Continue # Mc BENGALI AU LENGTH MARK
+09DC..09DD ; XID_Continue # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; XID_Continue # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E2..09E3 ; XID_Continue # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09E6..09EF ; XID_Continue # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+09F0..09F1 ; XID_Continue # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A01..0A02 ; XID_Continue # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; XID_Continue # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; XID_Continue # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; XID_Continue # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; XID_Continue # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; XID_Continue # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; XID_Continue # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; XID_Continue # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; XID_Continue # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3C ; XID_Continue # Mn GURMUKHI SIGN NUKTA
+0A3E..0A40 ; XID_Continue # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; XID_Continue # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; XID_Continue # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; XID_Continue # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; XID_Continue # Mn GURMUKHI SIGN UDAAT
+0A59..0A5C ; XID_Continue # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; XID_Continue # Lo GURMUKHI LETTER FA
+0A66..0A6F ; XID_Continue # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0A70..0A71 ; XID_Continue # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A72..0A74 ; XID_Continue # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A75 ; XID_Continue # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; XID_Continue # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; XID_Continue # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; XID_Continue # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; XID_Continue # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; XID_Continue # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; XID_Continue # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; XID_Continue # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; XID_Continue # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABC ; XID_Continue # Mn GUJARATI SIGN NUKTA
+0ABD ; XID_Continue # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; XID_Continue # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; XID_Continue # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; XID_Continue # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; XID_Continue # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; XID_Continue # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0ACD ; XID_Continue # Mn GUJARATI SIGN VIRAMA
+0AD0 ; XID_Continue # Lo GUJARATI OM
+0AE0..0AE1 ; XID_Continue # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE2..0AE3 ; XID_Continue # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AE6..0AEF ; XID_Continue # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0AF9 ; XID_Continue # Lo GUJARATI LETTER ZHA
+0B01 ; XID_Continue # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; XID_Continue # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; XID_Continue # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; XID_Continue # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; XID_Continue # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; XID_Continue # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; XID_Continue # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; XID_Continue # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3C ; XID_Continue # Mn ORIYA SIGN NUKTA
+0B3D ; XID_Continue # Lo ORIYA SIGN AVAGRAHA
+0B3E ; XID_Continue # Mc ORIYA VOWEL SIGN AA
+0B3F ; XID_Continue # Mn ORIYA VOWEL SIGN I
+0B40 ; XID_Continue # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; XID_Continue # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; XID_Continue # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; XID_Continue # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B4D ; XID_Continue # Mn ORIYA SIGN VIRAMA
+0B56 ; XID_Continue # Mn ORIYA AI LENGTH MARK
+0B57 ; XID_Continue # Mc ORIYA AU LENGTH MARK
+0B5C..0B5D ; XID_Continue # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; XID_Continue # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B62..0B63 ; XID_Continue # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B66..0B6F ; XID_Continue # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0B71 ; XID_Continue # Lo ORIYA LETTER WA
+0B82 ; XID_Continue # Mn TAMIL SIGN ANUSVARA
+0B83 ; XID_Continue # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; XID_Continue # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; XID_Continue # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; XID_Continue # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; XID_Continue # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; XID_Continue # Lo TAMIL LETTER JA
+0B9E..0B9F ; XID_Continue # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; XID_Continue # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; XID_Continue # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; XID_Continue # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBE..0BBF ; XID_Continue # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; XID_Continue # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; XID_Continue # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; XID_Continue # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; XID_Continue # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BCD ; XID_Continue # Mn TAMIL SIGN VIRAMA
+0BD0 ; XID_Continue # Lo TAMIL OM
+0BD7 ; XID_Continue # Mc TAMIL AU LENGTH MARK
+0BE6..0BEF ; XID_Continue # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0C00 ; XID_Continue # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C01..0C03 ; XID_Continue # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; XID_Continue # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; XID_Continue # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; XID_Continue # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; XID_Continue # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; XID_Continue # Lo TELUGU SIGN AVAGRAHA
+0C3E..0C40 ; XID_Continue # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; XID_Continue # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; XID_Continue # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; XID_Continue # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; XID_Continue # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C58..0C5A ; XID_Continue # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; XID_Continue # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C62..0C63 ; XID_Continue # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C66..0C6F ; XID_Continue # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0C80 ; XID_Continue # Lo KANNADA SIGN SPACING CANDRABINDU
+0C81 ; XID_Continue # Mn KANNADA SIGN CANDRABINDU
+0C82..0C83 ; XID_Continue # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; XID_Continue # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; XID_Continue # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; XID_Continue # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; XID_Continue # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; XID_Continue # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBC ; XID_Continue # Mn KANNADA SIGN NUKTA
+0CBD ; XID_Continue # Lo KANNADA SIGN AVAGRAHA
+0CBE ; XID_Continue # Mc KANNADA VOWEL SIGN AA
+0CBF ; XID_Continue # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; XID_Continue # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; XID_Continue # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; XID_Continue # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; XID_Continue # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC..0CCD ; XID_Continue # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; XID_Continue # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CDE ; XID_Continue # Lo KANNADA LETTER FA
+0CE0..0CE1 ; XID_Continue # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE2..0CE3 ; XID_Continue # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CE6..0CEF ; XID_Continue # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0CF1..0CF2 ; XID_Continue # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D01 ; XID_Continue # Mn MALAYALAM SIGN CANDRABINDU
+0D02..0D03 ; XID_Continue # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; XID_Continue # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; XID_Continue # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; XID_Continue # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; XID_Continue # Lo MALAYALAM SIGN AVAGRAHA
+0D3E..0D40 ; XID_Continue # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; XID_Continue # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; XID_Continue # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; XID_Continue # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4D ; XID_Continue # Mn MALAYALAM SIGN VIRAMA
+0D4E ; XID_Continue # Lo MALAYALAM LETTER DOT REPH
+0D54..0D56 ; XID_Continue # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D57 ; XID_Continue # Mc MALAYALAM AU LENGTH MARK
+0D5F..0D61 ; XID_Continue # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D62..0D63 ; XID_Continue # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D66..0D6F ; XID_Continue # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0D7A..0D7F ; XID_Continue # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D82..0D83 ; XID_Continue # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; XID_Continue # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; XID_Continue # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; XID_Continue # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; XID_Continue # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; XID_Continue # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DCA ; XID_Continue # Mn SINHALA SIGN AL-LAKUNA
+0DCF..0DD1 ; XID_Continue # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; XID_Continue # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; XID_Continue # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; XID_Continue # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DE6..0DEF ; XID_Continue # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+0DF2..0DF3 ; XID_Continue # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0E01..0E30 ; XID_Continue # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E31 ; XID_Continue # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; XID_Continue # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E3A ; XID_Continue # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E40..0E45 ; XID_Continue # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; XID_Continue # Lm THAI CHARACTER MAIYAMOK
+0E47..0E4E ; XID_Continue # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0E50..0E59 ; XID_Continue # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0E81..0E82 ; XID_Continue # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; XID_Continue # Lo LAO LETTER KHO TAM
+0E87..0E88 ; XID_Continue # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; XID_Continue # Lo LAO LETTER SO TAM
+0E8D ; XID_Continue # Lo LAO LETTER NYO
+0E94..0E97 ; XID_Continue # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; XID_Continue # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; XID_Continue # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; XID_Continue # Lo LAO LETTER LO LOOT
+0EA7 ; XID_Continue # Lo LAO LETTER WO
+0EAA..0EAB ; XID_Continue # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; XID_Continue # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB1 ; XID_Continue # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; XID_Continue # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB9 ; XID_Continue # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; XID_Continue # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EBD ; XID_Continue # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; XID_Continue # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; XID_Continue # Lm LAO KO LA
+0EC8..0ECD ; XID_Continue # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0ED0..0ED9 ; XID_Continue # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0EDC..0EDF ; XID_Continue # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; XID_Continue # Lo TIBETAN SYLLABLE OM
+0F18..0F19 ; XID_Continue # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F20..0F29 ; XID_Continue # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+0F35 ; XID_Continue # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; XID_Continue # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; XID_Continue # Mn TIBETAN MARK TSA -PHRU
+0F3E..0F3F ; XID_Continue # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F40..0F47 ; XID_Continue # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; XID_Continue # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F71..0F7E ; XID_Continue # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F7F ; XID_Continue # Mc TIBETAN SIGN RNAM BCAD
+0F80..0F84 ; XID_Continue # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; XID_Continue # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F88..0F8C ; XID_Continue # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+0F8D..0F97 ; XID_Continue # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; XID_Continue # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; XID_Continue # Mn TIBETAN SYMBOL PADMA GDAN
+1000..102A ; XID_Continue # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; XID_Continue # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; XID_Continue # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; XID_Continue # Mc MYANMAR VOWEL SIGN E
+1032..1037 ; XID_Continue # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1038 ; XID_Continue # Mc MYANMAR SIGN VISARGA
+1039..103A ; XID_Continue # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103B..103C ; XID_Continue # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; XID_Continue # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+103F ; XID_Continue # Lo MYANMAR LETTER GREAT SA
+1040..1049 ; XID_Continue # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+1050..1055 ; XID_Continue # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; XID_Continue # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; XID_Continue # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105A..105D ; XID_Continue # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+105E..1060 ; XID_Continue # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1061 ; XID_Continue # Lo MYANMAR LETTER SGAW KAREN SHA
+1062..1064 ; XID_Continue # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1065..1066 ; XID_Continue # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..106D ; XID_Continue # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+106E..1070 ; XID_Continue # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1071..1074 ; XID_Continue # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1075..1081 ; XID_Continue # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1082 ; XID_Continue # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; XID_Continue # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; XID_Continue # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+1087..108C ; XID_Continue # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108D ; XID_Continue # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+108E ; XID_Continue # Lo MYANMAR LETTER RUMAI PALAUNG FA
+108F ; XID_Continue # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+1090..1099 ; XID_Continue # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+109A..109C ; XID_Continue # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+109D ; XID_Continue # Mn MYANMAR VOWEL SIGN AITON AI
+10A0..10C5 ; XID_Continue # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; XID_Continue # L& GEORGIAN CAPITAL LETTER YN
+10CD ; XID_Continue # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; XID_Continue # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; XID_Continue # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; XID_Continue # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; XID_Continue # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; XID_Continue # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; XID_Continue # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; XID_Continue # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; XID_Continue # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; XID_Continue # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; XID_Continue # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; XID_Continue # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+135D..135F ; XID_Continue # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+1369..1371 ; XID_Continue # No [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE
+1380..138F ; XID_Continue # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F5 ; XID_Continue # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; XID_Continue # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1401..166C ; XID_Continue # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..167F ; XID_Continue # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1681..169A ; XID_Continue # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; XID_Continue # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; XID_Continue # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; XID_Continue # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; XID_Continue # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; XID_Continue # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1712..1714 ; XID_Continue # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1720..1731 ; XID_Continue # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1732..1734 ; XID_Continue # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1740..1751 ; XID_Continue # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1752..1753 ; XID_Continue # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1760..176C ; XID_Continue # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; XID_Continue # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1772..1773 ; XID_Continue # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+1780..17B3 ; XID_Continue # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B4..17B5 ; XID_Continue # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B6 ; XID_Continue # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; XID_Continue # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; XID_Continue # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; XID_Continue # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; XID_Continue # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17C9..17D3 ; XID_Continue # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17D7 ; XID_Continue # Lm KHMER SIGN LEK TOO
+17DC ; XID_Continue # Lo KHMER SIGN AVAKRAHASANYA
+17DD ; XID_Continue # Mn KHMER SIGN ATTHACAN
+17E0..17E9 ; XID_Continue # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+180B..180D ; XID_Continue # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+1810..1819 ; XID_Continue # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1820..1842 ; XID_Continue # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; XID_Continue # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; XID_Continue # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; XID_Continue # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1885..1886 ; XID_Continue # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+1887..18A8 ; XID_Continue # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18A9 ; XID_Continue # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+18AA ; XID_Continue # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; XID_Continue # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; XID_Continue # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1920..1922 ; XID_Continue # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; XID_Continue # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; XID_Continue # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; XID_Continue # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; XID_Continue # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; XID_Continue # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; XID_Continue # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1939..193B ; XID_Continue # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1946..194F ; XID_Continue # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+1950..196D ; XID_Continue # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; XID_Continue # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; XID_Continue # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; XID_Continue # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+19D0..19D9 ; XID_Continue # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+19DA ; XID_Continue # No NEW TAI LUE THAM DIGIT ONE
+1A00..1A16 ; XID_Continue # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A17..1A18 ; XID_Continue # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A19..1A1A ; XID_Continue # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+1A1B ; XID_Continue # Mn BUGINESE VOWEL SIGN AE
+1A20..1A54 ; XID_Continue # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1A55 ; XID_Continue # Mc TAI THAM CONSONANT SIGN MEDIAL RA
+1A56 ; XID_Continue # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A57 ; XID_Continue # Mc TAI THAM CONSONANT SIGN LA TANG LAI
+1A58..1A5E ; XID_Continue # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A60 ; XID_Continue # Mn TAI THAM SIGN SAKOT
+1A61 ; XID_Continue # Mc TAI THAM VOWEL SIGN A
+1A62 ; XID_Continue # Mn TAI THAM VOWEL SIGN MAI SAT
+1A63..1A64 ; XID_Continue # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+1A65..1A6C ; XID_Continue # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A6D..1A72 ; XID_Continue # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+1A73..1A7C ; XID_Continue # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F ; XID_Continue # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+1A80..1A89 ; XID_Continue # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+1A90..1A99 ; XID_Continue # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+1AA7 ; XID_Continue # Lm TAI THAM SIGN MAI YAMOK
+1AB0..1ABD ; XID_Continue # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+1B00..1B03 ; XID_Continue # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; XID_Continue # Mc BALINESE SIGN BISAH
+1B05..1B33 ; XID_Continue # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B34 ; XID_Continue # Mn BALINESE SIGN REREKAN
+1B35 ; XID_Continue # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; XID_Continue # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; XID_Continue # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; XID_Continue # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; XID_Continue # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; XID_Continue # Mn BALINESE VOWEL SIGN PEPET
+1B43..1B44 ; XID_Continue # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B45..1B4B ; XID_Continue # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B50..1B59 ; XID_Continue # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1B6B..1B73 ; XID_Continue # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; XID_Continue # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; XID_Continue # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; XID_Continue # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; XID_Continue # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; XID_Continue # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; XID_Continue # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; XID_Continue # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAA ; XID_Continue # Mc SUNDANESE SIGN PAMAAEH
+1BAB..1BAD ; XID_Continue # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BAE..1BAF ; XID_Continue # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BB0..1BB9 ; XID_Continue # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1BBA..1BE5 ; XID_Continue # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1BE6 ; XID_Continue # Mn BATAK SIGN TOMPI
+1BE7 ; XID_Continue # Mc BATAK VOWEL SIGN E
+1BE8..1BE9 ; XID_Continue # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BEA..1BEC ; XID_Continue # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+1BED ; XID_Continue # Mn BATAK VOWEL SIGN KARO O
+1BEE ; XID_Continue # Mc BATAK VOWEL SIGN U
+1BEF..1BF1 ; XID_Continue # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1BF2..1BF3 ; XID_Continue # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+1C00..1C23 ; XID_Continue # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; XID_Continue # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; XID_Continue # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; XID_Continue # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C36..1C37 ; XID_Continue # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1C40..1C49 ; XID_Continue # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C4D..1C4F ; XID_Continue # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C50..1C59 ; XID_Continue # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+1C5A..1C77 ; XID_Continue # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; XID_Continue # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C80..1C88 ; XID_Continue # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CD0..1CD2 ; XID_Continue # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+1CD4..1CE0 ; XID_Continue # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+1CE1 ; XID_Continue # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+1CE2..1CE8 ; XID_Continue # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+1CE9..1CEC ; XID_Continue # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CED ; XID_Continue # Mn VEDIC SIGN TIRYAK
+1CEE..1CF1 ; XID_Continue # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF2..1CF3 ; XID_Continue # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF4 ; XID_Continue # Mn VEDIC TONE CANDRA ABOVE
+1CF5..1CF6 ; XID_Continue # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1CF8..1CF9 ; XID_Continue # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+1D00..1D2B ; XID_Continue # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; XID_Continue # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; XID_Continue # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; XID_Continue # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; XID_Continue # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; XID_Continue # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1DC0..1DF5 ; XID_Continue # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
+1DFB..1DFF ; XID_Continue # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+1E00..1F15 ; XID_Continue # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; XID_Continue # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; XID_Continue # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; XID_Continue # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; XID_Continue # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; XID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; XID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; XID_Continue # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; XID_Continue # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; XID_Continue # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; XID_Continue # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE ; XID_Continue # L& GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; XID_Continue # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; XID_Continue # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD0..1FD3 ; XID_Continue # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; XID_Continue # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE0..1FEC ; XID_Continue # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2..1FF4 ; XID_Continue # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; XID_Continue # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+203F..2040 ; XID_Continue # Pc [2] UNDERTIE..CHARACTER TIE
+2054 ; XID_Continue # Pc INVERTED UNDERTIE
+2071 ; XID_Continue # Lm SUPERSCRIPT LATIN SMALL LETTER I
+207F ; XID_Continue # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2090..209C ; XID_Continue # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+20D0..20DC ; XID_Continue # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20E1 ; XID_Continue # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E5..20F0 ; XID_Continue # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2102 ; XID_Continue # L& DOUBLE-STRUCK CAPITAL C
+2107 ; XID_Continue # L& EULER CONSTANT
+210A..2113 ; XID_Continue # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2115 ; XID_Continue # L& DOUBLE-STRUCK CAPITAL N
+2118 ; XID_Continue # Sm SCRIPT CAPITAL P
+2119..211D ; XID_Continue # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; XID_Continue # L& DOUBLE-STRUCK CAPITAL Z
+2126 ; XID_Continue # L& OHM SIGN
+2128 ; XID_Continue # L& BLACK-LETTER CAPITAL Z
+212A..212D ; XID_Continue # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; XID_Continue # So ESTIMATED SYMBOL
+212F..2134 ; XID_Continue # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; XID_Continue # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; XID_Continue # L& INFORMATION SOURCE
+213C..213F ; XID_Continue # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2145..2149 ; XID_Continue # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; XID_Continue # L& TURNED SMALL F
+2160..2182 ; XID_Continue # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; XID_Continue # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; XID_Continue # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2C00..2C2E ; XID_Continue # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; XID_Continue # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; XID_Continue # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; XID_Continue # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; XID_Continue # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CEB..2CEE ; XID_Continue # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CEF..2CF1 ; XID_Continue # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+2CF2..2CF3 ; XID_Continue # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2D00..2D25 ; XID_Continue # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; XID_Continue # L& GEORGIAN SMALL LETTER YN
+2D2D ; XID_Continue # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; XID_Continue # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; XID_Continue # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D7F ; XID_Continue # Mn TIFINAGH CONSONANT JOINER
+2D80..2D96 ; XID_Continue # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2DE0..2DFF ; XID_Continue # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+3005 ; XID_Continue # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; XID_Continue # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; XID_Continue # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; XID_Continue # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+302A..302D ; XID_Continue # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+302E..302F ; XID_Continue # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3031..3035 ; XID_Continue # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3038..303A ; XID_Continue # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; XID_Continue # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; XID_Continue # Lo MASU MARK
+3041..3096 ; XID_Continue # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+3099..309A ; XID_Continue # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; XID_Continue # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; XID_Continue # Lo HIRAGANA DIGRAPH YORI
+30A1..30FA ; XID_Continue # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FC..30FE ; XID_Continue # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; XID_Continue # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; XID_Continue # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; XID_Continue # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31BA ; XID_Continue # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31F0..31FF ; XID_Continue # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; XID_Continue # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FD5 ; XID_Continue # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; XID_Continue # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; XID_Continue # Lm YI SYLLABLE WU
+A016..A48C ; XID_Continue # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A4D0..A4F7 ; XID_Continue # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; XID_Continue # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A500..A60B ; XID_Continue # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; XID_Continue # Lm VAI SYLLABLE LENGTHENER
+A610..A61F ; XID_Continue # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A620..A629 ; XID_Continue # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A62A..A62B ; XID_Continue # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; XID_Continue # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; XID_Continue # Lo CYRILLIC LETTER MULTIOCULAR O
+A66F ; XID_Continue # Mn COMBINING CYRILLIC VZMET
+A674..A67D ; XID_Continue # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+A67F ; XID_Continue # Lm CYRILLIC PAYEROK
+A680..A69B ; XID_Continue # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; XID_Continue # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A69E..A69F ; XID_Continue # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6A0..A6E5 ; XID_Continue # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; XID_Continue # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A6F0..A6F1 ; XID_Continue # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+A717..A71F ; XID_Continue # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A722..A76F ; XID_Continue # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; XID_Continue # Lm MODIFIER LETTER US
+A771..A787 ; XID_Continue # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; XID_Continue # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A78B..A78E ; XID_Continue # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; XID_Continue # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; XID_Continue # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; XID_Continue # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; XID_Continue # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; XID_Continue # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; XID_Continue # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; XID_Continue # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A802 ; XID_Continue # Mn SYLOTI NAGRI SIGN DVISVARA
+A803..A805 ; XID_Continue # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A806 ; XID_Continue # Mn SYLOTI NAGRI SIGN HASANTA
+A807..A80A ; XID_Continue # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80B ; XID_Continue # Mn SYLOTI NAGRI SIGN ANUSVARA
+A80C..A822 ; XID_Continue # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; XID_Continue # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; XID_Continue # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; XID_Continue # Mc SYLOTI NAGRI VOWEL SIGN OO
+A840..A873 ; XID_Continue # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A880..A881 ; XID_Continue # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; XID_Continue # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; XID_Continue # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8C4..A8C5 ; XID_Continue # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+A8D0..A8D9 ; XID_Continue # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A8E0..A8F1 ; XID_Continue # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A8F2..A8F7 ; XID_Continue # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8FB ; XID_Continue # Lo DEVANAGARI HEADSTROKE
+A8FD ; XID_Continue # Lo DEVANAGARI JAIN OM
+A900..A909 ; XID_Continue # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A90A..A925 ; XID_Continue # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A926..A92D ; XID_Continue # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A930..A946 ; XID_Continue # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A947..A951 ; XID_Continue # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952..A953 ; XID_Continue # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+A960..A97C ; XID_Continue # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A980..A982 ; XID_Continue # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A983 ; XID_Continue # Mc JAVANESE SIGN WIGNYAN
+A984..A9B2 ; XID_Continue # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9B3 ; XID_Continue # Mn JAVANESE SIGN CECAK TELU
+A9B4..A9B5 ; XID_Continue # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+A9B6..A9B9 ; XID_Continue # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BA..A9BB ; XID_Continue # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+A9BC ; XID_Continue # Mn JAVANESE VOWEL SIGN PEPET
+A9BD..A9C0 ; XID_Continue # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON
+A9CF ; XID_Continue # Lm JAVANESE PANGRANGKEP
+A9D0..A9D9 ; XID_Continue # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+A9E0..A9E4 ; XID_Continue # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E5 ; XID_Continue # Mn MYANMAR SIGN SHAN SAW
+A9E6 ; XID_Continue # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; XID_Continue # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9F0..A9F9 ; XID_Continue # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+A9FA..A9FE ; XID_Continue # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; XID_Continue # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA29..AA2E ; XID_Continue # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; XID_Continue # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; XID_Continue # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; XID_Continue # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; XID_Continue # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA40..AA42 ; XID_Continue # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA43 ; XID_Continue # Mn CHAM CONSONANT SIGN FINAL NG
+AA44..AA4B ; XID_Continue # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4C ; XID_Continue # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; XID_Continue # Mc CHAM CONSONANT SIGN FINAL H
+AA50..AA59 ; XID_Continue # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+AA60..AA6F ; XID_Continue # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; XID_Continue # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; XID_Continue # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA7A ; XID_Continue # Lo MYANMAR LETTER AITON RA
+AA7B ; XID_Continue # Mc MYANMAR SIGN PAO KAREN TONE
+AA7C ; XID_Continue # Mn MYANMAR SIGN TAI LAING TONE-2
+AA7D ; XID_Continue # Mc MYANMAR SIGN TAI LAING TONE-5
+AA7E..AAAF ; XID_Continue # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB0 ; XID_Continue # Mn TAI VIET MAI KANG
+AAB1 ; XID_Continue # Lo TAI VIET VOWEL AA
+AAB2..AAB4 ; XID_Continue # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB5..AAB6 ; XID_Continue # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB7..AAB8 ; XID_Continue # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AAB9..AABD ; XID_Continue # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AABE..AABF ; XID_Continue # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+AAC0 ; XID_Continue # Lo TAI VIET TONE MAI NUENG
+AAC1 ; XID_Continue # Mn TAI VIET TONE MAI THO
+AAC2 ; XID_Continue # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; XID_Continue # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; XID_Continue # Lm TAI VIET SYMBOL SAM
+AAE0..AAEA ; XID_Continue # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAEB ; XID_Continue # Mc MEETEI MAYEK VOWEL SIGN II
+AAEC..AAED ; XID_Continue # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAEE..AAEF ; XID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+AAF2 ; XID_Continue # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; XID_Continue # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AAF5 ; XID_Continue # Mc MEETEI MAYEK VOWEL SIGN VISARGA
+AAF6 ; XID_Continue # Mn MEETEI MAYEK VIRAMA
+AB01..AB06 ; XID_Continue # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; XID_Continue # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; XID_Continue # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; XID_Continue # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; XID_Continue # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5C..AB5F ; XID_Continue # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; XID_Continue # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; XID_Continue # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; XID_Continue # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ABE3..ABE4 ; XID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ABE5 ; XID_Continue # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE6..ABE7 ; XID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ABE8 ; XID_Continue # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABE9..ABEA ; XID_Continue # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ABEC ; XID_Continue # Mc MEETEI MAYEK LUM IYEK
+ABED ; XID_Continue # Mn MEETEI MAYEK APUN IYEK
+ABF0..ABF9 ; XID_Continue # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+AC00..D7A3 ; XID_Continue # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; XID_Continue # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; XID_Continue # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; XID_Continue # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; XID_Continue # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; XID_Continue # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; XID_Continue # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; XID_Continue # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1E ; XID_Continue # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FB1F..FB28 ; XID_Continue # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; XID_Continue # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; XID_Continue # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; XID_Continue # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; XID_Continue # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; XID_Continue # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; XID_Continue # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FC5D ; XID_Continue # Lo [139] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM
+FC64..FD3D ; XID_Continue # Lo [218] ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; XID_Continue # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; XID_Continue # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDF9 ; XID_Continue # Lo [10] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE SALLA ISOLATED FORM
+FE00..FE0F ; XID_Continue # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE2F ; XID_Continue # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+FE33..FE34 ; XID_Continue # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE4D..FE4F ; XID_Continue # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FE71 ; XID_Continue # Lo ARABIC TATWEEL WITH FATHATAN ABOVE
+FE73 ; XID_Continue # Lo ARABIC TAIL FRAGMENT
+FE77 ; XID_Continue # Lo ARABIC FATHA MEDIAL FORM
+FE79 ; XID_Continue # Lo ARABIC DAMMA MEDIAL FORM
+FE7B ; XID_Continue # Lo ARABIC KASRA MEDIAL FORM
+FE7D ; XID_Continue # Lo ARABIC SHADDA MEDIAL FORM
+FE7F..FEFC ; XID_Continue # Lo [126] ARABIC SUKUN MEDIAL FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF10..FF19 ; XID_Continue # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+FF21..FF3A ; XID_Continue # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF3F ; XID_Continue # Pc FULLWIDTH LOW LINE
+FF41..FF5A ; XID_Continue # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF66..FF6F ; XID_Continue # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; XID_Continue # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; XID_Continue # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FF9E..FF9F ; XID_Continue # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFA0..FFBE ; XID_Continue # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; XID_Continue # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; XID_Continue # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; XID_Continue # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; XID_Continue # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; XID_Continue # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; XID_Continue # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; XID_Continue # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; XID_Continue # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; XID_Continue # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; XID_Continue # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; XID_Continue # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10140..10174 ; XID_Continue # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+101FD ; XID_Continue # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+10280..1029C ; XID_Continue # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; XID_Continue # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+102E0 ; XID_Continue # Mn COPTIC EPACT THOUSANDS MARK
+10300..1031F ; XID_Continue # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10330..10340 ; XID_Continue # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; XID_Continue # Nl GOTHIC LETTER NINETY
+10342..10349 ; XID_Continue # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; XID_Continue # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; XID_Continue # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10376..1037A ; XID_Continue # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10380..1039D ; XID_Continue # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; XID_Continue # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; XID_Continue # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D1..103D5 ; XID_Continue # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; XID_Continue # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; XID_Continue # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104A0..104A9 ; XID_Continue # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+104B0..104D3 ; XID_Continue # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; XID_Continue # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; XID_Continue # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; XID_Continue # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+10600..10736 ; XID_Continue # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; XID_Continue # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; XID_Continue # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; XID_Continue # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; XID_Continue # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; XID_Continue # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; XID_Continue # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; XID_Continue # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; XID_Continue # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10860..10876 ; XID_Continue # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10880..1089E ; XID_Continue # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108E0..108F2 ; XID_Continue # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; XID_Continue # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+10900..10915 ; XID_Continue # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; XID_Continue # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10980..109B7 ; XID_Continue # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BE..109BF ; XID_Continue # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+10A00 ; XID_Continue # Lo KHAROSHTHI LETTER A
+10A01..10A03 ; XID_Continue # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; XID_Continue # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; XID_Continue # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A10..10A13 ; XID_Continue # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; XID_Continue # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; XID_Continue # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A38..10A3A ; XID_Continue # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; XID_Continue # Mn KHAROSHTHI VIRAMA
+10A60..10A7C ; XID_Continue # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A80..10A9C ; XID_Continue # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10AC0..10AC7 ; XID_Continue # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC9..10AE4 ; XID_Continue # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10AE5..10AE6 ; XID_Continue # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10B00..10B35 ; XID_Continue # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B40..10B55 ; XID_Continue # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B60..10B72 ; XID_Continue # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B80..10B91 ; XID_Continue # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10C00..10C48 ; XID_Continue # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; XID_Continue # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; XID_Continue # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+11000 ; XID_Continue # Mc BRAHMI SIGN CANDRABINDU
+11001 ; XID_Continue # Mn BRAHMI SIGN ANUSVARA
+11002 ; XID_Continue # Mc BRAHMI SIGN VISARGA
+11003..11037 ; XID_Continue # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11038..11046 ; XID_Continue # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+11066..1106F ; XID_Continue # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+1107F..11081 ; XID_Continue # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+11082 ; XID_Continue # Mc KAITHI SIGN VISARGA
+11083..110AF ; XID_Continue # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110B0..110B2 ; XID_Continue # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+110B3..110B6 ; XID_Continue # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B7..110B8 ; XID_Continue # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+110B9..110BA ; XID_Continue # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+110D0..110E8 ; XID_Continue # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+110F0..110F9 ; XID_Continue # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+11100..11102 ; XID_Continue # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11103..11126 ; XID_Continue # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+11127..1112B ; XID_Continue # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112C ; XID_Continue # Mc CHAKMA VOWEL SIGN E
+1112D..11134 ; XID_Continue # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+11136..1113F ; XID_Continue # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+11150..11172 ; XID_Continue # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11173 ; XID_Continue # Mn MAHAJANI SIGN NUKTA
+11176 ; XID_Continue # Lo MAHAJANI LIGATURE SHRI
+11180..11181 ; XID_Continue # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+11182 ; XID_Continue # Mc SHARADA SIGN VISARGA
+11183..111B2 ; XID_Continue # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111B3..111B5 ; XID_Continue # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+111B6..111BE ; XID_Continue # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111BF..111C0 ; XID_Continue # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+111C1..111C4 ; XID_Continue # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111CA..111CC ; XID_Continue # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+111D0..111D9 ; XID_Continue # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+111DA ; XID_Continue # Lo SHARADA EKAM
+111DC ; XID_Continue # Lo SHARADA HEADSTROKE
+11200..11211 ; XID_Continue # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; XID_Continue # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+1122C..1122E ; XID_Continue # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+1122F..11231 ; XID_Continue # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11232..11233 ; XID_Continue # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+11234 ; XID_Continue # Mn KHOJKI SIGN ANUSVARA
+11235 ; XID_Continue # Mc KHOJKI SIGN VIRAMA
+11236..11237 ; XID_Continue # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+1123E ; XID_Continue # Mn KHOJKI SIGN SUKUN
+11280..11286 ; XID_Continue # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; XID_Continue # Lo MULTANI LETTER GHA
+1128A..1128D ; XID_Continue # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; XID_Continue # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; XID_Continue # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112B0..112DE ; XID_Continue # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+112DF ; XID_Continue # Mn KHUDAWADI SIGN ANUSVARA
+112E0..112E2 ; XID_Continue # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+112E3..112EA ; XID_Continue # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+112F0..112F9 ; XID_Continue # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+11300..11301 ; XID_Continue # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+11302..11303 ; XID_Continue # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+11305..1130C ; XID_Continue # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; XID_Continue # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; XID_Continue # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; XID_Continue # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; XID_Continue # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; XID_Continue # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133C ; XID_Continue # Mn GRANTHA SIGN NUKTA
+1133D ; XID_Continue # Lo GRANTHA SIGN AVAGRAHA
+1133E..1133F ; XID_Continue # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
+11340 ; XID_Continue # Mn GRANTHA VOWEL SIGN II
+11341..11344 ; XID_Continue # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+11347..11348 ; XID_Continue # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+1134B..1134D ; XID_Continue # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+11350 ; XID_Continue # Lo GRANTHA OM
+11357 ; XID_Continue # Mc GRANTHA AU LENGTH MARK
+1135D..11361 ; XID_Continue # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11362..11363 ; XID_Continue # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+11366..1136C ; XID_Continue # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+11370..11374 ; XID_Continue # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+11400..11434 ; XID_Continue # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11435..11437 ; XID_Continue # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+11438..1143F ; XID_Continue # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11440..11441 ; XID_Continue # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+11442..11444 ; XID_Continue # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+11445 ; XID_Continue # Mc NEWA SIGN VISARGA
+11446 ; XID_Continue # Mn NEWA SIGN NUKTA
+11447..1144A ; XID_Continue # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+11450..11459 ; XID_Continue # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+11480..114AF ; XID_Continue # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114B0..114B2 ; XID_Continue # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
+114B3..114B8 ; XID_Continue # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114B9 ; XID_Continue # Mc TIRHUTA VOWEL SIGN E
+114BA ; XID_Continue # Mn TIRHUTA VOWEL SIGN SHORT E
+114BB..114BE ; XID_Continue # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
+114BF..114C0 ; XID_Continue # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C1 ; XID_Continue # Mc TIRHUTA SIGN VISARGA
+114C2..114C3 ; XID_Continue # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+114C4..114C5 ; XID_Continue # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C7 ; XID_Continue # Lo TIRHUTA OM
+114D0..114D9 ; XID_Continue # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+11580..115AE ; XID_Continue # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115AF..115B1 ; XID_Continue # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
+115B2..115B5 ; XID_Continue # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115B8..115BB ; XID_Continue # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+115BC..115BD ; XID_Continue # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BE ; XID_Continue # Mc SIDDHAM SIGN VISARGA
+115BF..115C0 ; XID_Continue # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+115D8..115DB ; XID_Continue # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+115DC..115DD ; XID_Continue # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11600..1162F ; XID_Continue # Lo [48] MODI LETTER A..MODI LETTER LLA
+11630..11632 ; XID_Continue # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+11633..1163A ; XID_Continue # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163B..1163C ; XID_Continue # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+1163D ; XID_Continue # Mn MODI SIGN ANUSVARA
+1163E ; XID_Continue # Mc MODI SIGN VISARGA
+1163F..11640 ; XID_Continue # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+11644 ; XID_Continue # Lo MODI SIGN HUVA
+11650..11659 ; XID_Continue # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+11680..116AA ; XID_Continue # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+116AB ; XID_Continue # Mn TAKRI SIGN ANUSVARA
+116AC ; XID_Continue # Mc TAKRI SIGN VISARGA
+116AD ; XID_Continue # Mn TAKRI VOWEL SIGN AA
+116AE..116AF ; XID_Continue # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+116B0..116B5 ; XID_Continue # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+116B6 ; XID_Continue # Mc TAKRI SIGN VIRAMA
+116B7 ; XID_Continue # Mn TAKRI SIGN NUKTA
+116C0..116C9 ; XID_Continue # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+11700..11719 ; XID_Continue # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+1171D..1171F ; XID_Continue # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11720..11721 ; XID_Continue # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+11722..11725 ; XID_Continue # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11726 ; XID_Continue # Mc AHOM VOWEL SIGN E
+11727..1172B ; XID_Continue # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+11730..11739 ; XID_Continue # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+118A0..118DF ; XID_Continue # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118E0..118E9 ; XID_Continue # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+118FF ; XID_Continue # Lo WARANG CITI OM
+11AC0..11AF8 ; XID_Continue # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; XID_Continue # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; XID_Continue # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C2F ; XID_Continue # Mc BHAIKSUKI VOWEL SIGN AA
+11C30..11C36 ; XID_Continue # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; XID_Continue # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3E ; XID_Continue # Mc BHAIKSUKI SIGN VISARGA
+11C3F ; XID_Continue # Mn BHAIKSUKI SIGN VIRAMA
+11C40 ; XID_Continue # Lo BHAIKSUKI SIGN AVAGRAHA
+11C50..11C59 ; XID_Continue # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+11C72..11C8F ; XID_Continue # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+11C92..11CA7 ; XID_Continue # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CA9 ; XID_Continue # Mc MARCHEN SUBJOINED LETTER YA
+11CAA..11CB0 ; XID_Continue # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB1 ; XID_Continue # Mc MARCHEN VOWEL SIGN I
+11CB2..11CB3 ; XID_Continue # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB4 ; XID_Continue # Mc MARCHEN VOWEL SIGN O
+11CB5..11CB6 ; XID_Continue # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+12000..12399 ; XID_Continue # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; XID_Continue # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12480..12543 ; XID_Continue # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; XID_Continue # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; XID_Continue # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; XID_Continue # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; XID_Continue # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16A60..16A69 ; XID_Continue # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+16AD0..16AED ; XID_Continue # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16AF0..16AF4 ; XID_Continue # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+16B00..16B2F ; XID_Continue # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B30..16B36 ; XID_Continue # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16B40..16B43 ; XID_Continue # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B50..16B59 ; XID_Continue # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+16B63..16B77 ; XID_Continue # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; XID_Continue # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; XID_Continue # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; XID_Continue # Lo MIAO LETTER NASALIZATION
+16F51..16F7E ; XID_Continue # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
+16F8F..16F92 ; XID_Continue # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+16F93..16F9F ; XID_Continue # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; XID_Continue # Lm TANGUT ITERATION MARK
+17000..187EC ; XID_Continue # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; XID_Continue # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; XID_Continue # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; XID_Continue # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; XID_Continue # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; XID_Continue # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; XID_Continue # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1BC9D..1BC9E ; XID_Continue # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1D165..1D166 ; XID_Continue # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D167..1D169 ; XID_Continue # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D16D..1D172 ; XID_Continue # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+1D17B..1D182 ; XID_Continue # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; XID_Continue # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; XID_Continue # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; XID_Continue # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1D400..1D454 ; XID_Continue # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; XID_Continue # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; XID_Continue # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; XID_Continue # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; XID_Continue # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; XID_Continue # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; XID_Continue # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; XID_Continue # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; XID_Continue # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; XID_Continue # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; XID_Continue # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; XID_Continue # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; XID_Continue # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; XID_Continue # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; XID_Continue # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; XID_Continue # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; XID_Continue # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; XID_Continue # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; XID_Continue # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; XID_Continue # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C2..1D6DA ; XID_Continue # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6FA ; XID_Continue # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FC..1D714 ; XID_Continue # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D734 ; XID_Continue # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D736..1D74E ; XID_Continue # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D76E ; XID_Continue # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D770..1D788 ; XID_Continue # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D7A8 ; XID_Continue # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7AA..1D7C2 ; XID_Continue # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7CB ; XID_Continue # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; XID_Continue # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1DA00..1DA36 ; XID_Continue # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+1DA3B..1DA6C ; XID_Continue # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+1DA75 ; XID_Continue # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+1DA84 ; XID_Continue # Mn SIGNWRITING LOCATION HEAD NECK
+1DA9B..1DA9F ; XID_Continue # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+1DAA1..1DAAF ; XID_Continue # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+1E000..1E006 ; XID_Continue # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; XID_Continue # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; XID_Continue # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; XID_Continue # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; XID_Continue # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E800..1E8C4 ; XID_Continue # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E8D0..1E8D6 ; XID_Continue # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+1E900..1E943 ; XID_Continue # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E944..1E94A ; XID_Continue # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1E950..1E959 ; XID_Continue # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+1EE00..1EE03 ; XID_Continue # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; XID_Continue # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; XID_Continue # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; XID_Continue # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; XID_Continue # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; XID_Continue # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; XID_Continue # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; XID_Continue # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; XID_Continue # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; XID_Continue # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; XID_Continue # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; XID_Continue # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; XID_Continue # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; XID_Continue # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; XID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; XID_Continue # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; XID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; XID_Continue # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; XID_Continue # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; XID_Continue # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; XID_Continue # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; XID_Continue # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; XID_Continue # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; XID_Continue # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+20000..2A6D6 ; XID_Continue # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; XID_Continue # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; XID_Continue # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; XID_Continue # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; XID_Continue # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+E0100..E01EF ; XID_Continue # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 119672
+
+# ================================================
+
+# Derived Property: Default_Ignorable_Code_Point
+# Generated from
+# Other_Default_Ignorable_Code_Point
+# + Cf (Format characters)
+# + Variation_Selector
+# - White_Space
+# - FFF9..FFFB (Annotation Characters)
+# - 0600..0605, 06DD, 070F, 08E2, 110BD (exceptional Cf characters that should be visible)
+
+00AD ; Default_Ignorable_Code_Point # Cf SOFT HYPHEN
+034F ; Default_Ignorable_Code_Point # Mn COMBINING GRAPHEME JOINER
+061C ; Default_Ignorable_Code_Point # Cf ARABIC LETTER MARK
+115F..1160 ; Default_Ignorable_Code_Point # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
+17B4..17B5 ; Default_Ignorable_Code_Point # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+180B..180D ; Default_Ignorable_Code_Point # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180E ; Default_Ignorable_Code_Point # Cf MONGOLIAN VOWEL SEPARATOR
+200B..200F ; Default_Ignorable_Code_Point # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+202A..202E ; Default_Ignorable_Code_Point # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+2060..2064 ; Default_Ignorable_Code_Point # Cf [5] WORD JOINER..INVISIBLE PLUS
+2065 ; Default_Ignorable_Code_Point # Cn <reserved-2065>
+2066..206F ; Default_Ignorable_Code_Point # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+3164 ; Default_Ignorable_Code_Point # Lo HANGUL FILLER
+FE00..FE0F ; Default_Ignorable_Code_Point # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FEFF ; Default_Ignorable_Code_Point # Cf ZERO WIDTH NO-BREAK SPACE
+FFA0 ; Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER
+FFF0..FFF8 ; Default_Ignorable_Code_Point # Cn [9] <reserved-FFF0>..<reserved-FFF8>
+1BCA0..1BCA3 ; Default_Ignorable_Code_Point # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+1D173..1D17A ; Default_Ignorable_Code_Point # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+E0000 ; Default_Ignorable_Code_Point # Cn <reserved-E0000>
+E0001 ; Default_Ignorable_Code_Point # Cf LANGUAGE TAG
+E0002..E001F ; Default_Ignorable_Code_Point # Cn [30] <reserved-E0002>..<reserved-E001F>
+E0020..E007F ; Default_Ignorable_Code_Point # Cf [96] TAG SPACE..CANCEL TAG
+E0080..E00FF ; Default_Ignorable_Code_Point # Cn [128] <reserved-E0080>..<reserved-E00FF>
+E0100..E01EF ; Default_Ignorable_Code_Point # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+E01F0..E0FFF ; Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
+
+# Total code points: 4173
+
+# ================================================
+
+# Derived Property: Grapheme_Extend
+# Generated from: Me + Mn + Other_Grapheme_Extend
+# Note: depending on an application's interpretation of Co (private use),
+# they may be either in Grapheme_Base, or in Grapheme_Extend, or in neither.
+
+0300..036F ; Grapheme_Extend # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0483..0487 ; Grapheme_Extend # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0488..0489 ; Grapheme_Extend # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+0591..05BD ; Grapheme_Extend # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; Grapheme_Extend # Mn HEBREW POINT RAFE
+05C1..05C2 ; Grapheme_Extend # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Grapheme_Extend # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Grapheme_Extend # Mn HEBREW POINT QAMATS QATAN
+0610..061A ; Grapheme_Extend # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+064B..065F ; Grapheme_Extend # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW
+0670 ; Grapheme_Extend # Mn ARABIC LETTER SUPERSCRIPT ALEF
+06D6..06DC ; Grapheme_Extend # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E4 ; Grapheme_Extend # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E7..06E8 ; Grapheme_Extend # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; Grapheme_Extend # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+0711 ; Grapheme_Extend # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0730..074A ; Grapheme_Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+07A6..07B0 ; Grapheme_Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07EB..07F3 ; Grapheme_Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+0816..0819 ; Grapheme_Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
+081B..0823 ; Grapheme_Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
+0825..0827 ; Grapheme_Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
+0829..082D ; Grapheme_Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
+0859..085B ; Grapheme_Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
+08D4..08E1 ; Grapheme_Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08E3..0902 ; Grapheme_Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
+093A ; Grapheme_Extend # Mn DEVANAGARI VOWEL SIGN OE
+093C ; Grapheme_Extend # Mn DEVANAGARI SIGN NUKTA
+0941..0948 ; Grapheme_Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+094D ; Grapheme_Extend # Mn DEVANAGARI SIGN VIRAMA
+0951..0957 ; Grapheme_Extend # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE
+0962..0963 ; Grapheme_Extend # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0981 ; Grapheme_Extend # Mn BENGALI SIGN CANDRABINDU
+09BC ; Grapheme_Extend # Mn BENGALI SIGN NUKTA
+09BE ; Grapheme_Extend # Mc BENGALI VOWEL SIGN AA
+09C1..09C4 ; Grapheme_Extend # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09CD ; Grapheme_Extend # Mn BENGALI SIGN VIRAMA
+09D7 ; Grapheme_Extend # Mc BENGALI AU LENGTH MARK
+09E2..09E3 ; Grapheme_Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+0A01..0A02 ; Grapheme_Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A3C ; Grapheme_Extend # Mn GURMUKHI SIGN NUKTA
+0A41..0A42 ; Grapheme_Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Grapheme_Extend # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Grapheme_Extend # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Grapheme_Extend # Mn GURMUKHI SIGN UDAAT
+0A70..0A71 ; Grapheme_Extend # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A75 ; Grapheme_Extend # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; Grapheme_Extend # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0ABC ; Grapheme_Extend # Mn GUJARATI SIGN NUKTA
+0AC1..0AC5 ; Grapheme_Extend # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Grapheme_Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0ACD ; Grapheme_Extend # Mn GUJARATI SIGN VIRAMA
+0AE2..0AE3 ; Grapheme_Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0B01 ; Grapheme_Extend # Mn ORIYA SIGN CANDRABINDU
+0B3C ; Grapheme_Extend # Mn ORIYA SIGN NUKTA
+0B3E ; Grapheme_Extend # Mc ORIYA VOWEL SIGN AA
+0B3F ; Grapheme_Extend # Mn ORIYA VOWEL SIGN I
+0B41..0B44 ; Grapheme_Extend # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B4D ; Grapheme_Extend # Mn ORIYA SIGN VIRAMA
+0B56 ; Grapheme_Extend # Mn ORIYA AI LENGTH MARK
+0B57 ; Grapheme_Extend # Mc ORIYA AU LENGTH MARK
+0B62..0B63 ; Grapheme_Extend # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B82 ; Grapheme_Extend # Mn TAMIL SIGN ANUSVARA
+0BBE ; Grapheme_Extend # Mc TAMIL VOWEL SIGN AA
+0BC0 ; Grapheme_Extend # Mn TAMIL VOWEL SIGN II
+0BCD ; Grapheme_Extend # Mn TAMIL SIGN VIRAMA
+0BD7 ; Grapheme_Extend # Mc TAMIL AU LENGTH MARK
+0C00 ; Grapheme_Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C3E..0C40 ; Grapheme_Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C46..0C48 ; Grapheme_Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Grapheme_Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Grapheme_Extend # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C62..0C63 ; Grapheme_Extend # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C81 ; Grapheme_Extend # Mn KANNADA SIGN CANDRABINDU
+0CBC ; Grapheme_Extend # Mn KANNADA SIGN NUKTA
+0CBF ; Grapheme_Extend # Mn KANNADA VOWEL SIGN I
+0CC2 ; Grapheme_Extend # Mc KANNADA VOWEL SIGN UU
+0CC6 ; Grapheme_Extend # Mn KANNADA VOWEL SIGN E
+0CCC..0CCD ; Grapheme_Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; Grapheme_Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CE2..0CE3 ; Grapheme_Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0D01 ; Grapheme_Extend # Mn MALAYALAM SIGN CANDRABINDU
+0D3E ; Grapheme_Extend # Mc MALAYALAM VOWEL SIGN AA
+0D41..0D44 ; Grapheme_Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D4D ; Grapheme_Extend # Mn MALAYALAM SIGN VIRAMA
+0D57 ; Grapheme_Extend # Mc MALAYALAM AU LENGTH MARK
+0D62..0D63 ; Grapheme_Extend # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0DCA ; Grapheme_Extend # Mn SINHALA SIGN AL-LAKUNA
+0DCF ; Grapheme_Extend # Mc SINHALA VOWEL SIGN AELA-PILLA
+0DD2..0DD4 ; Grapheme_Extend # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Grapheme_Extend # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DDF ; Grapheme_Extend # Mc SINHALA VOWEL SIGN GAYANUKITTA
+0E31 ; Grapheme_Extend # Mn THAI CHARACTER MAI HAN-AKAT
+0E34..0E3A ; Grapheme_Extend # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E47..0E4E ; Grapheme_Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0EB1 ; Grapheme_Extend # Mn LAO VOWEL SIGN MAI KAN
+0EB4..0EB9 ; Grapheme_Extend # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Grapheme_Extend # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EC8..0ECD ; Grapheme_Extend # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0F18..0F19 ; Grapheme_Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; Grapheme_Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; Grapheme_Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; Grapheme_Extend # Mn TIBETAN MARK TSA -PHRU
+0F71..0F7E ; Grapheme_Extend # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F80..0F84 ; Grapheme_Extend # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; Grapheme_Extend # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F8D..0F97 ; Grapheme_Extend # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Grapheme_Extend # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; Grapheme_Extend # Mn TIBETAN SYMBOL PADMA GDAN
+102D..1030 ; Grapheme_Extend # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1032..1037 ; Grapheme_Extend # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1039..103A ; Grapheme_Extend # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103D..103E ; Grapheme_Extend # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+1058..1059 ; Grapheme_Extend # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105E..1060 ; Grapheme_Extend # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1071..1074 ; Grapheme_Extend # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1082 ; Grapheme_Extend # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1085..1086 ; Grapheme_Extend # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+108D ; Grapheme_Extend # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+109D ; Grapheme_Extend # Mn MYANMAR VOWEL SIGN AITON AI
+135D..135F ; Grapheme_Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK
+1712..1714 ; Grapheme_Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1732..1734 ; Grapheme_Extend # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1752..1753 ; Grapheme_Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1772..1773 ; Grapheme_Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+17B4..17B5 ; Grapheme_Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B7..17BD ; Grapheme_Extend # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17C6 ; Grapheme_Extend # Mn KHMER SIGN NIKAHIT
+17C9..17D3 ; Grapheme_Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17DD ; Grapheme_Extend # Mn KHMER SIGN ATTHACAN
+180B..180D ; Grapheme_Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+1885..1886 ; Grapheme_Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
+18A9 ; Grapheme_Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+1920..1922 ; Grapheme_Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1927..1928 ; Grapheme_Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1932 ; Grapheme_Extend # Mn LIMBU SMALL LETTER ANUSVARA
+1939..193B ; Grapheme_Extend # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1A17..1A18 ; Grapheme_Extend # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A1B ; Grapheme_Extend # Mn BUGINESE VOWEL SIGN AE
+1A56 ; Grapheme_Extend # Mn TAI THAM CONSONANT SIGN MEDIAL LA
+1A58..1A5E ; Grapheme_Extend # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA
+1A60 ; Grapheme_Extend # Mn TAI THAM SIGN SAKOT
+1A62 ; Grapheme_Extend # Mn TAI THAM VOWEL SIGN MAI SAT
+1A65..1A6C ; Grapheme_Extend # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW
+1A73..1A7C ; Grapheme_Extend # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN
+1A7F ; Grapheme_Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
+1AB0..1ABD ; Grapheme_Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
+1ABE ; Grapheme_Extend # Me COMBINING PARENTHESES OVERLAY
+1B00..1B03 ; Grapheme_Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B34 ; Grapheme_Extend # Mn BALINESE SIGN REREKAN
+1B36..1B3A ; Grapheme_Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3C ; Grapheme_Extend # Mn BALINESE VOWEL SIGN LA LENGA
+1B42 ; Grapheme_Extend # Mn BALINESE VOWEL SIGN PEPET
+1B6B..1B73 ; Grapheme_Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; Grapheme_Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1BA2..1BA5 ; Grapheme_Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA8..1BA9 ; Grapheme_Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAB..1BAD ; Grapheme_Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
+1BE6 ; Grapheme_Extend # Mn BATAK SIGN TOMPI
+1BE8..1BE9 ; Grapheme_Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
+1BED ; Grapheme_Extend # Mn BATAK VOWEL SIGN KARO O
+1BEF..1BF1 ; Grapheme_Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H
+1C2C..1C33 ; Grapheme_Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C36..1C37 ; Grapheme_Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1CD0..1CD2 ; Grapheme_Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
+1CD4..1CE0 ; Grapheme_Extend # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
+1CE2..1CE8 ; Grapheme_Extend # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
+1CED ; Grapheme_Extend # Mn VEDIC SIGN TIRYAK
+1CF4 ; Grapheme_Extend # Mn VEDIC TONE CANDRA ABOVE
+1CF8..1CF9 ; Grapheme_Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
+1DC0..1DF5 ; Grapheme_Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
+1DFB..1DFF ; Grapheme_Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+200C ; Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
+20D0..20DC ; Grapheme_Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20DD..20E0 ; Grapheme_Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E1 ; Grapheme_Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E2..20E4 ; Grapheme_Extend # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+20E5..20F0 ; Grapheme_Extend # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2CEF..2CF1 ; Grapheme_Extend # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS
+2D7F ; Grapheme_Extend # Mn TIFINAGH CONSONANT JOINER
+2DE0..2DFF ; Grapheme_Extend # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+302A..302D ; Grapheme_Extend # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
+302E..302F ; Grapheme_Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3099..309A ; Grapheme_Extend # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+A66F ; Grapheme_Extend # Mn COMBINING CYRILLIC VZMET
+A670..A672 ; Grapheme_Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A674..A67D ; Grapheme_Extend # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
+A69E..A69F ; Grapheme_Extend # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E
+A6F0..A6F1 ; Grapheme_Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
+A802 ; Grapheme_Extend # Mn SYLOTI NAGRI SIGN DVISVARA
+A806 ; Grapheme_Extend # Mn SYLOTI NAGRI SIGN HASANTA
+A80B ; Grapheme_Extend # Mn SYLOTI NAGRI SIGN ANUSVARA
+A825..A826 ; Grapheme_Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A8C4..A8C5 ; Grapheme_Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
+A8E0..A8F1 ; Grapheme_Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A926..A92D ; Grapheme_Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A947..A951 ; Grapheme_Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A980..A982 ; Grapheme_Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
+A9B3 ; Grapheme_Extend # Mn JAVANESE SIGN CECAK TELU
+A9B6..A9B9 ; Grapheme_Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT
+A9BC ; Grapheme_Extend # Mn JAVANESE VOWEL SIGN PEPET
+A9E5 ; Grapheme_Extend # Mn MYANMAR SIGN SHAN SAW
+AA29..AA2E ; Grapheme_Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA31..AA32 ; Grapheme_Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA35..AA36 ; Grapheme_Extend # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA43 ; Grapheme_Extend # Mn CHAM CONSONANT SIGN FINAL NG
+AA4C ; Grapheme_Extend # Mn CHAM CONSONANT SIGN FINAL M
+AA7C ; Grapheme_Extend # Mn MYANMAR SIGN TAI LAING TONE-2
+AAB0 ; Grapheme_Extend # Mn TAI VIET MAI KANG
+AAB2..AAB4 ; Grapheme_Extend # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U
+AAB7..AAB8 ; Grapheme_Extend # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA
+AABE..AABF ; Grapheme_Extend # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK
+AAC1 ; Grapheme_Extend # Mn TAI VIET TONE MAI THO
+AAEC..AAED ; Grapheme_Extend # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI
+AAF6 ; Grapheme_Extend # Mn MEETEI MAYEK VIRAMA
+ABE5 ; Grapheme_Extend # Mn MEETEI MAYEK VOWEL SIGN ANAP
+ABE8 ; Grapheme_Extend # Mn MEETEI MAYEK VOWEL SIGN UNAP
+ABED ; Grapheme_Extend # Mn MEETEI MAYEK APUN IYEK
+FB1E ; Grapheme_Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FE00..FE0F ; Grapheme_Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE2F ; Grapheme_Extend # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF
+FF9E..FF9F ; Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+101FD ; Grapheme_Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+102E0 ; Grapheme_Extend # Mn COPTIC EPACT THOUSANDS MARK
+10376..1037A ; Grapheme_Extend # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
+10A01..10A03 ; Grapheme_Extend # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Grapheme_Extend # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Grapheme_Extend # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A38..10A3A ; Grapheme_Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Grapheme_Extend # Mn KHAROSHTHI VIRAMA
+10AE5..10AE6 ; Grapheme_Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+11001 ; Grapheme_Extend # Mn BRAHMI SIGN ANUSVARA
+11038..11046 ; Grapheme_Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
+1107F..11081 ; Grapheme_Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
+110B3..110B6 ; Grapheme_Extend # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI
+110B9..110BA ; Grapheme_Extend # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
+11100..11102 ; Grapheme_Extend # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA
+11127..1112B ; Grapheme_Extend # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
+1112D..11134 ; Grapheme_Extend # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA
+11173 ; Grapheme_Extend # Mn MAHAJANI SIGN NUKTA
+11180..11181 ; Grapheme_Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
+111B6..111BE ; Grapheme_Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
+111CA..111CC ; Grapheme_Extend # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+1122F..11231 ; Grapheme_Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
+11234 ; Grapheme_Extend # Mn KHOJKI SIGN ANUSVARA
+11236..11237 ; Grapheme_Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
+1123E ; Grapheme_Extend # Mn KHOJKI SIGN SUKUN
+112DF ; Grapheme_Extend # Mn KHUDAWADI SIGN ANUSVARA
+112E3..112EA ; Grapheme_Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
+11300..11301 ; Grapheme_Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
+1133C ; Grapheme_Extend # Mn GRANTHA SIGN NUKTA
+1133E ; Grapheme_Extend # Mc GRANTHA VOWEL SIGN AA
+11340 ; Grapheme_Extend # Mn GRANTHA VOWEL SIGN II
+11357 ; Grapheme_Extend # Mc GRANTHA AU LENGTH MARK
+11366..1136C ; Grapheme_Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
+11370..11374 ; Grapheme_Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
+11438..1143F ; Grapheme_Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
+11442..11444 ; Grapheme_Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
+11446 ; Grapheme_Extend # Mn NEWA SIGN NUKTA
+114B0 ; Grapheme_Extend # Mc TIRHUTA VOWEL SIGN AA
+114B3..114B8 ; Grapheme_Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
+114BA ; Grapheme_Extend # Mn TIRHUTA VOWEL SIGN SHORT E
+114BD ; Grapheme_Extend # Mc TIRHUTA VOWEL SIGN SHORT O
+114BF..114C0 ; Grapheme_Extend # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
+114C2..114C3 ; Grapheme_Extend # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
+115AF ; Grapheme_Extend # Mc SIDDHAM VOWEL SIGN AA
+115B2..115B5 ; Grapheme_Extend # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
+115BC..115BD ; Grapheme_Extend # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
+115BF..115C0 ; Grapheme_Extend # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
+115DC..115DD ; Grapheme_Extend # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU
+11633..1163A ; Grapheme_Extend # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
+1163D ; Grapheme_Extend # Mn MODI SIGN ANUSVARA
+1163F..11640 ; Grapheme_Extend # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
+116AB ; Grapheme_Extend # Mn TAKRI SIGN ANUSVARA
+116AD ; Grapheme_Extend # Mn TAKRI VOWEL SIGN AA
+116B0..116B5 ; Grapheme_Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
+116B7 ; Grapheme_Extend # Mn TAKRI SIGN NUKTA
+1171D..1171F ; Grapheme_Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
+11722..11725 ; Grapheme_Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
+11727..1172B ; Grapheme_Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
+11C30..11C36 ; Grapheme_Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
+11C38..11C3D ; Grapheme_Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
+11C3F ; Grapheme_Extend # Mn BHAIKSUKI SIGN VIRAMA
+11C92..11CA7 ; Grapheme_Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA
+11CAA..11CB0 ; Grapheme_Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA
+11CB2..11CB3 ; Grapheme_Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E
+11CB5..11CB6 ; Grapheme_Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU
+16AF0..16AF4 ; Grapheme_Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
+16B30..16B36 ; Grapheme_Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
+16F8F..16F92 ; Grapheme_Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
+1BC9D..1BC9E ; Grapheme_Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
+1D165 ; Grapheme_Extend # Mc MUSICAL SYMBOL COMBINING STEM
+1D167..1D169 ; Grapheme_Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D16E..1D172 ; Grapheme_Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
+1D17B..1D182 ; Grapheme_Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Grapheme_Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Grapheme_Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; Grapheme_Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1DA00..1DA36 ; Grapheme_Extend # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN
+1DA3B..1DA6C ; Grapheme_Extend # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT
+1DA75 ; Grapheme_Extend # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS
+1DA84 ; Grapheme_Extend # Mn SIGNWRITING LOCATION HEAD NECK
+1DA9B..1DA9F ; Grapheme_Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6
+1DAA1..1DAAF ; Grapheme_Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16
+1E000..1E006 ; Grapheme_Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE
+1E008..1E018 ; Grapheme_Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU
+1E01B..1E021 ; Grapheme_Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI
+1E023..1E024 ; Grapheme_Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS
+1E026..1E02A ; Grapheme_Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
+1E8D0..1E8D6 ; Grapheme_Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
+1E944..1E94A ; Grapheme_Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+E0020..E007F ; Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
+E0100..E01EF ; Grapheme_Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 1828
+
+# ================================================
+
+# Derived Property: Grapheme_Base
+# Generated from: [0..10FFFF] - Cc - Cf - Cs - Co - Cn - Zl - Zp - Grapheme_Extend
+# Note: depending on an application's interpretation of Co (private use),
+# they may be either in Grapheme_Base, or in Grapheme_Extend, or in neither.
+
+0020 ; Grapheme_Base # Zs SPACE
+0021..0023 ; Grapheme_Base # Po [3] EXCLAMATION MARK..NUMBER SIGN
+0024 ; Grapheme_Base # Sc DOLLAR SIGN
+0025..0027 ; Grapheme_Base # Po [3] PERCENT SIGN..APOSTROPHE
+0028 ; Grapheme_Base # Ps LEFT PARENTHESIS
+0029 ; Grapheme_Base # Pe RIGHT PARENTHESIS
+002A ; Grapheme_Base # Po ASTERISK
+002B ; Grapheme_Base # Sm PLUS SIGN
+002C ; Grapheme_Base # Po COMMA
+002D ; Grapheme_Base # Pd HYPHEN-MINUS
+002E..002F ; Grapheme_Base # Po [2] FULL STOP..SOLIDUS
+0030..0039 ; Grapheme_Base # Nd [10] DIGIT ZERO..DIGIT NINE
+003A..003B ; Grapheme_Base # Po [2] COLON..SEMICOLON
+003C..003E ; Grapheme_Base # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+003F..0040 ; Grapheme_Base # Po [2] QUESTION MARK..COMMERCIAL AT
+0041..005A ; Grapheme_Base # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+005B ; Grapheme_Base # Ps LEFT SQUARE BRACKET
+005C ; Grapheme_Base # Po REVERSE SOLIDUS
+005D ; Grapheme_Base # Pe RIGHT SQUARE BRACKET
+005E ; Grapheme_Base # Sk CIRCUMFLEX ACCENT
+005F ; Grapheme_Base # Pc LOW LINE
+0060 ; Grapheme_Base # Sk GRAVE ACCENT
+0061..007A ; Grapheme_Base # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+007B ; Grapheme_Base # Ps LEFT CURLY BRACKET
+007C ; Grapheme_Base # Sm VERTICAL LINE
+007D ; Grapheme_Base # Pe RIGHT CURLY BRACKET
+007E ; Grapheme_Base # Sm TILDE
+00A0 ; Grapheme_Base # Zs NO-BREAK SPACE
+00A1 ; Grapheme_Base # Po INVERTED EXCLAMATION MARK
+00A2..00A5 ; Grapheme_Base # Sc [4] CENT SIGN..YEN SIGN
+00A6 ; Grapheme_Base # So BROKEN BAR
+00A7 ; Grapheme_Base # Po SECTION SIGN
+00A8 ; Grapheme_Base # Sk DIAERESIS
+00A9 ; Grapheme_Base # So COPYRIGHT SIGN
+00AA ; Grapheme_Base # Lo FEMININE ORDINAL INDICATOR
+00AB ; Grapheme_Base # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+00AC ; Grapheme_Base # Sm NOT SIGN
+00AE ; Grapheme_Base # So REGISTERED SIGN
+00AF ; Grapheme_Base # Sk MACRON
+00B0 ; Grapheme_Base # So DEGREE SIGN
+00B1 ; Grapheme_Base # Sm PLUS-MINUS SIGN
+00B2..00B3 ; Grapheme_Base # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+00B4 ; Grapheme_Base # Sk ACUTE ACCENT
+00B5 ; Grapheme_Base # L& MICRO SIGN
+00B6..00B7 ; Grapheme_Base # Po [2] PILCROW SIGN..MIDDLE DOT
+00B8 ; Grapheme_Base # Sk CEDILLA
+00B9 ; Grapheme_Base # No SUPERSCRIPT ONE
+00BA ; Grapheme_Base # Lo MASCULINE ORDINAL INDICATOR
+00BB ; Grapheme_Base # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+00BC..00BE ; Grapheme_Base # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+00BF ; Grapheme_Base # Po INVERTED QUESTION MARK
+00C0..00D6 ; Grapheme_Base # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D7 ; Grapheme_Base # Sm MULTIPLICATION SIGN
+00D8..00F6 ; Grapheme_Base # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F7 ; Grapheme_Base # Sm DIVISION SIGN
+00F8..01BA ; Grapheme_Base # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; Grapheme_Base # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; Grapheme_Base # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; Grapheme_Base # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; Grapheme_Base # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; Grapheme_Base # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; Grapheme_Base # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; Grapheme_Base # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C2..02C5 ; Grapheme_Base # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02C6..02D1 ; Grapheme_Base # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02D2..02DF ; Grapheme_Base # Sk [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT
+02E0..02E4 ; Grapheme_Base # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02E5..02EB ; Grapheme_Base # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02EC ; Grapheme_Base # Lm MODIFIER LETTER VOICING
+02ED ; Grapheme_Base # Sk MODIFIER LETTER UNASPIRATED
+02EE ; Grapheme_Base # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+02EF..02FF ; Grapheme_Base # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+0370..0373 ; Grapheme_Base # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; Grapheme_Base # Lm GREEK NUMERAL SIGN
+0375 ; Grapheme_Base # Sk GREEK LOWER NUMERAL SIGN
+0376..0377 ; Grapheme_Base # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; Grapheme_Base # Lm GREEK YPOGEGRAMMENI
+037B..037D ; Grapheme_Base # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037E ; Grapheme_Base # Po GREEK QUESTION MARK
+037F ; Grapheme_Base # L& GREEK CAPITAL LETTER YOT
+0384..0385 ; Grapheme_Base # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+0386 ; Grapheme_Base # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0387 ; Grapheme_Base # Po GREEK ANO TELEIA
+0388..038A ; Grapheme_Base # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Grapheme_Base # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; Grapheme_Base # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; Grapheme_Base # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F6 ; Grapheme_Base # Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+03F7..0481 ; Grapheme_Base # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+0482 ; Grapheme_Base # So CYRILLIC THOUSANDS SIGN
+048A..052F ; Grapheme_Base # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
+0531..0556 ; Grapheme_Base # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; Grapheme_Base # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+055A..055F ; Grapheme_Base # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+0561..0587 ; Grapheme_Base # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+0589 ; Grapheme_Base # Po ARMENIAN FULL STOP
+058A ; Grapheme_Base # Pd ARMENIAN HYPHEN
+058D..058E ; Grapheme_Base # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN
+058F ; Grapheme_Base # Sc ARMENIAN DRAM SIGN
+05BE ; Grapheme_Base # Pd HEBREW PUNCTUATION MAQAF
+05C0 ; Grapheme_Base # Po HEBREW PUNCTUATION PASEQ
+05C3 ; Grapheme_Base # Po HEBREW PUNCTUATION SOF PASUQ
+05C6 ; Grapheme_Base # Po HEBREW PUNCTUATION NUN HAFUKHA
+05D0..05EA ; Grapheme_Base # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; Grapheme_Base # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+05F3..05F4 ; Grapheme_Base # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+0606..0608 ; Grapheme_Base # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+0609..060A ; Grapheme_Base # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+060B ; Grapheme_Base # Sc AFGHANI SIGN
+060C..060D ; Grapheme_Base # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+060E..060F ; Grapheme_Base # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+061B ; Grapheme_Base # Po ARABIC SEMICOLON
+061E..061F ; Grapheme_Base # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
+0620..063F ; Grapheme_Base # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; Grapheme_Base # Lm ARABIC TATWEEL
+0641..064A ; Grapheme_Base # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+0660..0669 ; Grapheme_Base # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+066A..066D ; Grapheme_Base # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+066E..066F ; Grapheme_Base # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; Grapheme_Base # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D4 ; Grapheme_Base # Po ARABIC FULL STOP
+06D5 ; Grapheme_Base # Lo ARABIC LETTER AE
+06DE ; Grapheme_Base # So ARABIC START OF RUB EL HIZB
+06E5..06E6 ; Grapheme_Base # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E9 ; Grapheme_Base # So ARABIC PLACE OF SAJDAH
+06EE..06EF ; Grapheme_Base # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06F0..06F9 ; Grapheme_Base # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+06FA..06FC ; Grapheme_Base # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FD..06FE ; Grapheme_Base # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+06FF ; Grapheme_Base # Lo ARABIC LETTER HEH WITH INVERTED V
+0700..070D ; Grapheme_Base # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+0710 ; Grapheme_Base # Lo SYRIAC LETTER ALAPH
+0712..072F ; Grapheme_Base # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; Grapheme_Base # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07B1 ; Grapheme_Base # Lo THAANA LETTER NAA
+07C0..07C9 ; Grapheme_Base # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+07CA..07EA ; Grapheme_Base # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; Grapheme_Base # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07F6 ; Grapheme_Base # So NKO SYMBOL OO DENNEN
+07F7..07F9 ; Grapheme_Base # Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+07FA ; Grapheme_Base # Lm NKO LAJANYALAN
+0800..0815 ; Grapheme_Base # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
+081A ; Grapheme_Base # Lm SAMARITAN MODIFIER LETTER EPENTHETIC YUT
+0824 ; Grapheme_Base # Lm SAMARITAN MODIFIER LETTER SHORT A
+0828 ; Grapheme_Base # Lm SAMARITAN MODIFIER LETTER I
+0830..083E ; Grapheme_Base # Po [15] SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU
+0840..0858 ; Grapheme_Base # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
+085E ; Grapheme_Base # Po MANDAIC PUNCTUATION
+08A0..08B4 ; Grapheme_Base # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW
+08B6..08BD ; Grapheme_Base # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON
+0903 ; Grapheme_Base # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; Grapheme_Base # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093B ; Grapheme_Base # Mc DEVANAGARI VOWEL SIGN OOE
+093D ; Grapheme_Base # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; Grapheme_Base # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0949..094C ; Grapheme_Base # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094E..094F ; Grapheme_Base # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW
+0950 ; Grapheme_Base # Lo DEVANAGARI OM
+0958..0961 ; Grapheme_Base # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0964..0965 ; Grapheme_Base # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+0966..096F ; Grapheme_Base # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+0970 ; Grapheme_Base # Po DEVANAGARI ABBREVIATION SIGN
+0971 ; Grapheme_Base # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972..0980 ; Grapheme_Base # Lo [15] DEVANAGARI LETTER CANDRA A..BENGALI ANJI
+0982..0983 ; Grapheme_Base # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; Grapheme_Base # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; Grapheme_Base # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; Grapheme_Base # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; Grapheme_Base # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; Grapheme_Base # Lo BENGALI LETTER LA
+09B6..09B9 ; Grapheme_Base # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; Grapheme_Base # Lo BENGALI SIGN AVAGRAHA
+09BF..09C0 ; Grapheme_Base # Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II
+09C7..09C8 ; Grapheme_Base # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; Grapheme_Base # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CE ; Grapheme_Base # Lo BENGALI LETTER KHANDA TA
+09DC..09DD ; Grapheme_Base # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; Grapheme_Base # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E6..09EF ; Grapheme_Base # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+09F0..09F1 ; Grapheme_Base # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+09F2..09F3 ; Grapheme_Base # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+09F4..09F9 ; Grapheme_Base # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+09FA ; Grapheme_Base # So BENGALI ISSHAR
+09FB ; Grapheme_Base # Sc BENGALI GANDA MARK
+0A03 ; Grapheme_Base # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; Grapheme_Base # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; Grapheme_Base # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; Grapheme_Base # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; Grapheme_Base # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; Grapheme_Base # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; Grapheme_Base # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; Grapheme_Base # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3E..0A40 ; Grapheme_Base # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A59..0A5C ; Grapheme_Base # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; Grapheme_Base # Lo GURMUKHI LETTER FA
+0A66..0A6F ; Grapheme_Base # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0A72..0A74 ; Grapheme_Base # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A83 ; Grapheme_Base # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; Grapheme_Base # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; Grapheme_Base # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; Grapheme_Base # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; Grapheme_Base # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; Grapheme_Base # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; Grapheme_Base # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; Grapheme_Base # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; Grapheme_Base # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC9 ; Grapheme_Base # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; Grapheme_Base # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0AD0 ; Grapheme_Base # Lo GUJARATI OM
+0AE0..0AE1 ; Grapheme_Base # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE6..0AEF ; Grapheme_Base # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0AF0 ; Grapheme_Base # Po GUJARATI ABBREVIATION SIGN
+0AF1 ; Grapheme_Base # Sc GUJARATI RUPEE SIGN
+0AF9 ; Grapheme_Base # Lo GUJARATI LETTER ZHA
+0B02..0B03 ; Grapheme_Base # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; Grapheme_Base # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; Grapheme_Base # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; Grapheme_Base # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; Grapheme_Base # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; Grapheme_Base # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; Grapheme_Base # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; Grapheme_Base # Lo ORIYA SIGN AVAGRAHA
+0B40 ; Grapheme_Base # Mc ORIYA VOWEL SIGN II
+0B47..0B48 ; Grapheme_Base # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; Grapheme_Base # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B5C..0B5D ; Grapheme_Base # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; Grapheme_Base # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B66..0B6F ; Grapheme_Base # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0B70 ; Grapheme_Base # So ORIYA ISSHAR
+0B71 ; Grapheme_Base # Lo ORIYA LETTER WA
+0B72..0B77 ; Grapheme_Base # No [6] ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS
+0B83 ; Grapheme_Base # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; Grapheme_Base # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; Grapheme_Base # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; Grapheme_Base # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; Grapheme_Base # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; Grapheme_Base # Lo TAMIL LETTER JA
+0B9E..0B9F ; Grapheme_Base # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; Grapheme_Base # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; Grapheme_Base # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; Grapheme_Base # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBF ; Grapheme_Base # Mc TAMIL VOWEL SIGN I
+0BC1..0BC2 ; Grapheme_Base # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; Grapheme_Base # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; Grapheme_Base # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BD0 ; Grapheme_Base # Lo TAMIL OM
+0BE6..0BEF ; Grapheme_Base # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0BF0..0BF2 ; Grapheme_Base # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+0BF3..0BF8 ; Grapheme_Base # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+0BF9 ; Grapheme_Base # Sc TAMIL RUPEE SIGN
+0BFA ; Grapheme_Base # So TAMIL NUMBER SIGN
+0C01..0C03 ; Grapheme_Base # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; Grapheme_Base # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; Grapheme_Base # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; Grapheme_Base # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C39 ; Grapheme_Base # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
+0C3D ; Grapheme_Base # Lo TELUGU SIGN AVAGRAHA
+0C41..0C44 ; Grapheme_Base # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C58..0C5A ; Grapheme_Base # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
+0C60..0C61 ; Grapheme_Base # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C66..0C6F ; Grapheme_Base # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0C78..0C7E ; Grapheme_Base # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+0C7F ; Grapheme_Base # So TELUGU SIGN TUUMU
+0C80 ; Grapheme_Base # Lo KANNADA SIGN SPACING CANDRABINDU
+0C82..0C83 ; Grapheme_Base # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; Grapheme_Base # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; Grapheme_Base # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; Grapheme_Base # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; Grapheme_Base # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; Grapheme_Base # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; Grapheme_Base # Lo KANNADA SIGN AVAGRAHA
+0CBE ; Grapheme_Base # Mc KANNADA VOWEL SIGN AA
+0CC0..0CC1 ; Grapheme_Base # Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U
+0CC3..0CC4 ; Grapheme_Base # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR
+0CC7..0CC8 ; Grapheme_Base # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; Grapheme_Base # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CDE ; Grapheme_Base # Lo KANNADA LETTER FA
+0CE0..0CE1 ; Grapheme_Base # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE6..0CEF ; Grapheme_Base # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0CF1..0CF2 ; Grapheme_Base # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D02..0D03 ; Grapheme_Base # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; Grapheme_Base # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; Grapheme_Base # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D3A ; Grapheme_Base # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA
+0D3D ; Grapheme_Base # Lo MALAYALAM SIGN AVAGRAHA
+0D3F..0D40 ; Grapheme_Base # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II
+0D46..0D48 ; Grapheme_Base # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; Grapheme_Base # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4E ; Grapheme_Base # Lo MALAYALAM LETTER DOT REPH
+0D4F ; Grapheme_Base # So MALAYALAM SIGN PARA
+0D54..0D56 ; Grapheme_Base # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL
+0D58..0D5E ; Grapheme_Base # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH
+0D5F..0D61 ; Grapheme_Base # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL
+0D66..0D6F ; Grapheme_Base # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0D70..0D78 ; Grapheme_Base # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS
+0D79 ; Grapheme_Base # So MALAYALAM DATE MARK
+0D7A..0D7F ; Grapheme_Base # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D82..0D83 ; Grapheme_Base # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; Grapheme_Base # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; Grapheme_Base # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; Grapheme_Base # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; Grapheme_Base # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; Grapheme_Base # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DD0..0DD1 ; Grapheme_Base # Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD8..0DDE ; Grapheme_Base # Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+0DE6..0DEF ; Grapheme_Base # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
+0DF2..0DF3 ; Grapheme_Base # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0DF4 ; Grapheme_Base # Po SINHALA PUNCTUATION KUNDDALIYA
+0E01..0E30 ; Grapheme_Base # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E32..0E33 ; Grapheme_Base # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E3F ; Grapheme_Base # Sc THAI CURRENCY SYMBOL BAHT
+0E40..0E45 ; Grapheme_Base # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; Grapheme_Base # Lm THAI CHARACTER MAIYAMOK
+0E4F ; Grapheme_Base # Po THAI CHARACTER FONGMAN
+0E50..0E59 ; Grapheme_Base # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0E5A..0E5B ; Grapheme_Base # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+0E81..0E82 ; Grapheme_Base # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; Grapheme_Base # Lo LAO LETTER KHO TAM
+0E87..0E88 ; Grapheme_Base # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; Grapheme_Base # Lo LAO LETTER SO TAM
+0E8D ; Grapheme_Base # Lo LAO LETTER NYO
+0E94..0E97 ; Grapheme_Base # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; Grapheme_Base # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; Grapheme_Base # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; Grapheme_Base # Lo LAO LETTER LO LOOT
+0EA7 ; Grapheme_Base # Lo LAO LETTER WO
+0EAA..0EAB ; Grapheme_Base # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; Grapheme_Base # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB2..0EB3 ; Grapheme_Base # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EBD ; Grapheme_Base # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; Grapheme_Base # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; Grapheme_Base # Lm LAO KO LA
+0ED0..0ED9 ; Grapheme_Base # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0EDC..0EDF ; Grapheme_Base # Lo [4] LAO HO NO..LAO LETTER KHMU NYO
+0F00 ; Grapheme_Base # Lo TIBETAN SYLLABLE OM
+0F01..0F03 ; Grapheme_Base # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+0F04..0F12 ; Grapheme_Base # Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+0F13 ; Grapheme_Base # So TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN
+0F14 ; Grapheme_Base # Po TIBETAN MARK GTER TSHEG
+0F15..0F17 ; Grapheme_Base # So [3] TIBETAN LOGOTYPE SIGN CHAD RTAGS..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+0F1A..0F1F ; Grapheme_Base # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+0F20..0F29 ; Grapheme_Base # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+0F2A..0F33 ; Grapheme_Base # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+0F34 ; Grapheme_Base # So TIBETAN MARK BSDUS RTAGS
+0F36 ; Grapheme_Base # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+0F38 ; Grapheme_Base # So TIBETAN MARK CHE MGO
+0F3A ; Grapheme_Base # Ps TIBETAN MARK GUG RTAGS GYON
+0F3B ; Grapheme_Base # Pe TIBETAN MARK GUG RTAGS GYAS
+0F3C ; Grapheme_Base # Ps TIBETAN MARK ANG KHANG GYON
+0F3D ; Grapheme_Base # Pe TIBETAN MARK ANG KHANG GYAS
+0F3E..0F3F ; Grapheme_Base # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F40..0F47 ; Grapheme_Base # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; Grapheme_Base # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F7F ; Grapheme_Base # Mc TIBETAN SIGN RNAM BCAD
+0F85 ; Grapheme_Base # Po TIBETAN MARK PALUTA
+0F88..0F8C ; Grapheme_Base # Lo [5] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN INVERTED MCHU CAN
+0FBE..0FC5 ; Grapheme_Base # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+0FC7..0FCC ; Grapheme_Base # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+0FCE..0FCF ; Grapheme_Base # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+0FD0..0FD4 ; Grapheme_Base # Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+0FD5..0FD8 ; Grapheme_Base # So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS
+0FD9..0FDA ; Grapheme_Base # Po [2] TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS
+1000..102A ; Grapheme_Base # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; Grapheme_Base # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+1031 ; Grapheme_Base # Mc MYANMAR VOWEL SIGN E
+1038 ; Grapheme_Base # Mc MYANMAR SIGN VISARGA
+103B..103C ; Grapheme_Base # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103F ; Grapheme_Base # Lo MYANMAR LETTER GREAT SA
+1040..1049 ; Grapheme_Base # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+104A..104F ; Grapheme_Base # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+1050..1055 ; Grapheme_Base # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; Grapheme_Base # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+105A..105D ; Grapheme_Base # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+1061 ; Grapheme_Base # Lo MYANMAR LETTER SGAW KAREN SHA
+1062..1064 ; Grapheme_Base # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1065..1066 ; Grapheme_Base # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..106D ; Grapheme_Base # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+106E..1070 ; Grapheme_Base # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1075..1081 ; Grapheme_Base # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1083..1084 ; Grapheme_Base # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1087..108C ; Grapheme_Base # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108E ; Grapheme_Base # Lo MYANMAR LETTER RUMAI PALAUNG FA
+108F ; Grapheme_Base # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+1090..1099 ; Grapheme_Base # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+109A..109C ; Grapheme_Base # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
+109E..109F ; Grapheme_Base # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+10A0..10C5 ; Grapheme_Base # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10C7 ; Grapheme_Base # L& GEORGIAN CAPITAL LETTER YN
+10CD ; Grapheme_Base # L& GEORGIAN CAPITAL LETTER AEN
+10D0..10FA ; Grapheme_Base # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FB ; Grapheme_Base # Po GEORGIAN PARAGRAPH SEPARATOR
+10FC ; Grapheme_Base # Lm MODIFIER LETTER GEORGIAN NAR
+10FD..1248 ; Grapheme_Base # Lo [332] GEORGIAN LETTER AEN..ETHIOPIC SYLLABLE QWA
+124A..124D ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; Grapheme_Base # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; Grapheme_Base # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; Grapheme_Base # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; Grapheme_Base # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; Grapheme_Base # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; Grapheme_Base # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; Grapheme_Base # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; Grapheme_Base # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1360..1368 ; Grapheme_Base # Po [9] ETHIOPIC SECTION MARK..ETHIOPIC PARAGRAPH SEPARATOR
+1369..137C ; Grapheme_Base # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+1380..138F ; Grapheme_Base # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+1390..1399 ; Grapheme_Base # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+13A0..13F5 ; Grapheme_Base # L& [86] CHEROKEE LETTER A..CHEROKEE LETTER MV
+13F8..13FD ; Grapheme_Base # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV
+1400 ; Grapheme_Base # Pd CANADIAN SYLLABICS HYPHEN
+1401..166C ; Grapheme_Base # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166D..166E ; Grapheme_Base # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP
+166F..167F ; Grapheme_Base # Lo [17] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS BLACKFOOT W
+1680 ; Grapheme_Base # Zs OGHAM SPACE MARK
+1681..169A ; Grapheme_Base # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+169B ; Grapheme_Base # Ps OGHAM FEATHER MARK
+169C ; Grapheme_Base # Pe OGHAM REVERSED FEATHER MARK
+16A0..16EA ; Grapheme_Base # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EB..16ED ; Grapheme_Base # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+16EE..16F0 ; Grapheme_Base # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+16F1..16F8 ; Grapheme_Base # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
+1700..170C ; Grapheme_Base # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; Grapheme_Base # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1720..1731 ; Grapheme_Base # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1735..1736 ; Grapheme_Base # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+1740..1751 ; Grapheme_Base # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1760..176C ; Grapheme_Base # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; Grapheme_Base # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1780..17B3 ; Grapheme_Base # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B6 ; Grapheme_Base # Mc KHMER VOWEL SIGN AA
+17BE..17C5 ; Grapheme_Base # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C7..17C8 ; Grapheme_Base # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17D4..17D6 ; Grapheme_Base # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+17D7 ; Grapheme_Base # Lm KHMER SIGN LEK TOO
+17D8..17DA ; Grapheme_Base # Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+17DB ; Grapheme_Base # Sc KHMER CURRENCY SYMBOL RIEL
+17DC ; Grapheme_Base # Lo KHMER SIGN AVAKRAHASANYA
+17E0..17E9 ; Grapheme_Base # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+17F0..17F9 ; Grapheme_Base # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+1800..1805 ; Grapheme_Base # Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS
+1806 ; Grapheme_Base # Pd MONGOLIAN TODO SOFT HYPHEN
+1807..180A ; Grapheme_Base # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+1810..1819 ; Grapheme_Base # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1820..1842 ; Grapheme_Base # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; Grapheme_Base # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; Grapheme_Base # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..1884 ; Grapheme_Base # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA
+1887..18A8 ; Grapheme_Base # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; Grapheme_Base # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+18B0..18F5 ; Grapheme_Base # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S
+1900..191E ; Grapheme_Base # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
+1923..1926 ; Grapheme_Base # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1929..192B ; Grapheme_Base # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; Grapheme_Base # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1933..1938 ; Grapheme_Base # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1940 ; Grapheme_Base # So LIMBU SIGN LOO
+1944..1945 ; Grapheme_Base # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+1946..194F ; Grapheme_Base # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+1950..196D ; Grapheme_Base # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; Grapheme_Base # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19AB ; Grapheme_Base # Lo [44] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW SUA
+19B0..19C9 ; Grapheme_Base # Lo [26] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2
+19D0..19D9 ; Grapheme_Base # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+19DA ; Grapheme_Base # No NEW TAI LUE THAM DIGIT ONE
+19DE..19FF ; Grapheme_Base # So [34] NEW TAI LUE SIGN LAE..KHMER SYMBOL DAP-PRAM ROC
+1A00..1A16 ; Grapheme_Base # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A19..1A1A ; Grapheme_Base # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
+1A1E..1A1F ; Grapheme_Base # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+1A20..1A54 ; Grapheme_Base # Lo [53] TAI THAM LETTER HIGH KA..TAI THAM LETTER GREAT SA
+1A55 ; Grapheme_Base # Mc TAI THAM CONSONANT SIGN MEDIAL RA
+1A57 ; Grapheme_Base # Mc TAI THAM CONSONANT SIGN LA TANG LAI
+1A61 ; Grapheme_Base # Mc TAI THAM VOWEL SIGN A
+1A63..1A64 ; Grapheme_Base # Mc [2] TAI THAM VOWEL SIGN AA..TAI THAM VOWEL SIGN TALL AA
+1A6D..1A72 ; Grapheme_Base # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI
+1A80..1A89 ; Grapheme_Base # Nd [10] TAI THAM HORA DIGIT ZERO..TAI THAM HORA DIGIT NINE
+1A90..1A99 ; Grapheme_Base # Nd [10] TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE
+1AA0..1AA6 ; Grapheme_Base # Po [7] TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA
+1AA7 ; Grapheme_Base # Lm TAI THAM SIGN MAI YAMOK
+1AA8..1AAD ; Grapheme_Base # Po [6] TAI THAM SIGN KAAN..TAI THAM SIGN CAANG
+1B04 ; Grapheme_Base # Mc BALINESE SIGN BISAH
+1B05..1B33 ; Grapheme_Base # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B35 ; Grapheme_Base # Mc BALINESE VOWEL SIGN TEDUNG
+1B3B ; Grapheme_Base # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3D..1B41 ; Grapheme_Base # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B43..1B44 ; Grapheme_Base # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B45..1B4B ; Grapheme_Base # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B50..1B59 ; Grapheme_Base # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1B5A..1B60 ; Grapheme_Base # Po [7] BALINESE PANTI..BALINESE PAMENENG
+1B61..1B6A ; Grapheme_Base # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+1B74..1B7C ; Grapheme_Base # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+1B82 ; Grapheme_Base # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; Grapheme_Base # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; Grapheme_Base # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA6..1BA7 ; Grapheme_Base # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BAA ; Grapheme_Base # Mc SUNDANESE SIGN PAMAAEH
+1BAE..1BAF ; Grapheme_Base # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BB0..1BB9 ; Grapheme_Base # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1BBA..1BE5 ; Grapheme_Base # Lo [44] SUNDANESE AVAGRAHA..BATAK LETTER U
+1BE7 ; Grapheme_Base # Mc BATAK VOWEL SIGN E
+1BEA..1BEC ; Grapheme_Base # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
+1BEE ; Grapheme_Base # Mc BATAK VOWEL SIGN U
+1BF2..1BF3 ; Grapheme_Base # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+1BFC..1BFF ; Grapheme_Base # Po [4] BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT
+1C00..1C23 ; Grapheme_Base # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; Grapheme_Base # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C34..1C35 ; Grapheme_Base # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C3B..1C3F ; Grapheme_Base # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+1C40..1C49 ; Grapheme_Base # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C4D..1C4F ; Grapheme_Base # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C50..1C59 ; Grapheme_Base # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+1C5A..1C77 ; Grapheme_Base # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; Grapheme_Base # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C7E..1C7F ; Grapheme_Base # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+1C80..1C88 ; Grapheme_Base # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK
+1CC0..1CC7 ; Grapheme_Base # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA
+1CD3 ; Grapheme_Base # Po VEDIC SIGN NIHSHVASA
+1CE1 ; Grapheme_Base # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
+1CE9..1CEC ; Grapheme_Base # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
+1CEE..1CF1 ; Grapheme_Base # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
+1CF2..1CF3 ; Grapheme_Base # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
+1CF5..1CF6 ; Grapheme_Base # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
+1D00..1D2B ; Grapheme_Base # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D6A ; Grapheme_Base # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
+1D6B..1D77 ; Grapheme_Base # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D78 ; Grapheme_Base # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; Grapheme_Base # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; Grapheme_Base # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; Grapheme_Base # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; Grapheme_Base # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; Grapheme_Base # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; Grapheme_Base # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Grapheme_Base # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; Grapheme_Base # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Grapheme_Base # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Grapheme_Base # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; Grapheme_Base # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Grapheme_Base # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; Grapheme_Base # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBD ; Grapheme_Base # Sk GREEK KORONIS
+1FBE ; Grapheme_Base # L& GREEK PROSGEGRAMMENI
+1FBF..1FC1 ; Grapheme_Base # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+1FC2..1FC4 ; Grapheme_Base # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; Grapheme_Base # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCD..1FCF ; Grapheme_Base # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+1FD0..1FD3 ; Grapheme_Base # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; Grapheme_Base # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FDD..1FDF ; Grapheme_Base # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+1FE0..1FEC ; Grapheme_Base # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FED..1FEF ; Grapheme_Base # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+1FF2..1FF4 ; Grapheme_Base # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; Grapheme_Base # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFD..1FFE ; Grapheme_Base # Sk [2] GREEK OXIA..GREEK DASIA
+2000..200A ; Grapheme_Base # Zs [11] EN QUAD..HAIR SPACE
+2010..2015 ; Grapheme_Base # Pd [6] HYPHEN..HORIZONTAL BAR
+2016..2017 ; Grapheme_Base # Po [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE
+2018 ; Grapheme_Base # Pi LEFT SINGLE QUOTATION MARK
+2019 ; Grapheme_Base # Pf RIGHT SINGLE QUOTATION MARK
+201A ; Grapheme_Base # Ps SINGLE LOW-9 QUOTATION MARK
+201B..201C ; Grapheme_Base # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK
+201D ; Grapheme_Base # Pf RIGHT DOUBLE QUOTATION MARK
+201E ; Grapheme_Base # Ps DOUBLE LOW-9 QUOTATION MARK
+201F ; Grapheme_Base # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+2020..2027 ; Grapheme_Base # Po [8] DAGGER..HYPHENATION POINT
+202F ; Grapheme_Base # Zs NARROW NO-BREAK SPACE
+2030..2038 ; Grapheme_Base # Po [9] PER MILLE SIGN..CARET
+2039 ; Grapheme_Base # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+203A ; Grapheme_Base # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+203B..203E ; Grapheme_Base # Po [4] REFERENCE MARK..OVERLINE
+203F..2040 ; Grapheme_Base # Pc [2] UNDERTIE..CHARACTER TIE
+2041..2043 ; Grapheme_Base # Po [3] CARET INSERTION POINT..HYPHEN BULLET
+2044 ; Grapheme_Base # Sm FRACTION SLASH
+2045 ; Grapheme_Base # Ps LEFT SQUARE BRACKET WITH QUILL
+2046 ; Grapheme_Base # Pe RIGHT SQUARE BRACKET WITH QUILL
+2047..2051 ; Grapheme_Base # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+2052 ; Grapheme_Base # Sm COMMERCIAL MINUS SIGN
+2053 ; Grapheme_Base # Po SWUNG DASH
+2054 ; Grapheme_Base # Pc INVERTED UNDERTIE
+2055..205E ; Grapheme_Base # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+205F ; Grapheme_Base # Zs MEDIUM MATHEMATICAL SPACE
+2070 ; Grapheme_Base # No SUPERSCRIPT ZERO
+2071 ; Grapheme_Base # Lm SUPERSCRIPT LATIN SMALL LETTER I
+2074..2079 ; Grapheme_Base # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE
+207A..207C ; Grapheme_Base # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+207D ; Grapheme_Base # Ps SUPERSCRIPT LEFT PARENTHESIS
+207E ; Grapheme_Base # Pe SUPERSCRIPT RIGHT PARENTHESIS
+207F ; Grapheme_Base # Lm SUPERSCRIPT LATIN SMALL LETTER N
+2080..2089 ; Grapheme_Base # No [10] SUBSCRIPT ZERO..SUBSCRIPT NINE
+208A..208C ; Grapheme_Base # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+208D ; Grapheme_Base # Ps SUBSCRIPT LEFT PARENTHESIS
+208E ; Grapheme_Base # Pe SUBSCRIPT RIGHT PARENTHESIS
+2090..209C ; Grapheme_Base # Lm [13] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER T
+20A0..20BE ; Grapheme_Base # Sc [31] EURO-CURRENCY SIGN..LARI SIGN
+2100..2101 ; Grapheme_Base # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+2102 ; Grapheme_Base # L& DOUBLE-STRUCK CAPITAL C
+2103..2106 ; Grapheme_Base # So [4] DEGREE CELSIUS..CADA UNA
+2107 ; Grapheme_Base # L& EULER CONSTANT
+2108..2109 ; Grapheme_Base # So [2] SCRUPLE..DEGREE FAHRENHEIT
+210A..2113 ; Grapheme_Base # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2114 ; Grapheme_Base # So L B BAR SYMBOL
+2115 ; Grapheme_Base # L& DOUBLE-STRUCK CAPITAL N
+2116..2117 ; Grapheme_Base # So [2] NUMERO SIGN..SOUND RECORDING COPYRIGHT
+2118 ; Grapheme_Base # Sm SCRIPT CAPITAL P
+2119..211D ; Grapheme_Base # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+211E..2123 ; Grapheme_Base # So [6] PRESCRIPTION TAKE..VERSICLE
+2124 ; Grapheme_Base # L& DOUBLE-STRUCK CAPITAL Z
+2125 ; Grapheme_Base # So OUNCE SIGN
+2126 ; Grapheme_Base # L& OHM SIGN
+2127 ; Grapheme_Base # So INVERTED OHM SIGN
+2128 ; Grapheme_Base # L& BLACK-LETTER CAPITAL Z
+2129 ; Grapheme_Base # So TURNED GREEK SMALL LETTER IOTA
+212A..212D ; Grapheme_Base # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; Grapheme_Base # So ESTIMATED SYMBOL
+212F..2134 ; Grapheme_Base # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; Grapheme_Base # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; Grapheme_Base # L& INFORMATION SOURCE
+213A..213B ; Grapheme_Base # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+213C..213F ; Grapheme_Base # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2140..2144 ; Grapheme_Base # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+2145..2149 ; Grapheme_Base # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214A ; Grapheme_Base # So PROPERTY LINE
+214B ; Grapheme_Base # Sm TURNED AMPERSAND
+214C..214D ; Grapheme_Base # So [2] PER SIGN..AKTIESELSKAB
+214E ; Grapheme_Base # L& TURNED SMALL F
+214F ; Grapheme_Base # So SYMBOL FOR SAMARITAN SOURCE
+2150..215F ; Grapheme_Base # No [16] VULGAR FRACTION ONE SEVENTH..FRACTION NUMERATOR ONE
+2160..2182 ; Grapheme_Base # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; Grapheme_Base # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; Grapheme_Base # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2189 ; Grapheme_Base # No VULGAR FRACTION ZERO THIRDS
+218A..218B ; Grapheme_Base # So [2] TURNED DIGIT TWO..TURNED DIGIT THREE
+2190..2194 ; Grapheme_Base # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+2195..2199 ; Grapheme_Base # So [5] UP DOWN ARROW..SOUTH WEST ARROW
+219A..219B ; Grapheme_Base # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+219C..219F ; Grapheme_Base # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+21A0 ; Grapheme_Base # Sm RIGHTWARDS TWO HEADED ARROW
+21A1..21A2 ; Grapheme_Base # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+21A3 ; Grapheme_Base # Sm RIGHTWARDS ARROW WITH TAIL
+21A4..21A5 ; Grapheme_Base # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+21A6 ; Grapheme_Base # Sm RIGHTWARDS ARROW FROM BAR
+21A7..21AD ; Grapheme_Base # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+21AE ; Grapheme_Base # Sm LEFT RIGHT ARROW WITH STROKE
+21AF..21CD ; Grapheme_Base # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+21CE..21CF ; Grapheme_Base # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+21D0..21D1 ; Grapheme_Base # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+21D2 ; Grapheme_Base # Sm RIGHTWARDS DOUBLE ARROW
+21D3 ; Grapheme_Base # So DOWNWARDS DOUBLE ARROW
+21D4 ; Grapheme_Base # Sm LEFT RIGHT DOUBLE ARROW
+21D5..21F3 ; Grapheme_Base # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
+21F4..22FF ; Grapheme_Base # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
+2300..2307 ; Grapheme_Base # So [8] DIAMETER SIGN..WAVY LINE
+2308 ; Grapheme_Base # Ps LEFT CEILING
+2309 ; Grapheme_Base # Pe RIGHT CEILING
+230A ; Grapheme_Base # Ps LEFT FLOOR
+230B ; Grapheme_Base # Pe RIGHT FLOOR
+230C..231F ; Grapheme_Base # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
+2320..2321 ; Grapheme_Base # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+2322..2328 ; Grapheme_Base # So [7] FROWN..KEYBOARD
+2329 ; Grapheme_Base # Ps LEFT-POINTING ANGLE BRACKET
+232A ; Grapheme_Base # Pe RIGHT-POINTING ANGLE BRACKET
+232B..237B ; Grapheme_Base # So [81] ERASE TO THE LEFT..NOT CHECK MARK
+237C ; Grapheme_Base # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+237D..239A ; Grapheme_Base # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+239B..23B3 ; Grapheme_Base # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+23B4..23DB ; Grapheme_Base # So [40] TOP SQUARE BRACKET..FUSE
+23DC..23E1 ; Grapheme_Base # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+23E2..23FE ; Grapheme_Base # So [29] WHITE TRAPEZIUM..POWER SLEEP SYMBOL
+2400..2426 ; Grapheme_Base # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+2440..244A ; Grapheme_Base # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
+2460..249B ; Grapheme_Base # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+249C..24E9 ; Grapheme_Base # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+24EA..24FF ; Grapheme_Base # No [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO
+2500..25B6 ; Grapheme_Base # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE
+25B7 ; Grapheme_Base # Sm WHITE RIGHT-POINTING TRIANGLE
+25B8..25C0 ; Grapheme_Base # So [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE
+25C1 ; Grapheme_Base # Sm WHITE LEFT-POINTING TRIANGLE
+25C2..25F7 ; Grapheme_Base # So [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+25F8..25FF ; Grapheme_Base # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+2600..266E ; Grapheme_Base # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
+266F ; Grapheme_Base # Sm MUSIC SHARP SIGN
+2670..2767 ; Grapheme_Base # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET
+2768 ; Grapheme_Base # Ps MEDIUM LEFT PARENTHESIS ORNAMENT
+2769 ; Grapheme_Base # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
+276A ; Grapheme_Base # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+276B ; Grapheme_Base # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+276C ; Grapheme_Base # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+276D ; Grapheme_Base # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+276E ; Grapheme_Base # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+276F ; Grapheme_Base # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+2770 ; Grapheme_Base # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+2771 ; Grapheme_Base # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+2772 ; Grapheme_Base # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+2773 ; Grapheme_Base # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+2774 ; Grapheme_Base # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT
+2775 ; Grapheme_Base # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT
+2776..2793 ; Grapheme_Base # No [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+2794..27BF ; Grapheme_Base # So [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP
+27C0..27C4 ; Grapheme_Base # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+27C5 ; Grapheme_Base # Ps LEFT S-SHAPED BAG DELIMITER
+27C6 ; Grapheme_Base # Pe RIGHT S-SHAPED BAG DELIMITER
+27C7..27E5 ; Grapheme_Base # Sm [31] OR WITH DOT INSIDE..WHITE SQUARE WITH RIGHTWARDS TICK
+27E6 ; Grapheme_Base # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+27E7 ; Grapheme_Base # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+27E8 ; Grapheme_Base # Ps MATHEMATICAL LEFT ANGLE BRACKET
+27E9 ; Grapheme_Base # Pe MATHEMATICAL RIGHT ANGLE BRACKET
+27EA ; Grapheme_Base # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+27EB ; Grapheme_Base # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+27EC ; Grapheme_Base # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+27ED ; Grapheme_Base # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+27EE ; Grapheme_Base # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+27EF ; Grapheme_Base # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+27F0..27FF ; Grapheme_Base # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+2800..28FF ; Grapheme_Base # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+2900..2982 ; Grapheme_Base # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON
+2983 ; Grapheme_Base # Ps LEFT WHITE CURLY BRACKET
+2984 ; Grapheme_Base # Pe RIGHT WHITE CURLY BRACKET
+2985 ; Grapheme_Base # Ps LEFT WHITE PARENTHESIS
+2986 ; Grapheme_Base # Pe RIGHT WHITE PARENTHESIS
+2987 ; Grapheme_Base # Ps Z NOTATION LEFT IMAGE BRACKET
+2988 ; Grapheme_Base # Pe Z NOTATION RIGHT IMAGE BRACKET
+2989 ; Grapheme_Base # Ps Z NOTATION LEFT BINDING BRACKET
+298A ; Grapheme_Base # Pe Z NOTATION RIGHT BINDING BRACKET
+298B ; Grapheme_Base # Ps LEFT SQUARE BRACKET WITH UNDERBAR
+298C ; Grapheme_Base # Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+298D ; Grapheme_Base # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+298E ; Grapheme_Base # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+298F ; Grapheme_Base # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2990 ; Grapheme_Base # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+2991 ; Grapheme_Base # Ps LEFT ANGLE BRACKET WITH DOT
+2992 ; Grapheme_Base # Pe RIGHT ANGLE BRACKET WITH DOT
+2993 ; Grapheme_Base # Ps LEFT ARC LESS-THAN BRACKET
+2994 ; Grapheme_Base # Pe RIGHT ARC GREATER-THAN BRACKET
+2995 ; Grapheme_Base # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+2996 ; Grapheme_Base # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+2997 ; Grapheme_Base # Ps LEFT BLACK TORTOISE SHELL BRACKET
+2998 ; Grapheme_Base # Pe RIGHT BLACK TORTOISE SHELL BRACKET
+2999..29D7 ; Grapheme_Base # Sm [63] DOTTED FENCE..BLACK HOURGLASS
+29D8 ; Grapheme_Base # Ps LEFT WIGGLY FENCE
+29D9 ; Grapheme_Base # Pe RIGHT WIGGLY FENCE
+29DA ; Grapheme_Base # Ps LEFT DOUBLE WIGGLY FENCE
+29DB ; Grapheme_Base # Pe RIGHT DOUBLE WIGGLY FENCE
+29DC..29FB ; Grapheme_Base # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+29FC ; Grapheme_Base # Ps LEFT-POINTING CURVED ANGLE BRACKET
+29FD ; Grapheme_Base # Pe RIGHT-POINTING CURVED ANGLE BRACKET
+29FE..2AFF ; Grapheme_Base # Sm [258] TINY..N-ARY WHITE VERTICAL BAR
+2B00..2B2F ; Grapheme_Base # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE
+2B30..2B44 ; Grapheme_Base # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+2B45..2B46 ; Grapheme_Base # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+2B47..2B4C ; Grapheme_Base # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+2B4D..2B73 ; Grapheme_Base # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
+2B76..2B95 ; Grapheme_Base # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
+2B98..2BB9 ; Grapheme_Base # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX
+2BBD..2BC8 ; Grapheme_Base # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
+2BCA..2BD1 ; Grapheme_Base # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN
+2BEC..2BEF ; Grapheme_Base # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS
+2C00..2C2E ; Grapheme_Base # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; Grapheme_Base # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C7B ; Grapheme_Base # L& [28] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN LETTER SMALL CAPITAL TURNED E
+2C7C..2C7D ; Grapheme_Base # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
+2C7E..2CE4 ; Grapheme_Base # L& [103] LATIN CAPITAL LETTER S WITH SWASH TAIL..COPTIC SYMBOL KAI
+2CE5..2CEA ; Grapheme_Base # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+2CEB..2CEE ; Grapheme_Base # L& [4] COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI..COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA
+2CF2..2CF3 ; Grapheme_Base # L& [2] COPTIC CAPITAL LETTER BOHAIRIC KHEI..COPTIC SMALL LETTER BOHAIRIC KHEI
+2CF9..2CFC ; Grapheme_Base # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+2CFD ; Grapheme_Base # No COPTIC FRACTION ONE HALF
+2CFE..2CFF ; Grapheme_Base # Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+2D00..2D25 ; Grapheme_Base # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D27 ; Grapheme_Base # L& GEORGIAN SMALL LETTER YN
+2D2D ; Grapheme_Base # L& GEORGIAN SMALL LETTER AEN
+2D30..2D67 ; Grapheme_Base # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO
+2D6F ; Grapheme_Base # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D70 ; Grapheme_Base # Po TIFINAGH SEPARATOR MARK
+2D80..2D96 ; Grapheme_Base # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2E00..2E01 ; Grapheme_Base # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+2E02 ; Grapheme_Base # Pi LEFT SUBSTITUTION BRACKET
+2E03 ; Grapheme_Base # Pf RIGHT SUBSTITUTION BRACKET
+2E04 ; Grapheme_Base # Pi LEFT DOTTED SUBSTITUTION BRACKET
+2E05 ; Grapheme_Base # Pf RIGHT DOTTED SUBSTITUTION BRACKET
+2E06..2E08 ; Grapheme_Base # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+2E09 ; Grapheme_Base # Pi LEFT TRANSPOSITION BRACKET
+2E0A ; Grapheme_Base # Pf RIGHT TRANSPOSITION BRACKET
+2E0B ; Grapheme_Base # Po RAISED SQUARE
+2E0C ; Grapheme_Base # Pi LEFT RAISED OMISSION BRACKET
+2E0D ; Grapheme_Base # Pf RIGHT RAISED OMISSION BRACKET
+2E0E..2E16 ; Grapheme_Base # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+2E17 ; Grapheme_Base # Pd DOUBLE OBLIQUE HYPHEN
+2E18..2E19 ; Grapheme_Base # Po [2] INVERTED INTERROBANG..PALM BRANCH
+2E1A ; Grapheme_Base # Pd HYPHEN WITH DIAERESIS
+2E1B ; Grapheme_Base # Po TILDE WITH RING ABOVE
+2E1C ; Grapheme_Base # Pi LEFT LOW PARAPHRASE BRACKET
+2E1D ; Grapheme_Base # Pf RIGHT LOW PARAPHRASE BRACKET
+2E1E..2E1F ; Grapheme_Base # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+2E20 ; Grapheme_Base # Pi LEFT VERTICAL BAR WITH QUILL
+2E21 ; Grapheme_Base # Pf RIGHT VERTICAL BAR WITH QUILL
+2E22 ; Grapheme_Base # Ps TOP LEFT HALF BRACKET
+2E23 ; Grapheme_Base # Pe TOP RIGHT HALF BRACKET
+2E24 ; Grapheme_Base # Ps BOTTOM LEFT HALF BRACKET
+2E25 ; Grapheme_Base # Pe BOTTOM RIGHT HALF BRACKET
+2E26 ; Grapheme_Base # Ps LEFT SIDEWAYS U BRACKET
+2E27 ; Grapheme_Base # Pe RIGHT SIDEWAYS U BRACKET
+2E28 ; Grapheme_Base # Ps LEFT DOUBLE PARENTHESIS
+2E29 ; Grapheme_Base # Pe RIGHT DOUBLE PARENTHESIS
+2E2A..2E2E ; Grapheme_Base # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+2E2F ; Grapheme_Base # Lm VERTICAL TILDE
+2E30..2E39 ; Grapheme_Base # Po [10] RING POINT..TOP HALF SECTION SIGN
+2E3A..2E3B ; Grapheme_Base # Pd [2] TWO-EM DASH..THREE-EM DASH
+2E3C..2E3F ; Grapheme_Base # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM
+2E40 ; Grapheme_Base # Pd DOUBLE HYPHEN
+2E41 ; Grapheme_Base # Po REVERSED COMMA
+2E42 ; Grapheme_Base # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
+2E43..2E44 ; Grapheme_Base # Po [2] DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK
+2E80..2E99 ; Grapheme_Base # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+2E9B..2EF3 ; Grapheme_Base # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+2F00..2FD5 ; Grapheme_Base # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+2FF0..2FFB ; Grapheme_Base # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+3000 ; Grapheme_Base # Zs IDEOGRAPHIC SPACE
+3001..3003 ; Grapheme_Base # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
+3004 ; Grapheme_Base # So JAPANESE INDUSTRIAL STANDARD SYMBOL
+3005 ; Grapheme_Base # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; Grapheme_Base # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; Grapheme_Base # Nl IDEOGRAPHIC NUMBER ZERO
+3008 ; Grapheme_Base # Ps LEFT ANGLE BRACKET
+3009 ; Grapheme_Base # Pe RIGHT ANGLE BRACKET
+300A ; Grapheme_Base # Ps LEFT DOUBLE ANGLE BRACKET
+300B ; Grapheme_Base # Pe RIGHT DOUBLE ANGLE BRACKET
+300C ; Grapheme_Base # Ps LEFT CORNER BRACKET
+300D ; Grapheme_Base # Pe RIGHT CORNER BRACKET
+300E ; Grapheme_Base # Ps LEFT WHITE CORNER BRACKET
+300F ; Grapheme_Base # Pe RIGHT WHITE CORNER BRACKET
+3010 ; Grapheme_Base # Ps LEFT BLACK LENTICULAR BRACKET
+3011 ; Grapheme_Base # Pe RIGHT BLACK LENTICULAR BRACKET
+3012..3013 ; Grapheme_Base # So [2] POSTAL MARK..GETA MARK
+3014 ; Grapheme_Base # Ps LEFT TORTOISE SHELL BRACKET
+3015 ; Grapheme_Base # Pe RIGHT TORTOISE SHELL BRACKET
+3016 ; Grapheme_Base # Ps LEFT WHITE LENTICULAR BRACKET
+3017 ; Grapheme_Base # Pe RIGHT WHITE LENTICULAR BRACKET
+3018 ; Grapheme_Base # Ps LEFT WHITE TORTOISE SHELL BRACKET
+3019 ; Grapheme_Base # Pe RIGHT WHITE TORTOISE SHELL BRACKET
+301A ; Grapheme_Base # Ps LEFT WHITE SQUARE BRACKET
+301B ; Grapheme_Base # Pe RIGHT WHITE SQUARE BRACKET
+301C ; Grapheme_Base # Pd WAVE DASH
+301D ; Grapheme_Base # Ps REVERSED DOUBLE PRIME QUOTATION MARK
+301E..301F ; Grapheme_Base # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+3020 ; Grapheme_Base # So POSTAL MARK FACE
+3021..3029 ; Grapheme_Base # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3030 ; Grapheme_Base # Pd WAVY DASH
+3031..3035 ; Grapheme_Base # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3036..3037 ; Grapheme_Base # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+3038..303A ; Grapheme_Base # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; Grapheme_Base # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; Grapheme_Base # Lo MASU MARK
+303D ; Grapheme_Base # Po PART ALTERNATION MARK
+303E..303F ; Grapheme_Base # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
+3041..3096 ; Grapheme_Base # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309B..309C ; Grapheme_Base # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; Grapheme_Base # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; Grapheme_Base # Lo HIRAGANA DIGRAPH YORI
+30A0 ; Grapheme_Base # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+30A1..30FA ; Grapheme_Base # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FB ; Grapheme_Base # Po KATAKANA MIDDLE DOT
+30FC..30FE ; Grapheme_Base # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; Grapheme_Base # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; Grapheme_Base # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; Grapheme_Base # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+3190..3191 ; Grapheme_Base # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+3192..3195 ; Grapheme_Base # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+3196..319F ; Grapheme_Base # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+31A0..31BA ; Grapheme_Base # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY
+31C0..31E3 ; Grapheme_Base # So [36] CJK STROKE T..CJK STROKE Q
+31F0..31FF ; Grapheme_Base # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3200..321E ; Grapheme_Base # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+3220..3229 ; Grapheme_Base # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+322A..3247 ; Grapheme_Base # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO
+3248..324F ; Grapheme_Base # No [8] CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE
+3250 ; Grapheme_Base # So PARTNERSHIP SIGN
+3251..325F ; Grapheme_Base # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+3260..327F ; Grapheme_Base # So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+3280..3289 ; Grapheme_Base # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+328A..32B0 ; Grapheme_Base # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+32B1..32BF ; Grapheme_Base # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+32C0..32FE ; Grapheme_Base # So [63] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..CIRCLED KATAKANA WO
+3300..33FF ; Grapheme_Base # So [256] SQUARE APAATO..SQUARE GAL
+3400..4DB5 ; Grapheme_Base # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4DC0..4DFF ; Grapheme_Base # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+4E00..9FD5 ; Grapheme_Base # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5
+A000..A014 ; Grapheme_Base # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; Grapheme_Base # Lm YI SYLLABLE WU
+A016..A48C ; Grapheme_Base # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A490..A4C6 ; Grapheme_Base # So [55] YI RADICAL QOT..YI RADICAL KE
+A4D0..A4F7 ; Grapheme_Base # Lo [40] LISU LETTER BA..LISU LETTER OE
+A4F8..A4FD ; Grapheme_Base # Lm [6] LISU LETTER TONE MYA TI..LISU LETTER TONE MYA JEU
+A4FE..A4FF ; Grapheme_Base # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
+A500..A60B ; Grapheme_Base # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; Grapheme_Base # Lm VAI SYLLABLE LENGTHENER
+A60D..A60F ; Grapheme_Base # Po [3] VAI COMMA..VAI QUESTION MARK
+A610..A61F ; Grapheme_Base # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A620..A629 ; Grapheme_Base # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A62A..A62B ; Grapheme_Base # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A66D ; Grapheme_Base # L& [46] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; Grapheme_Base # Lo CYRILLIC LETTER MULTIOCULAR O
+A673 ; Grapheme_Base # Po SLAVONIC ASTERISK
+A67E ; Grapheme_Base # Po CYRILLIC KAVYKA
+A67F ; Grapheme_Base # Lm CYRILLIC PAYEROK
+A680..A69B ; Grapheme_Base # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
+A69C..A69D ; Grapheme_Base # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
+A6A0..A6E5 ; Grapheme_Base # Lo [70] BAMUM LETTER A..BAMUM LETTER KI
+A6E6..A6EF ; Grapheme_Base # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM
+A6F2..A6F7 ; Grapheme_Base # Po [6] BAMUM NJAEMLI..BAMUM QUESTION MARK
+A700..A716 ; Grapheme_Base # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A717..A71F ; Grapheme_Base # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A720..A721 ; Grapheme_Base # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A722..A76F ; Grapheme_Base # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; Grapheme_Base # Lm MODIFIER LETTER US
+A771..A787 ; Grapheme_Base # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; Grapheme_Base # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A789..A78A ; Grapheme_Base # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+A78B..A78E ; Grapheme_Base # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
+A78F ; Grapheme_Base # Lo LATIN LETTER SINOLOGICAL DOT
+A790..A7AE ; Grapheme_Base # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0..A7B7 ; Grapheme_Base # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA
+A7F7 ; Grapheme_Base # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
+A7F8..A7F9 ; Grapheme_Base # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
+A7FA ; Grapheme_Base # L& LATIN LETTER SMALL CAPITAL TURNED M
+A7FB..A801 ; Grapheme_Base # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; Grapheme_Base # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; Grapheme_Base # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; Grapheme_Base # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; Grapheme_Base # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A827 ; Grapheme_Base # Mc SYLOTI NAGRI VOWEL SIGN OO
+A828..A82B ; Grapheme_Base # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+A830..A835 ; Grapheme_Base # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE SIXTEENTHS
+A836..A837 ; Grapheme_Base # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
+A838 ; Grapheme_Base # Sc NORTH INDIC RUPEE MARK
+A839 ; Grapheme_Base # So NORTH INDIC QUANTITY MARK
+A840..A873 ; Grapheme_Base # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A874..A877 ; Grapheme_Base # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+A880..A881 ; Grapheme_Base # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; Grapheme_Base # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; Grapheme_Base # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8CE..A8CF ; Grapheme_Base # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+A8D0..A8D9 ; Grapheme_Base # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A8F2..A8F7 ; Grapheme_Base # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
+A8F8..A8FA ; Grapheme_Base # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET
+A8FB ; Grapheme_Base # Lo DEVANAGARI HEADSTROKE
+A8FC ; Grapheme_Base # Po DEVANAGARI SIGN SIDDHAM
+A8FD ; Grapheme_Base # Lo DEVANAGARI JAIN OM
+A900..A909 ; Grapheme_Base # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A90A..A925 ; Grapheme_Base # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A92E..A92F ; Grapheme_Base # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+A930..A946 ; Grapheme_Base # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A952..A953 ; Grapheme_Base # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+A95F ; Grapheme_Base # Po REJANG SECTION MARK
+A960..A97C ; Grapheme_Base # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH
+A983 ; Grapheme_Base # Mc JAVANESE SIGN WIGNYAN
+A984..A9B2 ; Grapheme_Base # Lo [47] JAVANESE LETTER A..JAVANESE LETTER HA
+A9B4..A9B5 ; Grapheme_Base # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG
+A9BA..A9BB ; Grapheme_Base # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE
+A9BD..A9C0 ; Grapheme_Base # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON
+A9C1..A9CD ; Grapheme_Base # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH
+A9CF ; Grapheme_Base # Lm JAVANESE PANGRANGKEP
+A9D0..A9D9 ; Grapheme_Base # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
+A9DE..A9DF ; Grapheme_Base # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN
+A9E0..A9E4 ; Grapheme_Base # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
+A9E6 ; Grapheme_Base # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
+A9E7..A9EF ; Grapheme_Base # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
+A9F0..A9F9 ; Grapheme_Base # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
+A9FA..A9FE ; Grapheme_Base # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
+AA00..AA28 ; Grapheme_Base # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA2F..AA30 ; Grapheme_Base # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA33..AA34 ; Grapheme_Base # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA40..AA42 ; Grapheme_Base # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA44..AA4B ; Grapheme_Base # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4D ; Grapheme_Base # Mc CHAM CONSONANT SIGN FINAL H
+AA50..AA59 ; Grapheme_Base # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+AA5C..AA5F ; Grapheme_Base # Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+AA60..AA6F ; Grapheme_Base # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
+AA70 ; Grapheme_Base # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
+AA71..AA76 ; Grapheme_Base # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
+AA77..AA79 ; Grapheme_Base # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO
+AA7A ; Grapheme_Base # Lo MYANMAR LETTER AITON RA
+AA7B ; Grapheme_Base # Mc MYANMAR SIGN PAO KAREN TONE
+AA7D ; Grapheme_Base # Mc MYANMAR SIGN TAI LAING TONE-5
+AA7E..AAAF ; Grapheme_Base # Lo [50] MYANMAR LETTER SHWE PALAUNG CHA..TAI VIET LETTER HIGH O
+AAB1 ; Grapheme_Base # Lo TAI VIET VOWEL AA
+AAB5..AAB6 ; Grapheme_Base # Lo [2] TAI VIET VOWEL E..TAI VIET VOWEL O
+AAB9..AABD ; Grapheme_Base # Lo [5] TAI VIET VOWEL UEA..TAI VIET VOWEL AN
+AAC0 ; Grapheme_Base # Lo TAI VIET TONE MAI NUENG
+AAC2 ; Grapheme_Base # Lo TAI VIET TONE MAI SONG
+AADB..AADC ; Grapheme_Base # Lo [2] TAI VIET SYMBOL KON..TAI VIET SYMBOL NUENG
+AADD ; Grapheme_Base # Lm TAI VIET SYMBOL SAM
+AADE..AADF ; Grapheme_Base # Po [2] TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI
+AAE0..AAEA ; Grapheme_Base # Lo [11] MEETEI MAYEK LETTER E..MEETEI MAYEK LETTER SSA
+AAEB ; Grapheme_Base # Mc MEETEI MAYEK VOWEL SIGN II
+AAEE..AAEF ; Grapheme_Base # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU
+AAF0..AAF1 ; Grapheme_Base # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM
+AAF2 ; Grapheme_Base # Lo MEETEI MAYEK ANJI
+AAF3..AAF4 ; Grapheme_Base # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
+AAF5 ; Grapheme_Base # Mc MEETEI MAYEK VOWEL SIGN VISARGA
+AB01..AB06 ; Grapheme_Base # Lo [6] ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO
+AB09..AB0E ; Grapheme_Base # Lo [6] ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO
+AB11..AB16 ; Grapheme_Base # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO
+AB20..AB26 ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO
+AB28..AB2E ; Grapheme_Base # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
+AB30..AB5A ; Grapheme_Base # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
+AB5B ; Grapheme_Base # Sk MODIFIER BREVE WITH INVERTED BREVE
+AB5C..AB5F ; Grapheme_Base # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
+AB60..AB65 ; Grapheme_Base # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA
+AB70..ABBF ; Grapheme_Base # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA
+ABC0..ABE2 ; Grapheme_Base # Lo [35] MEETEI MAYEK LETTER KOK..MEETEI MAYEK LETTER I LONSUM
+ABE3..ABE4 ; Grapheme_Base # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP
+ABE6..ABE7 ; Grapheme_Base # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP
+ABE9..ABEA ; Grapheme_Base # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
+ABEB ; Grapheme_Base # Po MEETEI MAYEK CHEIKHEI
+ABEC ; Grapheme_Base # Mc MEETEI MAYEK LUM IYEK
+ABF0..ABF9 ; Grapheme_Base # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE
+AC00..D7A3 ; Grapheme_Base # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+D7B0..D7C6 ; Grapheme_Base # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E
+D7CB..D7FB ; Grapheme_Base # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH
+F900..FA6D ; Grapheme_Base # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
+FA70..FAD9 ; Grapheme_Base # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; Grapheme_Base # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Grapheme_Base # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; Grapheme_Base # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; Grapheme_Base # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB29 ; Grapheme_Base # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+FB2A..FB36 ; Grapheme_Base # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; Grapheme_Base # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; Grapheme_Base # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; Grapheme_Base # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; Grapheme_Base # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; Grapheme_Base # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBB2..FBC1 ; Grapheme_Base # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW
+FBD3..FD3D ; Grapheme_Base # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD3E ; Grapheme_Base # Pe ORNATE LEFT PARENTHESIS
+FD3F ; Grapheme_Base # Ps ORNATE RIGHT PARENTHESIS
+FD50..FD8F ; Grapheme_Base # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; Grapheme_Base # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; Grapheme_Base # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FDFC ; Grapheme_Base # Sc RIAL SIGN
+FDFD ; Grapheme_Base # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
+FE10..FE16 ; Grapheme_Base # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+FE17 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+FE18 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+FE19 ; Grapheme_Base # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+FE30 ; Grapheme_Base # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+FE31..FE32 ; Grapheme_Base # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+FE33..FE34 ; Grapheme_Base # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE35 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+FE36 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+FE37 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+FE38 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+FE39 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+FE3A ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+FE3B ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+FE3C ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+FE3D ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+FE3E ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+FE3F ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+FE40 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+FE41 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+FE42 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+FE43 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+FE44 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+FE45..FE46 ; Grapheme_Base # Po [2] SESAME DOT..WHITE SESAME DOT
+FE47 ; Grapheme_Base # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+FE48 ; Grapheme_Base # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+FE49..FE4C ; Grapheme_Base # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+FE4D..FE4F ; Grapheme_Base # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FE50..FE52 ; Grapheme_Base # Po [3] SMALL COMMA..SMALL FULL STOP
+FE54..FE57 ; Grapheme_Base # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+FE58 ; Grapheme_Base # Pd SMALL EM DASH
+FE59 ; Grapheme_Base # Ps SMALL LEFT PARENTHESIS
+FE5A ; Grapheme_Base # Pe SMALL RIGHT PARENTHESIS
+FE5B ; Grapheme_Base # Ps SMALL LEFT CURLY BRACKET
+FE5C ; Grapheme_Base # Pe SMALL RIGHT CURLY BRACKET
+FE5D ; Grapheme_Base # Ps SMALL LEFT TORTOISE SHELL BRACKET
+FE5E ; Grapheme_Base # Pe SMALL RIGHT TORTOISE SHELL BRACKET
+FE5F..FE61 ; Grapheme_Base # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK
+FE62 ; Grapheme_Base # Sm SMALL PLUS SIGN
+FE63 ; Grapheme_Base # Pd SMALL HYPHEN-MINUS
+FE64..FE66 ; Grapheme_Base # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+FE68 ; Grapheme_Base # Po SMALL REVERSE SOLIDUS
+FE69 ; Grapheme_Base # Sc SMALL DOLLAR SIGN
+FE6A..FE6B ; Grapheme_Base # Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+FE70..FE74 ; Grapheme_Base # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; Grapheme_Base # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF01..FF03 ; Grapheme_Base # Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+FF04 ; Grapheme_Base # Sc FULLWIDTH DOLLAR SIGN
+FF05..FF07 ; Grapheme_Base # Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+FF08 ; Grapheme_Base # Ps FULLWIDTH LEFT PARENTHESIS
+FF09 ; Grapheme_Base # Pe FULLWIDTH RIGHT PARENTHESIS
+FF0A ; Grapheme_Base # Po FULLWIDTH ASTERISK
+FF0B ; Grapheme_Base # Sm FULLWIDTH PLUS SIGN
+FF0C ; Grapheme_Base # Po FULLWIDTH COMMA
+FF0D ; Grapheme_Base # Pd FULLWIDTH HYPHEN-MINUS
+FF0E..FF0F ; Grapheme_Base # Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+FF10..FF19 ; Grapheme_Base # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+FF1A..FF1B ; Grapheme_Base # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+FF1C..FF1E ; Grapheme_Base # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+FF1F..FF20 ; Grapheme_Base # Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+FF21..FF3A ; Grapheme_Base # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF3B ; Grapheme_Base # Ps FULLWIDTH LEFT SQUARE BRACKET
+FF3C ; Grapheme_Base # Po FULLWIDTH REVERSE SOLIDUS
+FF3D ; Grapheme_Base # Pe FULLWIDTH RIGHT SQUARE BRACKET
+FF3E ; Grapheme_Base # Sk FULLWIDTH CIRCUMFLEX ACCENT
+FF3F ; Grapheme_Base # Pc FULLWIDTH LOW LINE
+FF40 ; Grapheme_Base # Sk FULLWIDTH GRAVE ACCENT
+FF41..FF5A ; Grapheme_Base # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF5B ; Grapheme_Base # Ps FULLWIDTH LEFT CURLY BRACKET
+FF5C ; Grapheme_Base # Sm FULLWIDTH VERTICAL LINE
+FF5D ; Grapheme_Base # Pe FULLWIDTH RIGHT CURLY BRACKET
+FF5E ; Grapheme_Base # Sm FULLWIDTH TILDE
+FF5F ; Grapheme_Base # Ps FULLWIDTH LEFT WHITE PARENTHESIS
+FF60 ; Grapheme_Base # Pe FULLWIDTH RIGHT WHITE PARENTHESIS
+FF61 ; Grapheme_Base # Po HALFWIDTH IDEOGRAPHIC FULL STOP
+FF62 ; Grapheme_Base # Ps HALFWIDTH LEFT CORNER BRACKET
+FF63 ; Grapheme_Base # Pe HALFWIDTH RIGHT CORNER BRACKET
+FF64..FF65 ; Grapheme_Base # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+FF66..FF6F ; Grapheme_Base # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; Grapheme_Base # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; Grapheme_Base # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FFA0..FFBE ; Grapheme_Base # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; Grapheme_Base # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; Grapheme_Base # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; Grapheme_Base # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; Grapheme_Base # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+FFE0..FFE1 ; Grapheme_Base # Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+FFE2 ; Grapheme_Base # Sm FULLWIDTH NOT SIGN
+FFE3 ; Grapheme_Base # Sk FULLWIDTH MACRON
+FFE4 ; Grapheme_Base # So FULLWIDTH BROKEN BAR
+FFE5..FFE6 ; Grapheme_Base # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+FFE8 ; Grapheme_Base # So HALFWIDTH FORMS LIGHT VERTICAL
+FFE9..FFEC ; Grapheme_Base # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+FFED..FFEE ; Grapheme_Base # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+FFFC..FFFD ; Grapheme_Base # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER
+10000..1000B ; Grapheme_Base # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; Grapheme_Base # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; Grapheme_Base # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; Grapheme_Base # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; Grapheme_Base # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; Grapheme_Base # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; Grapheme_Base # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10100..10102 ; Grapheme_Base # Po [3] AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK
+10107..10133 ; Grapheme_Base # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+10137..1013F ; Grapheme_Base # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+10140..10174 ; Grapheme_Base # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10175..10178 ; Grapheme_Base # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+10179..10189 ; Grapheme_Base # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+1018A..1018B ; Grapheme_Base # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
+1018C..1018E ; Grapheme_Base # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN
+10190..1019B ; Grapheme_Base # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
+101A0 ; Grapheme_Base # So GREEK SYMBOL TAU RHO
+101D0..101FC ; Grapheme_Base # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+10280..1029C ; Grapheme_Base # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; Grapheme_Base # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+102E1..102FB ; Grapheme_Base # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
+10300..1031F ; Grapheme_Base # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
+10320..10323 ; Grapheme_Base # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+10330..10340 ; Grapheme_Base # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; Grapheme_Base # Nl GOTHIC LETTER NINETY
+10342..10349 ; Grapheme_Base # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; Grapheme_Base # Nl GOTHIC LETTER NINE HUNDRED
+10350..10375 ; Grapheme_Base # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
+10380..1039D ; Grapheme_Base # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+1039F ; Grapheme_Base # Po UGARITIC WORD DIVIDER
+103A0..103C3 ; Grapheme_Base # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; Grapheme_Base # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D0 ; Grapheme_Base # Po OLD PERSIAN WORD DIVIDER
+103D1..103D5 ; Grapheme_Base # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; Grapheme_Base # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; Grapheme_Base # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104A0..104A9 ; Grapheme_Base # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+104B0..104D3 ; Grapheme_Base # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA
+104D8..104FB ; Grapheme_Base # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA
+10500..10527 ; Grapheme_Base # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
+10530..10563 ; Grapheme_Base # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
+1056F ; Grapheme_Base # Po CAUCASIAN ALBANIAN CITATION MARK
+10600..10736 ; Grapheme_Base # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
+10740..10755 ; Grapheme_Base # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
+10760..10767 ; Grapheme_Base # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
+10800..10805 ; Grapheme_Base # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; Grapheme_Base # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; Grapheme_Base # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; Grapheme_Base # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; Grapheme_Base # Lo CYPRIOT SYLLABLE ZA
+1083F..10855 ; Grapheme_Base # Lo [23] CYPRIOT SYLLABLE ZO..IMPERIAL ARAMAIC LETTER TAW
+10857 ; Grapheme_Base # Po IMPERIAL ARAMAIC SECTION SIGN
+10858..1085F ; Grapheme_Base # No [8] IMPERIAL ARAMAIC NUMBER ONE..IMPERIAL ARAMAIC NUMBER TEN THOUSAND
+10860..10876 ; Grapheme_Base # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
+10877..10878 ; Grapheme_Base # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON
+10879..1087F ; Grapheme_Base # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY
+10880..1089E ; Grapheme_Base # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
+108A7..108AF ; Grapheme_Base # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED
+108E0..108F2 ; Grapheme_Base # Lo [19] HATRAN LETTER ALEPH..HATRAN LETTER QOPH
+108F4..108F5 ; Grapheme_Base # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
+108FB..108FF ; Grapheme_Base # No [5] HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED
+10900..10915 ; Grapheme_Base # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10916..1091B ; Grapheme_Base # No [6] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER THREE
+1091F ; Grapheme_Base # Po PHOENICIAN WORD SEPARATOR
+10920..10939 ; Grapheme_Base # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+1093F ; Grapheme_Base # Po LYDIAN TRIANGULAR MARK
+10980..109B7 ; Grapheme_Base # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
+109BC..109BD ; Grapheme_Base # No [2] MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF
+109BE..109BF ; Grapheme_Base # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
+109C0..109CF ; Grapheme_Base # No [16] MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY
+109D2..109FF ; Grapheme_Base # No [46] MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS
+10A00 ; Grapheme_Base # Lo KHAROSHTHI LETTER A
+10A10..10A13 ; Grapheme_Base # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; Grapheme_Base # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; Grapheme_Base # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A40..10A47 ; Grapheme_Base # No [8] KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND
+10A50..10A58 ; Grapheme_Base # Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+10A60..10A7C ; Grapheme_Base # Lo [29] OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH
+10A7D..10A7E ; Grapheme_Base # No [2] OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMBER FIFTY
+10A7F ; Grapheme_Base # Po OLD SOUTH ARABIAN NUMERIC INDICATOR
+10A80..10A9C ; Grapheme_Base # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
+10A9D..10A9F ; Grapheme_Base # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY
+10AC0..10AC7 ; Grapheme_Base # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
+10AC8 ; Grapheme_Base # So MANICHAEAN SIGN UD
+10AC9..10AE4 ; Grapheme_Base # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
+10AEB..10AEF ; Grapheme_Base # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED
+10AF0..10AF6 ; Grapheme_Base # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER
+10B00..10B35 ; Grapheme_Base # Lo [54] AVESTAN LETTER A..AVESTAN LETTER HE
+10B39..10B3F ; Grapheme_Base # Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION
+10B40..10B55 ; Grapheme_Base # Lo [22] INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW
+10B58..10B5F ; Grapheme_Base # No [8] INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
+10B60..10B72 ; Grapheme_Base # Lo [19] INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW
+10B78..10B7F ; Grapheme_Base # No [8] INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
+10B80..10B91 ; Grapheme_Base # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
+10B99..10B9C ; Grapheme_Base # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+10BA9..10BAF ; Grapheme_Base # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED
+10C00..10C48 ; Grapheme_Base # Lo [73] OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH
+10C80..10CB2 ; Grapheme_Base # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US
+10CC0..10CF2 ; Grapheme_Base # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US
+10CFA..10CFF ; Grapheme_Base # No [6] OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND
+10E60..10E7E ; Grapheme_Base # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
+11000 ; Grapheme_Base # Mc BRAHMI SIGN CANDRABINDU
+11002 ; Grapheme_Base # Mc BRAHMI SIGN VISARGA
+11003..11037 ; Grapheme_Base # Lo [53] BRAHMI SIGN JIHVAMULIYA..BRAHMI LETTER OLD TAMIL NNNA
+11047..1104D ; Grapheme_Base # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
+11052..11065 ; Grapheme_Base # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND
+11066..1106F ; Grapheme_Base # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
+11082 ; Grapheme_Base # Mc KAITHI SIGN VISARGA
+11083..110AF ; Grapheme_Base # Lo [45] KAITHI LETTER A..KAITHI LETTER HA
+110B0..110B2 ; Grapheme_Base # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
+110B7..110B8 ; Grapheme_Base # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
+110BB..110BC ; Grapheme_Base # Po [2] KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN
+110BE..110C1 ; Grapheme_Base # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
+110D0..110E8 ; Grapheme_Base # Lo [25] SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE
+110F0..110F9 ; Grapheme_Base # Nd [10] SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE
+11103..11126 ; Grapheme_Base # Lo [36] CHAKMA LETTER AA..CHAKMA LETTER HAA
+1112C ; Grapheme_Base # Mc CHAKMA VOWEL SIGN E
+11136..1113F ; Grapheme_Base # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE
+11140..11143 ; Grapheme_Base # Po [4] CHAKMA SECTION MARK..CHAKMA QUESTION MARK
+11150..11172 ; Grapheme_Base # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
+11174..11175 ; Grapheme_Base # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK
+11176 ; Grapheme_Base # Lo MAHAJANI LIGATURE SHRI
+11182 ; Grapheme_Base # Mc SHARADA SIGN VISARGA
+11183..111B2 ; Grapheme_Base # Lo [48] SHARADA LETTER A..SHARADA LETTER HA
+111B3..111B5 ; Grapheme_Base # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
+111BF..111C0 ; Grapheme_Base # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
+111C1..111C4 ; Grapheme_Base # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
+111C5..111C9 ; Grapheme_Base # Po [5] SHARADA DANDA..SHARADA SANDHI MARK
+111CD ; Grapheme_Base # Po SHARADA SUTRA MARK
+111D0..111D9 ; Grapheme_Base # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
+111DA ; Grapheme_Base # Lo SHARADA EKAM
+111DB ; Grapheme_Base # Po SHARADA SIGN SIDDHAM
+111DC ; Grapheme_Base # Lo SHARADA HEADSTROKE
+111DD..111DF ; Grapheme_Base # Po [3] SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2
+111E1..111F4 ; Grapheme_Base # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND
+11200..11211 ; Grapheme_Base # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
+11213..1122B ; Grapheme_Base # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
+1122C..1122E ; Grapheme_Base # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
+11232..11233 ; Grapheme_Base # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
+11235 ; Grapheme_Base # Mc KHOJKI SIGN VIRAMA
+11238..1123D ; Grapheme_Base # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN
+11280..11286 ; Grapheme_Base # Lo [7] MULTANI LETTER A..MULTANI LETTER GA
+11288 ; Grapheme_Base # Lo MULTANI LETTER GHA
+1128A..1128D ; Grapheme_Base # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA
+1128F..1129D ; Grapheme_Base # Lo [15] MULTANI LETTER NYA..MULTANI LETTER BA
+1129F..112A8 ; Grapheme_Base # Lo [10] MULTANI LETTER BHA..MULTANI LETTER RHA
+112A9 ; Grapheme_Base # Po MULTANI SECTION MARK
+112B0..112DE ; Grapheme_Base # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
+112E0..112E2 ; Grapheme_Base # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
+112F0..112F9 ; Grapheme_Base # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
+11302..11303 ; Grapheme_Base # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
+11305..1130C ; Grapheme_Base # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
+1130F..11310 ; Grapheme_Base # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
+11313..11328 ; Grapheme_Base # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
+1132A..11330 ; Grapheme_Base # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
+11332..11333 ; Grapheme_Base # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
+11335..11339 ; Grapheme_Base # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
+1133D ; Grapheme_Base # Lo GRANTHA SIGN AVAGRAHA
+1133F ; Grapheme_Base # Mc GRANTHA VOWEL SIGN I
+11341..11344 ; Grapheme_Base # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
+11347..11348 ; Grapheme_Base # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
+1134B..1134D ; Grapheme_Base # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
+11350 ; Grapheme_Base # Lo GRANTHA OM
+1135D..11361 ; Grapheme_Base # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
+11362..11363 ; Grapheme_Base # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
+11400..11434 ; Grapheme_Base # Lo [53] NEWA LETTER A..NEWA LETTER HA
+11435..11437 ; Grapheme_Base # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II
+11440..11441 ; Grapheme_Base # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU
+11445 ; Grapheme_Base # Mc NEWA SIGN VISARGA
+11447..1144A ; Grapheme_Base # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI
+1144B..1144F ; Grapheme_Base # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN
+11450..11459 ; Grapheme_Base # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE
+1145B ; Grapheme_Base # Po NEWA PLACEHOLDER MARK
+1145D ; Grapheme_Base # Po NEWA INSERTION SIGN
+11480..114AF ; Grapheme_Base # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
+114B1..114B2 ; Grapheme_Base # Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II
+114B9 ; Grapheme_Base # Mc TIRHUTA VOWEL SIGN E
+114BB..114BC ; Grapheme_Base # Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O
+114BE ; Grapheme_Base # Mc TIRHUTA VOWEL SIGN AU
+114C1 ; Grapheme_Base # Mc TIRHUTA SIGN VISARGA
+114C4..114C5 ; Grapheme_Base # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
+114C6 ; Grapheme_Base # Po TIRHUTA ABBREVIATION SIGN
+114C7 ; Grapheme_Base # Lo TIRHUTA OM
+114D0..114D9 ; Grapheme_Base # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
+11580..115AE ; Grapheme_Base # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
+115B0..115B1 ; Grapheme_Base # Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II
+115B8..115BB ; Grapheme_Base # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
+115BE ; Grapheme_Base # Mc SIDDHAM SIGN VISARGA
+115C1..115D7 ; Grapheme_Base # Po [23] SIDDHAM SIGN SIDDHAM..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES
+115D8..115DB ; Grapheme_Base # Lo [4] SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM LETTER ALTERNATE U
+11600..1162F ; Grapheme_Base # Lo [48] MODI LETTER A..MODI LETTER LLA
+11630..11632 ; Grapheme_Base # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
+1163B..1163C ; Grapheme_Base # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
+1163E ; Grapheme_Base # Mc MODI SIGN VISARGA
+11641..11643 ; Grapheme_Base # Po [3] MODI DANDA..MODI ABBREVIATION SIGN
+11644 ; Grapheme_Base # Lo MODI SIGN HUVA
+11650..11659 ; Grapheme_Base # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
+11660..1166C ; Grapheme_Base # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT
+11680..116AA ; Grapheme_Base # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA
+116AC ; Grapheme_Base # Mc TAKRI SIGN VISARGA
+116AE..116AF ; Grapheme_Base # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
+116B6 ; Grapheme_Base # Mc TAKRI SIGN VIRAMA
+116C0..116C9 ; Grapheme_Base # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE
+11700..11719 ; Grapheme_Base # Lo [26] AHOM LETTER KA..AHOM LETTER JHA
+11720..11721 ; Grapheme_Base # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
+11726 ; Grapheme_Base # Mc AHOM VOWEL SIGN E
+11730..11739 ; Grapheme_Base # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE
+1173A..1173B ; Grapheme_Base # No [2] AHOM NUMBER TEN..AHOM NUMBER TWENTY
+1173C..1173E ; Grapheme_Base # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI
+1173F ; Grapheme_Base # So AHOM SYMBOL VI
+118A0..118DF ; Grapheme_Base # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
+118E0..118E9 ; Grapheme_Base # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
+118EA..118F2 ; Grapheme_Base # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
+118FF ; Grapheme_Base # Lo WARANG CITI OM
+11AC0..11AF8 ; Grapheme_Base # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
+11C00..11C08 ; Grapheme_Base # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L
+11C0A..11C2E ; Grapheme_Base # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA
+11C2F ; Grapheme_Base # Mc BHAIKSUKI VOWEL SIGN AA
+11C3E ; Grapheme_Base # Mc BHAIKSUKI SIGN VISARGA
+11C40 ; Grapheme_Base # Lo BHAIKSUKI SIGN AVAGRAHA
+11C41..11C45 ; Grapheme_Base # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2
+11C50..11C59 ; Grapheme_Base # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
+11C5A..11C6C ; Grapheme_Base # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK
+11C70..11C71 ; Grapheme_Base # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD
+11C72..11C8F ; Grapheme_Base # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A
+11CA9 ; Grapheme_Base # Mc MARCHEN SUBJOINED LETTER YA
+11CB1 ; Grapheme_Base # Mc MARCHEN VOWEL SIGN I
+11CB4 ; Grapheme_Base # Mc MARCHEN VOWEL SIGN O
+12000..12399 ; Grapheme_Base # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U
+12400..1246E ; Grapheme_Base # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
+12470..12474 ; Grapheme_Base # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
+12480..12543 ; Grapheme_Base # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU
+13000..1342E ; Grapheme_Base # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
+14400..14646 ; Grapheme_Base # Lo [583] ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530
+16800..16A38 ; Grapheme_Base # Lo [569] BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ
+16A40..16A5E ; Grapheme_Base # Lo [31] MRO LETTER TA..MRO LETTER TEK
+16A60..16A69 ; Grapheme_Base # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
+16A6E..16A6F ; Grapheme_Base # Po [2] MRO DANDA..MRO DOUBLE DANDA
+16AD0..16AED ; Grapheme_Base # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
+16AF5 ; Grapheme_Base # Po BASSA VAH FULL STOP
+16B00..16B2F ; Grapheme_Base # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
+16B37..16B3B ; Grapheme_Base # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM
+16B3C..16B3F ; Grapheme_Base # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB
+16B40..16B43 ; Grapheme_Base # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
+16B44 ; Grapheme_Base # Po PAHAWH HMONG SIGN XAUS
+16B45 ; Grapheme_Base # So PAHAWH HMONG SIGN CIM TSOV ROG
+16B50..16B59 ; Grapheme_Base # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
+16B5B..16B61 ; Grapheme_Base # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS
+16B63..16B77 ; Grapheme_Base # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
+16B7D..16B8F ; Grapheme_Base # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
+16F00..16F44 ; Grapheme_Base # Lo [69] MIAO LETTER PA..MIAO LETTER HHA
+16F50 ; Grapheme_Base # Lo MIAO LETTER NASALIZATION
+16F51..16F7E ; Grapheme_Base # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
+16F93..16F9F ; Grapheme_Base # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
+16FE0 ; Grapheme_Base # Lm TANGUT ITERATION MARK
+17000..187EC ; Grapheme_Base # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+18800..18AF2 ; Grapheme_Base # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
+1B000..1B001 ; Grapheme_Base # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE
+1BC00..1BC6A ; Grapheme_Base # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
+1BC70..1BC7C ; Grapheme_Base # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
+1BC80..1BC88 ; Grapheme_Base # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
+1BC90..1BC99 ; Grapheme_Base # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
+1BC9C ; Grapheme_Base # So DUPLOYAN SIGN O WITH CROSS
+1BC9F ; Grapheme_Base # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
+1D000..1D0F5 ; Grapheme_Base # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+1D100..1D126 ; Grapheme_Base # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+1D129..1D164 ; Grapheme_Base # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+1D166 ; Grapheme_Base # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D16A..1D16C ; Grapheme_Base # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+1D16D ; Grapheme_Base # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
+1D183..1D184 ; Grapheme_Base # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+1D18C..1D1A9 ; Grapheme_Base # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+1D1AE..1D1E8 ; Grapheme_Base # So [59] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL KIEVAN FLAT SIGN
+1D200..1D241 ; Grapheme_Base # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+1D245 ; Grapheme_Base # So GREEK MUSICAL LEIMMA
+1D300..1D356 ; Grapheme_Base # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+1D360..1D371 ; Grapheme_Base # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE
+1D400..1D454 ; Grapheme_Base # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; Grapheme_Base # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Grapheme_Base # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Grapheme_Base # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Grapheme_Base # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Grapheme_Base # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; Grapheme_Base # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Grapheme_Base # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Grapheme_Base # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; Grapheme_Base # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Grapheme_Base # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Grapheme_Base # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Grapheme_Base # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; Grapheme_Base # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Grapheme_Base # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Grapheme_Base # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Grapheme_Base # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Grapheme_Base # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; Grapheme_Base # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; Grapheme_Base # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C1 ; Grapheme_Base # Sm MATHEMATICAL BOLD NABLA
+1D6C2..1D6DA ; Grapheme_Base # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DB ; Grapheme_Base # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+1D6DC..1D6FA ; Grapheme_Base # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FB ; Grapheme_Base # Sm MATHEMATICAL ITALIC NABLA
+1D6FC..1D714 ; Grapheme_Base # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D715 ; Grapheme_Base # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+1D716..1D734 ; Grapheme_Base # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D735 ; Grapheme_Base # Sm MATHEMATICAL BOLD ITALIC NABLA
+1D736..1D74E ; Grapheme_Base # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D74F ; Grapheme_Base # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+1D750..1D76E ; Grapheme_Base # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D76F ; Grapheme_Base # Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+1D770..1D788 ; Grapheme_Base # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D789 ; Grapheme_Base # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+1D78A..1D7A8 ; Grapheme_Base # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7A9 ; Grapheme_Base # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+1D7AA..1D7C2 ; Grapheme_Base # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C3 ; Grapheme_Base # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+1D7C4..1D7CB ; Grapheme_Base # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; Grapheme_Base # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1D800..1D9FF ; Grapheme_Base # So [512] SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD
+1DA37..1DA3A ; Grapheme_Base # So [4] SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE
+1DA6D..1DA74 ; Grapheme_Base # So [8] SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING
+1DA76..1DA83 ; Grapheme_Base # So [14] SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH
+1DA85..1DA86 ; Grapheme_Base # So [2] SIGNWRITING LOCATION TORSO..SIGNWRITING LOCATION LIMBS DIGITS
+1DA87..1DA8B ; Grapheme_Base # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS
+1E800..1E8C4 ; Grapheme_Base # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
+1E8C7..1E8CF ; Grapheme_Base # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE
+1E900..1E943 ; Grapheme_Base # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA
+1E950..1E959 ; Grapheme_Base # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
+1E95E..1E95F ; Grapheme_Base # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK
+1EE00..1EE03 ; Grapheme_Base # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL
+1EE05..1EE1F ; Grapheme_Base # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF
+1EE21..1EE22 ; Grapheme_Base # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM
+1EE24 ; Grapheme_Base # Lo ARABIC MATHEMATICAL INITIAL HEH
+1EE27 ; Grapheme_Base # Lo ARABIC MATHEMATICAL INITIAL HAH
+1EE29..1EE32 ; Grapheme_Base # Lo [10] ARABIC MATHEMATICAL INITIAL YEH..ARABIC MATHEMATICAL INITIAL QAF
+1EE34..1EE37 ; Grapheme_Base # Lo [4] ARABIC MATHEMATICAL INITIAL SHEEN..ARABIC MATHEMATICAL INITIAL KHAH
+1EE39 ; Grapheme_Base # Lo ARABIC MATHEMATICAL INITIAL DAD
+1EE3B ; Grapheme_Base # Lo ARABIC MATHEMATICAL INITIAL GHAIN
+1EE42 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED JEEM
+1EE47 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED HAH
+1EE49 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED YEH
+1EE4B ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED LAM
+1EE4D..1EE4F ; Grapheme_Base # Lo [3] ARABIC MATHEMATICAL TAILED NOON..ARABIC MATHEMATICAL TAILED AIN
+1EE51..1EE52 ; Grapheme_Base # Lo [2] ARABIC MATHEMATICAL TAILED SAD..ARABIC MATHEMATICAL TAILED QAF
+1EE54 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED SHEEN
+1EE57 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED KHAH
+1EE59 ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED DAD
+1EE5B ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED GHAIN
+1EE5D ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED DOTLESS NOON
+1EE5F ; Grapheme_Base # Lo ARABIC MATHEMATICAL TAILED DOTLESS QAF
+1EE61..1EE62 ; Grapheme_Base # Lo [2] ARABIC MATHEMATICAL STRETCHED BEH..ARABIC MATHEMATICAL STRETCHED JEEM
+1EE64 ; Grapheme_Base # Lo ARABIC MATHEMATICAL STRETCHED HEH
+1EE67..1EE6A ; Grapheme_Base # Lo [4] ARABIC MATHEMATICAL STRETCHED HAH..ARABIC MATHEMATICAL STRETCHED KAF
+1EE6C..1EE72 ; Grapheme_Base # Lo [7] ARABIC MATHEMATICAL STRETCHED MEEM..ARABIC MATHEMATICAL STRETCHED QAF
+1EE74..1EE77 ; Grapheme_Base # Lo [4] ARABIC MATHEMATICAL STRETCHED SHEEN..ARABIC MATHEMATICAL STRETCHED KHAH
+1EE79..1EE7C ; Grapheme_Base # Lo [4] ARABIC MATHEMATICAL STRETCHED DAD..ARABIC MATHEMATICAL STRETCHED DOTLESS BEH
+1EE7E ; Grapheme_Base # Lo ARABIC MATHEMATICAL STRETCHED DOTLESS FEH
+1EE80..1EE89 ; Grapheme_Base # Lo [10] ARABIC MATHEMATICAL LOOPED ALEF..ARABIC MATHEMATICAL LOOPED YEH
+1EE8B..1EE9B ; Grapheme_Base # Lo [17] ARABIC MATHEMATICAL LOOPED LAM..ARABIC MATHEMATICAL LOOPED GHAIN
+1EEA1..1EEA3 ; Grapheme_Base # Lo [3] ARABIC MATHEMATICAL DOUBLE-STRUCK BEH..ARABIC MATHEMATICAL DOUBLE-STRUCK DAL
+1EEA5..1EEA9 ; Grapheme_Base # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
+1EEAB..1EEBB ; Grapheme_Base # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
+1EEF0..1EEF1 ; Grapheme_Base # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+1F000..1F02B ; Grapheme_Base # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F030..1F093 ; Grapheme_Base # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+1F0A0..1F0AE ; Grapheme_Base # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+1F0B1..1F0BF ; Grapheme_Base # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER
+1F0C1..1F0CF ; Grapheme_Base # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER
+1F0D1..1F0F5 ; Grapheme_Base # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
+1F100..1F10C ; Grapheme_Base # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
+1F110..1F12E ; Grapheme_Base # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ
+1F130..1F16B ; Grapheme_Base # So [60] SQUARED LATIN CAPITAL LETTER A..RAISED MD SIGN
+1F170..1F1AC ; Grapheme_Base # So [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD
+1F1E6..1F202 ; Grapheme_Base # So [29] REGIONAL INDICATOR SYMBOL LETTER A..SQUARED KATAKANA SA
+1F210..1F23B ; Grapheme_Base # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D
+1F240..1F248 ; Grapheme_Base # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
+1F250..1F251 ; Grapheme_Base # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
+1F300..1F3FA ; Grapheme_Base # So [251] CYCLONE..AMPHORA
+1F3FB..1F3FF ; Grapheme_Base # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
+1F400..1F6D2 ; Grapheme_Base # So [723] RAT..SHOPPING TROLLEY
+1F6E0..1F6EC ; Grapheme_Base # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING
+1F6F0..1F6F6 ; Grapheme_Base # So [7] SATELLITE..CANOE
+1F700..1F773 ; Grapheme_Base # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE
+1F780..1F7D4 ; Grapheme_Base # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR
+1F800..1F80B ; Grapheme_Base # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD
+1F810..1F847 ; Grapheme_Base # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW
+1F850..1F859 ; Grapheme_Base # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
+1F860..1F887 ; Grapheme_Base # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
+1F890..1F8AD ; Grapheme_Base # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
+1F910..1F91E ; Grapheme_Base # So [15] ZIPPER-MOUTH FACE..HAND WITH INDEX AND MIDDLE FINGERS CROSSED
+1F920..1F927 ; Grapheme_Base # So [8] FACE WITH COWBOY HAT..SNEEZING FACE
+1F930 ; Grapheme_Base # So PREGNANT WOMAN
+1F933..1F93E ; Grapheme_Base # So [12] SELFIE..HANDBALL
+1F940..1F94B ; Grapheme_Base # So [12] WILTED FLOWER..MARTIAL ARTS UNIFORM
+1F950..1F95E ; Grapheme_Base # So [15] CROISSANT..PANCAKES
+1F980..1F991 ; Grapheme_Base # So [18] CRAB..SQUID
+1F9C0 ; Grapheme_Base # So CHEESE WEDGE
+20000..2A6D6 ; Grapheme_Base # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2A700..2B734 ; Grapheme_Base # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734
+2B740..2B81D ; Grapheme_Base # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D
+2B820..2CEA1 ; Grapheme_Base # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
+2F800..2FA1D ; Grapheme_Base # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 126288
+
+# ================================================
+
+# Derived Property: Grapheme_Link (deprecated)
+# Generated from: Canonical_Combining_Class=Virama
+# Use Canonical_Combining_Class=Virama directly instead
+
+094D ; Grapheme_Link # Mn DEVANAGARI SIGN VIRAMA
+09CD ; Grapheme_Link # Mn BENGALI SIGN VIRAMA
+0A4D ; Grapheme_Link # Mn GURMUKHI SIGN VIRAMA
+0ACD ; Grapheme_Link # Mn GUJARATI SIGN VIRAMA
+0B4D ; Grapheme_Link # Mn ORIYA SIGN VIRAMA
+0BCD ; Grapheme_Link # Mn TAMIL SIGN VIRAMA
+0C4D ; Grapheme_Link # Mn TELUGU SIGN VIRAMA
+0CCD ; Grapheme_Link # Mn KANNADA SIGN VIRAMA
+0D4D ; Grapheme_Link # Mn MALAYALAM SIGN VIRAMA
+0DCA ; Grapheme_Link # Mn SINHALA SIGN AL-LAKUNA
+0E3A ; Grapheme_Link # Mn THAI CHARACTER PHINTHU
+0F84 ; Grapheme_Link # Mn TIBETAN MARK HALANTA
+1039..103A ; Grapheme_Link # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+1714 ; Grapheme_Link # Mn TAGALOG SIGN VIRAMA
+1734 ; Grapheme_Link # Mn HANUNOO SIGN PAMUDPOD
+17D2 ; Grapheme_Link # Mn KHMER SIGN COENG
+1A60 ; Grapheme_Link # Mn TAI THAM SIGN SAKOT
+1B44 ; Grapheme_Link # Mc BALINESE ADEG ADEG
+1BAA ; Grapheme_Link # Mc SUNDANESE SIGN PAMAAEH
+1BAB ; Grapheme_Link # Mn SUNDANESE SIGN VIRAMA
+1BF2..1BF3 ; Grapheme_Link # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN
+2D7F ; Grapheme_Link # Mn TIFINAGH CONSONANT JOINER
+A806 ; Grapheme_Link # Mn SYLOTI NAGRI SIGN HASANTA
+A8C4 ; Grapheme_Link # Mn SAURASHTRA SIGN VIRAMA
+A953 ; Grapheme_Link # Mc REJANG VIRAMA
+A9C0 ; Grapheme_Link # Mc JAVANESE PANGKON
+AAF6 ; Grapheme_Link # Mn MEETEI MAYEK VIRAMA
+ABED ; Grapheme_Link # Mn MEETEI MAYEK APUN IYEK
+10A3F ; Grapheme_Link # Mn KHAROSHTHI VIRAMA
+11046 ; Grapheme_Link # Mn BRAHMI VIRAMA
+1107F ; Grapheme_Link # Mn BRAHMI NUMBER JOINER
+110B9 ; Grapheme_Link # Mn KAITHI SIGN VIRAMA
+11133..11134 ; Grapheme_Link # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA
+111C0 ; Grapheme_Link # Mc SHARADA SIGN VIRAMA
+11235 ; Grapheme_Link # Mc KHOJKI SIGN VIRAMA
+112EA ; Grapheme_Link # Mn KHUDAWADI SIGN VIRAMA
+1134D ; Grapheme_Link # Mc GRANTHA SIGN VIRAMA
+11442 ; Grapheme_Link # Mn NEWA SIGN VIRAMA
+114C2 ; Grapheme_Link # Mn TIRHUTA SIGN VIRAMA
+115BF ; Grapheme_Link # Mn SIDDHAM SIGN VIRAMA
+1163F ; Grapheme_Link # Mn MODI SIGN VIRAMA
+116B6 ; Grapheme_Link # Mc TAKRI SIGN VIRAMA
+1172B ; Grapheme_Link # Mn AHOM SIGN KILLER
+11C3F ; Grapheme_Link # Mn BHAIKSUKI SIGN VIRAMA
+
+# Total code points: 47
+
+# EOF
diff --git a/js/src/vm/EnvironmentObject-inl.h b/js/src/vm/EnvironmentObject-inl.h
new file mode 100644
index 000000000..0cb3a41e9
--- /dev/null
+++ b/js/src/vm/EnvironmentObject-inl.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_EnvironmentObject_inl_h
+#define vm_EnvironmentObject_inl_h
+
+#include "vm/EnvironmentObject.h"
+#include "frontend/SharedContext.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/TypeInference-inl.h"
+
+namespace js {
+
+inline LexicalEnvironmentObject&
+NearestEnclosingExtensibleLexicalEnvironment(JSObject* env)
+{
+ while (!IsExtensibleLexicalEnvironment(env))
+ env = env->enclosingEnvironment();
+ return env->as<LexicalEnvironmentObject>();
+}
+
+inline void
+EnvironmentObject::setAliasedBinding(JSContext* cx, uint32_t slot, PropertyName* name,
+ const Value& v)
+{
+ if (isSingleton()) {
+ MOZ_ASSERT(name);
+ AddTypePropertyId(cx, this, NameToId(name), v);
+
+ // Keep track of properties which have ever been overwritten.
+ if (!getSlot(slot).isUndefined()) {
+ Shape* shape = lookup(cx, name);
+ shape->setOverwritten();
+ }
+ }
+
+ setSlot(slot, v);
+}
+
+inline void
+EnvironmentObject::setAliasedBinding(JSContext* cx, EnvironmentCoordinate ec, PropertyName* name,
+ const Value& v)
+{
+ setAliasedBinding(cx, ec.slot(), name, v);
+}
+
+inline void
+EnvironmentObject::setAliasedBinding(JSContext* cx, const BindingIter& bi, const Value& v)
+{
+ MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment);
+ setAliasedBinding(cx, bi.location().slot(), bi.name()->asPropertyName(), v);
+}
+
+inline void
+CallObject::setAliasedFormalFromArguments(JSContext* cx, const Value& argsValue, jsid id,
+ const Value& v)
+{
+ setSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue), v);
+ if (isSingleton())
+ AddTypePropertyId(cx, this, id, v);
+}
+
+} /* namespace js */
+
+inline JSObject*
+JSObject::enclosingEnvironment() const
+{
+ if (is<js::EnvironmentObject>())
+ return &as<js::EnvironmentObject>().enclosingEnvironment();
+
+ if (is<js::DebugEnvironmentProxy>())
+ return &as<js::DebugEnvironmentProxy>().enclosingEnvironment();
+
+ if (is<js::GlobalObject>())
+ return nullptr;
+
+ MOZ_ASSERT_IF(is<JSFunction>(), as<JSFunction>().isInterpreted());
+ return &global();
+}
+
+#endif /* vm_EnvironmentObject_inl_h */
diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp
new file mode 100644
index 000000000..34c39eabf
--- /dev/null
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -0,0 +1,3594 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/EnvironmentObject-inl.h"
+
+#include "mozilla/PodOperations.h"
+#include "mozilla/ScopeExit.h"
+#include "mozilla/SizePrintfMacros.h"
+
+#include "jscompartment.h"
+#include "jsiter.h"
+
+#include "builtin/ModuleObject.h"
+#include "frontend/ParseNode.h"
+#include "gc/Policy.h"
+#include "vm/ArgumentsObject.h"
+#include "vm/AsyncFunction.h"
+#include "vm/GlobalObject.h"
+#include "vm/ProxyObject.h"
+#include "vm/Shape.h"
+#include "vm/Xdr.h"
+
+#include "jsatominlines.h"
+#include "jsobjinlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/Stack-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::PodZero;
+using mozilla::Maybe;
+using mozilla::Some;
+using mozilla::Nothing;
+using mozilla::MakeScopeExit;
+
+typedef Rooted<ArgumentsObject*> RootedArgumentsObject;
+typedef MutableHandle<ArgumentsObject*> MutableHandleArgumentsObject;
+
+
+/*****************************************************************************/
+
+Shape*
+js::EnvironmentCoordinateToEnvironmentShape(JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
+ ScopeIter si(script->innermostScope(pc));
+ uint32_t hops = EnvironmentCoordinate(pc).hops();
+ while (true) {
+ MOZ_ASSERT(!si.done());
+ if (si.hasSyntacticEnvironment()) {
+ if (!hops)
+ break;
+ hops--;
+ }
+ si++;
+ }
+ return si.environmentShape();
+}
+
+static const uint32_t ENV_COORDINATE_NAME_THRESHOLD = 20;
+
+void
+EnvironmentCoordinateNameCache::purge()
+{
+ shape = nullptr;
+ if (map.initialized())
+ map.finish();
+}
+
+PropertyName*
+js::EnvironmentCoordinateName(EnvironmentCoordinateNameCache& cache, JSScript* script,
+ jsbytecode* pc)
+{
+ Shape* shape = EnvironmentCoordinateToEnvironmentShape(script, pc);
+ if (shape != cache.shape && shape->slot() >= ENV_COORDINATE_NAME_THRESHOLD) {
+ cache.purge();
+ if (cache.map.init(shape->slot())) {
+ cache.shape = shape;
+ Shape::Range<NoGC> r(shape);
+ while (!r.empty()) {
+ if (!cache.map.putNew(r.front().slot(), r.front().propid())) {
+ cache.purge();
+ break;
+ }
+ r.popFront();
+ }
+ }
+ }
+
+ jsid id;
+ EnvironmentCoordinate ec(pc);
+ if (shape == cache.shape) {
+ EnvironmentCoordinateNameCache::Map::Ptr p = cache.map.lookup(ec.slot());
+ id = p->value();
+ } else {
+ Shape::Range<NoGC> r(shape);
+ while (r.front().slot() != ec.slot())
+ r.popFront();
+ id = r.front().propidRaw();
+ }
+
+ /* Beware nameless destructuring formal. */
+ if (!JSID_IS_ATOM(id))
+ return script->runtimeFromAnyThread()->commonNames->empty;
+ return JSID_TO_ATOM(id)->asPropertyName();
+}
+
+JSScript*
+js::EnvironmentCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
+ ScopeIter si(script->innermostScope(pc));
+ uint32_t hops = EnvironmentCoordinate(pc).hops();
+ while (true) {
+ if (si.hasSyntacticEnvironment()) {
+ if (!hops)
+ break;
+ hops--;
+ }
+ si++;
+ }
+ if (si.kind() != ScopeKind::Function)
+ return nullptr;
+ return si.scope()->as<FunctionScope>().script();
+}
+
+/*****************************************************************************/
+
+CallObject*
+CallObject::create(JSContext* cx, HandleShape shape, HandleObjectGroup group)
+{
+ MOZ_ASSERT(!group->singleton(),
+ "passed a singleton group to create() (use createSingleton() "
+ "instead)");
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ JSObject* obj = JSObject::create(cx, kind, gc::DefaultHeap, shape, group);
+ if (!obj)
+ return nullptr;
+
+ return &obj->as<CallObject>();
+}
+
+CallObject*
+CallObject::createSingleton(JSContext* cx, HandleShape shape)
+{
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+ RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, group));
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(obj->isSingleton(),
+ "group created inline above must be a singleton");
+
+ return &obj->as<CallObject>();
+}
+
+/*
+ * Create a CallObject for a JSScript that is not initialized to any particular
+ * callsite. This object can either be initialized (with an enclosing scope and
+ * callee) or used as a template for jit compilation.
+ */
+CallObject*
+CallObject::createTemplateObject(JSContext* cx, HandleScript script, HandleObject enclosing,
+ gc::InitialHeap heap)
+{
+ Rooted<FunctionScope*> scope(cx, &script->bodyScope()->as<FunctionScope>());
+ RootedShape shape(cx, scope->environmentShape());
+ MOZ_ASSERT(shape->getObjectClass() == &class_);
+
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ JSObject* obj = JSObject::create(cx, kind, heap, shape, group);
+ if (!obj)
+ return nullptr;
+
+ CallObject* callObj = &obj->as<CallObject>();
+ callObj->initEnclosingEnvironment(enclosing);
+
+ if (scope->hasParameterExprs()) {
+ // If there are parameter expressions, all parameters are lexical and
+ // have TDZ.
+ for (BindingIter bi(script->bodyScope()); bi; bi++) {
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Environment && BindingKindIsLexical(bi.kind()))
+ callObj->initSlot(loc.slot(), MagicValue(JS_UNINITIALIZED_LEXICAL));
+ }
+ }
+
+ return callObj;
+}
+
+/*
+ * Construct a call object for the given bindings. If this is a call object
+ * for a function invocation, callee should be the function being called.
+ * Otherwise it must be a call object for eval of strict mode code, and callee
+ * must be null.
+ */
+CallObject*
+CallObject::create(JSContext* cx, HandleFunction callee, HandleObject enclosing)
+{
+ RootedScript script(cx, callee->nonLazyScript());
+ gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
+ CallObject* callobj = CallObject::createTemplateObject(cx, script, enclosing, heap);
+ if (!callobj)
+ return nullptr;
+
+ callobj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
+
+ if (script->treatAsRunOnce()) {
+ Rooted<CallObject*> ncallobj(cx, callobj);
+ if (!JSObject::setSingleton(cx, ncallobj))
+ return nullptr;
+ return ncallobj;
+ }
+
+ return callobj;
+}
+
+CallObject*
+CallObject::create(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT(frame.isFunctionFrame());
+ assertSameCompartment(cx, frame);
+
+ RootedObject envChain(cx, frame.environmentChain());
+ RootedFunction callee(cx, frame.callee());
+
+ CallObject* callobj = create(cx, callee, envChain);
+ if (!callobj)
+ return nullptr;
+
+ if (!frame.script()->bodyScope()->as<FunctionScope>().hasParameterExprs()) {
+ // If there are no defaults, copy the aliased arguments into the call
+ // object manually. If there are defaults, bytecode is generated to do
+ // the copying.
+
+ for (PositionalFormalParameterIter fi(frame.script()); fi; fi++) {
+ if (!fi.closedOver())
+ continue;
+ callobj->setAliasedBinding(cx, fi, frame.unaliasedFormal(fi.argumentSlot(),
+ DONT_CHECK_ALIASING));
+ }
+ }
+
+ return callobj;
+}
+
+CallObject*
+CallObject::createHollowForDebug(JSContext* cx, HandleFunction callee)
+{
+ MOZ_ASSERT(!callee->needsCallObject());
+
+ RootedScript script(cx, callee->nonLazyScript());
+ Rooted<FunctionScope*> scope(cx, &script->bodyScope()->as<FunctionScope>());
+ RootedShape shape(cx, FunctionScope::getEmptyEnvironmentShape(cx, scope->hasParameterExprs()));
+ if (!shape)
+ return nullptr;
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+ Rooted<CallObject*> callobj(cx, create(cx, shape, group));
+ if (!callobj)
+ return nullptr;
+
+ // This environment's enclosing link is never used: the
+ // DebugEnvironmentProxy that refers to this scope carries its own
+ // enclosing link, which is what Debugger uses to construct the tree of
+ // Debugger.Environment objects.
+ callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
+ callobj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
+
+ RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
+ RootedId id(cx);
+ for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
+ id = NameToId(bi.name()->asPropertyName());
+ if (!SetProperty(cx, callobj, id, optimizedOut))
+ return nullptr;
+ }
+
+ return callobj;
+}
+
+const Class CallObject::class_ = {
+ "Call",
+ JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS)
+};
+
+/*****************************************************************************/
+
+/* static */ VarEnvironmentObject*
+VarEnvironmentObject::create(JSContext* cx, HandleShape shape, HandleObject enclosing,
+ gc::InitialHeap heap)
+{
+ MOZ_ASSERT(shape->getObjectClass() == &class_);
+
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ NativeObject* obj = MaybeNativeObject(JSObject::create(cx, kind, heap, shape, group));
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(!obj->inDictionaryMode());
+ MOZ_ASSERT(obj->isDelegate());
+
+ VarEnvironmentObject* env = &obj->as<VarEnvironmentObject>();
+ env->initEnclosingEnvironment(enclosing);
+
+ return env;
+}
+
+/* static */ VarEnvironmentObject*
+VarEnvironmentObject::create(JSContext* cx, HandleScope scope, AbstractFramePtr frame)
+{
+#ifdef DEBUG
+ if (frame.isEvalFrame()) {
+ MOZ_ASSERT(scope->is<EvalScope>() && scope == frame.script()->bodyScope());
+ MOZ_ASSERT_IF(frame.isInterpreterFrame(),
+ cx->interpreterFrame() == frame.asInterpreterFrame());
+ MOZ_ASSERT_IF(frame.isInterpreterFrame(),
+ cx->interpreterRegs().pc == frame.script()->code());
+ } else {
+ MOZ_ASSERT(frame.environmentChain());
+ MOZ_ASSERT_IF(frame.callee()->needsCallObject(),
+ &frame.environmentChain()->as<CallObject>().callee() == frame.callee());
+ }
+#endif
+
+ RootedScript script(cx, frame.script());
+ RootedObject envChain(cx, frame.environmentChain());
+ gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
+ RootedShape shape(cx, scope->environmentShape());
+ VarEnvironmentObject* env = create(cx, shape, envChain, heap);
+ if (!env)
+ return nullptr;
+ env->initScope(scope);
+ return env;
+}
+
+/* static */ VarEnvironmentObject*
+VarEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<VarScope*> scope)
+{
+ MOZ_ASSERT(!scope->hasEnvironment());
+
+ RootedShape shape(cx, VarScope::getEmptyEnvironmentShape(cx));
+ if (!shape)
+ return nullptr;
+
+ // This environment's enclosing link is never used: the
+ // DebugEnvironmentProxy that refers to this scope carries its own
+ // enclosing link, which is what Debugger uses to construct the tree of
+ // Debugger.Environment objects.
+ RootedObject enclosingEnv(cx, &cx->global()->lexicalEnvironment());
+ Rooted<VarEnvironmentObject*> env(cx, create(cx, shape, enclosingEnv, gc::TenuredHeap));
+ if (!env)
+ return nullptr;
+
+ RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
+ RootedId id(cx);
+ for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
+ id = NameToId(bi.name()->asPropertyName());
+ if (!SetProperty(cx, env, id, optimizedOut))
+ return nullptr;
+ }
+
+ env->initScope(scope);
+ return env;
+}
+
+const Class VarEnvironmentObject::class_ = {
+ "Var",
+ JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(VarEnvironmentObject::RESERVED_SLOTS)
+};
+
+/*****************************************************************************/
+
+const ObjectOps ModuleEnvironmentObject::objectOps_ = {
+ ModuleEnvironmentObject::lookupProperty,
+ nullptr, /* defineProperty */
+ ModuleEnvironmentObject::hasProperty,
+ ModuleEnvironmentObject::getProperty,
+ ModuleEnvironmentObject::setProperty,
+ ModuleEnvironmentObject::getOwnPropertyDescriptor,
+ ModuleEnvironmentObject::deleteProperty,
+ nullptr, nullptr, /* watch/unwatch */
+ nullptr, /* getElements */
+ ModuleEnvironmentObject::enumerate,
+ nullptr
+};
+
+const Class ModuleEnvironmentObject::class_ = {
+ "ModuleEnvironmentObject",
+ JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS) |
+ JSCLASS_IS_ANONYMOUS,
+ JS_NULL_CLASS_OPS,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ &ModuleEnvironmentObject::objectOps_
+};
+
+/* static */ ModuleEnvironmentObject*
+ModuleEnvironmentObject::create(ExclusiveContext* cx, HandleModuleObject module)
+{
+ RootedScript script(cx, module->script());
+ RootedShape shape(cx, script->bodyScope()->as<ModuleScope>().environmentShape());
+ MOZ_ASSERT(shape->getObjectClass() == &class_);
+
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
+ kind = gc::GetBackgroundAllocKind(kind);
+
+ JSObject* obj = JSObject::create(cx, kind, TenuredHeap, shape, group);
+ if (!obj)
+ return nullptr;
+
+ RootedModuleEnvironmentObject env(cx, &obj->as<ModuleEnvironmentObject>());
+
+ env->initReservedSlot(MODULE_SLOT, ObjectValue(*module));
+ if (!JSObject::setSingleton(cx, env))
+ return nullptr;
+
+ // Initialize this early so that we can manipulate the env object without
+ // causing assertions.
+ env->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
+
+ // Initialize all lexical bindings and imports as uninitialized. Imports
+ // get uninitialized because they have a special TDZ for cyclic imports.
+ for (BindingIter bi(script); bi; bi++) {
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Environment && BindingKindIsLexical(bi.kind()))
+ env->initSlot(loc.slot(), MagicValue(JS_UNINITIALIZED_LEXICAL));
+ }
+
+ // It is not be possible to add or remove bindings from a module environment
+ // after this point as module code is always strict.
+#ifdef DEBUG
+ for (Shape::Range<NoGC> r(env->lastProperty()); !r.empty(); r.popFront())
+ MOZ_ASSERT(!r.front().configurable());
+ MOZ_ASSERT(env->lastProperty()->getObjectFlags() & BaseShape::NOT_EXTENSIBLE);
+ MOZ_ASSERT(!env->inDictionaryMode());
+#endif
+
+ return env;
+}
+
+ModuleObject&
+ModuleEnvironmentObject::module()
+{
+ return getReservedSlot(MODULE_SLOT).toObject().as<ModuleObject>();
+}
+
+IndirectBindingMap&
+ModuleEnvironmentObject::importBindings()
+{
+ return module().importBindings();
+}
+
+bool
+ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importName,
+ HandleModuleObject module, HandleAtom localName)
+{
+ RootedId importNameId(cx, AtomToId(importName));
+ RootedId localNameId(cx, AtomToId(localName));
+ RootedModuleEnvironmentObject env(cx, module->environment());
+ if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ModuleEnvironmentObject::hasImportBinding(HandlePropertyName name)
+{
+ return importBindings().has(NameToId(name));
+}
+
+bool
+ModuleEnvironmentObject::lookupImport(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut)
+{
+ return importBindings().lookup(name, envOut, shapeOut);
+}
+
+void
+ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObject& global)
+{
+ setEnclosingEnvironment(&global.lexicalEnvironment());
+}
+
+/* static */ bool
+ModuleEnvironmentObject::lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
+ Shape* shape;
+ ModuleEnvironmentObject* env;
+ if (bindings.lookup(id, &env, &shape)) {
+ objp.set(env);
+ propp.set(shape);
+ return true;
+ }
+
+ RootedNativeObject target(cx, &obj->as<NativeObject>());
+ if (!NativeLookupOwnProperty<CanGC>(cx, target, id, propp))
+ return false;
+
+ objp.set(obj);
+ return true;
+}
+
+/* static */ bool
+ModuleEnvironmentObject::hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ if (obj->as<ModuleEnvironmentObject>().importBindings().has(id)) {
+ *foundp = true;
+ return true;
+ }
+
+ RootedNativeObject self(cx, &obj->as<NativeObject>());
+ return NativeHasProperty(cx, self, id, foundp);
+}
+
+/* static */ bool
+ModuleEnvironmentObject::getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
+ HandleId id, MutableHandleValue vp)
+{
+ const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
+ Shape* shape;
+ ModuleEnvironmentObject* env;
+ if (bindings.lookup(id, &env, &shape)) {
+ vp.set(env->getSlot(shape->slot()));
+ return true;
+ }
+
+ RootedNativeObject self(cx, &obj->as<NativeObject>());
+ return NativeGetProperty(cx, self, receiver, id, vp);
+}
+
+/* static */ bool
+ModuleEnvironmentObject::setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, JS::ObjectOpResult& result)
+{
+ RootedModuleEnvironmentObject self(cx, &obj->as<ModuleEnvironmentObject>());
+ if (self->importBindings().has(id))
+ return result.failReadOnly();
+
+ return NativeSetProperty(cx, self, id, v, receiver, Qualified, result);
+}
+
+/* static */ bool
+ModuleEnvironmentObject::getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
+ Shape* shape;
+ ModuleEnvironmentObject* env;
+ if (bindings.lookup(id, &env, &shape)) {
+ desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT);
+ desc.object().set(obj);
+ RootedValue value(cx, env->getSlot(shape->slot()));
+ desc.setValue(value);
+ desc.assertComplete();
+ return true;
+ }
+
+ RootedNativeObject self(cx, &obj->as<NativeObject>());
+ return NativeGetOwnPropertyDescriptor(cx, self, id, desc);
+}
+
+/* static */ bool
+ModuleEnvironmentObject::deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result)
+{
+ return result.failCantDelete();
+}
+
+/* static */ bool
+ModuleEnvironmentObject::enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly)
+{
+ RootedModuleEnvironmentObject self(cx, &obj->as<ModuleEnvironmentObject>());
+ const IndirectBindingMap& bs(self->importBindings());
+
+ MOZ_ASSERT(properties.length() == 0);
+ size_t count = bs.count() + self->slotSpan() - RESERVED_SLOTS;
+ if (!properties.reserve(count)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ bs.forEachExportedName([&] (jsid name) {
+ properties.infallibleAppend(name);
+ });
+
+ for (Shape::Range<NoGC> r(self->lastProperty()); !r.empty(); r.popFront())
+ properties.infallibleAppend(r.front().propid());
+
+ MOZ_ASSERT(properties.length() == count);
+ return true;
+}
+
+/*****************************************************************************/
+
+WithEnvironmentObject*
+WithEnvironmentObject::create(JSContext* cx, HandleObject object, HandleObject enclosing,
+ Handle<WithScope*> scope)
+{
+ Rooted<WithEnvironmentObject*> obj(cx);
+ obj = NewObjectWithNullTaggedProto<WithEnvironmentObject>(cx, GenericObject,
+ BaseShape::DELEGATE);
+ if (!obj)
+ return nullptr;
+
+ Value thisv = GetThisValue(object);
+
+ obj->initEnclosingEnvironment(enclosing);
+ obj->initReservedSlot(OBJECT_SLOT, ObjectValue(*object));
+ obj->initReservedSlot(THIS_SLOT, thisv);
+ if (scope)
+ obj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
+ else
+ obj->initReservedSlot(SCOPE_SLOT, NullValue());
+
+ return obj;
+}
+
+WithEnvironmentObject*
+WithEnvironmentObject::createNonSyntactic(JSContext* cx, HandleObject object,
+ HandleObject enclosing)
+{
+ return create(cx, object, enclosing, nullptr);
+}
+
+static inline bool
+IsUnscopableDotName(JSContext* cx, HandleId id)
+{
+ return JSID_IS_ATOM(id, cx->names().dotThis) || JSID_IS_ATOM(id, cx->names().dotGenerator);
+}
+
+/* Implements ES6 8.1.1.2.1 HasBinding steps 7-9. */
+static bool
+CheckUnscopables(JSContext *cx, HandleObject obj, HandleId id, bool *scopable)
+{
+ RootedId unscopablesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols()
+ .get(JS::SymbolCode::unscopables)));
+ RootedValue v(cx);
+ if (!GetProperty(cx, obj, obj, unscopablesId, &v))
+ return false;
+ if (v.isObject()) {
+ RootedObject unscopablesObj(cx, &v.toObject());
+ if (!GetProperty(cx, unscopablesObj, unscopablesObj, id, &v))
+ return false;
+ *scopable = !ToBoolean(v);
+ } else {
+ *scopable = true;
+ }
+ return true;
+}
+
+static bool
+with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ // SpiderMonkey-specific: consider internal '.generator' and '.this' names
+ // to be unscopable.
+ if (IsUnscopableDotName(cx, id)) {
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+ }
+
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ if (!LookupProperty(cx, actual, id, objp, propp))
+ return false;
+
+ if (propp) {
+ bool scopable;
+ if (!CheckUnscopables(cx, actual, id, &scopable))
+ return false;
+ if (!scopable) {
+ objp.set(nullptr);
+ propp.set(nullptr);
+ }
+ }
+ return true;
+}
+
+static bool
+with_DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ return DefineProperty(cx, actual, id, desc, result);
+}
+
+static bool
+with_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+
+ // ES 8.1.1.2.1 step 3-5.
+ if (!HasProperty(cx, actual, id, foundp))
+ return false;
+ if (!*foundp)
+ return true;
+
+ // Steps 7-10. (Step 6 is a no-op.)
+ return CheckUnscopables(cx, actual, id, foundp);
+}
+
+static bool
+with_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ RootedValue actualReceiver(cx, receiver);
+ if (receiver.isObject() && &receiver.toObject() == obj)
+ actualReceiver.setObject(*actual);
+ return GetProperty(cx, actual, actualReceiver, id, vp);
+}
+
+static bool
+with_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ RootedValue actualReceiver(cx, receiver);
+ if (receiver.isObject() && &receiver.toObject() == obj)
+ actualReceiver.setObject(*actual);
+ return SetProperty(cx, actual, id, v, actualReceiver, result);
+}
+
+static bool
+with_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ return GetOwnPropertyDescriptor(cx, actual, id, desc);
+}
+
+static bool
+with_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
+{
+ MOZ_ASSERT(!IsUnscopableDotName(cx, id));
+ RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
+ return DeleteProperty(cx, actual, id, result);
+}
+
+static const ObjectOps WithEnvironmentObjectOps = {
+ with_LookupProperty,
+ with_DefineProperty,
+ with_HasProperty,
+ with_GetProperty,
+ with_SetProperty,
+ with_GetOwnPropertyDescriptor,
+ with_DeleteProperty,
+ nullptr, nullptr, /* watch/unwatch */
+ nullptr, /* getElements */
+ nullptr, /* enumerate (native enumeration of target doesn't work) */
+ nullptr,
+};
+
+const Class WithEnvironmentObject::class_ = {
+ "With",
+ JSCLASS_HAS_RESERVED_SLOTS(WithEnvironmentObject::RESERVED_SLOTS) |
+ JSCLASS_IS_ANONYMOUS,
+ JS_NULL_CLASS_OPS,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ &WithEnvironmentObjectOps
+};
+
+/* static */ NonSyntacticVariablesObject*
+NonSyntacticVariablesObject::create(JSContext* cx)
+{
+ Rooted<NonSyntacticVariablesObject*> obj(cx,
+ NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
+ BaseShape::DELEGATE));
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(obj->isUnqualifiedVarObj());
+ if (!obj->setQualifiedVarObj(cx))
+ return nullptr;
+
+ obj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
+ return obj;
+}
+
+const Class NonSyntacticVariablesObject::class_ = {
+ "NonSyntacticVariablesObject",
+ JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS) |
+ JSCLASS_IS_ANONYMOUS
+};
+
+/*****************************************************************************/
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::createTemplateObject(JSContext* cx, HandleShape shape,
+ HandleObject enclosing, gc::InitialHeap heap)
+{
+ MOZ_ASSERT(shape->getObjectClass() == &LexicalEnvironmentObject::class_);
+
+ RootedObjectGroup group(cx,
+ ObjectGroup::defaultNewGroup(cx, &LexicalEnvironmentObject::class_, TaggedProto(nullptr)));
+ if (!group)
+ return nullptr;
+
+ gc::AllocKind allocKind = gc::GetGCObjectKind(shape->numFixedSlots());
+ MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &LexicalEnvironmentObject::class_));
+ allocKind = GetBackgroundAllocKind(allocKind);
+ RootedNativeObject obj(cx,
+ MaybeNativeObject(JSObject::create(cx, allocKind, heap, shape, group)));
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(!obj->inDictionaryMode());
+ MOZ_ASSERT(obj->isDelegate());
+
+ LexicalEnvironmentObject* env = &obj->as<LexicalEnvironmentObject>();
+ if (enclosing)
+ env->initEnclosingEnvironment(enclosing);
+
+ return env;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::createTemplateObject(JSContext* cx, Handle<LexicalScope*> scope,
+ HandleObject enclosing, gc::InitialHeap heap)
+{
+ assertSameCompartment(cx, enclosing);
+ MOZ_ASSERT(scope->hasEnvironment());
+
+ RootedShape shape(cx, scope->environmentShape());
+ LexicalEnvironmentObject* env = createTemplateObject(cx, shape, enclosing, heap);
+ if (!env)
+ return nullptr;
+
+ // All lexical bindings start off uninitialized for TDZ.
+ uint32_t lastSlot = shape->slot();
+ MOZ_ASSERT(lastSlot == env->lastProperty()->slot());
+ for (uint32_t slot = JSSLOT_FREE(&class_); slot <= lastSlot; slot++)
+ env->initSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL));
+
+ env->initScopeUnchecked(scope);
+ return env;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
+ AbstractFramePtr frame)
+{
+ RootedObject enclosing(cx, frame.environmentChain());
+ return createTemplateObject(cx, scope, enclosing, gc::DefaultHeap);
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::createGlobal(JSContext* cx, Handle<GlobalObject*> global)
+{
+ MOZ_ASSERT(global);
+
+ RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
+ if (!shape)
+ return nullptr;
+
+ Rooted<LexicalEnvironmentObject*> env(cx,
+ LexicalEnvironmentObject::createTemplateObject(cx, shape, global, gc::TenuredHeap));
+ if (!env)
+ return nullptr;
+
+ if (!JSObject::setSingleton(cx, env))
+ return nullptr;
+
+ env->initThisValue(global);
+ return env;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::createNonSyntactic(JSContext* cx, HandleObject enclosing)
+{
+ MOZ_ASSERT(enclosing);
+ MOZ_ASSERT(!IsSyntacticEnvironment(enclosing));
+
+ RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
+ if (!shape)
+ return nullptr;
+
+ LexicalEnvironmentObject* env =
+ LexicalEnvironmentObject::createTemplateObject(cx, shape, enclosing, gc::TenuredHeap);
+ if (!env)
+ return nullptr;
+
+ env->initThisValue(enclosing);
+ return env;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<LexicalScope*> scope)
+{
+ MOZ_ASSERT(!scope->hasEnvironment());
+
+ RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
+ if (!shape)
+ return nullptr;
+
+ // This environment's enclosing link is never used: the
+ // DebugEnvironmentProxy that refers to this scope carries its own
+ // enclosing link, which is what Debugger uses to construct the tree of
+ // Debugger.Environment objects.
+ RootedObject enclosingEnv(cx, &cx->global()->lexicalEnvironment());
+ Rooted<LexicalEnvironmentObject*> env(cx, createTemplateObject(cx, shape, enclosingEnv,
+ gc::TenuredHeap));
+ if (!env)
+ return nullptr;
+
+ RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
+ RootedId id(cx);
+ for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
+ id = NameToId(bi.name()->asPropertyName());
+ if (!SetProperty(cx, env, id, optimizedOut))
+ return nullptr;
+ }
+
+ if (!env->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
+ return nullptr;
+
+ env->initScopeUnchecked(scope);
+ return env;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
+{
+ Rooted<LexicalScope*> scope(cx, &env->scope());
+ RootedObject enclosing(cx, &env->enclosingEnvironment());
+ Rooted<LexicalEnvironmentObject*> copy(cx, createTemplateObject(cx, scope, enclosing,
+ gc::TenuredHeap));
+ if (!copy)
+ return nullptr;
+
+ // We can't assert that the clone has the same shape, because it could
+ // have been reshaped by PurgeEnvironmentChain.
+ MOZ_ASSERT(env->slotSpan() == copy->slotSpan());
+ for (uint32_t i = JSSLOT_FREE(&class_); i < copy->slotSpan(); i++)
+ copy->setSlot(i, env->getSlot(i));
+
+ return copy;
+}
+
+/* static */ LexicalEnvironmentObject*
+LexicalEnvironmentObject::recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
+{
+ Rooted<LexicalScope*> scope(cx, &env->scope());
+ RootedObject enclosing(cx, &env->enclosingEnvironment());
+ return createTemplateObject(cx, scope, enclosing, gc::TenuredHeap);
+}
+
+bool
+LexicalEnvironmentObject::isExtensible() const
+{
+ return nonProxyIsExtensible();
+}
+
+Value
+LexicalEnvironmentObject::thisValue() const
+{
+ MOZ_ASSERT(isExtensible());
+ Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT);
+ if (v.isObject()) {
+ // If `v` is a Window, return the WindowProxy instead. We called
+ // GetThisValue (which also does ToWindowProxyIfWindow) when storing
+ // the value in THIS_VALUE_OR_SCOPE_SLOT, but it's possible the
+ // WindowProxy was attached to the global *after* we set
+ // THIS_VALUE_OR_SCOPE_SLOT.
+ return ObjectValue(*ToWindowProxyIfWindow(&v.toObject()));
+ }
+ return v;
+}
+
+const Class LexicalEnvironmentObject::class_ = {
+ "LexicalEnvironment",
+ JSCLASS_HAS_RESERVED_SLOTS(LexicalEnvironmentObject::RESERVED_SLOTS) |
+ JSCLASS_IS_ANONYMOUS,
+ JS_NULL_CLASS_OPS,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ JS_NULL_OBJECT_OPS
+};
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::create(JSContext* cx, HandleFunction callee,
+ HandleFunction func,
+ HandleObject enclosing,
+ gc::InitialHeap heap)
+{
+ MOZ_ASSERT(callee->isNamedLambda());
+ RootedScope scope(cx, callee->nonLazyScript()->maybeNamedLambdaScope());
+ MOZ_ASSERT(scope && scope->environmentShape());
+ MOZ_ASSERT(scope->environmentShape()->slot() == lambdaSlot());
+ MOZ_ASSERT(!scope->environmentShape()->writable());
+
+#ifdef DEBUG
+ // There should be exactly one binding in the named lambda scope.
+ BindingIter bi(scope);
+ bi++;
+ MOZ_ASSERT(bi.done());
+#endif
+
+ LexicalEnvironmentObject* obj =
+ LexicalEnvironmentObject::createTemplateObject(cx, scope.as<LexicalScope>(),
+ enclosing, heap);
+ if (!obj)
+ return nullptr;
+
+ obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
+ return static_cast<NamedLambdaObject*>(obj);
+}
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::createTemplateObject(JSContext* cx, HandleFunction callee, gc::InitialHeap heap)
+{
+ return create(cx, callee, callee, nullptr, heap);
+}
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame)
+{
+ RootedFunction fun(cx, frame.callee());
+ RootedObject enclosing(cx, frame.environmentChain());
+ return create(cx, fun, fun, enclosing, gc::DefaultHeap);
+}
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame, HandleFunction replacement)
+{
+ RootedFunction fun(cx, frame.callee());
+ RootedObject enclosing(cx, frame.environmentChain());
+ return create(cx, fun, replacement, enclosing, gc::DefaultHeap);
+}
+
+/* static */ size_t
+NamedLambdaObject::lambdaSlot()
+{
+ // Named lambda environments have exactly one name.
+ return JSSLOT_FREE(&LexicalEnvironmentObject::class_);
+}
+
+/* static */ RuntimeLexicalErrorObject*
+RuntimeLexicalErrorObject::create(JSContext* cx, HandleObject enclosing, unsigned errorNumber)
+{
+ RuntimeLexicalErrorObject* obj =
+ NewObjectWithNullTaggedProto<RuntimeLexicalErrorObject>(cx, GenericObject,
+ BaseShape::DELEGATE);
+ if (!obj)
+ return nullptr;
+ obj->initEnclosingEnvironment(enclosing);
+ obj->initReservedSlot(ERROR_SLOT, Int32Value(int32_t(errorNumber)));
+ return obj;
+}
+
+static void
+ReportRuntimeLexicalErrorId(JSContext* cx, unsigned errorNumber, HandleId id)
+{
+ if (JSID_IS_ATOM(id)) {
+ RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
+ ReportRuntimeLexicalError(cx, errorNumber, name);
+ return;
+ }
+ MOZ_CRASH("RuntimeLexicalErrorObject should only be used with property names");
+}
+
+static bool
+lexicalError_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static bool
+lexicalError_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static bool
+lexicalError_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static bool
+lexicalError_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static bool
+lexicalError_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static bool
+lexicalError_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
+{
+ ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
+ return false;
+}
+
+static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
+ lexicalError_LookupProperty,
+ nullptr, /* defineProperty */
+ lexicalError_HasProperty,
+ lexicalError_GetProperty,
+ lexicalError_SetProperty,
+ lexicalError_GetOwnPropertyDescriptor,
+ lexicalError_DeleteProperty,
+ nullptr, nullptr, /* watch/unwatch */
+ nullptr, /* getElements */
+ nullptr, /* enumerate (native enumeration of target doesn't work) */
+ nullptr, /* this */
+};
+
+const Class RuntimeLexicalErrorObject::class_ = {
+ "RuntimeLexicalError",
+ JSCLASS_HAS_RESERVED_SLOTS(RuntimeLexicalErrorObject::RESERVED_SLOTS) |
+ JSCLASS_IS_ANONYMOUS,
+ JS_NULL_CLASS_OPS,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ &RuntimeLexicalErrorObjectObjectOps
+};
+
+/*****************************************************************************/
+
+EnvironmentIter::EnvironmentIter(JSContext* cx, const EnvironmentIter& ei
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : si_(cx, ei.si_.get()),
+ env_(cx, ei.env_),
+ frame_(ei.frame_)
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+EnvironmentIter::EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : si_(cx, ScopeIter(scope)),
+ env_(cx, env),
+ frame_(NullFramePtr())
+{
+ settle();
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+EnvironmentIter::EnvironmentIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : si_(cx, frame.script()->innermostScope(pc)),
+ env_(cx, frame.environmentChain()),
+ frame_(frame)
+{
+ assertSameCompartment(cx, frame);
+ settle();
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+void
+EnvironmentIter::incrementScopeIter()
+{
+ if (si_.scope()->is<GlobalScope>()) {
+ // GlobalScopes may be syntactic or non-syntactic. Non-syntactic
+ // GlobalScopes correspond to zero or more non-syntactic
+ // EnvironmentsObjects followed by the global lexical scope, then the
+ // GlobalObject or another non-EnvironmentObject object.
+ if (!env_->is<EnvironmentObject>())
+ si_++;
+ } else {
+ si_++;
+ }
+}
+
+void
+EnvironmentIter::settle()
+{
+ // Check for trying to iterate a function or eval frame before the prologue has
+ // created the CallObject, in which case we have to skip.
+ if (frame_ && frame_.script()->initialEnvironmentShape() && !frame_.hasInitialEnvironment()) {
+ // Skip until we're at the enclosing scope of the script.
+ while (si_.scope() != frame_.script()->enclosingScope()) {
+ if (env_->is<LexicalEnvironmentObject>() &&
+ !env_->as<LexicalEnvironmentObject>().isExtensible() &&
+ &env_->as<LexicalEnvironmentObject>().scope() == si_.scope())
+ {
+ MOZ_ASSERT(si_.kind() == ScopeKind::NamedLambda ||
+ si_.kind() == ScopeKind::StrictNamedLambda);
+ env_ = &env_->as<EnvironmentObject>().enclosingEnvironment();
+ }
+ incrementScopeIter();
+ }
+ }
+
+ // Check if we have left the extent of the initial frame after we've
+ // settled on a static scope.
+ if (frame_ && (!si_ || si_.scope() == frame_.script()->enclosingScope()))
+ frame_ = NullFramePtr();
+
+#ifdef DEBUG
+ if (si_) {
+ if (hasSyntacticEnvironment()) {
+ Scope* scope = si_.scope();
+ if (scope->is<LexicalScope>()) {
+ MOZ_ASSERT(scope == &env_->as<LexicalEnvironmentObject>().scope());
+ } else if (scope->is<FunctionScope>()) {
+ MOZ_ASSERT(scope->as<FunctionScope>().script() ==
+ env_->as<CallObject>().callee().existingScriptNonDelazifying());
+ } else if (scope->is<VarScope>()) {
+ MOZ_ASSERT(scope == &env_->as<VarEnvironmentObject>().scope());
+ } else if (scope->is<WithScope>()) {
+ MOZ_ASSERT(scope == &env_->as<WithEnvironmentObject>().scope());
+ } else if (scope->is<EvalScope>()) {
+ MOZ_ASSERT(scope == &env_->as<VarEnvironmentObject>().scope());
+ } else if (scope->is<GlobalScope>()) {
+ MOZ_ASSERT(env_->is<GlobalObject>() || IsGlobalLexicalEnvironment(env_));
+ }
+ } else if (hasNonSyntacticEnvironmentObject()) {
+ if (env_->is<LexicalEnvironmentObject>()) {
+ // The global lexical environment still encloses non-syntactic
+ // environment objects.
+ MOZ_ASSERT(!env_->as<LexicalEnvironmentObject>().isSyntactic() ||
+ env_->as<LexicalEnvironmentObject>().isGlobal());
+ } else if (env_->is<WithEnvironmentObject>()) {
+ MOZ_ASSERT(!env_->as<WithEnvironmentObject>().isSyntactic());
+ } else {
+ MOZ_ASSERT(env_->is<NonSyntacticVariablesObject>());
+ }
+ }
+ }
+#endif
+}
+
+JSObject&
+EnvironmentIter::enclosingEnvironment() const
+{
+ // As an engine invariant (maintained internally and asserted by Execute),
+ // EnvironmentObjects and non-EnvironmentObjects cannot be interleaved on
+ // the scope chain; every scope chain must start with zero or more
+ // EnvironmentObjects and terminate with one or more
+ // non-EnvironmentObjects (viz., GlobalObject).
+ MOZ_ASSERT(done());
+ MOZ_ASSERT(!env_->is<EnvironmentObject>());
+ return *env_;
+}
+
+bool
+EnvironmentIter::hasNonSyntacticEnvironmentObject() const
+{
+ // The case we're worrying about here is a NonSyntactic static scope
+ // which has 0+ corresponding non-syntactic WithEnvironmentObject
+ // scopes, a NonSyntacticVariablesObject, or a non-syntactic
+ // LexicalEnvironmentObject.
+ if (si_.kind() == ScopeKind::NonSyntactic) {
+ MOZ_ASSERT_IF(env_->is<WithEnvironmentObject>(),
+ !env_->as<WithEnvironmentObject>().isSyntactic());
+ return env_->is<EnvironmentObject>();
+ }
+ return false;
+}
+
+/* static */ HashNumber
+MissingEnvironmentKey::hash(MissingEnvironmentKey ek)
+{
+ return size_t(ek.frame_.raw()) ^ size_t(ek.scope_);
+}
+
+/* static */ bool
+MissingEnvironmentKey::match(MissingEnvironmentKey ek1, MissingEnvironmentKey ek2)
+{
+ return ek1.frame_ == ek2.frame_ && ek1.scope_ == ek2.scope_;
+}
+
+bool
+LiveEnvironmentVal::needsSweep()
+{
+ if (scope_)
+ MOZ_ALWAYS_FALSE(IsAboutToBeFinalized(&scope_));
+ return false;
+}
+
+// Live EnvironmentIter values may be added to DebugEnvironments::liveEnvs, as
+// LiveEnvironmentVal instances. They need to have write barriers when they are added
+// to the hash table, but no barriers when rehashing inside GC. It's a nasty
+// hack, but the important thing is that LiveEnvironmentVal and MissingEnvironmentKey need to
+// alias each other.
+void
+LiveEnvironmentVal::staticAsserts()
+{
+ static_assert(sizeof(LiveEnvironmentVal) == sizeof(MissingEnvironmentKey),
+ "LiveEnvironmentVal must be same size of MissingEnvironmentKey");
+ static_assert(offsetof(LiveEnvironmentVal, scope_) == offsetof(MissingEnvironmentKey, scope_),
+ "LiveEnvironmentVal.scope_ must alias MissingEnvironmentKey.scope_");
+}
+
+/*****************************************************************************/
+
+namespace {
+
+static void
+ReportOptimizedOut(JSContext* cx, HandleId id)
+{
+ JSAutoByteString printable;
+ if (ValueToPrintable(cx, IdToValue(id), &printable)) {
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_OPTIMIZED_OUT,
+ printable.ptr());
+ }
+}
+
+/*
+ * DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy
+ * objects. Having a custom handler (rather than trying to reuse js::Wrapper)
+ * gives us several important abilities:
+ * - We want to pass the EnvironmentObject as the receiver to forwarded scope
+ * property ops on aliased variables so that Call/Block/With ops do not all
+ * require a 'normalization' step.
+ * - The debug scope proxy can directly manipulate the stack frame to allow
+ * the debugger to read/write args/locals that were otherwise unaliased.
+ * - The debug scope proxy can store unaliased variables after the stack frame
+ * is popped so that they may still be read/written by the debugger.
+ * - The engine has made certain assumptions about the possible reads/writes
+ * in a scope. DebugEnvironmentProxy allows us to prevent the debugger from
+ * breaking those assumptions.
+ * - The engine makes optimizations that are observable to the debugger. The
+ * proxy can either hide these optimizations or make the situation more
+ * clear to the debugger. An example is 'arguments'.
+ */
+class DebugEnvironmentProxyHandler : public BaseProxyHandler
+{
+ enum Action { SET, GET };
+
+ enum AccessResult {
+ ACCESS_UNALIASED,
+ ACCESS_GENERIC,
+ ACCESS_LOST
+ };
+
+ /*
+ * This function handles access to unaliased locals/formals. Since they
+ * are unaliased, the values of these variables are not stored in the
+ * slots of the normal CallObject and LexicalEnvironmentObject
+ * environments and thus must be recovered from somewhere else:
+ * + if the invocation for which the env was created is still executing,
+ * there is a JS frame live on the stack holding the values;
+ * + if the invocation for which the env was created finished executing:
+ * - and there was a DebugEnvironmentProxy associated with env, then
+ * the DebugEnvironments::onPop(Call|Lexical) handler copied out the
+ * unaliased variables. In both cases, a dense array is created in
+ * onPop(Call|Lexical) to hold the unaliased values and attached to
+ * the DebugEnvironmentProxy;
+ * - and there was not a DebugEnvironmentProxy yet associated with the
+ * scope, then the unaliased values are lost and not recoverable.
+ *
+ * Callers should check accessResult for non-failure results:
+ * - ACCESS_UNALIASED if the access was unaliased and completed
+ * - ACCESS_GENERIC if the access was aliased or the property not found
+ * - ACCESS_LOST if the value has been lost to the debugger and the
+ * action is GET; if the action is SET, we assign to the
+ * name of the variable on the environment object
+ */
+ bool handleUnaliasedAccess(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
+ Handle<EnvironmentObject*> env, HandleId id, Action action,
+ MutableHandleValue vp, AccessResult* accessResult) const
+ {
+ MOZ_ASSERT(&debugEnv->environment() == env);
+ MOZ_ASSERT_IF(action == SET, !debugEnv->isOptimizedOut());
+ *accessResult = ACCESS_GENERIC;
+ LiveEnvironmentVal* maybeLiveEnv = DebugEnvironments::hasLiveEnvironment(*env);
+
+ if (env->is<ModuleEnvironmentObject>()) {
+ /* Everything is aliased and stored in the environment object. */
+ return true;
+ }
+
+ /* Handle unaliased formals, vars, lets, and consts at function scope. */
+ if (env->is<CallObject>()) {
+ CallObject& callobj = env->as<CallObject>();
+ RootedScript script(cx, callobj.callee().getOrCreateScript(cx));
+ if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
+ return false;
+
+ BindingIter bi(script);
+ while (bi && NameToId(bi.name()->asPropertyName()) != id)
+ bi++;
+ if (!bi)
+ return true;
+
+ if (!bi.hasArgumentSlot()) {
+ if (bi.closedOver())
+ return true;
+
+ uint32_t i = bi.location().slot();
+ if (maybeLiveEnv) {
+ AbstractFramePtr frame = maybeLiveEnv->frame();
+ if (action == GET)
+ vp.set(frame.unaliasedLocal(i));
+ else
+ frame.unaliasedLocal(i) = vp;
+ } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
+ if (action == GET)
+ vp.set(snapshot->getDenseElement(script->numArgs() + i));
+ else
+ snapshot->setDenseElement(script->numArgs() + i, vp);
+ } else {
+ /* The unaliased value has been lost to the debugger. */
+ if (action == GET) {
+ *accessResult = ACCESS_LOST;
+ return true;
+ }
+ }
+ } else {
+ unsigned i = bi.argumentSlot();
+ if (bi.closedOver())
+ return true;
+
+ if (maybeLiveEnv) {
+ AbstractFramePtr frame = maybeLiveEnv->frame();
+ if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
+ if (action == GET)
+ vp.set(frame.argsObj().arg(i));
+ else
+ frame.argsObj().setArg(i, vp);
+ } else {
+ if (action == GET)
+ vp.set(frame.unaliasedFormal(i, DONT_CHECK_ALIASING));
+ else
+ frame.unaliasedFormal(i, DONT_CHECK_ALIASING) = vp;
+ }
+ } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
+ if (action == GET)
+ vp.set(snapshot->getDenseElement(i));
+ else
+ snapshot->setDenseElement(i, vp);
+ } else {
+ /* The unaliased value has been lost to the debugger. */
+ if (action == GET) {
+ *accessResult = ACCESS_LOST;
+ return true;
+ }
+ }
+
+ if (action == SET)
+ TypeScript::SetArgument(cx, script, i, vp);
+ }
+
+ // It is possible that an optimized out value flows to this
+ // location due to Debugger.Frame.prototype.eval operating on a
+ // live bailed-out Baseline frame. In that case, treat the access
+ // as lost.
+ if (vp.isMagic() && vp.whyMagic() == JS_OPTIMIZED_OUT)
+ *accessResult = ACCESS_LOST;
+ else
+ *accessResult = ACCESS_UNALIASED;
+
+ return true;
+ }
+
+ /*
+ * Handle unaliased vars in functions with parameter expressions and
+ * lexical bindings at block scope.
+ */
+ if (env->is<LexicalEnvironmentObject>() || env->is<VarEnvironmentObject>()) {
+ // Currently consider all global and non-syntactic top-level lexical
+ // bindings to be aliased.
+ if (env->is<LexicalEnvironmentObject>() &&
+ env->as<LexicalEnvironmentObject>().isExtensible())
+ {
+ MOZ_ASSERT(IsGlobalLexicalEnvironment(env) || !IsSyntacticEnvironment(env));
+ return true;
+ }
+
+ // Currently all vars inside eval var environments are aliased.
+ if (env->is<VarEnvironmentObject>() && env->as<VarEnvironmentObject>().isForEval())
+ return true;
+
+ RootedScope scope(cx, getEnvironmentScope(*env));
+ uint32_t firstFrameSlot;
+ if (env->is<LexicalEnvironmentObject>())
+ firstFrameSlot = scope->as<LexicalScope>().firstFrameSlot();
+ else
+ firstFrameSlot = scope->as<VarScope>().firstFrameSlot();
+
+ BindingIter bi(scope);
+ while (bi && NameToId(bi.name()->asPropertyName()) != id)
+ bi++;
+ if (!bi)
+ return true;
+
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Environment)
+ return true;
+
+ // Named lambdas that are not closed over are lost.
+ if (loc.kind() == BindingLocation::Kind::NamedLambdaCallee) {
+ if (action == GET)
+ *accessResult = ACCESS_LOST;
+ return true;
+ }
+
+ MOZ_ASSERT(loc.kind() == BindingLocation::Kind::Frame);
+
+ if (maybeLiveEnv) {
+ AbstractFramePtr frame = maybeLiveEnv->frame();
+ uint32_t local = loc.slot();
+ MOZ_ASSERT(local < frame.script()->nfixed());
+ if (action == GET)
+ vp.set(frame.unaliasedLocal(local));
+ else
+ frame.unaliasedLocal(local) = vp;
+ } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
+ // Indices in the frame snapshot are offset by the first frame
+ // slot. See DebugEnvironments::takeFrameSnapshot.
+ MOZ_ASSERT(loc.slot() >= firstFrameSlot);
+ uint32_t snapshotIndex = loc.slot() - firstFrameSlot;
+ if (action == GET)
+ vp.set(snapshot->getDenseElement(snapshotIndex));
+ else
+ snapshot->setDenseElement(snapshotIndex, vp);
+ } else {
+ if (action == GET) {
+ // A {Lexical,Var}EnvironmentObject whose static scope
+ // does not have an environment shape at all is a "hollow"
+ // block object reflected for missing block scopes. Their
+ // slot values are lost.
+ if (!scope->hasEnvironment()) {
+ *accessResult = ACCESS_LOST;
+ return true;
+ }
+
+ if (!GetProperty(cx, env, env, id, vp))
+ return false;
+ } else {
+ if (!SetProperty(cx, env, id, vp))
+ return false;
+ }
+ }
+
+ // See comment above in analogous CallObject case.
+ if (vp.isMagic() && vp.whyMagic() == JS_OPTIMIZED_OUT)
+ *accessResult = ACCESS_LOST;
+ else
+ *accessResult = ACCESS_UNALIASED;
+
+ return true;
+ }
+
+ /* The rest of the internal scopes do not have unaliased vars. */
+ MOZ_ASSERT(!IsSyntacticEnvironment(env) ||
+ env->is<WithEnvironmentObject>());
+ return true;
+ }
+
+ static bool isArguments(JSContext* cx, jsid id)
+ {
+ return id == NameToId(cx->names().arguments);
+ }
+ static bool isThis(JSContext* cx, jsid id)
+ {
+ return id == NameToId(cx->names().dotThis);
+ }
+
+ static bool isFunctionEnvironment(const JSObject& env)
+ {
+ return env.is<CallObject>();
+ }
+
+ static bool isNonExtensibleLexicalEnvironment(const JSObject& env)
+ {
+ return env.is<LexicalEnvironmentObject>() &&
+ !env.as<LexicalEnvironmentObject>().isExtensible();
+ }
+
+ static Scope* getEnvironmentScope(const JSObject& env)
+ {
+ if (isFunctionEnvironment(env))
+ return env.as<CallObject>().callee().nonLazyScript()->bodyScope();
+ if (isNonExtensibleLexicalEnvironment(env))
+ return &env.as<LexicalEnvironmentObject>().scope();
+ if (env.is<VarEnvironmentObject>())
+ return &env.as<VarEnvironmentObject>().scope();
+ return nullptr;
+ }
+
+ /*
+ * In theory, every non-arrow function scope contains an 'arguments'
+ * bindings. However, the engine only adds a binding if 'arguments' is
+ * used in the function body. Thus, from the debugger's perspective,
+ * 'arguments' may be missing from the list of bindings.
+ */
+ static bool isMissingArgumentsBinding(EnvironmentObject& env)
+ {
+ return isFunctionEnvironment(env) &&
+ !env.as<CallObject>().callee().nonLazyScript()->argumentsHasVarBinding();
+ }
+
+ /*
+ * Similar to 'arguments' above, we don't add a 'this' binding to
+ * non-arrow functions if it's not used.
+ */
+ static bool isMissingThisBinding(EnvironmentObject& env)
+ {
+ return isFunctionEnvironmentWithThis(env) &&
+ !env.as<CallObject>().callee().nonLazyScript()->functionHasThisBinding();
+ }
+
+ /*
+ * This function checks if an arguments object needs to be created when
+ * the debugger requests 'arguments' for a function scope where the
+ * arguments object has been optimized away (either because the binding is
+ * missing altogether or because !ScriptAnalysis::needsArgsObj).
+ */
+ static bool isMissingArguments(JSContext* cx, jsid id, EnvironmentObject& env)
+ {
+ return isArguments(cx, id) && isFunctionEnvironment(env) &&
+ !env.as<CallObject>().callee().nonLazyScript()->needsArgsObj();
+ }
+ static bool isMissingThis(JSContext* cx, jsid id, EnvironmentObject& env)
+ {
+ return isThis(cx, id) && isMissingThisBinding(env);
+ }
+
+ /*
+ * Check if the value is the magic value JS_OPTIMIZED_ARGUMENTS. The
+ * arguments analysis may have optimized out the 'arguments', and this
+ * magic value could have propagated to other local slots. e.g.,
+ *
+ * function f() { var a = arguments; h(); }
+ * function h() { evalInFrame(1, "a.push(0)"); }
+ *
+ * where evalInFrame(N, str) means to evaluate str N frames up.
+ *
+ * In this case we don't know we need to recover a missing arguments
+ * object until after we've performed the property get.
+ */
+ static bool isMagicMissingArgumentsValue(JSContext* cx, EnvironmentObject& env, HandleValue v)
+ {
+ bool isMagic = v.isMagic() && v.whyMagic() == JS_OPTIMIZED_ARGUMENTS;
+
+#ifdef DEBUG
+ // The |env| object here is not limited to CallObjects but may also
+ // be lexical envs in case of the following:
+ //
+ // function f() { { let a = arguments; } }
+ //
+ // We need to check that |env|'s scope's nearest function scope has an
+ // 'arguments' var binding. The environment chain is not sufficient:
+ // |f| above will not have a CallObject because there are no aliased
+ // body-level bindings.
+ if (isMagic) {
+ JSFunction* callee = nullptr;
+ if (isFunctionEnvironment(env)) {
+ callee = &env.as<CallObject>().callee();
+ } else {
+ // We will never have a WithEnvironmentObject here because no
+ // binding accesses on with scopes are unaliased.
+ for (ScopeIter si(getEnvironmentScope(env)); si; si++) {
+ if (si.kind() == ScopeKind::Function) {
+ callee = si.scope()->as<FunctionScope>().canonicalFunction();
+ break;
+ }
+ }
+ }
+ MOZ_ASSERT(callee && callee->nonLazyScript()->argumentsHasVarBinding());
+ }
+#endif
+
+ return isMagic;
+ }
+
+ /*
+ * If the value of |this| is requested before the this-binding has been
+ * initialized by JSOP_FUNCTIONTHIS, the this-binding will be |undefined|.
+ * In that case, we have to call createMissingThis to initialize the
+ * this-binding.
+ *
+ * Note that an |undefined| this-binding is perfectly valid in strict-mode
+ * code, but that's fine: createMissingThis will do the right thing in that
+ * case.
+ */
+ static bool isMaybeUninitializedThisValue(JSContext* cx, jsid id, const Value& v)
+ {
+ return isThis(cx, id) && v.isUndefined();
+ }
+
+ /*
+ * Create a missing arguments object. If the function returns true but
+ * argsObj is null, it means the env is dead.
+ */
+ static bool createMissingArguments(JSContext* cx, EnvironmentObject& env,
+ MutableHandleArgumentsObject argsObj)
+ {
+ argsObj.set(nullptr);
+
+ LiveEnvironmentVal* maybeEnv = DebugEnvironments::hasLiveEnvironment(env);
+ if (!maybeEnv)
+ return true;
+
+ argsObj.set(ArgumentsObject::createUnexpected(cx, maybeEnv->frame()));
+ return !!argsObj;
+ }
+
+ /*
+ * Create a missing this Value. If the function returns true but
+ * *success is false, it means the scope is dead.
+ */
+ static bool createMissingThis(JSContext* cx, EnvironmentObject& env,
+ MutableHandleValue thisv, bool* success)
+ {
+ *success = false;
+
+ LiveEnvironmentVal* maybeEnv = DebugEnvironments::hasLiveEnvironment(env);
+ if (!maybeEnv)
+ return true;
+
+ if (!GetFunctionThis(cx, maybeEnv->frame(), thisv))
+ return false;
+
+ // Update the this-argument to avoid boxing primitive |this| more
+ // than once.
+ maybeEnv->frame().thisArgument() = thisv;
+ *success = true;
+ return true;
+ }
+
+ public:
+ static const char family;
+ static const DebugEnvironmentProxyHandler singleton;
+
+ constexpr DebugEnvironmentProxyHandler() : BaseProxyHandler(&family) {}
+
+ static bool isFunctionEnvironmentWithThis(const JSObject& env)
+ {
+ // All functions except arrows and generator expression lambdas should
+ // have their own this binding.
+ return isFunctionEnvironment(env) && !env.as<CallObject>().callee().hasLexicalThis();
+ }
+
+ bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop) const override
+ {
+ MOZ_CRASH("shouldn't be possible to access the prototype chain of a DebugEnvironmentProxyHandler");
+ }
+
+ bool preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const override
+ {
+ // always [[Extensible]], can't be made non-[[Extensible]], like most
+ // proxies
+ return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
+ }
+
+ bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override
+ {
+ // See above.
+ *extensible = true;
+ return true;
+ }
+
+ bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const override
+ {
+ return getOwnPropertyDescriptor(cx, proxy, id, desc);
+ }
+
+ bool getMissingArgumentsPropertyDescriptor(JSContext* cx,
+ Handle<DebugEnvironmentProxy*> debugEnv,
+ EnvironmentObject& env,
+ MutableHandle<PropertyDescriptor> desc) const
+ {
+ RootedArgumentsObject argsObj(cx);
+ if (!createMissingArguments(cx, env, &argsObj))
+ return false;
+
+ if (!argsObj) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+ "Debugger scope");
+ return false;
+ }
+
+ desc.object().set(debugEnv);
+ desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
+ desc.value().setObject(*argsObj);
+ desc.setGetter(nullptr);
+ desc.setSetter(nullptr);
+ return true;
+ }
+ bool getMissingThisPropertyDescriptor(JSContext* cx,
+ Handle<DebugEnvironmentProxy*> debugEnv,
+ EnvironmentObject& env,
+ MutableHandle<PropertyDescriptor> desc) const
+ {
+ RootedValue thisv(cx);
+ bool success;
+ if (!createMissingThis(cx, env, &thisv, &success))
+ return false;
+
+ if (!success) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+ "Debugger scope");
+ return false;
+ }
+
+ desc.object().set(debugEnv);
+ desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
+ desc.value().set(thisv);
+ desc.setGetter(nullptr);
+ desc.setSetter(nullptr);
+ return true;
+ }
+
+ bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const override
+ {
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
+ Rooted<EnvironmentObject*> env(cx, &debugEnv->environment());
+
+ if (isMissingArguments(cx, id, *env))
+ return getMissingArgumentsPropertyDescriptor(cx, debugEnv, *env, desc);
+
+ if (isMissingThis(cx, id, *env))
+ return getMissingThisPropertyDescriptor(cx, debugEnv, *env, desc);
+
+ RootedValue v(cx);
+ AccessResult access;
+ if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, &v, &access))
+ return false;
+
+ switch (access) {
+ case ACCESS_UNALIASED:
+ if (isMagicMissingArgumentsValue(cx, *env, v))
+ return getMissingArgumentsPropertyDescriptor(cx, debugEnv, *env, desc);
+ desc.object().set(debugEnv);
+ desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
+ desc.value().set(v);
+ desc.setGetter(nullptr);
+ desc.setSetter(nullptr);
+ return true;
+ case ACCESS_GENERIC:
+ return JS_GetOwnPropertyDescriptorById(cx, env, id, desc);
+ case ACCESS_LOST:
+ ReportOptimizedOut(cx, id);
+ return false;
+ default:
+ MOZ_CRASH("bad AccessResult");
+ }
+ }
+
+ bool getMissingArguments(JSContext* cx, EnvironmentObject& env, MutableHandleValue vp) const
+ {
+ RootedArgumentsObject argsObj(cx);
+ if (!createMissingArguments(cx, env, &argsObj))
+ return false;
+
+ if (!argsObj) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+ "Debugger env");
+ return false;
+ }
+
+ vp.setObject(*argsObj);
+ return true;
+ }
+
+ bool getMissingThis(JSContext* cx, EnvironmentObject& env, MutableHandleValue vp) const
+ {
+ RootedValue thisv(cx);
+ bool success;
+ if (!createMissingThis(cx, env, &thisv, &success))
+ return false;
+
+ if (!success) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
+ "Debugger env");
+ return false;
+ }
+
+ vp.set(thisv);
+ return true;
+ }
+
+ bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+ MutableHandleValue vp) const override
+ {
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
+ Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
+
+ if (isMissingArguments(cx, id, *env))
+ return getMissingArguments(cx, *env, vp);
+
+ if (isMissingThis(cx, id, *env))
+ return getMissingThis(cx, *env, vp);
+
+ AccessResult access;
+ if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, vp, &access))
+ return false;
+
+ switch (access) {
+ case ACCESS_UNALIASED:
+ if (isMagicMissingArgumentsValue(cx, *env, vp))
+ return getMissingArguments(cx, *env, vp);
+ if (isMaybeUninitializedThisValue(cx, id, vp))
+ return getMissingThis(cx, *env, vp);
+ return true;
+ case ACCESS_GENERIC:
+ if (!GetProperty(cx, env, env, id, vp))
+ return false;
+ if (isMaybeUninitializedThisValue(cx, id, vp))
+ return getMissingThis(cx, *env, vp);
+ return true;
+ case ACCESS_LOST:
+ ReportOptimizedOut(cx, id);
+ return false;
+ default:
+ MOZ_CRASH("bad AccessResult");
+ }
+ }
+
+ bool getMissingArgumentsMaybeSentinelValue(JSContext* cx, EnvironmentObject& env,
+ MutableHandleValue vp) const
+ {
+ RootedArgumentsObject argsObj(cx);
+ if (!createMissingArguments(cx, env, &argsObj))
+ return false;
+ vp.set(argsObj ? ObjectValue(*argsObj) : MagicValue(JS_OPTIMIZED_ARGUMENTS));
+ return true;
+ }
+
+ bool getMissingThisMaybeSentinelValue(JSContext* cx, EnvironmentObject& env,
+ MutableHandleValue vp) const
+ {
+ RootedValue thisv(cx);
+ bool success;
+ if (!createMissingThis(cx, env, &thisv, &success))
+ return false;
+ vp.set(success ? thisv : MagicValue(JS_OPTIMIZED_OUT));
+ return true;
+ }
+
+ /*
+ * Like 'get', but returns sentinel values instead of throwing on
+ * exceptional cases.
+ */
+ bool getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
+ HandleId id, MutableHandleValue vp) const
+ {
+ Rooted<EnvironmentObject*> env(cx, &debugEnv->environment());
+
+ if (isMissingArguments(cx, id, *env))
+ return getMissingArgumentsMaybeSentinelValue(cx, *env, vp);
+ if (isMissingThis(cx, id, *env))
+ return getMissingThisMaybeSentinelValue(cx, *env, vp);
+
+ AccessResult access;
+ if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, vp, &access))
+ return false;
+
+ switch (access) {
+ case ACCESS_UNALIASED:
+ if (isMagicMissingArgumentsValue(cx, *env, vp))
+ return getMissingArgumentsMaybeSentinelValue(cx, *env, vp);
+ if (isMaybeUninitializedThisValue(cx, id, vp))
+ return getMissingThisMaybeSentinelValue(cx, *env, vp);
+ return true;
+ case ACCESS_GENERIC:
+ if (!GetProperty(cx, env, env, id, vp))
+ return false;
+ if (isMaybeUninitializedThisValue(cx, id, vp))
+ return getMissingThisMaybeSentinelValue(cx, *env, vp);
+ return true;
+ case ACCESS_LOST:
+ vp.setMagic(JS_OPTIMIZED_OUT);
+ return true;
+ default:
+ MOZ_CRASH("bad AccessResult");
+ }
+ }
+
+ bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
+ ObjectOpResult& result) const override
+ {
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
+ Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
+
+ if (debugEnv->isOptimizedOut())
+ return Throw(cx, id, JSMSG_DEBUG_CANT_SET_OPT_ENV);
+
+ AccessResult access;
+ RootedValue valCopy(cx, v);
+ if (!handleUnaliasedAccess(cx, debugEnv, env, id, SET, &valCopy, &access))
+ return false;
+
+ switch (access) {
+ case ACCESS_UNALIASED:
+ return result.succeed();
+ case ACCESS_GENERIC: {
+ RootedValue envVal(cx, ObjectValue(*env));
+ return SetProperty(cx, env, id, v, envVal, result);
+ }
+ default:
+ MOZ_CRASH("bad AccessResult");
+ }
+ }
+
+ bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const override
+ {
+ Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
+
+ bool found;
+ if (!has(cx, proxy, id, &found))
+ return false;
+ if (found)
+ return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
+
+ return JS_DefinePropertyById(cx, env, id, desc, result);
+ }
+
+ bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override
+ {
+ Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
+
+ if (isMissingArgumentsBinding(*env)) {
+ if (!props.append(NameToId(cx->names().arguments)))
+ return false;
+ }
+ if (isMissingThisBinding(*env)) {
+ if (!props.append(NameToId(cx->names().dotThis)))
+ return false;
+ }
+
+ // WithEnvironmentObject isn't a very good proxy. It doesn't have a
+ // JSNewEnumerateOp implementation, because if it just delegated to the
+ // target object, the object would indicate that native enumeration is
+ // the thing to do, but native enumeration over the WithEnvironmentObject
+ // wrapper yields no properties. So instead here we hack around the
+ // issue: punch a hole through to the with object target, then manually
+ // examine @@unscopables.
+ RootedObject target(cx);
+ bool isWith = env->is<WithEnvironmentObject>();
+ if (isWith)
+ target = &env->as<WithEnvironmentObject>().object();
+ else
+ target = env;
+ if (!GetPropertyKeys(cx, target, JSITER_OWNONLY, &props))
+ return false;
+
+ if (isWith) {
+ size_t j = 0;
+ for (size_t i = 0; i < props.length(); i++) {
+ bool inScope;
+ if (!CheckUnscopables(cx, env, props[i], &inScope))
+ return false;
+ if (inScope)
+ props[j++].set(props[i]);
+ }
+ if (!props.resize(j))
+ return false;
+ }
+
+ /*
+ * Environments with Scopes are optimized to not contain unaliased
+ * variables so they must be manually appended here.
+ */
+ if (Scope* scope = getEnvironmentScope(*env)) {
+ for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
+ if (!bi.closedOver() && !props.append(NameToId(bi.name()->asPropertyName())))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool has(JSContext* cx, HandleObject proxy, HandleId id_, bool* bp) const override
+ {
+ RootedId id(cx, id_);
+ EnvironmentObject& envObj = proxy->as<DebugEnvironmentProxy>().environment();
+
+ if (isArguments(cx, id) && isFunctionEnvironment(envObj)) {
+ *bp = true;
+ return true;
+ }
+
+ // Be careful not to look up '.this' as a normal binding below, it will
+ // assert in with_HasProperty.
+ if (isThis(cx, id)) {
+ *bp = isFunctionEnvironmentWithThis(envObj);
+ return true;
+ }
+
+ bool found;
+ RootedObject env(cx, &envObj);
+ if (!JS_HasPropertyById(cx, env, id, &found))
+ return false;
+
+ if (!found) {
+ if (Scope* scope = getEnvironmentScope(*env)) {
+ for (BindingIter bi(scope); bi; bi++) {
+ if (!bi.closedOver() && NameToId(bi.name()->asPropertyName()) == id) {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ *bp = found;
+ return true;
+ }
+
+ bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
+ ObjectOpResult& result) const override
+ {
+ return result.fail(JSMSG_CANT_DELETE);
+ }
+};
+
+} /* anonymous namespace */
+
+template<>
+bool
+JSObject::is<js::DebugEnvironmentProxy>() const
+{
+ return IsDerivedProxyObject(this, &DebugEnvironmentProxyHandler::singleton);
+}
+
+const char DebugEnvironmentProxyHandler::family = 0;
+const DebugEnvironmentProxyHandler DebugEnvironmentProxyHandler::singleton;
+
+/* static */ DebugEnvironmentProxy*
+DebugEnvironmentProxy::create(JSContext* cx, EnvironmentObject& env, HandleObject enclosing)
+{
+ MOZ_ASSERT(env.compartment() == cx->compartment());
+ MOZ_ASSERT(!enclosing->is<EnvironmentObject>());
+
+ RootedValue priv(cx, ObjectValue(env));
+ JSObject* obj = NewProxyObject(cx, &DebugEnvironmentProxyHandler::singleton, priv,
+ nullptr /* proto */);
+ if (!obj)
+ return nullptr;
+
+ DebugEnvironmentProxy* debugEnv = &obj->as<DebugEnvironmentProxy>();
+ debugEnv->setExtra(ENCLOSING_EXTRA, ObjectValue(*enclosing));
+ debugEnv->setExtra(SNAPSHOT_EXTRA, NullValue());
+
+ return debugEnv;
+}
+
+EnvironmentObject&
+DebugEnvironmentProxy::environment() const
+{
+ return target()->as<EnvironmentObject>();
+}
+
+JSObject&
+DebugEnvironmentProxy::enclosingEnvironment() const
+{
+ return extra(ENCLOSING_EXTRA).toObject();
+}
+
+ArrayObject*
+DebugEnvironmentProxy::maybeSnapshot() const
+{
+ JSObject* obj = extra(SNAPSHOT_EXTRA).toObjectOrNull();
+ return obj ? &obj->as<ArrayObject>() : nullptr;
+}
+
+void
+DebugEnvironmentProxy::initSnapshot(ArrayObject& o)
+{
+ MOZ_ASSERT(maybeSnapshot() == nullptr);
+ setExtra(SNAPSHOT_EXTRA, ObjectValue(o));
+}
+
+bool
+DebugEnvironmentProxy::isForDeclarative() const
+{
+ EnvironmentObject& e = environment();
+ return e.is<CallObject>() ||
+ e.is<VarEnvironmentObject>() ||
+ e.is<ModuleEnvironmentObject>() ||
+ e.is<LexicalEnvironmentObject>();
+}
+
+bool
+DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp)
+{
+ Rooted<DebugEnvironmentProxy*> self(cx, this);
+ return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, self, id, vp);
+}
+
+bool
+DebugEnvironmentProxy::isFunctionEnvironmentWithThis()
+{
+ return DebugEnvironmentProxyHandler::isFunctionEnvironmentWithThis(environment());
+}
+
+bool
+DebugEnvironmentProxy::isOptimizedOut() const
+{
+ EnvironmentObject& e = environment();
+
+ if (DebugEnvironments::hasLiveEnvironment(e))
+ return false;
+
+ if (e.is<LexicalEnvironmentObject>()) {
+ return !e.as<LexicalEnvironmentObject>().isExtensible() &&
+ !e.as<LexicalEnvironmentObject>().scope().hasEnvironment();
+ }
+
+ if (e.is<CallObject>()) {
+ return !e.as<CallObject>().callee().needsCallObject() &&
+ !maybeSnapshot();
+ }
+
+ return false;
+}
+
+/*****************************************************************************/
+
+DebugEnvironments::DebugEnvironments(JSContext* cx)
+ : proxiedEnvs(cx),
+ missingEnvs(cx->runtime()),
+ liveEnvs(cx->runtime())
+{}
+
+DebugEnvironments::~DebugEnvironments()
+{
+ MOZ_ASSERT_IF(missingEnvs.initialized(), missingEnvs.empty());
+}
+
+bool
+DebugEnvironments::init()
+{
+ return proxiedEnvs.init() && missingEnvs.init() && liveEnvs.init();
+}
+
+void
+DebugEnvironments::mark(JSTracer* trc)
+{
+ proxiedEnvs.trace(trc);
+}
+
+void
+DebugEnvironments::sweep(JSRuntime* rt)
+{
+ /*
+ * missingEnvs points to debug envs weakly so that debug envs can be
+ * released more eagerly.
+ */
+ for (MissingEnvironmentMap::Enum e(missingEnvs); !e.empty(); e.popFront()) {
+ if (IsAboutToBeFinalized(&e.front().value())) {
+ /*
+ * Note that onPopCall, onPopVar, and onPopLexical rely on
+ * missingEnvs to find environment objects that we synthesized for
+ * the debugger's sake, and clean up the synthetic environment
+ * objects' entries in liveEnvs. So if we remove an entry from
+ * missingEnvs here, we must also remove the corresponding
+ * liveEnvs entry.
+ *
+ * Since the DebugEnvironmentProxy is the only thing using its environment
+ * object, and the DSO is about to be finalized, you might assume
+ * that the synthetic SO is also about to be finalized too, and thus
+ * the loop below will take care of things. But complex GC behavior
+ * means that marks are only conservative approximations of
+ * liveness; we should assume that anything could be marked.
+ *
+ * Thus, we must explicitly remove the entries from both liveEnvs
+ * and missingEnvs here.
+ */
+ liveEnvs.remove(&e.front().value().unbarrieredGet()->environment());
+ e.removeFront();
+ } else {
+ MissingEnvironmentKey key = e.front().key();
+ if (IsForwarded(key.scope())) {
+ key.updateScope(Forwarded(key.scope()));
+ e.rekeyFront(key);
+ }
+ }
+ }
+
+ /*
+ * Scopes can be finalized when a debugger-synthesized EnvironmentObject is
+ * no longer reachable via its DebugEnvironmentProxy.
+ */
+ liveEnvs.sweep();
+}
+
+void
+DebugEnvironments::finish()
+{
+ proxiedEnvs.clear();
+}
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+void
+DebugEnvironments::checkHashTablesAfterMovingGC(JSRuntime* runtime)
+{
+ /*
+ * This is called at the end of StoreBuffer::mark() to check that our
+ * postbarriers have worked and that no hashtable keys (or values) are left
+ * pointing into the nursery.
+ */
+ proxiedEnvs.checkAfterMovingGC();
+ for (MissingEnvironmentMap::Range r = missingEnvs.all(); !r.empty(); r.popFront()) {
+ CheckGCThingAfterMovingGC(r.front().key().scope());
+ CheckGCThingAfterMovingGC(r.front().value().get());
+ }
+ for (LiveEnvironmentMap::Range r = liveEnvs.all(); !r.empty(); r.popFront()) {
+ CheckGCThingAfterMovingGC(r.front().key());
+ CheckGCThingAfterMovingGC(r.front().value().scope_.get());
+ }
+}
+#endif
+
+/*
+ * Unfortunately, GetDebugEnvironmentForFrame needs to work even outside debug mode
+ * (in particular, JS_GetFrameScopeChain does not require debug mode). Since
+ * DebugEnvironments::onPop* are only called in debuggee frames, this means we
+ * cannot use any of the maps in DebugEnvironments. This will produce debug scope
+ * chains that do not obey the debugger invariants but that is just fine.
+ */
+static bool
+CanUseDebugEnvironmentMaps(JSContext* cx)
+{
+ return cx->compartment()->isDebuggee();
+}
+
+DebugEnvironments*
+DebugEnvironments::ensureCompartmentData(JSContext* cx)
+{
+ JSCompartment* c = cx->compartment();
+ if (c->debugEnvs)
+ return c->debugEnvs;
+
+ auto debugEnvs = cx->make_unique<DebugEnvironments>(cx);
+ if (!debugEnvs || !debugEnvs->init()) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ c->debugEnvs = debugEnvs.release();
+ return c->debugEnvs;
+}
+
+/* static */ DebugEnvironmentProxy*
+DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
+{
+ DebugEnvironments* envs = env.compartment()->debugEnvs;
+ if (!envs)
+ return nullptr;
+
+ if (JSObject* obj = envs->proxiedEnvs.lookup(&env)) {
+ MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
+ return &obj->as<DebugEnvironmentProxy>();
+ }
+
+ return nullptr;
+}
+
+/* static */ bool
+DebugEnvironments::addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
+ Handle<DebugEnvironmentProxy*> debugEnv)
+{
+ MOZ_ASSERT(cx->compartment() == env->compartment());
+ MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
+
+ if (!CanUseDebugEnvironmentMaps(cx))
+ return true;
+
+ DebugEnvironments* envs = ensureCompartmentData(cx);
+ if (!envs)
+ return false;
+
+ return envs->proxiedEnvs.add(cx, env, debugEnv);
+}
+
+/* static */ DebugEnvironmentProxy*
+DebugEnvironments::hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
+{
+ MOZ_ASSERT(!ei.hasSyntacticEnvironment());
+
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return nullptr;
+
+ if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(MissingEnvironmentKey(ei))) {
+ MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
+ return p->value();
+ }
+ return nullptr;
+}
+
+/* static */ bool
+DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
+ Handle<DebugEnvironmentProxy*> debugEnv)
+{
+ MOZ_ASSERT(!ei.hasSyntacticEnvironment());
+ MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
+ // Generators should always have environments.
+ MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator());
+
+ if (!CanUseDebugEnvironmentMaps(cx))
+ return true;
+
+ DebugEnvironments* envs = ensureCompartmentData(cx);
+ if (!envs)
+ return false;
+
+ MissingEnvironmentKey key(ei);
+ MOZ_ASSERT(!envs->missingEnvs.has(key));
+ if (!envs->missingEnvs.put(key, ReadBarriered<DebugEnvironmentProxy*>(debugEnv))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ // Only add to liveEnvs if we synthesized the debug env on a live
+ // frame.
+ if (ei.withinInitialFrame()) {
+ MOZ_ASSERT(!envs->liveEnvs.has(&debugEnv->environment()));
+ if (!envs->liveEnvs.put(&debugEnv->environment(), LiveEnvironmentVal(ei))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */ void
+DebugEnvironments::takeFrameSnapshot(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
+ AbstractFramePtr frame)
+{
+ /*
+ * When the JS stack frame is popped, the values of unaliased variables
+ * are lost. If there is any debug env referring to this environment, save a
+ * copy of the unaliased variables' values in an array for later debugger
+ * access via DebugEnvironmentProxy::handleUnaliasedAccess.
+ *
+ * Note: since it is simplest for this function to be infallible, failure
+ * in this code will be silently ignored. This does not break any
+ * invariants since DebugEnvironmentProxy::maybeSnapshot can already be nullptr.
+ */
+
+ // Act like no snapshot was taken if we run OOM while taking the snapshot.
+ Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
+ if (debugEnv->environment().is<CallObject>()) {
+ JSScript* script = frame.script();
+
+ FunctionScope* scope = &script->bodyScope()->as<FunctionScope>();
+ uint32_t frameSlotCount = scope->nextFrameSlot();
+ MOZ_ASSERT(frameSlotCount <= script->nfixed());
+
+ // For simplicity, copy all frame slots from 0 to the frameSlotCount,
+ // even if we don't need all of them (like in the case of a defaults
+ // parameter scope having frame slots).
+ uint32_t numFormals = frame.numFormalArgs();
+ if (!vec.resize(numFormals + frameSlotCount)) {
+ cx->recoverFromOutOfMemory();
+ return;
+ }
+ mozilla::PodCopy(vec.begin(), frame.argv(), numFormals);
+ for (uint32_t slot = 0; slot < frameSlotCount; slot++)
+ vec[slot + frame.numFormalArgs()].set(frame.unaliasedLocal(slot));
+
+ /*
+ * Copy in formals that are not aliased via the scope chain
+ * but are aliased via the arguments object.
+ */
+ if (script->analyzedArgsUsage() && script->needsArgsObj() && frame.hasArgsObj()) {
+ for (unsigned i = 0; i < frame.numFormalArgs(); ++i) {
+ if (script->formalLivesInArgumentsObject(i))
+ vec[i].set(frame.argsObj().arg(i));
+ }
+ }
+ } else {
+ uint32_t frameSlotStart;
+ uint32_t frameSlotEnd;
+
+ if (debugEnv->environment().is<LexicalEnvironmentObject>()) {
+ LexicalScope* scope = &debugEnv->environment().as<LexicalEnvironmentObject>().scope();
+ frameSlotStart = scope->firstFrameSlot();
+ frameSlotEnd = scope->nextFrameSlot();
+ } else {
+ VarEnvironmentObject* env = &debugEnv->environment().as<VarEnvironmentObject>();
+ if (frame.isFunctionFrame()) {
+ VarScope* scope = &env->scope().as<VarScope>();
+ frameSlotStart = scope->firstFrameSlot();
+ frameSlotEnd = scope->nextFrameSlot();
+ } else {
+ EvalScope* scope = &env->scope().as<EvalScope>();
+ MOZ_ASSERT(scope == frame.script()->bodyScope());
+ frameSlotStart = 0;
+ frameSlotEnd = scope->nextFrameSlot();
+ }
+ }
+
+ uint32_t frameSlotCount = frameSlotEnd - frameSlotStart;
+ MOZ_ASSERT(frameSlotCount <= frame.script()->nfixed());
+
+ if (!vec.resize(frameSlotCount)) {
+ cx->recoverFromOutOfMemory();
+ return;
+ }
+ for (uint32_t slot = frameSlotStart; slot < frameSlotCount; slot++)
+ vec[slot - frameSlotStart].set(frame.unaliasedLocal(slot));
+ }
+
+ if (vec.length() == 0)
+ return;
+
+ /*
+ * Use a dense array as storage (since proxies do not have trace
+ * hooks). This array must not escape into the wild.
+ */
+ RootedArrayObject snapshot(cx, NewDenseCopiedArray(cx, vec.length(), vec.begin()));
+ if (!snapshot) {
+ cx->recoverFromOutOfMemory();
+ return;
+ }
+
+ debugEnv->initSnapshot(*snapshot);
+}
+
+/* static */ void
+DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
+{
+ assertSameCompartment(cx, frame);
+
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return;
+
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx, nullptr);
+
+ FunctionScope* funScope = &frame.script()->bodyScope()->as<FunctionScope>();
+ if (funScope->hasEnvironment()) {
+ MOZ_ASSERT(frame.callee()->needsCallObject());
+
+ /*
+ * The frame may be observed before the prologue has created the
+ * CallObject. See EnvironmentIter::settle.
+ */
+ if (!frame.environmentChain()->is<CallObject>())
+ return;
+
+ if (frame.callee()->isGenerator())
+ return;
+
+ CallObject& callobj = frame.environmentChain()->as<CallObject>();
+ envs->liveEnvs.remove(&callobj);
+ if (JSObject* obj = envs->proxiedEnvs.lookup(&callobj))
+ debugEnv = &obj->as<DebugEnvironmentProxy>();
+ } else {
+ MissingEnvironmentKey key(frame, funScope);
+ if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(key)) {
+ debugEnv = p->value();
+ envs->liveEnvs.remove(&debugEnv->environment().as<CallObject>());
+ envs->missingEnvs.remove(p);
+ }
+ }
+
+ if (debugEnv)
+ DebugEnvironments::takeFrameSnapshot(cx, debugEnv, frame);
+}
+
+void
+DebugEnvironments::onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
+{
+ assertSameCompartment(cx, frame);
+
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return;
+
+ EnvironmentIter ei(cx, frame, pc);
+ onPopLexical(cx, ei);
+}
+
+template <typename Environment, typename Scope>
+void
+DebugEnvironments::onPopGeneric(JSContext* cx, const EnvironmentIter& ei)
+{
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return;
+
+ MOZ_ASSERT(ei.withinInitialFrame());
+ MOZ_ASSERT(ei.scope().is<Scope>());
+
+ Rooted<Environment*> env(cx);
+ if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(MissingEnvironmentKey(ei))) {
+ env = &p->value()->environment().as<Environment>();
+ envs->missingEnvs.remove(p);
+ } else if (ei.hasSyntacticEnvironment()) {
+ env = &ei.environment().as<Environment>();
+ }
+
+ if (env) {
+ envs->liveEnvs.remove(env);
+
+ if (JSObject* obj = envs->proxiedEnvs.lookup(env)) {
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx, &obj->as<DebugEnvironmentProxy>());
+ DebugEnvironments::takeFrameSnapshot(cx, debugEnv, ei.initialFrame());
+ }
+ }
+}
+
+void
+DebugEnvironments::onPopLexical(JSContext* cx, const EnvironmentIter& ei)
+{
+ onPopGeneric<LexicalEnvironmentObject, LexicalScope>(cx, ei);
+}
+
+void
+DebugEnvironments::onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
+{
+ assertSameCompartment(cx, frame);
+
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return;
+
+ EnvironmentIter ei(cx, frame, pc);
+ onPopVar(cx, ei);
+}
+
+void
+DebugEnvironments::onPopVar(JSContext* cx, const EnvironmentIter& ei)
+{
+ if (ei.scope().is<EvalScope>())
+ onPopGeneric<VarEnvironmentObject, EvalScope>(cx, ei);
+ else
+ onPopGeneric<VarEnvironmentObject, VarScope>(cx, ei);
+}
+
+void
+DebugEnvironments::onPopWith(AbstractFramePtr frame)
+{
+ if (DebugEnvironments* envs = frame.compartment()->debugEnvs)
+ envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>());
+}
+
+void
+DebugEnvironments::onCompartmentUnsetIsDebuggee(JSCompartment* c)
+{
+ if (DebugEnvironments* envs = c->debugEnvs) {
+ envs->proxiedEnvs.clear();
+ envs->missingEnvs.clear();
+ envs->liveEnvs.clear();
+ }
+}
+
+bool
+DebugEnvironments::updateLiveEnvironments(JSContext* cx)
+{
+ JS_CHECK_RECURSION(cx, return false);
+
+ /*
+ * Note that we must always update the top frame's environment objects'
+ * entries in liveEnvs because we can't be sure code hasn't run in that
+ * frame to change the environment chain since we were last called. The
+ * fp->prevUpToDate() flag indicates whether the environments of frames
+ * older than fp are already included in liveEnvs. It might seem simpler
+ * to have fp instead carry a flag indicating whether fp itself is
+ * accurately described, but then we would need to clear that flag
+ * whenever fp ran code. By storing the 'up to date' bit for fp->prev() in
+ * fp, simply popping fp effectively clears the flag for us, at exactly
+ * the time when execution resumes fp->prev().
+ */
+ for (AllFramesIter i(cx); !i.done(); ++i) {
+ if (!i.hasUsableAbstractFramePtr())
+ continue;
+
+ AbstractFramePtr frame = i.abstractFramePtr();
+ if (frame.environmentChain()->compartment() != cx->compartment())
+ continue;
+
+ if (frame.isFunctionFrame() && frame.callee()->isGenerator())
+ continue;
+
+ if (!frame.isDebuggee())
+ continue;
+
+ for (EnvironmentIter ei(cx, frame, i.pc()); ei.withinInitialFrame(); ei++) {
+ if (ei.hasSyntacticEnvironment() && !ei.scope().is<GlobalScope>()) {
+ MOZ_ASSERT(ei.environment().compartment() == cx->compartment());
+ DebugEnvironments* envs = ensureCompartmentData(cx);
+ if (!envs)
+ return false;
+ if (!envs->liveEnvs.put(&ei.environment(), LiveEnvironmentVal(ei)))
+ return false;
+ }
+ }
+
+ if (frame.prevUpToDate())
+ return true;
+ MOZ_ASSERT(frame.environmentChain()->compartment()->isDebuggee());
+ frame.setPrevUpToDate();
+ }
+
+ return true;
+}
+
+LiveEnvironmentVal*
+DebugEnvironments::hasLiveEnvironment(EnvironmentObject& env)
+{
+ DebugEnvironments* envs = env.compartment()->debugEnvs;
+ if (!envs)
+ return nullptr;
+
+ if (LiveEnvironmentMap::Ptr p = envs->liveEnvs.lookup(&env))
+ return &p->value();
+
+ return nullptr;
+}
+
+/* static */ void
+DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
+{
+ // This are two exceptions where fp->prevUpToDate() is cleared without
+ // popping the frame. When a frame is rematerialized or has its
+ // debuggeeness toggled off->on, all frames younger than the frame must
+ // have their prevUpToDate set to false. This is because unrematerialized
+ // Ion frames and non-debuggee frames are skipped by updateLiveEnvironments. If
+ // in the future a frame suddenly gains a usable AbstractFramePtr via
+ // rematerialization or becomes a debuggee, the prevUpToDate invariant
+ // will no longer hold for older frames on its stack.
+ for (AllFramesIter i(cx); !i.done(); ++i) {
+ if (!i.hasUsableAbstractFramePtr())
+ continue;
+
+ AbstractFramePtr frame = i.abstractFramePtr();
+ if (frame == until)
+ return;
+
+ if (frame.environmentChain()->compartment() != cx->compartment())
+ continue;
+
+ frame.unsetPrevUpToDate();
+ }
+}
+
+/* static */ void
+DebugEnvironments::forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to)
+{
+ DebugEnvironments* envs = cx->compartment()->debugEnvs;
+ if (!envs)
+ return;
+
+ for (MissingEnvironmentMap::Enum e(envs->missingEnvs); !e.empty(); e.popFront()) {
+ MissingEnvironmentKey key = e.front().key();
+ if (key.frame() == from) {
+ key.updateFrame(to);
+ e.rekeyFront(key);
+ }
+ }
+
+ for (LiveEnvironmentMap::Enum e(envs->liveEnvs); !e.empty(); e.popFront()) {
+ LiveEnvironmentVal& val = e.front().value();
+ if (val.frame() == from)
+ val.updateFrame(to);
+ }
+}
+
+/* static */ void
+DebugEnvironments::markLiveFrame(JSTracer* trc, AbstractFramePtr frame)
+{
+ for (MissingEnvironmentMap::Enum e(missingEnvs); !e.empty(); e.popFront()) {
+ if (e.front().key().frame() == frame)
+ TraceEdge(trc, &e.front().value(), "debug-env-live-frame-missing-env");
+ }
+}
+
+/*****************************************************************************/
+
+static JSObject*
+GetDebugEnvironment(JSContext* cx, const EnvironmentIter& ei);
+
+static DebugEnvironmentProxy*
+GetDebugEnvironmentForEnvironmentObject(JSContext* cx, const EnvironmentIter& ei)
+{
+ Rooted<EnvironmentObject*> env(cx, &ei.environment());
+ if (DebugEnvironmentProxy* debugEnv = DebugEnvironments::hasDebugEnvironment(cx, *env))
+ return debugEnv;
+
+ EnvironmentIter copy(cx, ei);
+ RootedObject enclosingDebug(cx, GetDebugEnvironment(cx, ++copy));
+ if (!enclosingDebug)
+ return nullptr;
+
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx,
+ DebugEnvironmentProxy::create(cx, *env, enclosingDebug));
+ if (!debugEnv)
+ return nullptr;
+
+ if (!DebugEnvironments::addDebugEnvironment(cx, env, debugEnv))
+ return nullptr;
+
+ return debugEnv;
+}
+
+static DebugEnvironmentProxy*
+GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
+{
+ MOZ_ASSERT(!ei.hasSyntacticEnvironment() &&
+ (ei.scope().is<FunctionScope>() ||
+ ei.scope().is<LexicalScope>() ||
+ ei.scope().is<VarScope>()));
+
+ if (DebugEnvironmentProxy* debugEnv = DebugEnvironments::hasDebugEnvironment(cx, ei))
+ return debugEnv;
+
+ EnvironmentIter copy(cx, ei);
+ RootedObject enclosingDebug(cx, GetDebugEnvironment(cx, ++copy));
+ if (!enclosingDebug)
+ return nullptr;
+
+ /*
+ * Create the missing environment object. For lexical environment objects,
+ * this takes care of storing variable values after the stack frame has
+ * been popped. For call objects, we only use the pretend call object to
+ * access callee, bindings and to receive dynamically added
+ * properties. Together, this provides the nice invariant that every
+ * DebugEnvironmentProxy has a EnvironmentObject.
+ *
+ * Note: to preserve envChain depth invariants, these lazily-reified
+ * envs must not be put on the frame's environment chain; instead, they are
+ * maintained via DebugEnvironments hooks.
+ */
+ Rooted<DebugEnvironmentProxy*> debugEnv(cx);
+ if (ei.scope().is<FunctionScope>()) {
+ RootedFunction callee(cx, ei.scope().as<FunctionScope>().canonicalFunction());
+ // Generators should always reify their scopes.
+ MOZ_ASSERT(!callee->isGenerator());
+
+ JS::ExposeObjectToActiveJS(callee);
+ Rooted<CallObject*> callobj(cx, CallObject::createHollowForDebug(cx, callee));
+ if (!callobj)
+ return nullptr;
+
+ debugEnv = DebugEnvironmentProxy::create(cx, *callobj, enclosingDebug);
+ } else if (ei.scope().is<LexicalScope>()) {
+ Rooted<LexicalScope*> lexicalScope(cx, &ei.scope().as<LexicalScope>());
+ Rooted<LexicalEnvironmentObject*> env(cx,
+ LexicalEnvironmentObject::createHollowForDebug(cx, lexicalScope));
+ if (!env)
+ return nullptr;
+
+ debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
+ } else {
+ Rooted<VarScope*> varScope(cx, &ei.scope().as<VarScope>());
+ Rooted<VarEnvironmentObject*> env(cx,
+ VarEnvironmentObject::createHollowForDebug(cx, varScope));
+ if (!env)
+ return nullptr;
+
+ debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
+ }
+
+ if (!debugEnv)
+ return nullptr;
+
+ if (!DebugEnvironments::addDebugEnvironment(cx, ei, debugEnv))
+ return nullptr;
+
+ return debugEnv;
+}
+
+static JSObject*
+GetDebugEnvironmentForNonEnvironmentObject(const EnvironmentIter& ei)
+{
+ JSObject& enclosing = ei.enclosingEnvironment();
+#ifdef DEBUG
+ JSObject* o = &enclosing;
+ while ((o = o->enclosingEnvironment()))
+ MOZ_ASSERT(!o->is<EnvironmentObject>());
+#endif
+ return &enclosing;
+}
+
+static JSObject*
+GetDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
+{
+ JS_CHECK_RECURSION(cx, return nullptr);
+
+ if (ei.done())
+ return GetDebugEnvironmentForNonEnvironmentObject(ei);
+
+ if (ei.hasAnyEnvironmentObject())
+ return GetDebugEnvironmentForEnvironmentObject(cx, ei);
+
+ if (ei.scope().is<FunctionScope>() ||
+ ei.scope().is<LexicalScope>() ||
+ ei.scope().is<VarScope>())
+ {
+ return GetDebugEnvironmentForMissing(cx, ei);
+ }
+
+ EnvironmentIter copy(cx, ei);
+ return GetDebugEnvironment(cx, ++copy);
+}
+
+JSObject*
+js::GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun)
+{
+ assertSameCompartment(cx, fun);
+ MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
+ if (!DebugEnvironments::updateLiveEnvironments(cx))
+ return nullptr;
+ JSScript* script = fun->getOrCreateScript(cx);
+ if (!script)
+ return nullptr;
+ EnvironmentIter ei(cx, fun->environment(), script->enclosingScope());
+ return GetDebugEnvironment(cx, ei);
+}
+
+JSObject*
+js::GetDebugEnvironmentForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
+{
+ assertSameCompartment(cx, frame);
+ if (CanUseDebugEnvironmentMaps(cx) && !DebugEnvironments::updateLiveEnvironments(cx))
+ return nullptr;
+
+ EnvironmentIter ei(cx, frame, pc);
+ return GetDebugEnvironment(cx, ei);
+}
+
+JSObject*
+js::GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx)
+{
+ EnvironmentIter ei(cx, &cx->global()->lexicalEnvironment(), &cx->global()->emptyGlobalScope());
+ return GetDebugEnvironment(cx, ei);
+}
+
+// See declaration and documentation in jsfriendapi.h
+JS_FRIEND_API(JSObject*)
+js::GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun)
+{
+ if (!fun->isInterpreted())
+ return &fun->global();
+
+ JSObject* env = fun->environment();
+ while (env && !env->is<WithEnvironmentObject>())
+ env = env->enclosingEnvironment();
+
+ if (!env)
+ return &fun->global();
+
+ return &env->as<WithEnvironmentObject>().object();
+}
+
+bool
+js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
+ HandleObject terminatingEnv, MutableHandleObject envObj)
+{
+#ifdef DEBUG
+ for (size_t i = 0; i < chain.length(); ++i) {
+ assertSameCompartment(cx, chain[i]);
+ MOZ_ASSERT(!chain[i]->is<GlobalObject>());
+ }
+#endif
+
+ // Construct With object wrappers for the things on this environment chain
+ // and use the result as the thing to scope the function to.
+ Rooted<WithEnvironmentObject*> withEnv(cx);
+ RootedObject enclosingEnv(cx, terminatingEnv);
+ for (size_t i = chain.length(); i > 0; ) {
+ withEnv = WithEnvironmentObject::createNonSyntactic(cx, chain[--i], enclosingEnv);
+ if (!withEnv)
+ return false;
+ enclosingEnv = withEnv;
+ }
+
+ envObj.set(enclosingEnv);
+ return true;
+}
+
+JSObject&
+WithEnvironmentObject::object() const
+{
+ return getReservedSlot(OBJECT_SLOT).toObject();
+}
+
+JSObject*
+WithEnvironmentObject::withThis() const
+{
+ return &getReservedSlot(THIS_SLOT).toObject();
+}
+
+bool
+WithEnvironmentObject::isSyntactic() const
+{
+ Value v = getReservedSlot(SCOPE_SLOT);
+ MOZ_ASSERT(v.isPrivateGCThing() || v.isNull());
+ return v.isPrivateGCThing();
+}
+
+WithScope&
+WithEnvironmentObject::scope() const
+{
+ MOZ_ASSERT(isSyntactic());
+ return *static_cast<WithScope*>(getReservedSlot(SCOPE_SLOT).toGCThing());
+}
+
+ModuleEnvironmentObject*
+js::GetModuleEnvironmentForScript(JSScript* script)
+{
+ for (ScopeIter si(script); si; si++) {
+ if (si.kind() == ScopeKind::Module)
+ return si.scope()->as<ModuleScope>().module()->environment();
+ }
+ return nullptr;
+}
+
+bool
+js::GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
+ MutableHandleValue res)
+{
+ for (EnvironmentIter ei(cx, frame, pc); ei; ei++) {
+ if (ei.scope().kind() == ScopeKind::Module) {
+ res.setUndefined();
+ return true;
+ }
+
+ if (!ei.scope().is<FunctionScope>() ||
+ ei.scope().as<FunctionScope>().canonicalFunction()->hasLexicalThis())
+ {
+ continue;
+ }
+
+ RootedScript script(cx, ei.scope().as<FunctionScope>().script());
+
+ // Figure out if we executed JSOP_FUNCTIONTHIS and set it.
+ bool executedInitThisOp = false;
+ if (script->functionHasThisBinding()) {
+ for (jsbytecode* it = script->code(); it < script->codeEnd(); it = GetNextPc(it)) {
+ if (*it == JSOP_FUNCTIONTHIS) {
+ // The next op after JSOP_FUNCTIONTHIS always sets it.
+ executedInitThisOp = pc > GetNextPc(it);
+ break;
+ }
+ }
+ }
+
+ if (ei.withinInitialFrame() && !executedInitThisOp) {
+ // Either we're yet to initialize the this-binding
+ // (JSOP_FUNCTIONTHIS), or the script does not have a this-binding
+ // (because it doesn't use |this|).
+
+ // If our this-argument is an object, or we're in strict mode,
+ // the this-binding is always the same as our this-argument.
+ if (frame.thisArgument().isObject() || script->strict()) {
+ res.set(frame.thisArgument());
+ return true;
+ }
+
+ // We didn't initialize the this-binding yet. Determine the
+ // correct |this| value for this frame (box primitives if not
+ // in strict mode), and assign it to the this-argument slot so
+ // JSOP_FUNCTIONTHIS will use it and not box a second time.
+ if (!GetFunctionThis(cx, frame, res))
+ return false;
+ frame.thisArgument() = res;
+ return true;
+ }
+
+ if (!script->functionHasThisBinding()) {
+ res.setMagic(JS_OPTIMIZED_OUT);
+ return true;
+ }
+
+ for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
+ if (bi.name() != cx->names().dotThis)
+ continue;
+
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Environment) {
+ RootedObject callObj(cx, &ei.environment().as<CallObject>());
+ return GetProperty(cx, callObj, callObj, bi.name()->asPropertyName(), res);
+ }
+
+ if (loc.kind() == BindingLocation::Kind::Frame && ei.withinInitialFrame())
+ res.set(frame.unaliasedLocal(loc.slot()));
+ else
+ res.setMagic(JS_OPTIMIZED_OUT);
+
+ return true;
+ }
+
+ MOZ_CRASH("'this' binding must be found");
+ }
+
+ RootedObject scopeChain(cx, frame.environmentChain());
+ return GetNonSyntacticGlobalThis(cx, scopeChain, res);
+}
+
+bool
+js::CheckLexicalNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandleObject varObj, HandlePropertyName name)
+{
+ const char* redeclKind = nullptr;
+ RootedId id(cx, NameToId(name));
+ RootedShape shape(cx);
+ if (varObj->is<GlobalObject>() && varObj->compartment()->isInVarNames(name)) {
+ // ES 15.1.11 step 5.a
+ redeclKind = "var";
+ } else if ((shape = lexicalEnv->lookup(cx, name))) {
+ // ES 15.1.11 step 5.b
+ redeclKind = shape->writable() ? "let" : "const";
+ } else if (varObj->isNative() && (shape = varObj->as<NativeObject>().lookup(cx, name))) {
+ // Faster path for ES 15.1.11 step 5.c-d when the shape can be found
+ // without going through a resolve hook.
+ if (!shape->configurable())
+ redeclKind = "non-configurable global property";
+ } else {
+ // ES 15.1.11 step 5.c-d
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, varObj, id, &desc))
+ return false;
+ if (desc.object() && desc.hasConfigurable() && !desc.configurable())
+ redeclKind = "non-configurable global property";
+ }
+
+ if (redeclKind) {
+ ReportRuntimeRedeclaration(cx, name, redeclKind);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+js::CheckVarNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandlePropertyName name)
+{
+ if (Shape* shape = lexicalEnv->lookup(cx, name)) {
+ ReportRuntimeRedeclaration(cx, name, shape->writable() ? "let" : "const");
+ return false;
+ }
+ return true;
+}
+
+static void
+ReportCannotDeclareGlobalBinding(JSContext* cx, HandlePropertyName name, const char* reason)
+{
+ JSAutoByteString printable;
+ if (AtomToPrintableString(cx, name, &printable)) {
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
+ JSMSG_CANT_DECLARE_GLOBAL_BINDING,
+ printable.ptr(), reason);
+ }
+}
+
+bool
+js::CheckCanDeclareGlobalBinding(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, bool isFunction)
+{
+ RootedId id(cx, NameToId(name));
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, global, id, &desc))
+ return false;
+
+ // ES 8.1.1.4.15 CanDeclareGlobalVar
+ // ES 8.1.1.4.16 CanDeclareGlobalFunction
+
+ // Step 4.
+ if (!desc.object()) {
+ // 8.1.14.15 step 6.
+ // 8.1.14.16 step 5.
+ if (global->nonProxyIsExtensible())
+ return true;
+
+ ReportCannotDeclareGlobalBinding(cx, name, "global is non-extensible");
+ return false;
+ }
+
+ // Global functions have additional restrictions.
+ if (isFunction) {
+ // 8.1.14.16 step 6.
+ if (desc.configurable())
+ return true;
+
+ // 8.1.14.16 step 7.
+ if (desc.isDataDescriptor() && desc.writable() && desc.enumerable())
+ return true;
+
+ ReportCannotDeclareGlobalBinding(cx, name,
+ "property must be configurable or "
+ "both writable and enumerable");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+js::CheckGlobalDeclarationConflicts(JSContext* cx, HandleScript script,
+ Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandleObject varObj)
+{
+ // Due to the extensibility of the global lexical environment, we must
+ // check for redeclaring a binding.
+ //
+ // In the case of non-syntactic environment chains, we are checking
+ // redeclarations against the non-syntactic lexical environment and the
+ // variables object that the lexical environment corresponds to.
+ RootedPropertyName name(cx);
+ Rooted<BindingIter> bi(cx, BindingIter(script));
+
+ // ES 15.1.11 GlobalDeclarationInstantiation
+
+ // Step 6.
+ //
+ // Check 'var' declarations do not conflict with existing bindings in the
+ // global lexical environment.
+ for (; bi; bi++) {
+ if (bi.kind() != BindingKind::Var)
+ break;
+ name = bi.name()->asPropertyName();
+ if (!CheckVarNameConflict(cx, lexicalEnv, name))
+ return false;
+
+ // Step 10 and 12.
+ //
+ // Check that global functions and vars may be declared.
+ if (varObj->is<GlobalObject>()) {
+ Handle<GlobalObject*> global = varObj.as<GlobalObject>();
+ if (!CheckCanDeclareGlobalBinding(cx, global, name, bi.isTopLevelFunction()))
+ return false;
+ }
+ }
+
+ // Step 5.
+ //
+ // Check that lexical bindings do not conflict.
+ for (; bi; bi++) {
+ name = bi.name()->asPropertyName();
+ if (!CheckLexicalNameConflict(cx, lexicalEnv, varObj, name))
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+CheckVarNameConflictsInEnv(JSContext* cx, HandleScript script, HandleObject obj)
+{
+ Rooted<LexicalEnvironmentObject*> env(cx);
+
+ if (obj->is<LexicalEnvironmentObject>()) {
+ env = &obj->as<LexicalEnvironmentObject>();
+ } else if (obj->is<DebugEnvironmentProxy>() &&
+ obj->as<DebugEnvironmentProxy>().environment().is<LexicalEnvironmentObject>())
+ {
+ env = &obj->as<DebugEnvironmentProxy>().environment().as<LexicalEnvironmentObject>();
+ } else {
+ // Environment cannot contain lexical bindings.
+ return true;
+ }
+
+ if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::SimpleCatch) {
+ // Annex B.3.5 allows redeclaring simple (non-destructured) catch
+ // parameters with var declarations, except when it appears in a
+ // for-of. The for-of allowance is computed in
+ // Parser::isVarRedeclaredInEval.
+ return true;
+ }
+
+ RootedPropertyName name(cx);
+ for (BindingIter bi(script); bi; bi++) {
+ name = bi.name()->asPropertyName();
+ if (!CheckVarNameConflict(cx, env, name))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+js::CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script,
+ HandleObject scopeChain, HandleObject varObj)
+{
+ if (!script->bodyScope()->as<EvalScope>().hasBindings())
+ return true;
+
+ RootedObject obj(cx, scopeChain);
+
+ // ES 18.2.1.3.
+
+ // Step 5.
+ //
+ // Check that a direct eval will not hoist 'var' bindings over lexical
+ // bindings with the same name.
+ while (obj != varObj) {
+ if (!CheckVarNameConflictsInEnv(cx, script, obj))
+ return false;
+ obj = obj->enclosingEnvironment();
+ }
+
+ // Step 8.
+ //
+ // Check that global functions may be declared.
+ if (varObj->is<GlobalObject>()) {
+ Handle<GlobalObject*> global = varObj.as<GlobalObject>();
+ RootedPropertyName name(cx);
+ for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
+ name = bi.name()->asPropertyName();
+ if (!CheckCanDeclareGlobalBinding(cx, global, name, bi.isTopLevelFunction()))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+js::InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT(frame.isFunctionFrame());
+ MOZ_ASSERT(frame.callee()->needsSomeEnvironmentObject());
+
+ RootedFunction callee(cx, frame.callee());
+
+ // Named lambdas may have an environment that holds itself for recursion.
+ if (callee->needsNamedLambdaEnvironment()) {
+ NamedLambdaObject* declEnv;
+ if (callee->isAsync()) {
+ // Named async function needs special environment to return
+ // wrapped function for the binding.
+ RootedFunction fun(cx, GetWrappedAsyncFunction(callee));
+ declEnv = NamedLambdaObject::create(cx, frame, fun);
+ } else {
+ declEnv = NamedLambdaObject::create(cx, frame);
+ }
+ if (!declEnv)
+ return false;
+ frame.pushOnEnvironmentChain(*declEnv);
+ }
+
+ // If the function has parameter default expressions, there may be an
+ // extra environment to hold the parameters.
+ if (callee->needsCallObject()) {
+ CallObject* callObj = CallObject::create(cx, frame);
+ if (!callObj)
+ return false;
+ frame.pushOnEnvironmentChain(*callObj);
+ }
+
+ return true;
+}
+
+bool
+js::PushVarEnvironmentObject(JSContext* cx, HandleScope scope, AbstractFramePtr frame)
+{
+ VarEnvironmentObject* env = VarEnvironmentObject::create(cx, scope, frame);
+ if (!env)
+ return false;
+ frame.pushOnEnvironmentChain(*env);
+ return true;
+}
+
+#ifdef DEBUG
+
+typedef HashSet<PropertyName*> PropertyNameSet;
+
+static bool
+RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remainingNames)
+{
+ // Remove from remainingNames --- the closure variables in some outer
+ // script --- any free variables in this script. This analysis isn't perfect:
+ //
+ // - It will not account for free variables in an inner script which are
+ // actually accessing some name in an intermediate script between the
+ // inner and outer scripts. This can cause remainingNames to be an
+ // underapproximation.
+ //
+ // - It will not account for new names introduced via eval. This can cause
+ // remainingNames to be an overapproximation. This would be easy to fix
+ // but is nice to have as the eval will probably not access these
+ // these names and putting eval in an inner script is bad news if you
+ // care about entraining variables unnecessarily.
+
+ for (jsbytecode* pc = script->code(); pc != script->codeEnd(); pc += GetBytecodeLength(pc)) {
+ PropertyName* name;
+
+ switch (JSOp(*pc)) {
+ case JSOP_GETNAME:
+ case JSOP_SETNAME:
+ case JSOP_STRICTSETNAME:
+ name = script->getName(pc);
+ break;
+
+ case JSOP_GETGNAME:
+ case JSOP_SETGNAME:
+ case JSOP_STRICTSETGNAME:
+ if (script->hasNonSyntacticScope())
+ name = script->getName(pc);
+ else
+ name = nullptr;
+ break;
+
+ case JSOP_GETALIASEDVAR:
+ case JSOP_SETALIASEDVAR:
+ name = EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc);
+ break;
+
+ default:
+ name = nullptr;
+ break;
+ }
+
+ if (name)
+ remainingNames.remove(name);
+ }
+
+ if (script->hasObjects()) {
+ ObjectArray* objects = script->objects();
+ for (size_t i = 0; i < objects->length; i++) {
+ JSObject* obj = objects->vector[i];
+ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
+ JSFunction* fun = &obj->as<JSFunction>();
+ RootedScript innerScript(cx, fun->getOrCreateScript(cx));
+ if (!innerScript)
+ return false;
+
+ if (!RemoveReferencedNames(cx, innerScript, remainingNames))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool
+AnalyzeEntrainedVariablesInScript(JSContext* cx, HandleScript script, HandleScript innerScript)
+{
+ PropertyNameSet remainingNames(cx);
+ if (!remainingNames.init())
+ return false;
+
+ for (BindingIter bi(script); bi; bi++) {
+ if (bi.closedOver()) {
+ PropertyName* name = bi.name()->asPropertyName();
+ PropertyNameSet::AddPtr p = remainingNames.lookupForAdd(name);
+ if (!p && !remainingNames.add(p, name))
+ return false;
+ }
+ }
+
+ if (!RemoveReferencedNames(cx, innerScript, remainingNames))
+ return false;
+
+ if (!remainingNames.empty()) {
+ Sprinter buf(cx);
+ if (!buf.init())
+ return false;
+
+ buf.printf("Script ");
+
+ if (JSAtom* name = script->functionNonDelazifying()->displayAtom()) {
+ buf.putString(name);
+ buf.printf(" ");
+ }
+
+ buf.printf("(%s:%" PRIuSIZE ") has variables entrained by ", script->filename(), script->lineno());
+
+ if (JSAtom* name = innerScript->functionNonDelazifying()->displayAtom()) {
+ buf.putString(name);
+ buf.printf(" ");
+ }
+
+ buf.printf("(%s:%" PRIuSIZE ") ::", innerScript->filename(), innerScript->lineno());
+
+ for (PropertyNameSet::Range r = remainingNames.all(); !r.empty(); r.popFront()) {
+ buf.printf(" ");
+ buf.putString(r.front());
+ }
+
+ printf("%s\n", buf.string());
+ }
+
+ if (innerScript->hasObjects()) {
+ ObjectArray* objects = innerScript->objects();
+ for (size_t i = 0; i < objects->length; i++) {
+ JSObject* obj = objects->vector[i];
+ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
+ JSFunction* fun = &obj->as<JSFunction>();
+ RootedScript innerInnerScript(cx, fun->getOrCreateScript(cx));
+ if (!innerInnerScript ||
+ !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Look for local variables in script or any other script inner to it, which are
+// part of the script's call object and are unnecessarily entrained by their own
+// inner scripts which do not refer to those variables. An example is:
+//
+// function foo() {
+// var a, b;
+// function bar() { return a; }
+// function baz() { return b; }
+// }
+//
+// |bar| unnecessarily entrains |b|, and |baz| unnecessarily entrains |a|.
+bool
+js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script)
+{
+ if (!script->hasObjects())
+ return true;
+
+ ObjectArray* objects = script->objects();
+ for (size_t i = 0; i < objects->length; i++) {
+ JSObject* obj = objects->vector[i];
+ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
+ JSFunction* fun = &obj->as<JSFunction>();
+ RootedScript innerScript(cx, fun->getOrCreateScript(cx));
+ if (!innerScript)
+ return false;
+
+ if (script->functionDelazifying() && script->functionDelazifying()->needsCallObject()) {
+ if (!AnalyzeEntrainedVariablesInScript(cx, script, innerScript))
+ return false;
+ }
+
+ if (!AnalyzeEntrainedVariables(cx, innerScript))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#endif
diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h
new file mode 100644
index 000000000..6bdaac89e
--- /dev/null
+++ b/js/src/vm/EnvironmentObject.h
@@ -0,0 +1,1126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_EnvironmentObject_h
+#define vm_EnvironmentObject_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+#include "jsweakmap.h"
+
+#include "builtin/ModuleObject.h"
+#include "frontend/NameAnalysisTypes.h"
+#include "gc/Barrier.h"
+#include "js/GCHashTable.h"
+#include "vm/ArgumentsObject.h"
+#include "vm/ProxyObject.h"
+#include "vm/Scope.h"
+
+namespace js {
+
+class ModuleObject;
+typedef Handle<ModuleObject*> HandleModuleObject;
+
+/*
+ * Return a shape representing the static scope containing the variable
+ * accessed by the ALIASEDVAR op at 'pc'.
+ */
+extern Shape*
+EnvironmentCoordinateToEnvironmentShape(JSScript* script, jsbytecode* pc);
+
+/* Return the name being accessed by the given ALIASEDVAR op. */
+extern PropertyName*
+EnvironmentCoordinateName(EnvironmentCoordinateNameCache& cache, JSScript* script, jsbytecode* pc);
+
+/* Return the function script accessed by the given ALIASEDVAR op, or nullptr. */
+extern JSScript*
+EnvironmentCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
+
+
+/*** Environment objects *****************************************************/
+
+
+/*** Environment objects *****************************************************/
+
+/*
+ * About environments
+ * ------------------
+ *
+ * (See also: ecma262 rev c7952de (19 Aug 2016) 8.1 "Lexical Environments".)
+ *
+ * Scoping in ES is specified in terms of "Environment Records". There's a
+ * global Environment Record per realm, and a new Environment Record is created
+ * whenever control enters a function, block, or other scope.
+ *
+ * A "Lexical Environment" is a list of nested Environment Records, innermost
+ * first: everything that's in scope. Throughout SpiderMonkey, "environment"
+ * means a Lexical Environment.
+ *
+ * N.B.: "Scope" means something different: a static scope, the compile-time
+ * analogue of an environment. See Scope.h.
+ *
+ * How SpiderMonkey represents environments
+ * ----------------------------------------
+ *
+ * Some environments are stored as JSObjects. Several kinds of objects
+ * represent environments:
+ *
+ * JSObject
+ * |
+ * +--NativeObject
+ * | |
+ * | +--EnvironmentObject Engine-internal environment
+ * | | |
+ * | | +--CallObject Environment of entire function
+ * | | |
+ * | | +--ModuleEnvironmentObject Module top-level environment
+ * | | |
+ * | | +--LexicalEnvironmentObject Lexical (block) environment
+ * | | | |
+ * | | | +--NamedLambdaObject Environment for `(function f(){...})`
+ * | | | containing only a binding for `f`
+ * | | +--VarEnvironmentObject See VarScope in Scope.h.
+ * | | |
+ * | | +--WithEnvironmentObject Presents object properties as bindings
+ * | | |
+ * | | +--NonSyntacticVariablesObject See "Non-syntactic environments" below
+ * | |
+ * | +--GlobalObject The global environment
+ * |
+ * +--ProxyObject
+ * |
+ * +--DebugEnvironmentProxy Environment for debugger eval-in-frame
+ *
+ * EnvironmentObjects are technically real JSObjects but only belong on the
+ * environment chain (that is, fp->environmentChain() or fun->environment()).
+ * They are never exposed to scripts.
+ *
+ * Note that reserved slots in any base classes shown above are fixed for all
+ * derived classes. So e.g. EnvironmentObject::enclosingEnvironment() can
+ * simply access a fixed slot without further dynamic type information.
+ *
+ * When the current environment is represented by an object, the stack frame
+ * has a pointer to that object (see AbstractFramePtr::environmentChain()).
+ * However, that isn't always the case. Where possible, we store binding values
+ * in JS stack slots. For block and function scopes where all bindings can be
+ * stored in stack slots, nothing is allocated in the heap; there is no
+ * environment object.
+ *
+ * Full information about the environment chain is always recoverable:
+ * EnvironmentIter can do it, and we construct a fake environment for debugger
+ * eval-in-frame (see "Debug environment objects" below).
+ *
+ * Syntactic Environments
+ * ----------------------
+ *
+ * Environments may be syntactic, i.e., corresponding to source text, or
+ * non-syntactic, i.e., specially created by embedding. The distinction is
+ * necessary to maintain invariants about the environment chain: non-syntactic
+ * environments may not occur in arbitrary positions in the chain.
+ *
+ * CallObject, ModuleEnvironmentObject, and LexicalEnvironmentObject always
+ * represent syntactic environments. (CallObject is considered syntactic even
+ * when it's used as the scope of strict eval code.) WithEnvironmentObject is
+ * syntactic when it's used to represent the scope of a `with` block.
+ *
+ *
+ * Non-syntactic Environments
+ * --------------------------
+ *
+ * A non-syntactic environment is one that was not created due to JS source
+ * code. On the scope chain, a single NonSyntactic GlobalScope maps to 0+
+ * non-syntactic environment objects. This is contrasted with syntactic
+ * environments, where each scope corresponds to 0 or 1 environment object.
+ *
+ * There are 3 kinds of dynamic environment objects:
+ *
+ * 1. WithEnvironmentObject
+ *
+ * When the embedding compiles or executes a script, it has the option to
+ * pass in a vector of objects to be used as the initial env chain, ordered
+ * from outermost env to innermost env. Each of those objects is wrapped by
+ * a WithEnvironmentObject.
+ *
+ * The innermost object passed in by the embedding becomes a qualified
+ * variables object that captures 'var' bindings. That is, it wraps the
+ * holder object of 'var' bindings.
+ *
+ * Does not hold 'let' or 'const' bindings.
+ *
+ * 2. NonSyntacticVariablesObject
+ *
+ * When the embedding wants qualified 'var' bindings and unqualified
+ * bareword assignments to go on a different object than the global
+ * object. While any object can be made into a qualified variables object,
+ * only the GlobalObject and NonSyntacticVariablesObject are considered
+ * unqualified variables objects.
+ *
+ * Unlike WithEnvironmentObjects that delegate to the object they wrap,
+ * this object is itself the holder of 'var' bindings.
+ *
+ * Does not hold 'let' or 'const' bindings.
+ *
+ * 3. LexicalEnvironmentObject
+ *
+ * Each non-syntactic object used as a qualified variables object needs to
+ * enclose a non-syntactic LexicalEnvironmentObject to hold 'let' and
+ * 'const' bindings. There is a bijection per compartment between the
+ * non-syntactic variables objects and their non-syntactic
+ * LexicalEnvironmentObjects.
+ *
+ * Does not hold 'var' bindings.
+ *
+ * The embedding (Gecko) uses non-syntactic envs for various things, some of
+ * which are detailed below. All env chain listings below are, from top to
+ * bottom, outermost to innermost.
+ *
+ * A. Component loading
+ *
+ * Components may be loaded in "reuse loader global" mode, where to save on
+ * memory, all JSMs and JS-implemented XPCOM modules are loaded into a single
+ * global. Each individual JSMs are compiled as functions with their own
+ * FakeBackstagePass. They have the following env chain:
+ *
+ * BackstagePass global
+ * |
+ * Global lexical scope
+ * |
+ * WithEnvironmentObject wrapping FakeBackstagePass
+ * |
+ * LexicalEnvironmentObject
+ *
+ * B. Subscript loading
+ *
+ * Subscripts may be loaded into a target object. They have the following
+ * env chain:
+ *
+ * Loader global
+ * |
+ * Global lexical scope
+ * |
+ * WithEnvironmentObject wrapping target
+ * |
+ * LexicalEnvironmentObject
+ *
+ * C. Frame scripts
+ *
+ * XUL frame scripts are always loaded with a NonSyntacticVariablesObject as a
+ * "polluting global". This is done exclusively in
+ * js::ExecuteInGlobalAndReturnScope.
+ *
+ * Loader global
+ * |
+ * Global lexical scope
+ * |
+ * NonSyntacticVariablesObject
+ * |
+ * LexicalEnvironmentObject
+ *
+ * D. XBL and DOM event handlers
+ *
+ * XBL methods are compiled as functions with XUL elements on the env chain,
+ * and DOM event handlers are compiled as functions with HTML elements on the
+ * env chain. For a chain of elements e0,...,eN:
+ *
+ * ...
+ * |
+ * WithEnvironmentObject wrapping eN
+ * |
+ * ...
+ * |
+ * WithEnvironmentObject wrapping e0
+ * |
+ * LexicalEnvironmentObject
+ *
+ */
+
+class EnvironmentObject : public NativeObject
+{
+ protected:
+ // The enclosing environment. Either another EnvironmentObject, a
+ // GlobalObject, or a non-syntactic environment object.
+ static const uint32_t ENCLOSING_ENV_SLOT = 0;
+
+ inline void setAliasedBinding(JSContext* cx, uint32_t slot, PropertyName* name,
+ const Value& v);
+
+ void setEnclosingEnvironment(JSObject* enclosing) {
+ setReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
+ }
+
+ public:
+ // Since every env chain terminates with a global object, whether
+ // GlobalObject or a non-syntactic one, and since those objects do not
+ // derive EnvironmentObject (they have completely different layouts), the
+ // enclosing environment of an EnvironmentObject is necessarily non-null.
+ JSObject& enclosingEnvironment() const {
+ return getReservedSlot(ENCLOSING_ENV_SLOT).toObject();
+ }
+
+ void initEnclosingEnvironment(JSObject* enclosing) {
+ initReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
+ }
+
+ // Get or set a name contained in this environment.
+ const Value& aliasedBinding(EnvironmentCoordinate ec) {
+ return getSlot(ec.slot());
+ }
+
+ const Value& aliasedBinding(const BindingIter& bi) {
+ MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment);
+ return getSlot(bi.location().slot());
+ }
+
+ inline void setAliasedBinding(JSContext* cx, EnvironmentCoordinate ec, PropertyName* name,
+ const Value& v);
+
+ inline void setAliasedBinding(JSContext* cx, const BindingIter& bi, const Value& v);
+
+ // For JITs.
+ static size_t offsetOfEnclosingEnvironment() {
+ return getFixedSlotOffset(ENCLOSING_ENV_SLOT);
+ }
+
+ static uint32_t enclosingEnvironmentSlot() {
+ return ENCLOSING_ENV_SLOT;
+ }
+};
+
+class CallObject : public EnvironmentObject
+{
+ protected:
+ static const uint32_t CALLEE_SLOT = 1;
+
+ static CallObject* create(JSContext* cx, HandleScript script, HandleFunction callee,
+ HandleObject enclosing);
+
+ public:
+ static const uint32_t RESERVED_SLOTS = 2;
+ static const Class class_;
+
+ /* These functions are internal and are exposed only for JITs. */
+
+ /*
+ * Construct a bare-bones call object given a shape and a non-singleton
+ * group. The call object must be further initialized to be usable.
+ */
+ static CallObject* create(JSContext* cx, HandleShape shape, HandleObjectGroup group);
+
+ /*
+ * Construct a bare-bones call object given a shape and make it into
+ * a singleton. The call object must be initialized to be usable.
+ */
+ static CallObject* createSingleton(JSContext* cx, HandleShape shape);
+
+ static CallObject* createTemplateObject(JSContext* cx, HandleScript script,
+ HandleObject enclosing, gc::InitialHeap heap);
+
+ static CallObject* create(JSContext* cx, HandleFunction callee, HandleObject enclosing);
+ static CallObject* create(JSContext* cx, AbstractFramePtr frame);
+
+ static CallObject* createHollowForDebug(JSContext* cx, HandleFunction callee);
+
+ /*
+ * When an aliased formal (var accessed by nested closures) is also
+ * aliased by the arguments object, it must of course exist in one
+ * canonical location and that location is always the CallObject. For this
+ * to work, the ArgumentsObject stores special MagicValue in its array for
+ * forwarded-to-CallObject variables. This MagicValue's payload is the
+ * slot of the CallObject to access.
+ */
+ const Value& aliasedFormalFromArguments(const Value& argsValue) {
+ return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue));
+ }
+ inline void setAliasedFormalFromArguments(JSContext* cx, const Value& argsValue, jsid id,
+ const Value& v);
+
+ JSFunction& callee() const {
+ return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
+ }
+
+ /* For jit access. */
+ static size_t offsetOfCallee() {
+ return getFixedSlotOffset(CALLEE_SLOT);
+ }
+
+ static size_t calleeSlot() {
+ return CALLEE_SLOT;
+ }
+};
+
+class VarEnvironmentObject : public EnvironmentObject
+{
+ static const uint32_t SCOPE_SLOT = 1;
+
+ static VarEnvironmentObject* create(JSContext* cx, HandleShape shape, HandleObject enclosing,
+ gc::InitialHeap heap);
+
+ void initScope(Scope* scope) {
+ initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
+ }
+
+ public:
+ static const uint32_t RESERVED_SLOTS = 2;
+ static const Class class_;
+
+ static VarEnvironmentObject* create(JSContext* cx, HandleScope scope, AbstractFramePtr frame);
+ static VarEnvironmentObject* createHollowForDebug(JSContext* cx, Handle<VarScope*> scope);
+
+ Scope& scope() const {
+ Value v = getReservedSlot(SCOPE_SLOT);
+ MOZ_ASSERT(v.isPrivateGCThing());
+ Scope& s = *static_cast<Scope*>(v.toGCThing());
+ MOZ_ASSERT(s.is<VarScope>() || s.is<EvalScope>());
+ return s;
+ }
+
+ bool isForEval() const {
+ return scope().is<EvalScope>();
+ }
+};
+
+class ModuleEnvironmentObject : public EnvironmentObject
+{
+ static const uint32_t MODULE_SLOT = 1;
+
+ static const ObjectOps objectOps_;
+
+ public:
+ static const Class class_;
+
+ static const uint32_t RESERVED_SLOTS = 2;
+
+ static ModuleEnvironmentObject* create(ExclusiveContext* cx, HandleModuleObject module);
+ ModuleObject& module();
+ IndirectBindingMap& importBindings();
+
+ bool createImportBinding(JSContext* cx, HandleAtom importName, HandleModuleObject module,
+ HandleAtom exportName);
+
+ bool hasImportBinding(HandlePropertyName name);
+
+ bool lookupImport(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut);
+
+ void fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObject& global);
+
+ private:
+ static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp);
+ static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
+ static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp);
+ static bool setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, JS::ObjectOpResult& result);
+ static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc);
+ static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result);
+ static bool enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly);
+};
+
+typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
+typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
+typedef MutableHandle<ModuleEnvironmentObject*> MutableHandleModuleEnvironmentObject;
+
+class LexicalEnvironmentObject : public EnvironmentObject
+{
+ // Global and non-syntactic lexical environments need to store a 'this'
+ // value and all other lexical environments have a fixed shape and store a
+ // backpointer to the LexicalScope.
+ //
+ // Since the two sets are disjoint, we only use one slot to save space.
+ static const unsigned THIS_VALUE_OR_SCOPE_SLOT = 1;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 2;
+ static const Class class_;
+
+ private:
+ static LexicalEnvironmentObject* createTemplateObject(JSContext* cx, HandleShape shape,
+ HandleObject enclosing,
+ gc::InitialHeap heap);
+
+ void initThisValue(JSObject* obj) {
+ MOZ_ASSERT(isGlobal() || !isSyntactic());
+ initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, GetThisValue(obj));
+ }
+
+ void initScopeUnchecked(LexicalScope* scope) {
+ initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, PrivateGCThingValue(scope));
+ }
+
+ void initScope(LexicalScope* scope) {
+ MOZ_ASSERT(!isGlobal());
+ MOZ_ASSERT(isSyntactic());
+ initScopeUnchecked(scope);
+ }
+
+ public:
+ static LexicalEnvironmentObject* createTemplateObject(JSContext* cx,
+ Handle<LexicalScope*> scope,
+ HandleObject enclosing,
+ gc::InitialHeap heap);
+
+ static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
+ AbstractFramePtr frame);
+ static LexicalEnvironmentObject* createGlobal(JSContext* cx, Handle<GlobalObject*> global);
+ static LexicalEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject enclosing);
+ static LexicalEnvironmentObject* createHollowForDebug(JSContext* cx,
+ Handle<LexicalScope*> scope);
+
+ // Create a new LexicalEnvironmentObject with the same enclosing env and
+ // variable values as this.
+ static LexicalEnvironmentObject* clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env);
+
+ // Create a new LexicalEnvironmentObject with the same enclosing env as
+ // this, with all variables uninitialized.
+ static LexicalEnvironmentObject* recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env);
+
+ // For non-extensible lexical environments, the LexicalScope that created
+ // this environment. Otherwise asserts.
+ LexicalScope& scope() const {
+ Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT);
+ MOZ_ASSERT(!isExtensible() && v.isPrivateGCThing());
+ return *static_cast<LexicalScope*>(v.toGCThing());
+ }
+
+ // Is this the global lexical scope?
+ bool isGlobal() const {
+ return enclosingEnvironment().is<GlobalObject>();
+ }
+
+ GlobalObject& global() const {
+ return enclosingEnvironment().as<GlobalObject>();
+ }
+
+ // Global and non-syntactic lexical scopes are extensible. All other
+ // lexical scopes are not.
+ bool isExtensible() const;
+
+ // Is this a syntactic (i.e. corresponds to a source text) lexical
+ // environment?
+ bool isSyntactic() const {
+ return !isExtensible() || isGlobal();
+ }
+
+ // For extensible lexical environments, the 'this' value for its
+ // scope. Otherwise asserts.
+ Value thisValue() const;
+};
+
+class NamedLambdaObject : public LexicalEnvironmentObject
+{
+ static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
+ HandleFunction replacement,
+ HandleObject enclosing, gc::InitialHeap heap);
+
+ public:
+ static NamedLambdaObject* createTemplateObject(JSContext* cx, HandleFunction callee,
+ gc::InitialHeap heap);
+
+ static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
+ static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame,
+ HandleFunction replacement);
+
+ // For JITs.
+ static size_t lambdaSlot();
+};
+
+// A non-syntactic dynamic scope object that captures non-lexical
+// bindings. That is, a scope object that captures both qualified var
+// assignments and unqualified bareword assignments. Its parent is always the
+// global lexical environment.
+//
+// This is used in ExecuteInGlobalAndReturnScope and sits in front of the
+// global scope to store 'var' bindings, and to store fresh properties created
+// by assignments to undeclared variables that otherwise would have gone on
+// the global object.
+class NonSyntacticVariablesObject : public EnvironmentObject
+{
+ public:
+ static const unsigned RESERVED_SLOTS = 1;
+ static const Class class_;
+
+ static NonSyntacticVariablesObject* create(JSContext* cx);
+};
+
+// With environment objects on the run-time environment chain.
+class WithEnvironmentObject : public EnvironmentObject
+{
+ static const unsigned OBJECT_SLOT = 1;
+ static const unsigned THIS_SLOT = 2;
+ static const unsigned SCOPE_SLOT = 3;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 4;
+ static const Class class_;
+
+ static WithEnvironmentObject* create(JSContext* cx, HandleObject object, HandleObject enclosing,
+ Handle<WithScope*> scope);
+ static WithEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject object,
+ HandleObject enclosing);
+
+ /* Return the 'o' in 'with (o)'. */
+ JSObject& object() const;
+
+ /* Return object for GetThisValue. */
+ JSObject* withThis() const;
+
+ /*
+ * Return whether this object is a syntactic with object. If not, this is
+ * a With object we inserted between the outermost syntactic scope and the
+ * global object to wrap the environment chain someone explicitly passed
+ * via JSAPI to CompileFunction or script evaluation.
+ */
+ bool isSyntactic() const;
+
+ // For syntactic with environment objects, the with scope.
+ WithScope& scope() const;
+
+ static inline size_t objectSlot() {
+ return OBJECT_SLOT;
+ }
+
+ static inline size_t thisSlot() {
+ return THIS_SLOT;
+ }
+};
+
+// Internal scope object used by JSOP_BINDNAME upon encountering an
+// uninitialized lexical slot or an assignment to a 'const' binding.
+//
+// ES6 lexical bindings cannot be accessed in any way (throwing
+// ReferenceErrors) until initialized. Normally, NAME operations
+// unconditionally check for uninitialized lexical slots. When getting or
+// looking up names, this can be done without slowing down normal operations
+// on the return value. When setting names, however, we do not want to pollute
+// all set-property paths with uninitialized lexical checks. For setting names
+// (i.e. JSOP_SETNAME), we emit an accompanying, preceding JSOP_BINDNAME which
+// finds the right scope on which to set the name. Moreover, when the name on
+// the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
+// demands that the error be thrown after evaluating the RHS of
+// assignments. Instead, this sentinel scope object is pushed on the stack.
+// Attempting to access anything on this scope throws the appropriate
+// ReferenceError.
+//
+// ES6 'const' bindings induce a runtime error when assigned to outside
+// of initialization, regardless of strictness.
+class RuntimeLexicalErrorObject : public EnvironmentObject
+{
+ static const unsigned ERROR_SLOT = 1;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 2;
+ static const Class class_;
+
+ static RuntimeLexicalErrorObject* create(JSContext* cx, HandleObject enclosing,
+ unsigned errorNumber);
+
+ unsigned errorNumber() {
+ return getReservedSlot(ERROR_SLOT).toInt32();
+ }
+};
+
+
+/*****************************************************************************/
+
+// A environment iterator describes the active environments starting from an
+// environment, scope pair. This pair may be derived from the current point of
+// execution in a frame. If derived in such a fashion, the EnvironmentIter
+// tracks whether the current scope is within the extent of this initial
+// frame. Here, "frame" means a single activation of: a function, eval, or
+// global code.
+class MOZ_RAII EnvironmentIter
+{
+ Rooted<ScopeIter> si_;
+ RootedObject env_;
+ AbstractFramePtr frame_;
+
+ void incrementScopeIter();
+ void settle();
+
+ // No value semantics.
+ EnvironmentIter(const EnvironmentIter& ei) = delete;
+
+ public:
+ // Constructing from a copy of an existing EnvironmentIter.
+ EnvironmentIter(JSContext* cx, const EnvironmentIter& ei
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+ // Constructing from an environment, scope pair. All environments
+ // considered not to be withinInitialFrame, since no frame is given.
+ EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+ // Constructing from a frame. Places the EnvironmentIter on the innermost
+ // environment at pc.
+ EnvironmentIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+ bool done() const {
+ return si_.done();
+ }
+
+ explicit operator bool() const {
+ return !done();
+ }
+
+ void operator++(int) {
+ if (hasAnyEnvironmentObject())
+ env_ = &env_->as<EnvironmentObject>().enclosingEnvironment();
+ incrementScopeIter();
+ settle();
+ }
+
+ EnvironmentIter& operator++() {
+ operator++(1);
+ return *this;
+ }
+
+ // If done():
+ JSObject& enclosingEnvironment() const;
+
+ // If !done():
+ bool hasNonSyntacticEnvironmentObject() const;
+
+ bool hasSyntacticEnvironment() const {
+ return si_.hasSyntacticEnvironment();
+ }
+
+ bool hasAnyEnvironmentObject() const {
+ return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment();
+ }
+
+ EnvironmentObject& environment() const {
+ MOZ_ASSERT(hasAnyEnvironmentObject());
+ return env_->as<EnvironmentObject>();
+ }
+
+ Scope& scope() const {
+ return *si_.scope();
+ }
+
+ Scope* maybeScope() const {
+ if (si_)
+ return si_.scope();
+ return nullptr;
+ }
+
+ JSFunction& callee() const {
+ return env_->as<CallObject>().callee();
+ }
+
+ bool withinInitialFrame() const {
+ return !!frame_;
+ }
+
+ AbstractFramePtr initialFrame() const {
+ MOZ_ASSERT(withinInitialFrame());
+ return frame_;
+ }
+
+ AbstractFramePtr maybeInitialFrame() const {
+ return frame_;
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+// The key in MissingEnvironmentMap. For live frames, maps live frames to
+// their synthesized environments. For completely optimized-out environments,
+// maps the Scope to their synthesized environments. The env we synthesize for
+// Scopes are read-only, and we never use their parent links, so they don't
+// need to be distinct.
+//
+// That is, completely optimized out environments can't be distinguished by
+// frame. Note that even if the frame corresponding to the Scope is live on
+// the stack, it is unsound to synthesize an environment from that live
+// frame. In other words, the provenance of the environment chain is from
+// allocated closures (i.e., allocation sites) and is irrecoverable from
+// simple stack inspection (i.e., call sites).
+class MissingEnvironmentKey
+{
+ friend class LiveEnvironmentVal;
+
+ AbstractFramePtr frame_;
+ Scope* scope_;
+
+ public:
+ explicit MissingEnvironmentKey(const EnvironmentIter& ei)
+ : frame_(ei.maybeInitialFrame()),
+ scope_(ei.maybeScope())
+ { }
+
+ MissingEnvironmentKey(AbstractFramePtr frame, Scope* scope)
+ : frame_(frame),
+ scope_(scope)
+ { }
+
+ AbstractFramePtr frame() const { return frame_; }
+ Scope* scope() const { return scope_; }
+
+ void updateScope(Scope* scope) { scope_ = scope; }
+ void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
+
+ // For use as hash policy.
+ typedef MissingEnvironmentKey Lookup;
+ static HashNumber hash(MissingEnvironmentKey sk);
+ static bool match(MissingEnvironmentKey sk1, MissingEnvironmentKey sk2);
+ bool operator!=(const MissingEnvironmentKey& other) const {
+ return frame_ != other.frame_ || scope_ != other.scope_;
+ }
+ static void rekey(MissingEnvironmentKey& k, const MissingEnvironmentKey& newKey) {
+ k = newKey;
+ }
+};
+
+// The value in LiveEnvironmentMap, mapped from by live environment objects.
+class LiveEnvironmentVal
+{
+ friend class DebugEnvironments;
+ friend class MissingEnvironmentKey;
+
+ AbstractFramePtr frame_;
+ HeapPtr<Scope*> scope_;
+
+ static void staticAsserts();
+
+ public:
+ explicit LiveEnvironmentVal(const EnvironmentIter& ei)
+ : frame_(ei.initialFrame()),
+ scope_(ei.maybeScope())
+ { }
+
+ AbstractFramePtr frame() const { return frame_; }
+ Scope* scope() const { return scope_; }
+
+ void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
+
+ bool needsSweep();
+};
+
+
+/*****************************************************************************/
+
+/*
+ * Debug environment objects
+ *
+ * The debugger effectively turns every opcode into a potential direct eval.
+ * Naively, this would require creating a EnvironmentObject for every
+ * call/block scope and using JSOP_GETALIASEDVAR for every access. To optimize
+ * this, the engine assumes there is no debugger and optimizes scope access
+ * and creation accordingly. When the debugger wants to perform an unexpected
+ * eval-in-frame (or other, similar environment-requiring operations),
+ * fp->environmentChain is now incomplete.
+ *
+ * To resolve this, the debugger first calls GetDebugEnvironmentFor* to
+ * synthesize a "debug env chain". A debug env chain is just a chain of
+ * objects that fill in missing environments and protect the engine from
+ * unexpected access. (The latter means that some debugger operations, like
+ * redefining a lexical binding, can fail when a true eval would succeed.) To
+ * do both of these things, GetDebugEnvironmentFor* creates a new proxy
+ * DebugEnvironmentProxy to sit in front of every existing EnvironmentObject.
+ *
+ * GetDebugEnvironmentFor* ensures the invariant that the same
+ * DebugEnvironmentProxy is always produced for the same underlying
+ * environment (optimized or not!). This is maintained by some bookkeeping
+ * information stored in DebugEnvironments.
+ */
+
+extern JSObject*
+GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun);
+
+extern JSObject*
+GetDebugEnvironmentForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
+
+extern JSObject*
+GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx);
+
+/* Provides debugger access to a environment. */
+class DebugEnvironmentProxy : public ProxyObject
+{
+ /*
+ * The enclosing environment on the dynamic environment chain. This slot is analogous
+ * to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
+ */
+ static const unsigned ENCLOSING_EXTRA = 0;
+
+ /*
+ * NullValue or a dense array holding the unaliased variables of a function
+ * frame that has been popped.
+ */
+ static const unsigned SNAPSHOT_EXTRA = 1;
+
+ public:
+ static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env,
+ HandleObject enclosing);
+
+ EnvironmentObject& environment() const;
+ JSObject& enclosingEnvironment() const;
+
+ /* May only be called for proxies to function call objects. */
+ ArrayObject* maybeSnapshot() const;
+ void initSnapshot(ArrayObject& snapshot);
+
+ // Currently, the 'declarative' environments are function, module, and
+ // lexical environments.
+ bool isForDeclarative() const;
+
+ // Get a property by 'id', but returns sentinel values instead of throwing
+ // on exceptional cases.
+ bool getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp);
+
+ // Returns true iff this is a function environment with its own this-binding
+ // (all functions except arrow functions and generator expression lambdas).
+ bool isFunctionEnvironmentWithThis();
+
+ // Does this debug environment not have a real counterpart or was never
+ // live (and thus does not have a synthesized EnvironmentObject or a
+ // snapshot)?
+ bool isOptimizedOut() const;
+};
+
+/* Maintains per-compartment debug environment bookkeeping information. */
+class DebugEnvironments
+{
+ /* The map from (non-debug) environments to debug environments. */
+ ObjectWeakMap proxiedEnvs;
+
+ /*
+ * The map from live frames which have optimized-away environments to the
+ * corresponding debug environments.
+ */
+ typedef HashMap<MissingEnvironmentKey,
+ ReadBarrieredDebugEnvironmentProxy,
+ MissingEnvironmentKey,
+ RuntimeAllocPolicy> MissingEnvironmentMap;
+ MissingEnvironmentMap missingEnvs;
+
+ /*
+ * The map from environment objects of live frames to the live frame. This
+ * map updated lazily whenever the debugger needs the information. In
+ * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
+ * onPop* removes environments as they are popped). Thus, two consecutive
+ * debugger lazy updates of liveEnvs need only fill in the new
+ * environments.
+ */
+ typedef GCHashMap<ReadBarriered<JSObject*>,
+ LiveEnvironmentVal,
+ MovableCellHasher<ReadBarriered<JSObject*>>,
+ RuntimeAllocPolicy> LiveEnvironmentMap;
+ LiveEnvironmentMap liveEnvs;
+
+ public:
+ explicit DebugEnvironments(JSContext* cx);
+ ~DebugEnvironments();
+
+ private:
+ bool init();
+
+ static DebugEnvironments* ensureCompartmentData(JSContext* cx);
+
+ template <typename Environment, typename Scope>
+ static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei);
+
+ public:
+ void mark(JSTracer* trc);
+ void sweep(JSRuntime* rt);
+ void finish();
+#ifdef JS_GC_ZEAL
+ void checkHashTablesAfterMovingGC(JSRuntime* rt);
+#endif
+
+ // If a live frame has a synthesized entry in missingEnvs, make sure it's not
+ // collected.
+ void markLiveFrame(JSTracer* trc, AbstractFramePtr frame);
+
+ static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx, EnvironmentObject& env);
+ static bool addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
+ Handle<DebugEnvironmentProxy*> debugEnv);
+
+ static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei);
+ static bool addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
+ Handle<DebugEnvironmentProxy*> debugEnv);
+
+ static bool updateLiveEnvironments(JSContext* cx);
+ static LiveEnvironmentVal* hasLiveEnvironment(EnvironmentObject& env);
+ static void unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr frame);
+
+ // When a frame bails out from Ion to Baseline, there might be missing
+ // envs keyed on, and live envs containing, the old
+ // RematerializedFrame. Forward those values to the new BaselineFrame.
+ static void forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to);
+
+ // When an environment is popped, we store a snapshot of its bindings that
+ // live on the frame.
+ //
+ // This is done during frame unwinding, which cannot handle errors
+ // gracefully. Errors result in no snapshot being set on the
+ // DebugEnvironmentProxy.
+ static void takeFrameSnapshot(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
+ AbstractFramePtr frame);
+
+ // In debug-mode, these must be called whenever exiting a scope that might
+ // have stack-allocated locals.
+ static void onPopCall(JSContext* cx, AbstractFramePtr frame);
+ static void onPopVar(JSContext* cx, const EnvironmentIter& ei);
+ static void onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
+ static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
+ static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
+ static void onPopWith(AbstractFramePtr frame);
+ static void onCompartmentUnsetIsDebuggee(JSCompartment* c);
+};
+
+} /* namespace js */
+
+template <>
+inline bool
+JSObject::is<js::EnvironmentObject>() const
+{
+ return is<js::CallObject>() ||
+ is<js::VarEnvironmentObject>() ||
+ is<js::ModuleEnvironmentObject>() ||
+ is<js::LexicalEnvironmentObject>() ||
+ is<js::WithEnvironmentObject>() ||
+ is<js::NonSyntacticVariablesObject>() ||
+ is<js::RuntimeLexicalErrorObject>();
+}
+
+template<>
+bool
+JSObject::is<js::DebugEnvironmentProxy>() const;
+
+namespace js {
+
+inline bool
+IsSyntacticEnvironment(JSObject* env)
+{
+ if (!env->is<EnvironmentObject>())
+ return false;
+
+ if (env->is<WithEnvironmentObject>())
+ return env->as<WithEnvironmentObject>().isSyntactic();
+
+ if (env->is<LexicalEnvironmentObject>())
+ return env->as<LexicalEnvironmentObject>().isSyntactic();
+
+ if (env->is<NonSyntacticVariablesObject>())
+ return false;
+
+ return true;
+}
+
+inline bool
+IsExtensibleLexicalEnvironment(JSObject* env)
+{
+ return env->is<LexicalEnvironmentObject>() &&
+ env->as<LexicalEnvironmentObject>().isExtensible();
+}
+
+inline bool
+IsGlobalLexicalEnvironment(JSObject* env)
+{
+ return env->is<LexicalEnvironmentObject>() &&
+ env->as<LexicalEnvironmentObject>().isGlobal();
+}
+
+template <typename SpecificEnvironment>
+inline bool
+IsFrameInitialEnvironment(AbstractFramePtr frame, SpecificEnvironment& env)
+{
+ // A frame's initial environment is the innermost environment
+ // corresponding to the scope chain from frame.script()->bodyScope() to
+ // frame.script()->outermostScope(). This environment must be on the chain
+ // for the frame to be considered initialized. That is, it must be on the
+ // chain for the environment chain to fully match the scope chain at the
+ // start of execution in the frame.
+ //
+ // This logic must be in sync with the HAS_INITIAL_ENV logic in
+ // InitFromBailout.
+
+ // A function frame's CallObject, if present, is always the initial
+ // environment.
+ if (mozilla::IsSame<SpecificEnvironment, CallObject>::value)
+ return true;
+
+ // For an eval frame, the VarEnvironmentObject, if present, is always the
+ // initial environment.
+ if (mozilla::IsSame<SpecificEnvironment, VarEnvironmentObject>::value &&
+ frame.isEvalFrame())
+ {
+ return true;
+ }
+
+ // For named lambda frames without CallObjects (i.e., no binding in the
+ // body of the function was closed over), the LexicalEnvironmentObject
+ // corresponding to the named lambda scope is the initial environment.
+ if (mozilla::IsSame<SpecificEnvironment, NamedLambdaObject>::value &&
+ frame.isFunctionFrame() &&
+ frame.callee()->needsNamedLambdaEnvironment() &&
+ !frame.callee()->needsCallObject())
+ {
+ LexicalScope* namedLambdaScope = frame.script()->maybeNamedLambdaScope();
+ return &env.template as<LexicalEnvironmentObject>().scope() == namedLambdaScope;
+ }
+
+ return false;
+}
+
+extern bool
+CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
+ HandleObject terminatingEnv,
+ MutableHandleObject envObj);
+
+ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
+
+MOZ_MUST_USE bool
+GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, AbstractFramePtr frame,
+ jsbytecode* pc, MutableHandleValue res);
+
+MOZ_MUST_USE bool
+CheckVarNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandlePropertyName name);
+
+MOZ_MUST_USE bool
+CheckCanDeclareGlobalBinding(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, bool isFunction);
+
+MOZ_MUST_USE bool
+CheckLexicalNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandleObject varObj, HandlePropertyName name);
+
+MOZ_MUST_USE bool
+CheckGlobalDeclarationConflicts(JSContext* cx, HandleScript script,
+ Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandleObject varObj);
+
+MOZ_MUST_USE bool
+CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script, HandleObject envChain,
+ HandleObject varObj);
+
+MOZ_MUST_USE bool
+InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame);
+
+MOZ_MUST_USE bool
+PushVarEnvironmentObject(JSContext* cx, HandleScope scope, AbstractFramePtr frame);
+
+#ifdef DEBUG
+bool
+AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
+#endif
+
+} // namespace js
+
+namespace JS {
+
+template <>
+struct DeletePolicy<js::DebugEnvironments> : public js::GCManagedDeletePolicy<js::DebugEnvironments>
+{};
+
+} // namespace JS
+
+#endif /* vm_EnvironmentObject_h */
diff --git a/js/src/vm/ErrorObject-inl.h b/js/src/vm/ErrorObject-inl.h
new file mode 100644
index 000000000..d1e471a10
--- /dev/null
+++ b/js/src/vm/ErrorObject-inl.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ErrorObject_inl_h
+#define vm_ErrorObject_inl_h
+
+#include "vm/ErrorObject.h"
+
+#include "jscntxt.h"
+
+inline JSString*
+js::ErrorObject::fileName(JSContext* cx) const
+{
+ const HeapSlot& slot = getReservedSlotRef(FILENAME_SLOT);
+ return slot.isString() ? slot.toString() : cx->names().empty;
+}
+
+inline uint32_t
+js::ErrorObject::lineNumber() const
+{
+ const HeapSlot& slot = getReservedSlotRef(LINENUMBER_SLOT);
+ return slot.isInt32() ? slot.toInt32() : 0;
+}
+
+inline uint32_t
+js::ErrorObject::columnNumber() const
+{
+ const HeapSlot& slot = getReservedSlotRef(COLUMNNUMBER_SLOT);
+ return slot.isInt32() ? slot.toInt32() : 0;
+}
+
+inline JSObject*
+js::ErrorObject::stack() const
+{
+ return getReservedSlotRef(STACK_SLOT).toObjectOrNull();
+}
+
+#endif /* vm_ErrorObject_inl_h */
diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp
new file mode 100644
index 000000000..47b61b57b
--- /dev/null
+++ b/js/src/vm/ErrorObject.cpp
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ErrorObject-inl.h"
+
+#include "mozilla/Range.h"
+
+#include "jsexn.h"
+
+#include "js/CallArgs.h"
+#include "js/CharacterEncoding.h"
+#include "vm/GlobalObject.h"
+#include "vm/String.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/SavedStacks-inl.h"
+#include "vm/Shape-inl.h"
+
+using namespace js;
+
+/* static */ Shape*
+js::ErrorObject::assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> obj)
+{
+ MOZ_ASSERT(obj->empty());
+
+ if (!obj->addDataProperty(cx, cx->names().fileName, FILENAME_SLOT, 0))
+ return nullptr;
+ if (!obj->addDataProperty(cx, cx->names().lineNumber, LINENUMBER_SLOT, 0))
+ return nullptr;
+ return obj->addDataProperty(cx, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0);
+}
+
+/* static */ bool
+js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
+ ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName,
+ HandleObject stack, uint32_t lineNumber, uint32_t columnNumber,
+ HandleString message)
+{
+ AssertObjectIsSavedFrameOrWrapper(cx, stack);
+ assertSameCompartment(cx, obj, stack);
+
+ // Null out early in case of error, for exn_finalize's sake.
+ obj->initReservedSlot(ERROR_REPORT_SLOT, PrivateValue(nullptr));
+
+ if (!EmptyShape::ensureInitialCustomShape<ErrorObject>(cx, obj))
+ return false;
+
+ // The .message property isn't part of the initial shape because it's
+ // present in some error objects -- |Error.prototype|, |new Error("f")|,
+ // |new Error("")| -- but not in others -- |new Error(undefined)|,
+ // |new Error()|.
+ RootedShape messageShape(cx);
+ if (message) {
+ messageShape = obj->addDataProperty(cx, cx->names().message, MESSAGE_SLOT, 0);
+ if (!messageShape)
+ return false;
+ MOZ_ASSERT(messageShape->slot() == MESSAGE_SLOT);
+ }
+
+ MOZ_ASSERT(obj->lookupPure(NameToId(cx->names().fileName))->slot() == FILENAME_SLOT);
+ MOZ_ASSERT(obj->lookupPure(NameToId(cx->names().lineNumber))->slot() == LINENUMBER_SLOT);
+ MOZ_ASSERT(obj->lookupPure(NameToId(cx->names().columnNumber))->slot() ==
+ COLUMNNUMBER_SLOT);
+ MOZ_ASSERT_IF(message,
+ obj->lookupPure(NameToId(cx->names().message))->slot() == MESSAGE_SLOT);
+
+ MOZ_ASSERT(JSEXN_ERR <= type && type < JSEXN_LIMIT);
+
+ JSErrorReport* report = errorReport ? errorReport->forget() : nullptr;
+ obj->initReservedSlot(EXNTYPE_SLOT, Int32Value(type));
+ obj->initReservedSlot(STACK_SLOT, ObjectOrNullValue(stack));
+ obj->setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(report));
+ obj->initReservedSlot(FILENAME_SLOT, StringValue(fileName));
+ obj->initReservedSlot(LINENUMBER_SLOT, Int32Value(lineNumber));
+ obj->initReservedSlot(COLUMNNUMBER_SLOT, Int32Value(columnNumber));
+ if (message)
+ obj->setSlotWithType(cx, messageShape, StringValue(message));
+
+ return true;
+}
+
+/* static */ ErrorObject*
+js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack,
+ HandleString fileName, uint32_t lineNumber, uint32_t columnNumber,
+ ScopedJSFreePtr<JSErrorReport>* report, HandleString message,
+ HandleObject protoArg /* = nullptr */)
+{
+ AssertObjectIsSavedFrameOrWrapper(cx, stack);
+
+ RootedObject proto(cx, protoArg);
+ if (!proto) {
+ proto = GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType);
+ if (!proto)
+ return nullptr;
+ }
+
+ Rooted<ErrorObject*> errObject(cx);
+ {
+ const Class* clasp = ErrorObject::classForType(errorType);
+ JSObject* obj = NewObjectWithGivenProto(cx, clasp, proto);
+ if (!obj)
+ return nullptr;
+ errObject = &obj->as<ErrorObject>();
+ }
+
+ if (!ErrorObject::init(cx, errObject, errorType, report, fileName, stack,
+ lineNumber, columnNumber, message))
+ {
+ return nullptr;
+ }
+
+ return errObject;
+}
+
+JSErrorReport*
+js::ErrorObject::getOrCreateErrorReport(JSContext* cx)
+{
+ if (JSErrorReport* r = getErrorReport())
+ return r;
+
+ // We build an error report on the stack and then use CopyErrorReport to do
+ // the nitty-gritty malloc stuff.
+ JSErrorReport report;
+
+ // Type.
+ JSExnType type_ = type();
+ report.exnType = type_;
+
+ // Filename.
+ JSAutoByteString filenameStr;
+ if (!filenameStr.encodeLatin1(cx, fileName(cx)))
+ return nullptr;
+ report.filename = filenameStr.ptr();
+
+ // Coordinates.
+ report.lineno = lineNumber();
+ report.column = columnNumber();
+
+ // Message. Note that |new Error()| will result in an undefined |message|
+ // slot, so we need to explicitly substitute the empty string in that case.
+ RootedString message(cx, getMessage());
+ if (!message)
+ message = cx->runtime()->emptyString;
+ if (!message->ensureFlat(cx))
+ return nullptr;
+
+ UniquePtr<char[], JS::FreePolicy> utf8 = StringToNewUTF8CharsZ(cx, *message);
+ if (!utf8)
+ return nullptr;
+ report.initOwnedMessage(utf8.release());
+
+ // Cache and return.
+ JSErrorReport* copy = CopyErrorReport(cx, &report);
+ if (!copy)
+ return nullptr;
+ setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy));
+ return copy;
+}
+
+static bool
+ErrorObject_checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName,
+ MutableHandle<ErrorObject*> error)
+{
+ const Value& thisValue = args.thisv();
+
+ if (!thisValue.isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
+ InformalValueTypeName(thisValue));
+ return false;
+ }
+
+ // Walk up the prototype chain until we find the first ErrorObject that has
+ // the slots we need. This allows us to support the poor-man's subclassing
+ // of error: Object.create(Error.prototype).
+
+ RootedObject target(cx, CheckedUnwrap(&thisValue.toObject()));
+ if (!target) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ RootedObject proto(cx);
+ while (!target->is<ErrorObject>()) {
+ if (!GetPrototype(cx, target, &proto))
+ return false;
+
+ if (!proto) {
+ // We walked the whole prototype chain and did not find an Error
+ // object.
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ js_Error_str, fnName, thisValue.toObject().getClass()->name);
+ return false;
+ }
+
+ target = CheckedUnwrap(proto);
+ if (!target) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+ }
+
+ error.set(&target->as<ErrorObject>());
+ return true;
+}
+
+/* static */ bool
+js::ErrorObject::getStack(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ Rooted<ErrorObject*> error(cx);
+ if (!ErrorObject_checkAndUnwrapThis(cx, args, "(get stack)", &error))
+ return false;
+
+ RootedObject savedFrameObj(cx, error->stack());
+ RootedString stackString(cx);
+ if (!BuildStackString(cx, savedFrameObj, &stackString))
+ return false;
+
+ if (cx->stackFormat() == js::StackFormat::V8) {
+ // When emulating V8 stack frames, we also need to prepend the
+ // stringified Error to the stack string.
+ HandlePropertyName name = cx->names().ErrorToStringWithTrailingNewline;
+ RootedValue val(cx);
+ if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), name, name, 0, &val))
+ return false;
+
+ RootedValue rval(cx);
+ if (!js::Call(cx, val, args.thisv(), &rval))
+ return false;
+
+ if (!rval.isString())
+ return false;
+
+ RootedString stringified(cx, rval.toString());
+ stackString = ConcatStrings<CanGC>(cx, stringified, stackString);
+ }
+
+ args.rval().setString(stackString);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+IsObject(HandleValue v)
+{
+ return v.isObject();
+}
+
+/* static */ bool
+js::ErrorObject::setStack(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ // We accept any object here, because of poor-man's subclassing of Error.
+ return CallNonGenericMethod<IsObject, setStack_impl>(cx, args);
+}
+
+/* static */ bool
+js::ErrorObject::setStack_impl(JSContext* cx, const CallArgs& args)
+{
+ const Value& thisValue = args.thisv();
+ MOZ_ASSERT(thisValue.isObject());
+ RootedObject thisObj(cx, &thisValue.toObject());
+
+ if (!args.requireAtLeast(cx, "(set stack)", 1))
+ return false;
+ RootedValue val(cx, args[0]);
+
+ return DefineProperty(cx, thisObj, cx->names().stack, val);
+}
diff --git a/js/src/vm/ErrorObject.h b/js/src/vm/ErrorObject.h
new file mode 100644
index 000000000..32a691bb4
--- /dev/null
+++ b/js/src/vm/ErrorObject.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ErrorObject_h_
+#define vm_ErrorObject_h_
+
+#include "mozilla/ArrayUtils.h"
+
+#include "vm/NativeObject.h"
+#include "vm/SavedStacks.h"
+#include "vm/Shape.h"
+
+namespace js {
+
+/*
+ * Initialize the exception constructor/prototype hierarchy.
+ */
+extern JSObject*
+InitExceptionClasses(JSContext* cx, HandleObject obj);
+
+class ErrorObject : public NativeObject
+{
+ static JSObject*
+ createProto(JSContext* cx, JSProtoKey key);
+
+ static JSObject*
+ createConstructor(JSContext* cx, JSProtoKey key);
+
+ /* For access to createProto. */
+ friend JSObject*
+ js::InitExceptionClasses(JSContext* cx, HandleObject global);
+
+ static bool
+ init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
+ ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
+ uint32_t lineNumber, uint32_t columnNumber, HandleString message);
+
+ static const ClassSpec errorClassSpec_;
+ static const ClassSpec subErrorClassSpec_;
+ static const ClassSpec nonGlobalErrorClassSpec_;
+
+ protected:
+ static const uint32_t EXNTYPE_SLOT = 0;
+ static const uint32_t STACK_SLOT = EXNTYPE_SLOT + 1;
+ static const uint32_t ERROR_REPORT_SLOT = STACK_SLOT + 1;
+ static const uint32_t FILENAME_SLOT = ERROR_REPORT_SLOT + 1;
+ static const uint32_t LINENUMBER_SLOT = FILENAME_SLOT + 1;
+ static const uint32_t COLUMNNUMBER_SLOT = LINENUMBER_SLOT + 1;
+ static const uint32_t MESSAGE_SLOT = COLUMNNUMBER_SLOT + 1;
+
+ static const uint32_t RESERVED_SLOTS = MESSAGE_SLOT + 1;
+
+ public:
+ static const Class classes[JSEXN_LIMIT];
+
+ static const Class * classForType(JSExnType type) {
+ MOZ_ASSERT(type < JSEXN_WARN);
+ return &classes[type];
+ }
+
+ static bool isErrorClass(const Class* clasp) {
+ return &classes[0] <= clasp && clasp < &classes[0] + mozilla::ArrayLength(classes);
+ }
+
+ // Create an error of the given type corresponding to the provided location
+ // info. If |message| is non-null, then the error will have a .message
+ // property with that value; otherwise the error will have no .message
+ // property.
+ static ErrorObject*
+ create(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName,
+ uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr<JSErrorReport>* report,
+ HandleString message, HandleObject proto = nullptr);
+
+ /*
+ * Assign the initial error shape to the empty object. (This shape does
+ * *not* include .message, which must be added separately if needed; see
+ * ErrorObject::init.)
+ */
+ static Shape*
+ assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> obj);
+
+ JSExnType type() const {
+ return JSExnType(getReservedSlot(EXNTYPE_SLOT).toInt32());
+ }
+
+ JSErrorReport * getErrorReport() const {
+ const Value& slot = getReservedSlot(ERROR_REPORT_SLOT);
+ if (slot.isUndefined())
+ return nullptr;
+ return static_cast<JSErrorReport*>(slot.toPrivate());
+ }
+
+ JSErrorReport * getOrCreateErrorReport(JSContext* cx);
+
+ inline JSString * fileName(JSContext* cx) const;
+ inline uint32_t lineNumber() const;
+ inline uint32_t columnNumber() const;
+ inline JSObject * stack() const;
+
+ JSString * getMessage() const {
+ const HeapSlot& slot = getReservedSlotRef(MESSAGE_SLOT);
+ return slot.isString() ? slot.toString() : nullptr;
+ }
+
+ // Getter and setter for the Error.prototype.stack accessor.
+ static bool getStack(JSContext* cx, unsigned argc, Value* vp);
+ static bool setStack(JSContext* cx, unsigned argc, Value* vp);
+ static bool setStack_impl(JSContext* cx, const CallArgs& args);
+};
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::ErrorObject>() const
+{
+ return js::ErrorObject::isErrorClass(getClass());
+}
+
+#endif // vm_ErrorObject_h_
diff --git a/js/src/vm/ForOfIterator.cpp b/js/src/vm/ForOfIterator.cpp
new file mode 100644
index 000000000..7bd521a6a
--- /dev/null
+++ b/js/src/vm/ForOfIterator.cpp
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsobj.h"
+
+#include "vm/Interpreter.h"
+#include "vm/PIC.h"
+
+#include "jsobjinlines.h"
+
+using namespace js;
+using JS::ForOfIterator;
+
+bool
+ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavior)
+{
+ JSContext* cx = cx_;
+ RootedObject iterableObj(cx, ToObject(cx, iterable));
+ if (!iterableObj)
+ return false;
+
+ MOZ_ASSERT(index == NOT_ARRAY);
+
+ // Check the PIC first for a match.
+ if (iterableObj->is<ArrayObject>()) {
+ ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
+ if (!stubChain)
+ return false;
+
+ bool optimized;
+ if (!stubChain->tryOptimizeArray(cx, iterableObj.as<ArrayObject>(), &optimized))
+ return false;
+
+ if (optimized) {
+ // Got optimized stub. Array is optimizable.
+ index = 0;
+ iterator = iterableObj;
+ return true;
+ }
+ }
+
+ MOZ_ASSERT(index == NOT_ARRAY);
+
+ RootedValue callee(cx);
+ RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+ if (!GetProperty(cx, iterableObj, iterableObj, iteratorId, &callee))
+ return false;
+
+ // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
+ // bail out now without setting iterator. This will make valueIsIterable(),
+ // which our caller should check, return false.
+ if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
+ return true;
+
+ // Throw if obj[@@iterator] isn't callable.
+ // js::Invoke is about to check for this kind of error anyway, but it would
+ // throw an inscrutable error message about |method| rather than this nice
+ // one about |obj|.
+ if (!callee.isObject() || !callee.toObject().isCallable()) {
+ UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, nullptr);
+ if (!bytes)
+ return false;
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get());
+ return false;
+ }
+
+ RootedValue res(cx);
+ if (!js::Call(cx, callee, iterable, &res))
+ return false;
+
+ if (!res.isObject())
+ return ThrowCheckIsObject(cx, CheckIsObjectKind::GetIterator);
+
+ iterator = &res.toObject();
+ return true;
+}
+
+inline bool
+ForOfIterator::nextFromOptimizedArray(MutableHandleValue vp, bool* done)
+{
+ MOZ_ASSERT(index != NOT_ARRAY);
+
+ if (!CheckForInterrupt(cx_))
+ return false;
+
+ ArrayObject* arr = &iterator->as<ArrayObject>();
+
+ if (index >= arr->length()) {
+ vp.setUndefined();
+ *done = true;
+ return true;
+ }
+ *done = false;
+
+ // Try to get array element via direct access.
+ if (index < arr->getDenseInitializedLength()) {
+ vp.set(arr->getDenseElement(index));
+ if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
+ ++index;
+ return true;
+ }
+ }
+
+ return GetElement(cx_, iterator, iterator, index++, vp);
+}
+
+bool
+ForOfIterator::next(MutableHandleValue vp, bool* done)
+{
+ MOZ_ASSERT(iterator);
+ if (index != NOT_ARRAY) {
+ ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx_);
+ if (!stubChain)
+ return false;
+
+ if (stubChain->isArrayNextStillSane())
+ return nextFromOptimizedArray(vp, done);
+
+ // ArrayIterator.prototype.next changed, materialize a proper
+ // ArrayIterator instance and fall through to slowpath case.
+ if (!materializeArrayIterator())
+ return false;
+ }
+
+ RootedValue v(cx_);
+ if (!GetProperty(cx_, iterator, iterator, cx_->names().next, &v))
+ return false;
+
+ if (!js::Call(cx_, v, iterator, &v))
+ return false;
+
+ if (!v.isObject())
+ return ThrowCheckIsObject(cx_, CheckIsObjectKind::IteratorNext);
+
+ RootedObject resultObj(cx_, &v.toObject());
+ if (!GetProperty(cx_, resultObj, resultObj, cx_->names().done, &v))
+ return false;
+
+ *done = ToBoolean(v);
+ if (*done) {
+ vp.setUndefined();
+ return true;
+ }
+
+ return GetProperty(cx_, resultObj, resultObj, cx_->names().value, vp);
+}
+
+bool
+ForOfIterator::materializeArrayIterator()
+{
+ MOZ_ASSERT(index != NOT_ARRAY);
+
+ HandlePropertyName name = cx_->names().ArrayValuesAt;
+ RootedValue val(cx_);
+ if (!GlobalObject::getSelfHostedFunction(cx_, cx_->global(), name, name, 1, &val))
+ return false;
+
+ RootedValue indexOrRval(cx_, Int32Value(index));
+ if (!js::Call(cx_, val, iterator, indexOrRval, &indexOrRval))
+ return false;
+
+ index = NOT_ARRAY;
+ // Result of call to ArrayValuesAt must be an object.
+ iterator = &indexOrRval.toObject();
+ return true;
+}
diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp
new file mode 100644
index 000000000..690c0bf48
--- /dev/null
+++ b/js/src/vm/GeneratorObject.cpp
@@ -0,0 +1,367 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/GeneratorObject.h"
+
+#include "jsobj.h"
+
+#include "jsatominlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+
+JSObject*
+GeneratorObject::create(JSContext* cx, AbstractFramePtr frame)
+{
+ MOZ_ASSERT(frame.script()->isGenerator());
+ MOZ_ASSERT(frame.script()->nfixed() == 0);
+
+ Rooted<GlobalObject*> global(cx, cx->global());
+ RootedNativeObject obj(cx);
+ if (frame.script()->isStarGenerator()) {
+ RootedValue pval(cx);
+ RootedObject fun(cx, frame.callee());
+ // FIXME: This would be faster if we could avoid doing a lookup to get
+ // the prototype for the instance. Bug 906600.
+ if (!GetProperty(cx, fun, fun, cx->names().prototype, &pval))
+ return nullptr;
+ RootedObject proto(cx, pval.isObject() ? &pval.toObject() : nullptr);
+ if (!proto) {
+ proto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
+ if (!proto)
+ return nullptr;
+ }
+ obj = NewNativeObjectWithGivenProto(cx, &StarGeneratorObject::class_, proto);
+ } else {
+ MOZ_ASSERT(frame.script()->isLegacyGenerator());
+ RootedObject proto(cx, GlobalObject::getOrCreateLegacyGeneratorObjectPrototype(cx, global));
+ if (!proto)
+ return nullptr;
+ obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto);
+ }
+ if (!obj)
+ return nullptr;
+
+ GeneratorObject* genObj = &obj->as<GeneratorObject>();
+ genObj->setCallee(*frame.callee());
+ genObj->setNewTarget(frame.newTarget());
+ genObj->setEnvironmentChain(*frame.environmentChain());
+ if (frame.script()->needsArgsObj())
+ genObj->setArgsObj(frame.argsObj());
+ genObj->clearExpressionStack();
+
+ return obj;
+}
+
+bool
+GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
+ Value* vp, unsigned nvalues)
+{
+ MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
+
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(!genObj->hasExpressionStack());
+
+ if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
+ RootedValue val(cx, ObjectValue(*frame.callee()));
+ ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_IGNORE_STACK, val, nullptr);
+ return false;
+ }
+
+ uint32_t yieldIndex = GET_UINT24(pc);
+ genObj->setYieldIndex(yieldIndex);
+ genObj->setEnvironmentChain(*frame.environmentChain());
+
+ if (nvalues) {
+ ArrayObject* stack = NewDenseCopiedArray(cx, nvalues, vp);
+ if (!stack)
+ return false;
+ genObj->setExpressionStack(*stack);
+ }
+
+ return true;
+}
+
+bool
+GeneratorObject::finalSuspend(JSContext* cx, HandleObject obj)
+{
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(genObj->isRunning() || genObj->isClosing());
+
+ bool closing = genObj->isClosing();
+ genObj->setClosed();
+
+ if (genObj->is<LegacyGeneratorObject>() && !closing)
+ return ThrowStopIteration(cx);
+
+ return true;
+}
+
+void
+js::SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame)
+{
+ CallObject& callObj = frame.callObj();
+
+ // Get the generator object stored on the scope chain and close it.
+ Shape* shape = callObj.lookup(cx, cx->names().dotGenerator);
+ GeneratorObject& genObj = callObj.getSlot(shape->slot()).toObject().as<GeneratorObject>();
+ genObj.setClosed();
+
+ // Return value is already set in GeneratorThrowOrClose.
+ if (genObj.is<StarGeneratorObject>())
+ return;
+
+ // Legacy generator .close() always returns |undefined|.
+ MOZ_ASSERT(genObj.is<LegacyGeneratorObject>());
+ frame.setReturnValue(UndefinedValue());
+}
+
+bool
+js::GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj,
+ HandleValue arg, uint32_t resumeKind)
+{
+ if (resumeKind == GeneratorObject::THROW) {
+ cx->setPendingException(arg);
+ genObj->setRunning();
+ } else {
+ MOZ_ASSERT(resumeKind == GeneratorObject::CLOSE);
+
+ if (genObj->is<StarGeneratorObject>()) {
+ MOZ_ASSERT(arg.isObject());
+ frame.setReturnValue(arg);
+ } else {
+ MOZ_ASSERT(arg.isUndefined());
+ }
+
+ cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
+ genObj->setClosing();
+ }
+ return false;
+}
+
+bool
+GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
+ HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind)
+{
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(genObj->isSuspended());
+
+ RootedFunction callee(cx, &genObj->callee());
+ RootedValue newTarget(cx, genObj->newTarget());
+ RootedObject envChain(cx, &genObj->environmentChain());
+ if (!activation.resumeGeneratorFrame(callee, newTarget, envChain))
+ return false;
+ activation.regs().fp()->setResumedGenerator();
+
+ if (genObj->hasArgsObj())
+ activation.regs().fp()->initArgsObj(genObj->argsObj());
+
+ if (genObj->hasExpressionStack()) {
+ uint32_t len = genObj->expressionStack().length();
+ MOZ_ASSERT(activation.regs().spForStackDepth(len));
+ const Value* src = genObj->expressionStack().getDenseElements();
+ mozilla::PodCopy(activation.regs().sp, src, len);
+ activation.regs().sp += len;
+ genObj->clearExpressionStack();
+ }
+
+ JSScript* script = callee->nonLazyScript();
+ uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+ activation.regs().pc = script->offsetToPC(offset);
+
+ // Always push on a value, even if we are raising an exception. In the
+ // exception case, the stack needs to have something on it so that exception
+ // handling doesn't skip the catch blocks. See TryNoteIter::settle.
+ activation.regs().sp++;
+ MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth()));
+ activation.regs().sp[-1] = arg;
+
+ switch (resumeKind) {
+ case NEXT:
+ genObj->setRunning();
+ return true;
+
+ case THROW:
+ case CLOSE:
+ return GeneratorThrowOrClose(cx, activation.regs().fp(), genObj, arg, resumeKind);
+
+ default:
+ MOZ_CRASH("bad resumeKind");
+ }
+}
+
+bool
+LegacyGeneratorObject::close(JSContext* cx, HandleObject obj)
+{
+ Rooted<LegacyGeneratorObject*> genObj(cx, &obj->as<LegacyGeneratorObject>());
+
+ // Avoid calling back into JS unless it is necessary.
+ if (genObj->isClosed())
+ return true;
+
+ RootedValue rval(cx);
+
+ RootedValue closeValue(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().LegacyGeneratorCloseInternal,
+ &closeValue))
+ {
+ return false;
+ }
+ MOZ_ASSERT(closeValue.isObject());
+ MOZ_ASSERT(closeValue.toObject().is<JSFunction>());
+
+ FixedInvokeArgs<0> args(cx);
+
+ RootedValue v(cx, ObjectValue(*genObj));
+ return Call(cx, closeValue, v, args, &v);
+}
+
+const Class LegacyGeneratorObject::class_ = {
+ "Generator",
+ JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS)
+};
+
+const Class StarGeneratorObject::class_ = {
+ "Generator",
+ JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS)
+};
+
+static const JSFunctionSpec star_generator_methods[] = {
+ JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0),
+ JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0),
+ JS_SELF_HOSTED_FN("return", "StarGeneratorReturn", 1, 0),
+ JS_FS_END
+};
+
+#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
+
+static const JSFunctionSpec legacy_generator_methods[] = {
+ JS_SELF_HOSTED_SYM_FN(iterator, "LegacyGeneratorIteratorShim", 0, 0),
+ // "send" is an alias for "next".
+ JS_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("throw", "LegacyGeneratorThrow", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("close", "LegacyGeneratorClose", 0, JSPROP_ROPERM),
+ JS_FS_END
+};
+
+#undef JSPROP_ROPERM
+
+static JSObject*
+NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> global)
+{
+ RootedObject proto(cx, global->getOrCreateObjectPrototype(cx));
+ if (!proto)
+ return nullptr;
+ return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
+}
+
+JSObject*
+js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
+{
+ RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx));
+ if (!proto)
+ return nullptr;
+ return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
+}
+
+/* static */ bool
+GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO).isObject())
+ return true;
+
+ RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
+ if (!proto || !proto->setDelegate(cx))
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
+ return false;
+
+ global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
+ return true;
+}
+
+/* static */ bool
+GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(STAR_GENERATOR_OBJECT_PROTO).isObject())
+ return true;
+
+ RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global));
+ if (!iteratorProto)
+ return false;
+
+ RootedObject genObjectProto(cx, global->createBlankPrototypeInheriting(cx,
+ &PlainObject::class_,
+ iteratorProto));
+ if (!genObjectProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) ||
+ !DefineToStringTag(cx, genObjectProto, cx->names().Generator))
+ {
+ return false;
+ }
+
+ RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!genFunctionProto || !genFunctionProto->setDelegate(cx))
+ return false;
+ if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
+ !DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
+ {
+ return false;
+ }
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ return false;
+ RootedObject proto(cx, &function.toObject());
+ RootedAtom name(cx, cx->names().GeneratorFunction);
+ RootedObject genFunction(cx, NewFunctionWithProto(cx, Generator, 1,
+ JSFunction::NATIVE_CTOR, nullptr, name,
+ proto, gc::AllocKind::FUNCTION,
+ SingletonObject));
+ if (!genFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
+ return false;
+
+ global->setReservedSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
+ global->setReservedSlot(STAR_GENERATOR_FUNCTION, ObjectValue(*genFunction));
+ global->setReservedSlot(STAR_GENERATOR_FUNCTION_PROTO, ObjectValue(*genFunctionProto));
+ return true;
+}
+
+MOZ_MUST_USE bool
+js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
+{
+ // yield/return value should be an Object.
+ if (!v.isObject())
+ return false;
+
+ JSObject* obj = &v.toObject();
+
+ // It should have `done` data property with boolean value.
+ Value doneVal;
+ if (!GetPropertyPure(cx, obj, NameToId(cx->names().done), &doneVal))
+ return false;
+ if (!doneVal.isBoolean())
+ return false;
+
+ // It should have `value` data property, but the type doesn't matter
+ JSObject* ignored;
+ Shape* shape;
+ if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &shape))
+ return false;
+ if (!shape)
+ return false;
+ if (!shape->hasDefaultGetter())
+ return false;
+
+ return true;
+}
diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h
new file mode 100644
index 000000000..ca1452b34
--- /dev/null
+++ b/js/src/vm/GeneratorObject.h
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_GeneratorObject_h
+#define vm_GeneratorObject_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "vm/ArgumentsObject.h"
+#include "vm/ArrayObject.h"
+#include "vm/Stack.h"
+
+namespace js {
+
+class GeneratorObject : public NativeObject
+{
+ public:
+ // Magic values stored in the yield index slot when the generator is
+ // running or closing. See the yield index comment below.
+ static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
+ static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
+
+ enum {
+ CALLEE_SLOT = 0,
+ ENV_CHAIN_SLOT,
+ ARGS_OBJ_SLOT,
+ EXPRESSION_STACK_SLOT,
+ YIELD_INDEX_SLOT,
+ NEWTARGET_SLOT,
+ RESERVED_SLOTS
+ };
+
+ enum ResumeKind { NEXT, THROW, CLOSE };
+
+ private:
+ static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
+ Value* vp, unsigned nvalues);
+
+ public:
+ static inline ResumeKind getResumeKind(jsbytecode* pc) {
+ MOZ_ASSERT(*pc == JSOP_RESUME);
+ unsigned arg = GET_UINT16(pc);
+ MOZ_ASSERT(arg <= CLOSE);
+ return static_cast<ResumeKind>(arg);
+ }
+
+ static inline ResumeKind getResumeKind(ExclusiveContext* cx, JSAtom* atom) {
+ if (atom == cx->names().next)
+ return NEXT;
+ if (atom == cx->names().throw_)
+ return THROW;
+ MOZ_ASSERT(atom == cx->names().close);
+ return CLOSE;
+ }
+
+ static JSObject* create(JSContext* cx, AbstractFramePtr frame);
+
+ static bool resume(JSContext* cx, InterpreterActivation& activation,
+ HandleObject obj, HandleValue arg, ResumeKind resumeKind);
+
+ static bool initialSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc) {
+ return suspend(cx, obj, frame, pc, nullptr, 0);
+ }
+
+ static bool normalSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
+ Value* vp, unsigned nvalues) {
+ return suspend(cx, obj, frame, pc, vp, nvalues);
+ }
+
+ static bool finalSuspend(JSContext* cx, HandleObject obj);
+
+ JSFunction& callee() const {
+ return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
+ }
+ void setCallee(JSFunction& callee) {
+ setFixedSlot(CALLEE_SLOT, ObjectValue(callee));
+ }
+
+ JSObject& environmentChain() const {
+ return getFixedSlot(ENV_CHAIN_SLOT).toObject();
+ }
+ void setEnvironmentChain(JSObject& envChain) {
+ setFixedSlot(ENV_CHAIN_SLOT, ObjectValue(envChain));
+ }
+
+ bool hasArgsObj() const {
+ return getFixedSlot(ARGS_OBJ_SLOT).isObject();
+ }
+ ArgumentsObject& argsObj() const {
+ return getFixedSlot(ARGS_OBJ_SLOT).toObject().as<ArgumentsObject>();
+ }
+ void setArgsObj(ArgumentsObject& argsObj) {
+ setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj));
+ }
+
+ bool hasExpressionStack() const {
+ return getFixedSlot(EXPRESSION_STACK_SLOT).isObject();
+ }
+ ArrayObject& expressionStack() const {
+ return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as<ArrayObject>();
+ }
+ void setExpressionStack(ArrayObject& expressionStack) {
+ setFixedSlot(EXPRESSION_STACK_SLOT, ObjectValue(expressionStack));
+ }
+ void clearExpressionStack() {
+ setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
+ }
+
+ bool isConstructing() const {
+ return getFixedSlot(NEWTARGET_SLOT).isObject();
+ }
+ const Value& newTarget() const {
+ return getFixedSlot(NEWTARGET_SLOT);
+ }
+ void setNewTarget(const Value& newTarget) {
+ setFixedSlot(NEWTARGET_SLOT, newTarget);
+ }
+
+
+ // The yield index slot is abused for a few purposes. It's undefined if
+ // it hasn't been set yet (before the initial yield), and null if the
+ // generator is closed. If the generator is running, the yield index is
+ // YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing"
+ // state, the yield index is YIELD_INDEX_CLOSING.
+ //
+ // If the generator is suspended, it's the yield index (stored as
+ // JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that
+ // suspended the generator. The yield index can be mapped to the bytecode
+ // offset (interpreter) or to the native code offset (JIT).
+
+ bool isRunning() const {
+ MOZ_ASSERT(!isClosed());
+ return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING;
+ }
+ bool isClosing() const {
+ return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
+ }
+ bool isSuspended() const {
+ // Note: also update Baseline's IsSuspendedStarGenerator code if this
+ // changes.
+ MOZ_ASSERT(!isClosed());
+ static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
+ "test below should return false for YIELD_INDEX_RUNNING");
+ return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
+ }
+ void setRunning() {
+ MOZ_ASSERT(isSuspended());
+ setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING));
+ }
+ void setClosing() {
+ MOZ_ASSERT(isSuspended());
+ setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING));
+ }
+ void setYieldIndex(uint32_t yieldIndex) {
+ MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined());
+ MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing());
+ MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING));
+ setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
+ MOZ_ASSERT(isSuspended());
+ }
+ uint32_t yieldIndex() const {
+ MOZ_ASSERT(isSuspended());
+ return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
+ }
+ bool isClosed() const {
+ return getFixedSlot(CALLEE_SLOT).isNull();
+ }
+ void setClosed() {
+ setFixedSlot(CALLEE_SLOT, NullValue());
+ setFixedSlot(ENV_CHAIN_SLOT, NullValue());
+ setFixedSlot(ARGS_OBJ_SLOT, NullValue());
+ setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
+ setFixedSlot(YIELD_INDEX_SLOT, NullValue());
+ setFixedSlot(NEWTARGET_SLOT, NullValue());
+ }
+
+ static size_t offsetOfCalleeSlot() {
+ return getFixedSlotOffset(CALLEE_SLOT);
+ }
+ static size_t offsetOfEnvironmentChainSlot() {
+ return getFixedSlotOffset(ENV_CHAIN_SLOT);
+ }
+ static size_t offsetOfArgsObjSlot() {
+ return getFixedSlotOffset(ARGS_OBJ_SLOT);
+ }
+ static size_t offsetOfYieldIndexSlot() {
+ return getFixedSlotOffset(YIELD_INDEX_SLOT);
+ }
+ static size_t offsetOfExpressionStackSlot() {
+ return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
+ }
+ static size_t offsetOfNewTargetSlot() {
+ return getFixedSlotOffset(NEWTARGET_SLOT);
+ }
+};
+
+class LegacyGeneratorObject : public GeneratorObject
+{
+ public:
+ static const Class class_;
+
+ static bool close(JSContext* cx, HandleObject obj);
+};
+
+class StarGeneratorObject : public GeneratorObject
+{
+ public:
+ static const Class class_;
+};
+
+bool GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> obj,
+ HandleValue val, uint32_t resumeKind);
+void SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame);
+
+MOZ_MUST_USE bool
+CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v);
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::GeneratorObject>() const
+{
+ return is<js::LegacyGeneratorObject>() || is<js::StarGeneratorObject>();
+}
+
+#endif /* vm_GeneratorObject_h */
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
new file mode 100644
index 000000000..039be2e32
--- /dev/null
+++ b/js/src/vm/GlobalObject.cpp
@@ -0,0 +1,874 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/GlobalObject.h"
+
+#include "jscntxt.h"
+#include "jsdate.h"
+#include "jsexn.h"
+#include "jsfriendapi.h"
+#include "jsmath.h"
+#include "json.h"
+#include "jsprototypes.h"
+#include "jsweakmap.h"
+
+#include "builtin/AtomicsObject.h"
+#include "builtin/Eval.h"
+#if EXPOSE_INTL_API
+# include "builtin/Intl.h"
+#endif
+#include "builtin/MapObject.h"
+#include "builtin/ModuleObject.h"
+#include "builtin/Object.h"
+#ifdef SPIDERMONKEY_PROMISE
+#include "builtin/Promise.h"
+#endif
+#include "builtin/RegExp.h"
+#include "builtin/SelfHostingDefines.h"
+#include "builtin/SymbolObject.h"
+#include "builtin/TypedObject.h"
+#include "builtin/WeakMapObject.h"
+#include "builtin/WeakSetObject.h"
+#include "vm/Debugger.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/HelperThreads.h"
+#include "vm/PIC.h"
+#include "vm/RegExpStatics.h"
+#include "vm/RegExpStaticsObject.h"
+#include "vm/StopIterationObject.h"
+#include "wasm/WasmJS.h"
+
+#include "jscompartmentinlines.h"
+#include "jsobjinlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+struct ProtoTableEntry {
+ const Class* clasp;
+ ClassInitializerOp init;
+};
+
+namespace js {
+
+#define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init,clasp) \
+ extern JSObject* init(JSContext* cx, Handle<JSObject*> obj);
+JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
+#undef DECLARE_PROTOTYPE_CLASS_INIT
+
+} // namespace js
+
+JSObject*
+js::InitViaClassSpec(JSContext* cx, Handle<JSObject*> obj)
+{
+ MOZ_CRASH("InitViaClassSpec() should not be called.");
+}
+
+static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
+#define INIT_FUNC(name,code,init,clasp) { clasp, init },
+#define INIT_FUNC_DUMMY(name,code,init,clasp) { nullptr, nullptr },
+ JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
+#undef INIT_FUNC_DUMMY
+#undef INIT_FUNC
+};
+
+JS_FRIEND_API(const js::Class*)
+js::ProtoKeyToClass(JSProtoKey key)
+{
+ MOZ_ASSERT(key < JSProto_LIMIT);
+ return protoTable[key].clasp;
+}
+
+// This method is not in the header file to avoid having to include
+// TypedObject.h from GlobalObject.h. It is not generally perf
+// sensitive.
+TypedObjectModuleObject&
+js::GlobalObject::getTypedObjectModule() const {
+ Value v = getConstructor(JSProto_TypedObject);
+ // only gets called from contexts where TypedObject must be initialized
+ MOZ_ASSERT(v.isObject());
+ return v.toObject().as<TypedObjectModuleObject>();
+}
+
+/* static */ bool
+GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key)
+{
+ if (key == JSProto_WebAssembly)
+ return !wasm::HasSupport(cx);
+
+#ifdef ENABLE_SHARED_ARRAY_BUFFER
+ // Return true if the given constructor has been disabled at run-time.
+ switch (key) {
+ case JSProto_Atomics:
+ case JSProto_SharedArrayBuffer:
+ return !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled();
+ default:
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+/* static */ bool
+GlobalObject::ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
+{
+ if (global->isStandardClassResolved(key))
+ return true;
+ return resolveConstructor(cx, global, key);
+}
+
+/* static*/ bool
+GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
+{
+ MOZ_ASSERT(!global->isStandardClassResolved(key));
+
+ // Prohibit collection of allocation metadata. Metadata builders shouldn't
+ // need to observe lazily-constructed prototype objects coming into
+ // existence. And assertions start to fail when the builder itself attempts
+ // an allocation that re-entrantly tries to create the same prototype.
+ AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
+
+ // Constructor resolution may execute self-hosted scripts. These
+ // self-hosted scripts do not call out to user code by construction. Allow
+ // all scripts to execute, even in debuggee compartments that are paused.
+ AutoSuppressDebuggeeNoExecuteChecks suppressNX(cx);
+
+ // There are two different kinds of initialization hooks. One of them is
+ // the class js::InitFoo hook, defined in a JSProtoKey-keyed table at the
+ // top of this file. The other lives in the ClassSpec for classes that
+ // define it. Classes may use one or the other, but not both.
+ ClassInitializerOp init = protoTable[key].init;
+ if (init == InitViaClassSpec)
+ init = nullptr;
+
+ const Class* clasp = ProtoKeyToClass(key);
+ if (!init && !clasp)
+ return true; // JSProto_Null or a compile-time-disabled feature.
+
+ if (skipDeselectedConstructor(cx, key))
+ return true;
+
+ // Some classes have no init routine, which means that they're disabled at
+ // compile-time. We could try to enforce that callers never pass such keys
+ // to resolveConstructor, but that would cramp the style of consumers like
+ // GlobalObject::initStandardClasses that want to just carpet-bomb-call
+ // ensureConstructor with every JSProtoKey. So it's easier to just handle
+ // it here.
+ bool haveSpec = clasp && clasp->specDefined();
+ if (!init && !haveSpec)
+ return true;
+
+ // See if there's an old-style initialization hook.
+ if (init) {
+ MOZ_ASSERT(!haveSpec);
+ return init(cx, global);
+ }
+
+ //
+ // Ok, we're doing it with a class spec.
+ //
+
+ bool isObjectOrFunction = key == JSProto_Function || key == JSProto_Object;
+
+ // We need to create the prototype first, and immediately stash it in the
+ // slot. This is so the following bootstrap ordering is possible:
+ // * Object.prototype
+ // * Function.prototype
+ // * Function
+ // * Object
+ //
+ // We get the above when Object is resolved before Function. If Function
+ // is resolved before Object, we'll end up re-entering resolveConstructor
+ // for Function, which is a problem. So if Function is being resolved
+ // before Object.prototype exists, we just resolve Object instead, since we
+ // know that Function will also be resolved before we return.
+ if (key == JSProto_Function && global->getPrototype(JSProto_Object).isUndefined())
+ return resolveConstructor(cx, global, JSProto_Object);
+
+ // We don't always have a prototype (i.e. Math and JSON). If we don't,
+ // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
+ // should all be null.
+ RootedObject proto(cx);
+ if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
+ proto = createPrototype(cx, key);
+ if (!proto)
+ return false;
+
+ if (isObjectOrFunction) {
+ // Make sure that creating the prototype didn't recursively resolve
+ // our own constructor. We can't just assert that there's no
+ // prototype; OOMs can result in incomplete resolutions in which
+ // the prototype is saved but not the constructor. So use the same
+ // criteria that protects entry into this function.
+ MOZ_ASSERT(!global->isStandardClassResolved(key));
+
+ global->setPrototype(key, ObjectValue(*proto));
+ }
+ }
+
+ // Create the constructor.
+ RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
+ if (!ctor)
+ return false;
+
+ RootedId id(cx, NameToId(ClassName(key, cx)));
+ if (isObjectOrFunction) {
+ if (clasp->specShouldDefineConstructor()) {
+ RootedValue ctorValue(cx, ObjectValue(*ctor));
+ if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
+ return false;
+ }
+
+ global->setConstructor(key, ObjectValue(*ctor));
+ }
+
+ // If we're operating on the self-hosting global, we don't want any
+ // functions and properties on the builtins and their prototypes.
+ if (!cx->runtime()->isSelfHostingGlobal(global)) {
+ if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
+ if (!JS_DefineFunctions(cx, proto, funs))
+ return false;
+ }
+ if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
+ if (!JS_DefineProperties(cx, proto, props))
+ return false;
+ }
+ if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
+ if (!JS_DefineFunctions(cx, ctor, funs))
+ return false;
+ }
+ if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
+ if (!JS_DefineProperties(cx, ctor, props))
+ return false;
+ }
+ }
+
+ // If the prototype exists, link it with the constructor.
+ if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
+ return false;
+
+ // Call the post-initialization hook, if provided.
+ if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
+ if (!finishInit(cx, ctor, proto))
+ return false;
+ }
+
+ if (!isObjectOrFunction) {
+ // Any operations that modifies the global object should be placed
+ // after any other fallible operations.
+
+ // Fallible operation that modifies the global object.
+ if (clasp->specShouldDefineConstructor()) {
+ RootedValue ctorValue(cx, ObjectValue(*ctor));
+ if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
+ return false;
+ }
+
+ // Infallible operations that modify the global object.
+ global->setConstructor(key, ObjectValue(*ctor));
+ if (proto)
+ global->setPrototype(key, ObjectValue(*proto));
+ }
+
+ return true;
+}
+
+/* static */ bool
+GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
+ JSProtoKey key, HandleObject ctor, HandleObject proto)
+{
+ MOZ_ASSERT(!global->empty()); // reserved slots already allocated
+ MOZ_ASSERT(key != JSProto_Null);
+ MOZ_ASSERT(ctor);
+ MOZ_ASSERT(proto);
+
+ RootedId id(cx, NameToId(ClassName(key, cx)));
+ MOZ_ASSERT(!global->lookup(cx, id));
+
+ RootedValue ctorValue(cx, ObjectValue(*ctor));
+ if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
+ return false;
+
+ global->setConstructor(key, ObjectValue(*ctor));
+ global->setPrototype(key, ObjectValue(*proto));
+ return true;
+}
+
+GlobalObject*
+GlobalObject::createInternal(JSContext* cx, const Class* clasp)
+{
+ MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
+ MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
+
+ JSObject* obj = NewObjectWithGivenProto(cx, clasp, nullptr, SingletonObject);
+ if (!obj)
+ return nullptr;
+
+ Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+ MOZ_ASSERT(global->isUnqualifiedVarObj());
+
+ // Initialize the private slot to null if present, as GC can call class
+ // hooks before the caller gets to set this to a non-garbage value.
+ if (clasp->flags & JSCLASS_HAS_PRIVATE)
+ global->setPrivate(nullptr);
+
+ Rooted<LexicalEnvironmentObject*> lexical(cx,
+ LexicalEnvironmentObject::createGlobal(cx, global));
+ if (!lexical)
+ return nullptr;
+ global->setReservedSlot(LEXICAL_ENVIRONMENT, ObjectValue(*lexical));
+
+ Rooted<GlobalScope*> emptyGlobalScope(cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
+ if (!emptyGlobalScope)
+ return nullptr;
+ global->setReservedSlot(EMPTY_GLOBAL_SCOPE, PrivateGCThingValue(emptyGlobalScope));
+
+ cx->compartment()->initGlobal(*global);
+
+ if (!global->setQualifiedVarObj(cx))
+ return nullptr;
+ if (!global->setDelegate(cx))
+ return nullptr;
+
+ return global;
+}
+
+GlobalObject*
+GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
+ JS::OnNewGlobalHookOption hookOption,
+ const JS::CompartmentOptions& options)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
+
+ JSRuntime* rt = cx->runtime();
+
+ auto zoneSpecifier = options.creationOptions().zoneSpecifier();
+ Zone* zone;
+ if (zoneSpecifier == JS::SystemZone)
+ zone = rt->gc.systemZone;
+ else if (zoneSpecifier == JS::FreshZone)
+ zone = nullptr;
+ else
+ zone = static_cast<Zone*>(options.creationOptions().zonePointer());
+
+ JSCompartment* compartment = NewCompartment(cx, zone, principals, options);
+ if (!compartment)
+ return nullptr;
+
+ // Lazily create the system zone.
+ if (!rt->gc.systemZone && zoneSpecifier == JS::SystemZone) {
+ rt->gc.systemZone = compartment->zone();
+ rt->gc.systemZone->isSystem = true;
+ }
+
+ Rooted<GlobalObject*> global(cx);
+ {
+ AutoCompartment ac(cx, compartment);
+ global = GlobalObject::createInternal(cx, clasp);
+ if (!global)
+ return nullptr;
+ }
+
+ if (hookOption == JS::FireOnNewGlobalHook)
+ JS_FireOnNewGlobalObject(cx, global);
+
+ return global;
+}
+
+LexicalEnvironmentObject&
+GlobalObject::lexicalEnvironment() const
+{
+ return getReservedSlot(LEXICAL_ENVIRONMENT).toObject().as<LexicalEnvironmentObject>();
+}
+
+GlobalScope&
+GlobalObject::emptyGlobalScope() const
+{
+ const Value& v = getReservedSlot(EMPTY_GLOBAL_SCOPE);
+ MOZ_ASSERT(v.isPrivateGCThing() && v.traceKind() == JS::TraceKind::Scope);
+ return static_cast<Scope*>(v.toGCThing())->as<GlobalScope>();
+}
+
+/* static */ bool
+GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
+ MutableHandleObject eval)
+{
+ if (!global->getOrCreateObjectPrototype(cx))
+ return false;
+ eval.set(&global->getSlot(EVAL).toObject());
+ return true;
+}
+
+bool
+GlobalObject::valueIsEval(const Value& val)
+{
+ Value eval = getSlot(EVAL);
+ return eval.isObject() && eval == val;
+}
+
+/* static */ bool
+GlobalObject::initStandardClasses(JSContext* cx, Handle<GlobalObject*> global)
+{
+ /* Define a top-level property 'undefined' with the undefined value. */
+ if (!DefineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
+ nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING))
+ {
+ return false;
+ }
+
+ for (size_t k = 0; k < JSProto_LIMIT; ++k) {
+ if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Initializes a builtin constructor and its prototype without defining any
+ * properties or functions on it.
+ *
+ * Used in self-hosting to install the few builtin constructors required by
+ * self-hosted builtins.
+ */
+static bool
+InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey protoKey)
+{
+ MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
+ const Class* clasp = ProtoKeyToClass(protoKey);
+ RootedObject proto(cx);
+ proto = clasp->specCreatePrototypeHook()(cx, protoKey);
+ if (!proto)
+ return false;
+
+ RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, protoKey));
+ if (!ctor)
+ return false;
+
+ return GlobalObject::initBuiltinConstructor(cx, global, protoKey, ctor, proto);
+}
+
+/**
+ * The self-hosting global only gets a small subset of all standard classes.
+ * Even those are only created as bare constructors without any properties
+ * or functions.
+ */
+/* static */ bool
+GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
+ const JSFunctionSpec* builtins)
+{
+ // Define a top-level property 'undefined' with the undefined value.
+ if (!DefineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
+ nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_isConcatSpreadable(cx);
+ std_isConcatSpreadable.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::isConcatSpreadable));
+ if (!JS_DefineProperty(cx, global, "std_isConcatSpreadable", std_isConcatSpreadable,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ // Define a top-level property 'std_iterator' with the name of the method
+ // used by for-of loops to create an iterator.
+ RootedValue std_iterator(cx);
+ std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
+ if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_match(cx);
+ std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
+ if (!JS_DefineProperty(cx, global, "std_match", std_match,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_replace(cx);
+ std_replace.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::replace));
+ if (!JS_DefineProperty(cx, global, "std_replace", std_replace,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_search(cx);
+ std_search.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::search));
+ if (!JS_DefineProperty(cx, global, "std_search", std_search,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_species(cx);
+ std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
+ if (!JS_DefineProperty(cx, global, "std_species", std_species,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ RootedValue std_split(cx);
+ std_split.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::split));
+ if (!JS_DefineProperty(cx, global, "std_split", std_split,
+ JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
+ InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
+ InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
+ InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
+ InitBareWeakMapCtor(cx, global) &&
+ InitStopIterationClass(cx, global) &&
+ DefineFunctions(cx, global, builtins, AsIntrinsic);
+}
+
+/* static */ bool
+GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global)
+{
+ HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
+ if (v.isUndefined()) {
+ /*
+ * If there are callbacks, make sure that the CSP callback is installed
+ * and that it permits runtime code generation, then cache the result.
+ */
+ JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
+ Value boolValue = BooleanValue(!allows || allows(cx));
+ v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue);
+ }
+ return !v.isFalse();
+}
+
+/* static */ bool
+GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag,
+ unsigned errorNumber)
+{
+ Rooted<GlobalObject*> global(cx, &obj->global());
+ HeapSlot& v = global->getSlotRef(WARNED_ONCE_FLAGS);
+ MOZ_ASSERT_IF(!v.isUndefined(), v.toInt32());
+ int32_t flags = v.isUndefined() ? 0 : v.toInt32();
+ if (!(flags & flag)) {
+ if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
+ errorNumber))
+ {
+ return false;
+ }
+ if (v.isUndefined())
+ v.init(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
+ else
+ v.set(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
+ }
+ return true;
+}
+
+JSFunction*
+GlobalObject::createConstructor(JSContext* cx, Native ctor, JSAtom* nameArg, unsigned length,
+ gc::AllocKind kind, const JSJitInfo* jitInfo)
+{
+ RootedAtom name(cx, nameArg);
+ JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind);
+ if (!fun)
+ return nullptr;
+
+ if (jitInfo)
+ fun->setJitInfo(jitInfo);
+
+ return fun;
+}
+
+static NativeObject*
+CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleObject global)
+{
+ MOZ_ASSERT(clasp != &JSFunction::class_);
+
+ RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto,
+ SingletonObject));
+ if (!blankProto || !blankProto->setDelegate(cx))
+ return nullptr;
+
+ return blankProto;
+}
+
+NativeObject*
+GlobalObject::createBlankPrototype(JSContext* cx, const Class* clasp)
+{
+ Rooted<GlobalObject*> self(cx, this);
+ RootedObject objectProto(cx, getOrCreateObjectPrototype(cx));
+ if (!objectProto)
+ return nullptr;
+
+ return CreateBlankProto(cx, clasp, objectProto, self);
+}
+
+NativeObject*
+GlobalObject::createBlankPrototypeInheriting(JSContext* cx, const Class* clasp, HandleObject proto)
+{
+ Rooted<GlobalObject*> self(cx, this);
+ return CreateBlankProto(cx, clasp, proto, self);
+}
+
+bool
+js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_)
+{
+ RootedObject ctor(cx, ctor_), proto(cx, proto_);
+
+ RootedValue protoVal(cx, ObjectValue(*proto));
+ RootedValue ctorVal(cx, ObjectValue(*ctor));
+
+ return DefineProperty(cx, ctor, cx->names().prototype, protoVal,
+ nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY) &&
+ DefineProperty(cx, proto, cx->names().constructor, ctorVal,
+ nullptr, nullptr, 0);
+}
+
+bool
+js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
+ const JSPropertySpec* ps, const JSFunctionSpec* fs)
+{
+ if (ps && !JS_DefineProperties(cx, obj, ps))
+ return false;
+ if (fs && !JS_DefineFunctions(cx, obj, fs))
+ return false;
+ return true;
+}
+
+bool
+js::DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag)
+{
+ RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
+ RootedValue tagString(cx, StringValue(tag));
+ return DefineProperty(cx, obj, toStringTagId, tagString, nullptr, nullptr, JSPROP_READONLY);
+}
+
+static void
+GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->maybeOffMainThread());
+ fop->delete_((GlobalObject::DebuggerVector*) obj->as<NativeObject>().getPrivate());
+}
+
+static const ClassOps
+GlobalDebuggees_classOps = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ GlobalDebuggees_finalize
+};
+
+static const Class
+GlobalDebuggees_class = {
+ "GlobalDebuggee",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &GlobalDebuggees_classOps
+};
+
+GlobalObject::DebuggerVector*
+GlobalObject::getDebuggers() const
+{
+ Value debuggers = getReservedSlot(DEBUGGERS);
+ if (debuggers.isUndefined())
+ return nullptr;
+ MOZ_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class);
+ return (DebuggerVector*) debuggers.toObject().as<NativeObject>().getPrivate();
+}
+
+/* static */ GlobalObject::DebuggerVector*
+GlobalObject::getOrCreateDebuggers(JSContext* cx, Handle<GlobalObject*> global)
+{
+ assertSameCompartment(cx, global);
+ DebuggerVector* debuggers = global->getDebuggers();
+ if (debuggers)
+ return debuggers;
+
+ NativeObject* obj = NewNativeObjectWithGivenProto(cx, &GlobalDebuggees_class, nullptr);
+ if (!obj)
+ return nullptr;
+ debuggers = cx->new_<DebuggerVector>();
+ if (!debuggers)
+ return nullptr;
+ obj->setPrivate(debuggers);
+ global->setReservedSlot(DEBUGGERS, ObjectValue(*obj));
+ return debuggers;
+}
+
+/* static */ NativeObject*
+GlobalObject::getOrCreateForOfPICObject(JSContext* cx, Handle<GlobalObject*> global)
+{
+ assertSameCompartment(cx, global);
+ NativeObject* forOfPIC = global->getForOfPICObject();
+ if (forOfPIC)
+ return forOfPIC;
+
+ forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
+ if (!forOfPIC)
+ return nullptr;
+ global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
+ return forOfPIC;
+}
+
+bool
+GlobalObject::hasRegExpStatics() const
+{
+ return !getSlot(REGEXP_STATICS).isUndefined();
+}
+
+RegExpStatics*
+GlobalObject::getRegExpStatics(ExclusiveContext* cx) const
+{
+ MOZ_ASSERT(cx);
+ Rooted<GlobalObject*> self(cx, const_cast<GlobalObject*>(this));
+
+ RegExpStaticsObject* resObj = nullptr;
+ const Value& val = this->getSlot(REGEXP_STATICS);
+ if (!val.isObject()) {
+ MOZ_ASSERT(val.isUndefined());
+ resObj = RegExpStatics::create(cx, self);
+ if (!resObj)
+ return nullptr;
+
+ self->initSlot(REGEXP_STATICS, ObjectValue(*resObj));
+ } else {
+ resObj = &val.toObject().as<RegExpStaticsObject>();
+ }
+ return static_cast<RegExpStatics*>(resObj->getPrivate(/* nfixed = */ 1));
+}
+
+RegExpStatics*
+GlobalObject::getAlreadyCreatedRegExpStatics() const
+{
+ const Value& val = this->getSlot(REGEXP_STATICS);
+ MOZ_ASSERT(val.isObject());
+ return static_cast<RegExpStatics*>(val.toObject().as<RegExpStaticsObject>().getPrivate(/* nfixed = */ 1));
+}
+
+/* static */ NativeObject*
+GlobalObject::getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global)
+{
+ Value slot = global->getReservedSlot(INTRINSICS);
+ MOZ_ASSERT(slot.isUndefined() || slot.isObject());
+
+ if (slot.isObject())
+ return &slot.toObject().as<NativeObject>();
+
+ Rooted<NativeObject*> intrinsicsHolder(cx);
+ bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(global);
+ if (isSelfHostingGlobal) {
+ intrinsicsHolder = global;
+ } else {
+ intrinsicsHolder = NewObjectWithGivenProto<PlainObject>(cx, nullptr, TenuredObject);
+ if (!intrinsicsHolder)
+ return nullptr;
+ }
+
+ /* Define a property 'global' with the current global as its value. */
+ RootedValue globalValue(cx, ObjectValue(*global));
+ if (!DefineProperty(cx, intrinsicsHolder, cx->names().global, globalValue,
+ nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
+ {
+ return nullptr;
+ }
+
+ // Install the intrinsics holder in the intrinsics.
+ global->setReservedSlot(INTRINSICS, ObjectValue(*intrinsicsHolder));
+ return intrinsicsHolder;
+}
+
+/* static */ bool
+GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName selfHostedName, HandleAtom name,
+ unsigned nargs, MutableHandleValue funVal)
+{
+ bool exists = false;
+ if (!GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal, &exists))
+ return false;
+ if (exists) {
+ RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
+ if (fun->name() == name)
+ return true;
+
+ if (fun->name() == selfHostedName) {
+ // This function was initially cloned because it was called by
+ // other self-hosted code, so the clone kept its self-hosted name,
+ // instead of getting the name it's intended to have in content
+ // compartments. This can happen when a lazy builtin is initialized
+ // after self-hosted code for another builtin used the same
+ // function. In that case, we need to change the function's name,
+ // which is ok because it can't have been exposed to content
+ // before.
+ fun->initAtom(name);
+ return true;
+ }
+
+
+ // The function might be installed multiple times on the same or
+ // different builtins, under different property names, so its name
+ // might be neither "selfHostedName" nor "name". In that case, its
+ // canonical name must've been set using the `_SetCanonicalName`
+ // intrinsic.
+ cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName);
+ return true;
+ }
+
+ RootedFunction fun(cx);
+ if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs,
+ /* proto = */ nullptr,
+ SingletonObject, &fun))
+ {
+ return false;
+ }
+ funVal.setObject(*fun);
+
+ return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
+}
+
+/* static */ bool
+GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, HandleValue value)
+{
+ RootedNativeObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
+ if (!holder)
+ return false;
+
+ uint32_t slot = holder->slotSpan();
+ RootedShape last(cx, holder->lastProperty());
+ Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
+
+ RootedId id(cx, NameToId(name));
+ Rooted<StackShape> child(cx, StackShape(base, id, slot, 0, 0));
+ Shape* shape = cx->zone()->propertyTree.getChild(cx, last, child);
+ if (!shape)
+ return false;
+
+ if (!holder->setLastProperty(cx, shape))
+ return false;
+
+ holder->setSlot(shape->slot(), value);
+ return true;
+}
+
+/* static */ bool
+GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global)
+{
+ return global->getOrCreateObject(cx, MODULE_PROTO, initModuleProto) &&
+ global->getOrCreateObject(cx, IMPORT_ENTRY_PROTO, initImportEntryProto) &&
+ global->getOrCreateObject(cx, EXPORT_ENTRY_PROTO, initExportEntryProto);
+}
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h
new file mode 100644
index 000000000..05984bc5f
--- /dev/null
+++ b/js/src/vm/GlobalObject.h
@@ -0,0 +1,1024 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_GlobalObject_h
+#define vm_GlobalObject_h
+
+#include "jsarray.h"
+#include "jsbool.h"
+#include "jsexn.h"
+#include "jsfun.h"
+#include "jsnum.h"
+
+#include "builtin/RegExp.h"
+#include "js/Vector.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/ErrorObject.h"
+#include "vm/RegExpStatics.h"
+#include "vm/Runtime.h"
+
+namespace js {
+
+class Debugger;
+class TypedObjectModuleObject;
+class LexicalEnvironmentObject;
+
+class SimdTypeDescr;
+enum class SimdType;
+
+/*
+ * Global object slots are reserved as follows:
+ *
+ * [0, APPLICATION_SLOTS)
+ * Pre-reserved slots in all global objects set aside for the embedding's
+ * use. As with all reserved slots these start out as UndefinedValue() and
+ * are traced for GC purposes. Apart from that the engine never touches
+ * these slots, so the embedding can do whatever it wants with them.
+ * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT)
+ * Stores the original value of the constructor for the corresponding
+ * JSProtoKey.
+ * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT)
+ * Stores the prototype, if any, for the constructor for the corresponding
+ * JSProtoKey offset from JSProto_LIMIT.
+ * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, RESERVED_SLOTS)
+ * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
+ * the original eval for this global object (implementing |var eval =
+ * otherWindow.eval; eval(...)| as an indirect eval), a bit indicating
+ * whether this object has been cleared (see JS_ClearScope), and a cache for
+ * whether eval is allowed (per the global's Content Security Policy).
+ *
+ * The two JSProto_LIMIT-sized ranges are necessary to implement
+ * js::FindClassObject, and spec language speaking in terms of "the original
+ * Array prototype object", or "as if by the expression new Array()" referring
+ * to the original Array constructor. The actual (writable and even deletable)
+ * Object, Array, &c. properties are not stored in reserved slots.
+ */
+class GlobalObject : public NativeObject
+{
+ /* Count of slots set aside for application use. */
+ static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS;
+
+ /*
+ * Count of slots to store built-in prototypes and initial visible
+ * properties for the constructors.
+ */
+ static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 2;
+
+ enum : unsigned {
+ /* Various function values needed by the engine. */
+ EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS,
+ CREATE_DATAVIEW_FOR_THIS,
+ THROWTYPEERROR,
+
+ /*
+ * Instances of the internal createArrayFromBuffer function used by the
+ * typed array code, one per typed array element type.
+ */
+ FROM_BUFFER_UINT8,
+ FROM_BUFFER_INT8,
+ FROM_BUFFER_UINT16,
+ FROM_BUFFER_INT16,
+ FROM_BUFFER_UINT32,
+ FROM_BUFFER_INT32,
+ FROM_BUFFER_FLOAT32,
+ FROM_BUFFER_FLOAT64,
+ FROM_BUFFER_UINT8CLAMPED,
+
+ /* One-off properties stored after slots for built-ins. */
+ LEXICAL_ENVIRONMENT,
+ EMPTY_GLOBAL_SCOPE,
+ ITERATOR_PROTO,
+ ARRAY_ITERATOR_PROTO,
+ STRING_ITERATOR_PROTO,
+ LEGACY_GENERATOR_OBJECT_PROTO,
+ STAR_GENERATOR_OBJECT_PROTO,
+ STAR_GENERATOR_FUNCTION_PROTO,
+ STAR_GENERATOR_FUNCTION,
+ ASYNC_FUNCTION_PROTO,
+ ASYNC_FUNCTION,
+ MAP_ITERATOR_PROTO,
+ SET_ITERATOR_PROTO,
+ COLLATOR_PROTO,
+ NUMBER_FORMAT_PROTO,
+ DATE_TIME_FORMAT_PROTO,
+ MODULE_PROTO,
+ IMPORT_ENTRY_PROTO,
+ EXPORT_ENTRY_PROTO,
+ REGEXP_STATICS,
+ WARNED_ONCE_FLAGS,
+ RUNTIME_CODEGEN_ENABLED,
+ DEBUGGERS,
+ INTRINSICS,
+ FOR_OF_PIC_CHAIN,
+ MODULE_RESOLVE_HOOK,
+ WINDOW_PROXY,
+
+ /* Total reserved-slot count for global objects. */
+ RESERVED_SLOTS
+ };
+
+ /*
+ * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
+ * we won't expose GlobalObject, so just assert that the two values are
+ * synchronized.
+ */
+ static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS,
+ "global object slot counts are inconsistent");
+
+ enum WarnOnceFlag : int32_t {
+ WARN_WATCH_DEPRECATED = 1 << 0,
+ WARN_ARRAYBUFFER_SLICE_DEPRECATED = 1 << 1,
+ };
+
+ // Emit the specified warning if the given slot in |obj|'s global isn't
+ // true, then set the slot to true. Thus calling this method warns once
+ // for each global object it's called on, and every other call does
+ // nothing.
+ static bool
+ warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, unsigned errorNumber);
+
+
+ public:
+ LexicalEnvironmentObject& lexicalEnvironment() const;
+ GlobalScope& emptyGlobalScope() const;
+
+ void setThrowTypeError(JSFunction* fun) {
+ MOZ_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined());
+ setSlot(THROWTYPEERROR, ObjectValue(*fun));
+ }
+
+ void setOriginalEval(JSObject* evalobj) {
+ MOZ_ASSERT(getSlotRef(EVAL).isUndefined());
+ setSlot(EVAL, ObjectValue(*evalobj));
+ }
+
+ Value getConstructor(JSProtoKey key) const {
+ MOZ_ASSERT(key <= JSProto_LIMIT);
+ return getSlot(APPLICATION_SLOTS + key);
+ }
+ static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key);
+ static bool ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key);
+ static bool resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key);
+ static bool initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
+ JSProtoKey key, HandleObject ctor, HandleObject proto);
+
+ void setConstructor(JSProtoKey key, const Value& v) {
+ MOZ_ASSERT(key <= JSProto_LIMIT);
+ setSlot(APPLICATION_SLOTS + key, v);
+ }
+
+ Value getPrototype(JSProtoKey key) const {
+ MOZ_ASSERT(key <= JSProto_LIMIT);
+ return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key);
+ }
+
+ void setPrototype(JSProtoKey key, const Value& value) {
+ MOZ_ASSERT(key <= JSProto_LIMIT);
+ setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value);
+ }
+
+ bool classIsInitialized(JSProtoKey key) const {
+ bool inited = !getConstructor(key).isUndefined();
+ MOZ_ASSERT(inited == !getPrototype(key).isUndefined());
+ return inited;
+ }
+
+ bool functionObjectClassesInitialized() const {
+ bool inited = classIsInitialized(JSProto_Function);
+ MOZ_ASSERT(inited == classIsInitialized(JSProto_Object));
+ return inited;
+ }
+
+ /*
+ * Lazy standard classes need a way to indicate they have been initialized.
+ * Otherwise, when we delete them, we might accidentally recreate them via
+ * a lazy initialization. We use the presence of an object in the
+ * getConstructor(key) reserved slot to indicate that they've been
+ * initialized.
+ *
+ * Note: A few builtin objects, like JSON and Math, are not constructors,
+ * so getConstructor is a bit of a misnomer.
+ */
+ bool isStandardClassResolved(JSProtoKey key) const {
+ // If the constructor is undefined, then it hasn't been initialized.
+ MOZ_ASSERT(getConstructor(key).isUndefined() ||
+ getConstructor(key).isObject());
+ return !getConstructor(key).isUndefined();
+ }
+
+ /*
+ * Using a Handle<GlobalObject*> as a Handle<Object*> is always safe as
+ * GlobalObject derives JSObject. However, with C++'s semantics, Handle<T>
+ * is not related to Handle<S>, independent of how S and T are related.
+ * Further, Handle stores an indirect pointer and, again because of C++'s
+ * semantics, T** is not related to S**, independent of how S and T are
+ * related. Since we know that this specific case is safe, we provide a
+ * manual upcast operation here to do the reinterpret_cast in a known-safe
+ * manner.
+ */
+ static HandleObject upcast(Handle<GlobalObject*> global) {
+ return HandleObject::fromMarkedLocation(
+ reinterpret_cast<JSObject * const*>(global.address()));
+ }
+
+ private:
+ bool arrayClassInitialized() const {
+ return classIsInitialized(JSProto_Array);
+ }
+
+ bool booleanClassInitialized() const {
+ return classIsInitialized(JSProto_Boolean);
+ }
+ bool numberClassInitialized() const {
+ return classIsInitialized(JSProto_Number);
+ }
+ bool stringClassInitialized() const {
+ return classIsInitialized(JSProto_String);
+ }
+ bool regexpClassInitialized() const {
+ return classIsInitialized(JSProto_RegExp);
+ }
+ bool arrayBufferClassInitialized() const {
+ return classIsInitialized(JSProto_ArrayBuffer);
+ }
+ bool sharedArrayBufferClassInitialized() const {
+ return classIsInitialized(JSProto_SharedArrayBuffer);
+ }
+ bool errorClassesInitialized() const {
+ return classIsInitialized(JSProto_Error);
+ }
+ bool dataViewClassInitialized() const {
+ return classIsInitialized(JSProto_DataView);
+ }
+
+ Value createArrayFromBufferHelper(uint32_t slot) const {
+ MOZ_ASSERT(FROM_BUFFER_UINT8 <= slot && slot <= FROM_BUFFER_UINT8CLAMPED);
+ return getSlot(slot);
+ }
+
+ void setCreateArrayFromBufferHelper(uint32_t slot, Handle<JSFunction*> fun) {
+ MOZ_ASSERT(getSlotRef(slot).isUndefined());
+ setSlot(slot, ObjectValue(*fun));
+ }
+
+ public:
+ /* XXX Privatize me! */
+ void setCreateDataViewForThis(Handle<JSFunction*> fun) {
+ MOZ_ASSERT(getSlotRef(CREATE_DATAVIEW_FOR_THIS).isUndefined());
+ setSlot(CREATE_DATAVIEW_FOR_THIS, ObjectValue(*fun));
+ }
+
+ template<typename T>
+ inline void setCreateArrayFromBuffer(Handle<JSFunction*> fun);
+
+ private:
+ // Disallow use of unqualified JSObject::create in GlobalObject.
+ static GlobalObject* create(...) = delete;
+
+ friend struct ::JSRuntime;
+ static GlobalObject* createInternal(JSContext* cx, const Class* clasp);
+
+ public:
+ static GlobalObject*
+ new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
+ JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions& options);
+
+ /*
+ * Create a constructor function with the specified name and length using
+ * ctor, a method which creates objects with the given class.
+ */
+ JSFunction*
+ createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length,
+ gc::AllocKind kind = gc::AllocKind::FUNCTION,
+ const JSJitInfo* jitInfo = nullptr);
+
+ /*
+ * Create an object to serve as [[Prototype]] for instances of the given
+ * class, using |Object.prototype| as its [[Prototype]]. Users creating
+ * prototype objects with particular internal structure (e.g. reserved
+ * slots guaranteed to contain values of particular types) must immediately
+ * complete the minimal initialization to make the returned object safe to
+ * touch.
+ */
+ NativeObject* createBlankPrototype(JSContext* cx, const js::Class* clasp);
+
+ /*
+ * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
+ * of the returned blank prototype.
+ */
+ NativeObject* createBlankPrototypeInheriting(JSContext* cx, const js::Class* clasp,
+ HandleObject proto);
+
+ template <typename T>
+ T* createBlankPrototype(JSContext* cx) {
+ NativeObject* res = createBlankPrototype(cx, &T::class_);
+ return res ? &res->template as<T>() : nullptr;
+ }
+
+ NativeObject* getOrCreateObjectPrototype(JSContext* cx) {
+ if (functionObjectClassesInitialized())
+ return &getPrototype(JSProto_Object).toObject().as<NativeObject>();
+ RootedGlobalObject self(cx, this);
+ if (!ensureConstructor(cx, self, JSProto_Object))
+ return nullptr;
+ return &self->getPrototype(JSProto_Object).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return global->getOrCreateObjectPrototype(cx);
+ }
+
+ NativeObject* getOrCreateFunctionPrototype(JSContext* cx) {
+ if (functionObjectClassesInitialized())
+ return &getPrototype(JSProto_Function).toObject().as<NativeObject>();
+ RootedGlobalObject self(cx, this);
+ if (!ensureConstructor(cx, self, JSProto_Object))
+ return nullptr;
+ return &self->getPrototype(JSProto_Function).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return global->getOrCreateFunctionPrototype(cx);
+ }
+
+ static NativeObject* getOrCreateArrayPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Array))
+ return nullptr;
+ return &global->getPrototype(JSProto_Array).toObject().as<NativeObject>();
+ }
+
+ NativeObject* maybeGetArrayPrototype() {
+ if (arrayClassInitialized())
+ return &getPrototype(JSProto_Array).toObject().as<NativeObject>();
+ return nullptr;
+ }
+
+ static NativeObject* getOrCreateBooleanPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Boolean))
+ return nullptr;
+ return &global->getPrototype(JSProto_Boolean).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateNumberPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Number))
+ return nullptr;
+ return &global->getPrototype(JSProto_Number).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateStringPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_String))
+ return nullptr;
+ return &global->getPrototype(JSProto_String).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateSymbolPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Symbol))
+ return nullptr;
+ return &global->getPrototype(JSProto_Symbol).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreatePromisePrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Promise))
+ return nullptr;
+ return &global->getPrototype(JSProto_Promise).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateRegExpPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_RegExp))
+ return nullptr;
+ return &global->getPrototype(JSProto_RegExp).toObject().as<NativeObject>();
+ }
+
+ JSObject* maybeGetRegExpPrototype() {
+ if (regexpClassInitialized())
+ return &getPrototype(JSProto_RegExp).toObject();
+ return nullptr;
+ }
+
+ static NativeObject* getOrCreateSavedFramePrototype(JSContext* cx,
+ Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_SavedFrame))
+ return nullptr;
+ return &global->getPrototype(JSProto_SavedFrame).toObject().as<NativeObject>();
+ }
+
+ static JSObject* getOrCreateArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_ArrayBuffer))
+ return nullptr;
+ return &global->getPrototype(JSProto_ArrayBuffer).toObject();
+ }
+
+ JSObject* getOrCreateSharedArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer))
+ return nullptr;
+ return &global->getPrototype(JSProto_SharedArrayBuffer).toObject();
+ }
+
+ static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx,
+ Handle<GlobalObject*> global,
+ JSExnType exnType)
+ {
+ JSProtoKey key = GetExceptionProtoKey(exnType);
+ if (!ensureConstructor(cx, global, key))
+ return nullptr;
+ return &global->getPrototype(key).toObject();
+ }
+
+ static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Set))
+ return nullptr;
+ return &global->getPrototype(JSProto_Set).toObject().as<NativeObject>();
+ }
+
+ static NativeObject* getOrCreateWeakSetPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_WeakSet))
+ return nullptr;
+ return &global->getPrototype(JSProto_WeakSet).toObject().as<NativeObject>();
+ }
+
+ JSObject* getOrCreateIntlObject(JSContext* cx) {
+ return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject);
+ }
+
+ JSObject* getOrCreateTypedObjectModule(JSContext* cx) {
+ return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule);
+ }
+
+ JSObject* getOrCreateSimdGlobalObject(JSContext* cx) {
+ return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject);
+ }
+
+ // Get the type descriptor for one of the SIMD types.
+ // simdType is one of the JS_SIMDTYPEREPR_* constants.
+ // Implemented in builtin/SIMD.cpp.
+ static SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global,
+ SimdType simdType);
+
+ TypedObjectModuleObject& getTypedObjectModule() const;
+
+ JSObject* getLegacyIteratorPrototype() {
+ return &getPrototype(JSProto_Iterator).toObject();
+ }
+
+ JSObject* getOrCreateCollatorPrototype(JSContext* cx) {
+ return getOrCreateObject(cx, COLLATOR_PROTO, initIntlObject);
+ }
+
+ JSObject* getOrCreateNumberFormatPrototype(JSContext* cx) {
+ return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initIntlObject);
+ }
+
+ JSObject* getOrCreateDateTimeFormatPrototype(JSContext* cx) {
+ return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initIntlObject);
+ }
+
+ static bool ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global);
+
+ JSObject* maybeGetModulePrototype() {
+ Value value = getSlot(MODULE_PROTO);
+ return value.isUndefined() ? nullptr : &value.toObject();
+ }
+
+ JSObject* maybeGetImportEntryPrototype() {
+ Value value = getSlot(IMPORT_ENTRY_PROTO);
+ return value.isUndefined() ? nullptr : &value.toObject();
+ }
+
+ JSObject* maybeGetExportEntryPrototype() {
+ Value value = getSlot(EXPORT_ENTRY_PROTO);
+ return value.isUndefined() ? nullptr : &value.toObject();
+ }
+
+ JSObject* getModulePrototype() {
+ JSObject* proto = maybeGetModulePrototype();
+ MOZ_ASSERT(proto);
+ return proto;
+ }
+
+ JSObject* getImportEntryPrototype() {
+ JSObject* proto = maybeGetImportEntryPrototype();
+ MOZ_ASSERT(proto);
+ return proto;
+ }
+
+ JSObject* getExportEntryPrototype() {
+ JSObject* proto = maybeGetExportEntryPrototype();
+ MOZ_ASSERT(proto);
+ return proto;
+ }
+
+ static JSFunction*
+ getOrCreateTypedArrayConstructor(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_TypedArray))
+ return nullptr;
+ return &global->getConstructor(JSProto_TypedArray).toObject().as<JSFunction>();
+ }
+
+ static JSObject*
+ getOrCreateTypedArrayPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_TypedArray))
+ return nullptr;
+ return &global->getPrototype(JSProto_TypedArray).toObject();
+ }
+
+ private:
+ typedef bool (*ObjectInitOp)(JSContext* cx, Handle<GlobalObject*> global);
+
+ JSObject* getOrCreateObject(JSContext* cx, unsigned slot, ObjectInitOp init) {
+ Value v = getSlotRef(slot);
+ if (v.isObject())
+ return &v.toObject();
+ RootedGlobalObject self(cx, this);
+ if (!init(cx, self))
+ return nullptr;
+ return &self->getSlot(slot).toObject();
+ }
+
+ public:
+ static NativeObject* getOrCreateIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, ITERATOR_PROTO, initIteratorProto));
+ }
+
+ static NativeObject* getOrCreateArrayIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, ARRAY_ITERATOR_PROTO, initArrayIteratorProto));
+ }
+
+ static NativeObject* getOrCreateStringIteratorPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, STRING_ITERATOR_PROTO, initStringIteratorProto));
+ }
+
+ static NativeObject* getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, LEGACY_GENERATOR_OBJECT_PROTO,
+ initLegacyGeneratorProto));
+ }
+
+ static NativeObject* getOrCreateStarGeneratorObjectPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_OBJECT_PROTO, initStarGenerators));
+ }
+
+ static NativeObject* getOrCreateStarGeneratorFunctionPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION_PROTO, initStarGenerators));
+ }
+
+ static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators);
+ }
+
+ static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO,
+ initAsyncFunction));
+ }
+
+ static JSObject* getOrCreateAsyncFunction(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction);
+ }
+
+ static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto);
+ }
+
+ static JSObject* getOrCreateSetIteratorPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return global->getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto);
+ }
+
+ JSObject* getOrCreateDataViewPrototype(JSContext* cx) {
+ RootedGlobalObject self(cx, this);
+ if (!ensureConstructor(cx, self, JSProto_DataView))
+ return nullptr;
+ return &self->getPrototype(JSProto_DataView).toObject();
+ }
+
+ static JSFunction*
+ getOrCreatePromiseConstructor(JSContext* cx, Handle<GlobalObject*> global) {
+ if (!ensureConstructor(cx, global, JSProto_Promise))
+ return nullptr;
+ return &global->getConstructor(JSProto_Promise).toObject().as<JSFunction>();
+ }
+
+ static NativeObject* getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global);
+
+ bool maybeExistingIntrinsicValue(PropertyName* name, Value* vp) {
+ Value slot = getReservedSlot(INTRINSICS);
+ // If we're in the self-hosting compartment itself, the
+ // intrinsics-holder isn't initialized at this point.
+ if (slot.isUndefined()) {
+ *vp = UndefinedValue();
+ return false;
+ }
+
+ NativeObject* holder = &slot.toObject().as<NativeObject>();
+ Shape* shape = holder->lookupPure(name);
+ if (!shape) {
+ *vp = UndefinedValue();
+ return false;
+ }
+
+ *vp = holder->getSlot(shape->slot());
+ return true;
+ }
+
+ Value existingIntrinsicValue(PropertyName* name) {
+ Value val;
+ mozilla::DebugOnly<bool> exists = maybeExistingIntrinsicValue(name, &val);
+ MOZ_ASSERT(exists, "intrinsic must already have been added to holder");
+
+ return val;
+ }
+
+ static bool
+ maybeGetIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, Handle<PropertyName*> name,
+ MutableHandleValue vp, bool* exists)
+ {
+ NativeObject* holder = getIntrinsicsHolder(cx, global);
+ if (!holder)
+ return false;
+
+ if (Shape* shape = holder->lookupPure(name)) {
+ vp.set(holder->getSlot(shape->slot()));
+ *exists = true;
+ } else {
+ *exists = false;
+ }
+
+ return true;
+ }
+
+ static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, MutableHandleValue value)
+ {
+ bool exists = false;
+ if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists))
+ return false;
+ if (exists)
+ return true;
+ if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
+ return false;
+ return GlobalObject::addIntrinsicValue(cx, global, name, value);
+ }
+
+ static bool addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, HandleValue value);
+
+ static bool setIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName name, HandleValue value)
+ {
+ MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
+ RootedObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
+ if (!holder)
+ return false;
+ return SetProperty(cx, holder, name, value);
+ }
+
+ static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
+ HandlePropertyName selfHostedName, HandleAtom name,
+ unsigned nargs, MutableHandleValue funVal);
+
+ bool hasRegExpStatics() const;
+ RegExpStatics* getRegExpStatics(ExclusiveContext* cx) const;
+ RegExpStatics* getAlreadyCreatedRegExpStatics() const;
+
+ JSObject* getThrowTypeError() const {
+ const Value v = getReservedSlot(THROWTYPEERROR);
+ MOZ_ASSERT(v.isObject(),
+ "attempting to access [[ThrowTypeError]] too early");
+ return &v.toObject();
+ }
+
+ Value createDataViewForThis() const {
+ MOZ_ASSERT(dataViewClassInitialized());
+ return getSlot(CREATE_DATAVIEW_FOR_THIS);
+ }
+
+ template<typename T>
+ inline Value createArrayFromBuffer() const;
+
+ static bool isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Warn about use of the deprecated watch/unwatch functions in the global
+ // in which |obj| was created, if no prior warning was given.
+ static bool warnOnceAboutWatch(JSContext* cx, HandleObject obj) {
+ // Temporarily disabled until we've provided a watch/unwatch workaround for
+ // debuggers like Firebug (bug 934669).
+ //return warnOnceAbout(cx, obj, WARN_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED);
+ return true;
+ }
+
+ // Warn about use of the deprecated (static) ArrayBuffer.slice method.
+ static bool warnOnceAboutArrayBufferSlice(JSContext* cx, HandleObject obj) {
+ return warnOnceAbout(cx, obj, WARN_ARRAYBUFFER_SLICE_DEPRECATED,
+ JSMSG_ARRAYBUFFER_SLICE_DEPRECATED);
+ }
+
+ static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
+ MutableHandleObject eval);
+
+ // Infallibly test whether the given value is the eval function for this global.
+ bool valueIsEval(const Value& val);
+
+ // Implemented in jsiter.cpp.
+ static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in vm/GeneratorObject.cpp.
+ static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initStarGenerators(JSContext* cx, Handle<GlobalObject*> global);
+
+ static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in builtin/MapObject.cpp.
+ static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in Intl.cpp.
+ static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in builtin/ModuleObject.cpp
+ static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in builtin/TypedObject.cpp
+ static bool initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global);
+
+ // Implemented in builtin/SIMD.cpp
+ static bool initSimdObject(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType);
+
+ static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
+ const JSFunctionSpec* builtins);
+
+ typedef js::Vector<js::ReadBarriered<js::Debugger*>, 0, js::SystemAllocPolicy> DebuggerVector;
+
+ /*
+ * The collection of Debugger objects debugging this global. If this global
+ * is not a debuggee, this returns either nullptr or an empty vector.
+ */
+ DebuggerVector* getDebuggers() const;
+
+ /*
+ * The same, but create the empty vector if one does not already
+ * exist. Returns nullptr only on OOM.
+ */
+ static DebuggerVector* getOrCreateDebuggers(JSContext* cx, Handle<GlobalObject*> global);
+
+ inline NativeObject* getForOfPICObject() {
+ Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN);
+ if (forOfPIC.isUndefined())
+ return nullptr;
+ return &forOfPIC.toObject().as<NativeObject>();
+ }
+ static NativeObject* getOrCreateForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
+
+ JSObject* windowProxy() const {
+ return &getReservedSlot(WINDOW_PROXY).toObject();
+ }
+ JSObject* maybeWindowProxy() const {
+ Value v = getReservedSlot(WINDOW_PROXY);
+ MOZ_ASSERT(v.isObject() || v.isUndefined());
+ return v.isObject() ? &v.toObject() : nullptr;
+ }
+ void setWindowProxy(JSObject* windowProxy) {
+ setReservedSlot(WINDOW_PROXY, ObjectValue(*windowProxy));
+ }
+
+ void setModuleResolveHook(HandleFunction hook) {
+ MOZ_ASSERT(hook);
+ setSlot(MODULE_RESOLVE_HOOK, ObjectValue(*hook));
+ }
+
+ JSFunction* moduleResolveHook() {
+ Value value = getSlotRef(MODULE_RESOLVE_HOOK);
+ if (value.isUndefined())
+ return nullptr;
+
+ return &value.toObject().as<JSFunction>();
+ }
+
+ // Returns either this global's star-generator function prototype, or null
+ // if that object was never created. Dodgy; for use only in also-dodgy
+ // GlobalHelperThreadState::mergeParseTaskCompartment().
+ JSObject* getStarGeneratorFunctionPrototype();
+};
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<uint8_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<int8_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_INT8, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<uint16_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_UINT16, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<int16_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_INT16, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<uint32_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_UINT32, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<int32_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_INT32, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<float>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT32, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<double>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT64, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<uint8_clamped>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED, fun);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<uint8_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_UINT8);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<int8_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_INT8);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<uint16_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_UINT16);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<int16_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_INT16);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<uint32_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_UINT32);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<int32_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_INT32);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<float>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_FLOAT32);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<double>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_FLOAT64);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<uint8_clamped>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED);
+}
+
+/*
+ * Define ctor.prototype = proto as non-enumerable, non-configurable, and
+ * non-writable; define proto.constructor = ctor as non-enumerable but
+ * configurable and writable.
+ */
+extern bool
+LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto);
+
+/*
+ * Define properties and/or functions on any object. Either ps or fs, or both,
+ * may be null.
+ */
+extern bool
+DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
+ const JSPropertySpec* ps, const JSFunctionSpec* fs);
+
+typedef HashSet<GlobalObject*, DefaultHasher<GlobalObject*>, SystemAllocPolicy> GlobalObjectSet;
+
+extern bool
+DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag);
+
+/*
+ * Convenience templates to generic constructor and prototype creation functions
+ * for ClassSpecs.
+ */
+
+template<JSNative ctor, unsigned length, gc::AllocKind kind, const JSJitInfo* jitInfo = nullptr>
+JSObject*
+GenericCreateConstructor(JSContext* cx, JSProtoKey key)
+{
+ // Note - We duplicate the trick from ClassName() so that we don't need to
+ // include jsatominlines.h here.
+ PropertyName* name = (&cx->names().Null)[key];
+ return cx->global()->createConstructor(cx, ctor, name, length, kind, jitInfo);
+}
+
+inline JSObject*
+GenericCreatePrototype(JSContext* cx, JSProtoKey key)
+{
+ MOZ_ASSERT(key != JSProto_Object);
+ const Class* clasp = ProtoKeyToClass(key);
+ MOZ_ASSERT(clasp);
+ JSProtoKey protoKey = InheritanceProtoKeyForStandardClass(key);
+ if (!GlobalObject::ensureConstructor(cx, cx->global(), protoKey))
+ return nullptr;
+ RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject());
+ return cx->global()->createBlankPrototypeInheriting(cx, clasp, parentProto);
+}
+
+inline JSProtoKey
+StandardProtoKeyOrNull(const JSObject* obj)
+{
+ JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+ if (key == JSProto_Error)
+ return GetExceptionProtoKey(obj->as<ErrorObject>().type());
+ return key;
+}
+
+JSObject*
+NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global);
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::GlobalObject>() const
+{
+ return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
+}
+
+#endif /* vm_GlobalObject_h */
diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp
new file mode 100644
index 000000000..7381a97b5
--- /dev/null
+++ b/js/src/vm/HelperThreads.cpp
@@ -0,0 +1,1896 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/HelperThreads.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Unused.h"
+
+#include "jsnativestack.h"
+#include "jsnum.h" // For FIX_FPU()
+
+#include "builtin/Promise.h"
+#include "frontend/BytecodeCompiler.h"
+#include "gc/GCInternals.h"
+#include "jit/IonBuilder.h"
+#include "vm/Debugger.h"
+#include "vm/SharedImmutableStringsCache.h"
+#include "vm/Time.h"
+#include "vm/TraceLogging.h"
+#include "wasm/WasmIonCompile.h"
+
+#include "jscntxtinlines.h"
+#include "jscompartmentinlines.h"
+#include "jsobjinlines.h"
+#include "jsscriptinlines.h"
+
+using namespace js;
+
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::Unused;
+using mozilla::TimeDuration;
+
+namespace js {
+
+GlobalHelperThreadState* gHelperThreadState = nullptr;
+
+} // namespace js
+
+bool
+js::CreateHelperThreadsState()
+{
+ MOZ_ASSERT(!gHelperThreadState);
+ gHelperThreadState = js_new<GlobalHelperThreadState>();
+ return gHelperThreadState != nullptr;
+}
+
+void
+js::DestroyHelperThreadsState()
+{
+ MOZ_ASSERT(gHelperThreadState);
+ gHelperThreadState->finish();
+ js_delete(gHelperThreadState);
+ gHelperThreadState = nullptr;
+}
+
+bool
+js::EnsureHelperThreadsInitialized()
+{
+ MOZ_ASSERT(gHelperThreadState);
+ return gHelperThreadState->ensureInitialized();
+}
+
+static size_t
+ThreadCountForCPUCount(size_t cpuCount)
+{
+ // Create additional threads on top of the number of cores available, to
+ // provide some excess capacity in case threads pause each other.
+ static const uint32_t EXCESS_THREADS = 4;
+ return cpuCount + EXCESS_THREADS;
+}
+
+void
+js::SetFakeCPUCount(size_t count)
+{
+ // This must be called before the threads have been initialized.
+ MOZ_ASSERT(!HelperThreadState().threads);
+
+ HelperThreadState().cpuCount = count;
+ HelperThreadState().threadCount = ThreadCountForCPUCount(count);
+}
+
+bool
+js::StartOffThreadWasmCompile(wasm::IonCompileTask* task)
+{
+ AutoLockHelperThreadState lock;
+
+ // Don't append this task if another failed.
+ if (HelperThreadState().wasmFailed(lock))
+ return false;
+
+ if (!HelperThreadState().wasmWorklist(lock).append(task))
+ return false;
+
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+ return true;
+}
+
+bool
+js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
+{
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().ionWorklist(lock).append(builder))
+ return false;
+
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+ return true;
+}
+
+/*
+ * Move an IonBuilder for which compilation has either finished, failed, or
+ * been cancelled into the global finished compilation list. All off thread
+ * compilations which are started must eventually be finished.
+ */
+static void
+FinishOffThreadIonCompile(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock)
+{
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!HelperThreadState().ionFinishedList(lock).append(builder))
+ oomUnsafe.crash("FinishOffThreadIonCompile");
+}
+
+static JSRuntime*
+GetSelectorRuntime(CompilationSelector selector)
+{
+ struct Matcher
+ {
+ JSRuntime* match(JSScript* script) { return script->runtimeFromMainThread(); }
+ JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromMainThread(); }
+ JSRuntime* match(ZonesInState zbs) { return zbs.runtime; }
+ JSRuntime* match(JSRuntime* runtime) { return runtime; }
+ JSRuntime* match(AllCompilations all) { return nullptr; }
+ };
+
+ return selector.match(Matcher());
+}
+
+static bool
+JitDataStructuresExist(CompilationSelector selector)
+{
+ struct Matcher
+ {
+ bool match(JSScript* script) { return !!script->compartment()->jitCompartment(); }
+ bool match(JSCompartment* comp) { return !!comp->jitCompartment(); }
+ bool match(ZonesInState zbs) { return !!zbs.runtime->jitRuntime(); }
+ bool match(JSRuntime* runtime) { return !!runtime->jitRuntime(); }
+ bool match(AllCompilations all) { return true; }
+ };
+
+ return selector.match(Matcher());
+}
+
+static bool
+CompiledScriptMatches(CompilationSelector selector, JSScript* target)
+{
+ struct ScriptMatches
+ {
+ JSScript* target_;
+
+ bool match(JSScript* script) { return script == target_; }
+ bool match(JSCompartment* comp) { return comp == target_->compartment(); }
+ bool match(JSRuntime* runtime) { return runtime == target_->runtimeFromAnyThread(); }
+ bool match(AllCompilations all) { return true; }
+ bool match(ZonesInState zbs) {
+ return zbs.runtime == target_->runtimeFromAnyThread() &&
+ zbs.state == target_->zoneFromAnyThread()->gcState();
+ }
+ };
+
+ return selector.match(ScriptMatches{target});
+}
+
+void
+js::CancelOffThreadIonCompile(CompilationSelector selector, bool discardLazyLinkList)
+{
+ if (!JitDataStructuresExist(selector))
+ return;
+
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().threads)
+ return;
+
+ /* Cancel any pending entries for which processing hasn't started. */
+ GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist(lock);
+ for (size_t i = 0; i < worklist.length(); i++) {
+ jit::IonBuilder* builder = worklist[i];
+ if (CompiledScriptMatches(selector, builder->script())) {
+ FinishOffThreadIonCompile(builder, lock);
+ HelperThreadState().remove(worklist, &i);
+ }
+ }
+
+ /* Wait for in progress entries to finish up. */
+ bool cancelled;
+ do {
+ cancelled = false;
+ bool unpaused = false;
+ for (auto& helper : *HelperThreadState().threads) {
+ if (helper.ionBuilder() &&
+ CompiledScriptMatches(selector, helper.ionBuilder()->script()))
+ {
+ helper.ionBuilder()->cancel();
+ if (helper.pause) {
+ helper.pause = false;
+ unpaused = true;
+ }
+ cancelled = true;
+ }
+ }
+ if (unpaused)
+ HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, lock);
+ if (cancelled)
+ HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
+ } while (cancelled);
+
+ /* Cancel code generation for any completed entries. */
+ GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
+ for (size_t i = 0; i < finished.length(); i++) {
+ jit::IonBuilder* builder = finished[i];
+ if (CompiledScriptMatches(selector, builder->script())) {
+ jit::FinishOffThreadBuilder(nullptr, builder, lock);
+ HelperThreadState().remove(finished, &i);
+ }
+ }
+
+ /* Cancel lazy linking for pending builders (attached to the ionScript). */
+ if (discardLazyLinkList) {
+ MOZ_ASSERT(!selector.is<AllCompilations>());
+ JSRuntime* runtime = GetSelectorRuntime(selector);
+ jit::IonBuilder* builder = runtime->ionLazyLinkList().getFirst();
+ while (builder) {
+ jit::IonBuilder* next = builder->getNext();
+ if (CompiledScriptMatches(selector, builder->script()))
+ jit::FinishOffThreadBuilder(runtime, builder, lock);
+ builder = next;
+ }
+ }
+}
+
+#ifdef DEBUG
+bool
+js::HasOffThreadIonCompile(JSCompartment* comp)
+{
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().threads)
+ return false;
+
+ GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist(lock);
+ for (size_t i = 0; i < worklist.length(); i++) {
+ jit::IonBuilder* builder = worklist[i];
+ if (builder->script()->compartment() == comp)
+ return true;
+ }
+
+ for (auto& helper : *HelperThreadState().threads) {
+ if (helper.ionBuilder() && helper.ionBuilder()->script()->compartment() == comp)
+ return true;
+ }
+
+ GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
+ for (size_t i = 0; i < finished.length(); i++) {
+ jit::IonBuilder* builder = finished[i];
+ if (builder->script()->compartment() == comp)
+ return true;
+ }
+
+ jit::IonBuilder* builder = comp->runtimeFromMainThread()->ionLazyLinkList().getFirst();
+ while (builder) {
+ if (builder->script()->compartment() == comp)
+ return true;
+ builder = builder->getNext();
+ }
+
+ return false;
+}
+#endif
+
+static const JSClassOps parseTaskGlobalClassOps = {
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ JS_GlobalObjectTraceHook
+};
+
+static const JSClass parseTaskGlobalClass = {
+ "internal-parse-task-global", JSCLASS_GLOBAL_FLAGS,
+ &parseTaskGlobalClassOps
+};
+
+ParseTask::ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData)
+ : kind(kind), cx(cx), options(initCx), chars(chars), length(length),
+ alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+ exclusiveContextGlobal(exclusiveContextGlobal),
+ callback(callback), callbackData(callbackData),
+ script(nullptr), sourceObject(nullptr),
+ errors(cx), overRecursed(false), outOfMemory(false)
+{
+}
+
+bool
+ParseTask::init(JSContext* cx, const ReadOnlyCompileOptions& options)
+{
+ if (!this->options.copy(cx, options))
+ return false;
+
+ return true;
+}
+
+void
+ParseTask::activate(JSRuntime* rt)
+{
+ rt->setUsedByExclusiveThread(exclusiveContextGlobal->zone());
+ cx->enterCompartment(exclusiveContextGlobal->compartment());
+}
+
+bool
+ParseTask::finish(JSContext* cx)
+{
+ if (sourceObject) {
+ RootedScriptSource sso(cx, sourceObject);
+ if (!ScriptSourceObject::initFromOptions(cx, sso, options))
+ return false;
+ }
+
+ return true;
+}
+
+ParseTask::~ParseTask()
+{
+ // ParseTask takes over ownership of its input exclusive context.
+ js_delete(cx);
+
+ for (size_t i = 0; i < errors.length(); i++)
+ js_delete(errors[i]);
+}
+
+void
+ParseTask::trace(JSTracer* trc)
+{
+ if (!cx->runtimeMatches(trc->runtime()))
+ return;
+
+ TraceManuallyBarrieredEdge(trc, &exclusiveContextGlobal, "ParseTask::exclusiveContextGlobal");
+ if (script)
+ TraceManuallyBarrieredEdge(trc, &script, "ParseTask::script");
+ if (sourceObject)
+ TraceManuallyBarrieredEdge(trc, &sourceObject, "ParseTask::sourceObject");
+}
+
+ScriptParseTask::ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData)
+ : ParseTask(ParseTaskKind::Script, cx, exclusiveContextGlobal, initCx, chars, length, callback,
+ callbackData)
+{
+}
+
+void
+ScriptParseTask::parse()
+{
+ SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
+ script = frontend::CompileGlobalScript(cx, alloc, ScopeKind::Global,
+ options, srcBuf,
+ /* extraSct = */ nullptr,
+ /* sourceObjectOut = */ &sourceObject);
+}
+
+ModuleParseTask::ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData)
+ : ParseTask(ParseTaskKind::Module, cx, exclusiveContextGlobal, initCx, chars, length, callback,
+ callbackData)
+{
+}
+
+void
+ModuleParseTask::parse()
+{
+ SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
+ ModuleObject* module = frontend::CompileModule(cx, options, srcBuf, alloc, &sourceObject);
+ if (module)
+ script = module->script();
+}
+
+void
+js::CancelOffThreadParses(JSRuntime* rt)
+{
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().threads)
+ return;
+
+#ifdef DEBUG
+ GlobalHelperThreadState::ParseTaskVector& waitingOnGC =
+ HelperThreadState().parseWaitingOnGC(lock);
+ for (size_t i = 0; i < waitingOnGC.length(); i++)
+ MOZ_ASSERT(!waitingOnGC[i]->runtimeMatches(rt));
+#endif
+
+ // Instead of forcibly canceling pending parse tasks, just wait for all scheduled
+ // and in progress ones to complete. Otherwise the final GC may not collect
+ // everything due to zones being used off thread.
+ while (true) {
+ bool pending = false;
+ GlobalHelperThreadState::ParseTaskVector& worklist = HelperThreadState().parseWorklist(lock);
+ for (size_t i = 0; i < worklist.length(); i++) {
+ ParseTask* task = worklist[i];
+ if (task->runtimeMatches(rt))
+ pending = true;
+ }
+ if (!pending) {
+ bool inProgress = false;
+ for (auto& thread : *HelperThreadState().threads) {
+ ParseTask* task = thread.parseTask();
+ if (task && task->runtimeMatches(rt))
+ inProgress = true;
+ }
+ if (!inProgress)
+ break;
+ }
+ HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
+ }
+
+ // Clean up any parse tasks which haven't been finished by the main thread.
+ GlobalHelperThreadState::ParseTaskVector& finished = HelperThreadState().parseFinishedList(lock);
+ while (true) {
+ bool found = false;
+ for (size_t i = 0; i < finished.length(); i++) {
+ ParseTask* task = finished[i];
+ if (task->runtimeMatches(rt)) {
+ found = true;
+ AutoUnlockHelperThreadState unlock(lock);
+ HelperThreadState().cancelParseTask(rt->contextFromMainThread(), task->kind, task);
+ }
+ }
+ if (!found)
+ break;
+ }
+}
+
+bool
+js::OffThreadParsingMustWaitForGC(JSRuntime* rt)
+{
+ // Off thread parsing can't occur during incremental collections on the
+ // atoms compartment, to avoid triggering barriers. (Outside the atoms
+ // compartment, the compilation will use a new zone that is never
+ // collected.) If an atoms-zone GC is in progress, hold off on executing the
+ // parse task until the atoms-zone GC completes (see
+ // EnqueuePendingParseTasksAfterGC).
+ return rt->activeGCInAtomsZone();
+}
+
+static bool
+EnsureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
+{
+ if (!GlobalObject::ensureConstructor(cx, global, key))
+ return false;
+
+ MOZ_ASSERT(global->getPrototype(key).toObject().isDelegate(),
+ "standard class prototype wasn't a delegate from birth");
+ return true;
+}
+
+// Initialize all classes potentially created during parsing for use in parser
+// data structures, template objects, &c.
+static bool
+EnsureParserCreatedClasses(JSContext* cx, ParseTaskKind kind)
+{
+ Handle<GlobalObject*> global = cx->global();
+
+ if (!EnsureConstructor(cx, global, JSProto_Function))
+ return false; // needed by functions, also adds object literals' proto
+
+ if (!EnsureConstructor(cx, global, JSProto_Array))
+ return false; // needed by array literals
+
+ if (!EnsureConstructor(cx, global, JSProto_RegExp))
+ return false; // needed by regular expression literals
+
+ if (!EnsureConstructor(cx, global, JSProto_Iterator))
+ return false; // needed by ???
+
+ if (!GlobalObject::initStarGenerators(cx, global))
+ return false; // needed by function*() {} and generator comprehensions
+
+ if (kind == ParseTaskKind::Module && !GlobalObject::ensureModulePrototypesCreated(cx, global))
+ return false;
+
+ return true;
+}
+
+static JSObject*
+CreateGlobalForOffThreadParse(JSContext* cx, ParseTaskKind kind, const gc::AutoSuppressGC& nogc)
+{
+ JSCompartment* currentCompartment = cx->compartment();
+
+ JS::CompartmentOptions compartmentOptions(currentCompartment->creationOptions(),
+ currentCompartment->behaviors());
+
+ auto& creationOptions = compartmentOptions.creationOptions();
+
+ creationOptions.setInvisibleToDebugger(true)
+ .setMergeable(true)
+ .setZone(JS::FreshZone);
+
+ // Don't falsely inherit the host's global trace hook.
+ creationOptions.setTrace(nullptr);
+
+ JSObject* global = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr,
+ JS::FireOnNewGlobalHook, compartmentOptions);
+ if (!global)
+ return nullptr;
+
+ JS_SetCompartmentPrincipals(global->compartment(), currentCompartment->principals());
+
+ // Initialize all classes required for parsing while still on the main
+ // thread, for both the target and the new global so that prototype
+ // pointers can be changed infallibly after parsing finishes.
+ if (!EnsureParserCreatedClasses(cx, kind))
+ return nullptr;
+ {
+ AutoCompartment ac(cx, global);
+ if (!EnsureParserCreatedClasses(cx, kind))
+ return nullptr;
+ }
+
+ return global;
+}
+
+static bool
+QueueOffThreadParseTask(JSContext* cx, ParseTask* task)
+{
+ if (OffThreadParsingMustWaitForGC(cx->runtime())) {
+ AutoLockHelperThreadState lock;
+ if (!HelperThreadState().parseWaitingOnGC(lock).append(task)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ } else {
+ AutoLockHelperThreadState lock;
+ if (!HelperThreadState().parseWorklist(lock).append(task)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ task->activate(cx->runtime());
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+ }
+
+ return true;
+}
+
+bool
+js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData)
+{
+ // Suppress GC so that calls below do not trigger a new incremental GC
+ // which could require barriers on the atoms compartment.
+ gc::AutoSuppressGC nogc(cx);
+ gc::AutoAssertNoNurseryAlloc noNurseryAlloc(cx->runtime());
+ AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
+
+ JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Script, nogc);
+ if (!global)
+ return false;
+
+ ScopedJSDeletePtr<ExclusiveContext> helpercx(
+ cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
+ ExclusiveContext::Context_Exclusive, cx->options()));
+ if (!helpercx)
+ return false;
+
+ ScopedJSDeletePtr<ParseTask> task(
+ cx->new_<ScriptParseTask>(helpercx.get(), global, cx, chars, length,
+ callback, callbackData));
+ if (!task)
+ return false;
+
+ helpercx.forget();
+
+ if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task))
+ return false;
+
+ task.forget();
+
+ return true;
+}
+
+bool
+js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData)
+{
+ // Suppress GC so that calls below do not trigger a new incremental GC
+ // which could require barriers on the atoms compartment.
+ gc::AutoSuppressGC nogc(cx);
+ gc::AutoAssertNoNurseryAlloc noNurseryAlloc(cx->runtime());
+ AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
+
+ JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Module, nogc);
+ if (!global)
+ return false;
+
+ ScopedJSDeletePtr<ExclusiveContext> helpercx(
+ cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
+ ExclusiveContext::Context_Exclusive, cx->options()));
+ if (!helpercx)
+ return false;
+
+ ScopedJSDeletePtr<ParseTask> task(
+ cx->new_<ModuleParseTask>(helpercx.get(), global, cx, chars, length,
+ callback, callbackData));
+ if (!task)
+ return false;
+
+ helpercx.forget();
+
+ if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task))
+ return false;
+
+ task.forget();
+
+ return true;
+}
+
+void
+js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
+{
+ MOZ_ASSERT(!OffThreadParsingMustWaitForGC(rt));
+
+ GlobalHelperThreadState::ParseTaskVector newTasks;
+ {
+ AutoLockHelperThreadState lock;
+ GlobalHelperThreadState::ParseTaskVector& waiting =
+ HelperThreadState().parseWaitingOnGC(lock);
+
+ for (size_t i = 0; i < waiting.length(); i++) {
+ ParseTask* task = waiting[i];
+ if (task->runtimeMatches(rt)) {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!newTasks.append(task))
+ oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
+ HelperThreadState().remove(waiting, &i);
+ }
+ }
+ }
+
+ if (newTasks.empty())
+ return;
+
+ // This logic should mirror the contents of the !activeGCInAtomsZone()
+ // branch in StartOffThreadParseScript:
+
+ for (size_t i = 0; i < newTasks.length(); i++)
+ newTasks[i]->activate(rt);
+
+ AutoLockHelperThreadState lock;
+
+ {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!HelperThreadState().parseWorklist(lock).appendAll(newTasks))
+ oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
+ }
+
+ HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, lock);
+}
+
+static const uint32_t kDefaultHelperStackSize = 2048 * 1024;
+static const uint32_t kDefaultHelperStackQuota = 1800 * 1024;
+
+// TSan enforces a minimum stack size that's just slightly larger than our
+// default helper stack size. It does this to store blobs of TSan-specific
+// data on each thread's stack. Unfortunately, that means that even though
+// we'll actually receive a larger stack than we requested, the effective
+// usable space of that stack is significantly less than what we expect.
+// To offset TSan stealing our stack space from underneath us, double the
+// default.
+//
+// Note that we don't need this for ASan/MOZ_ASAN because ASan doesn't
+// require all the thread-specific state that TSan does.
+#if defined(MOZ_TSAN)
+static const uint32_t HELPER_STACK_SIZE = 2 * kDefaultHelperStackSize;
+static const uint32_t HELPER_STACK_QUOTA = 2 * kDefaultHelperStackQuota;
+#else
+static const uint32_t HELPER_STACK_SIZE = kDefaultHelperStackSize;
+static const uint32_t HELPER_STACK_QUOTA = kDefaultHelperStackQuota;
+#endif
+
+bool
+GlobalHelperThreadState::ensureInitialized()
+{
+ MOZ_ASSERT(CanUseExtraThreads());
+
+ MOZ_ASSERT(this == &HelperThreadState());
+ AutoLockHelperThreadState lock;
+
+ if (threads)
+ return true;
+
+ threads = js::UniquePtr<HelperThreadVector>(js_new<HelperThreadVector>());
+ if (!threads || !threads->initCapacity(threadCount))
+ return false;
+
+ for (size_t i = 0; i < threadCount; i++) {
+ threads->infallibleEmplaceBack();
+ HelperThread& helper = (*threads)[i];
+
+ helper.threadData.emplace(static_cast<JSRuntime*>(nullptr));
+ if (!helper.threadData->init())
+ goto error;
+
+ helper.thread = mozilla::Some(Thread(Thread::Options().setStackSize(HELPER_STACK_SIZE)));
+ if (!helper.thread->init(HelperThread::ThreadMain, &helper))
+ goto error;
+
+ continue;
+
+ error:
+ // Ensure that we do not leave uninitialized threads in the `threads`
+ // vector.
+ threads->popBack();
+ finishThreads();
+ return false;
+ }
+
+ return true;
+}
+
+GlobalHelperThreadState::GlobalHelperThreadState()
+ : cpuCount(0),
+ threadCount(0),
+ threads(nullptr),
+ wasmCompilationInProgress(false),
+ numWasmFailedJobs(0),
+ helperLock(mutexid::GlobalHelperThreadState)
+{
+ cpuCount = GetCPUCount();
+ threadCount = ThreadCountForCPUCount(cpuCount);
+
+ MOZ_ASSERT(cpuCount > 0, "GetCPUCount() seems broken");
+}
+
+void
+GlobalHelperThreadState::finish()
+{
+ finishThreads();
+}
+
+void
+GlobalHelperThreadState::finishThreads()
+{
+ if (!threads)
+ return;
+
+ MOZ_ASSERT(CanUseExtraThreads());
+ for (auto& thread : *threads)
+ thread.destroy();
+ threads.reset(nullptr);
+}
+
+void
+GlobalHelperThreadState::lock()
+{
+ helperLock.lock();
+}
+
+void
+GlobalHelperThreadState::unlock()
+{
+ helperLock.unlock();
+}
+
+void
+GlobalHelperThreadState::wait(AutoLockHelperThreadState& locked, CondVar which,
+ TimeDuration timeout /* = TimeDuration::Forever() */)
+{
+ whichWakeup(which).wait_for(locked, timeout);
+}
+
+void
+GlobalHelperThreadState::notifyAll(CondVar which, const AutoLockHelperThreadState&)
+{
+ whichWakeup(which).notify_all();
+}
+
+void
+GlobalHelperThreadState::notifyOne(CondVar which, const AutoLockHelperThreadState&)
+{
+ whichWakeup(which).notify_one();
+}
+
+bool
+GlobalHelperThreadState::hasActiveThreads(const AutoLockHelperThreadState&)
+{
+ if (!threads)
+ return false;
+
+ for (auto& thread : *threads) {
+ if (!thread.idle())
+ return true;
+ }
+
+ return false;
+}
+
+void
+GlobalHelperThreadState::waitForAllThreads()
+{
+ CancelOffThreadIonCompile();
+
+ AutoLockHelperThreadState lock;
+ while (hasActiveThreads(lock))
+ wait(lock, CONSUMER);
+}
+
+template <typename T>
+bool
+GlobalHelperThreadState::checkTaskThreadLimit(size_t maxThreads) const
+{
+ if (maxThreads >= threadCount)
+ return true;
+
+ size_t count = 0;
+ for (auto& thread : *threads) {
+ if (thread.currentTask.isSome() && thread.currentTask->is<T>())
+ count++;
+ if (count >= maxThreads)
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool
+IsHelperThreadSimulatingOOM(js::oom::ThreadType threadType)
+{
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+ return js::oom::targetThread == threadType;
+#else
+ return false;
+#endif
+}
+
+size_t
+GlobalHelperThreadState::maxIonCompilationThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_ION))
+ return 1;
+ return threadCount;
+}
+
+size_t
+GlobalHelperThreadState::maxUnpausedIonCompilationThreads() const
+{
+ return 1;
+}
+
+size_t
+GlobalHelperThreadState::maxWasmCompilationThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_ASMJS))
+ return 1;
+ if (cpuCount < 2)
+ return 2;
+ return cpuCount;
+}
+
+size_t
+GlobalHelperThreadState::maxParseThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_PARSE))
+ return 1;
+
+ // Don't allow simultaneous off thread parses, to reduce contention on the
+ // atoms table. Note that wasm compilation depends on this to avoid
+ // stalling the helper thread, as off thread parse tasks can trigger and
+ // block on other off thread wasm compilation tasks.
+ return 1;
+}
+
+size_t
+GlobalHelperThreadState::maxCompressionThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_COMPRESS))
+ return 1;
+ return threadCount;
+}
+
+size_t
+GlobalHelperThreadState::maxGCHelperThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_GCHELPER))
+ return 1;
+ return threadCount;
+}
+
+size_t
+GlobalHelperThreadState::maxGCParallelThreads() const
+{
+ if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_GCPARALLEL))
+ return 1;
+ return threadCount;
+}
+
+bool
+GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock)
+{
+ // Don't execute an wasm job if an earlier one failed.
+ if (wasmWorklist(lock).empty() || numWasmFailedJobs)
+ return false;
+
+ // Honor the maximum allowed threads to compile wasm jobs at once,
+ // to avoid oversaturating the machine.
+ if (!checkTaskThreadLimit<wasm::IonCompileTask*>(maxWasmCompilationThreads()))
+ return false;
+
+ return true;
+}
+
+bool
+GlobalHelperThreadState::canStartPromiseTask(const AutoLockHelperThreadState& lock)
+{
+ return !promiseTasks(lock).empty();
+}
+
+static bool
+IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second)
+{
+ // This method can return whatever it wants, though it really ought to be a
+ // total order. The ordering is allowed to race (change on the fly), however.
+
+ // A lower optimization level indicates a higher priority.
+ if (first->optimizationInfo().level() != second->optimizationInfo().level())
+ return first->optimizationInfo().level() < second->optimizationInfo().level();
+
+ // A script without an IonScript has precedence on one with.
+ if (first->scriptHasIonScript() != second->scriptHasIonScript())
+ return !first->scriptHasIonScript();
+
+ // A higher warm-up counter indicates a higher priority.
+ return first->script()->getWarmUpCount() / first->script()->length() >
+ second->script()->getWarmUpCount() / second->script()->length();
+}
+
+bool
+GlobalHelperThreadState::canStartIonCompile(const AutoLockHelperThreadState& lock)
+{
+ return !ionWorklist(lock).empty() &&
+ checkTaskThreadLimit<jit::IonBuilder*>(maxIonCompilationThreads());
+}
+
+jit::IonBuilder*
+GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
+ bool remove /* = false */)
+{
+ auto& worklist = ionWorklist(lock);
+ if (worklist.empty()) {
+ MOZ_ASSERT(!remove);
+ return nullptr;
+ }
+
+ // Get the highest priority IonBuilder which has not started compilation yet.
+ size_t index = 0;
+ for (size_t i = 1; i < worklist.length(); i++) {
+ if (IonBuilderHasHigherPriority(worklist[i], worklist[index]))
+ index = i;
+ }
+ jit::IonBuilder* builder = worklist[index];
+ if (remove)
+ worklist.erase(&worklist[index]);
+ return builder;
+}
+
+HelperThread*
+GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold(
+ const AutoLockHelperThreadState& lock)
+{
+ // Get the lowest priority IonBuilder which has started compilation and
+ // isn't paused, unless there are still fewer than the maximum number of
+ // such builders permitted.
+ size_t numBuilderThreads = 0;
+ HelperThread* thread = nullptr;
+ for (auto& thisThread : *threads) {
+ if (thisThread.ionBuilder() && !thisThread.pause) {
+ numBuilderThreads++;
+ if (!thread ||
+ IonBuilderHasHigherPriority(thread->ionBuilder(), thisThread.ionBuilder()))
+ {
+ thread = &thisThread;
+ }
+ }
+ }
+ if (numBuilderThreads < maxUnpausedIonCompilationThreads())
+ return nullptr;
+ return thread;
+}
+
+HelperThread*
+GlobalHelperThreadState::highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock)
+{
+ // Get the highest priority IonBuilder which has started compilation but
+ // which was subsequently paused.
+ HelperThread* thread = nullptr;
+ for (auto& thisThread : *threads) {
+ if (thisThread.pause) {
+ // Currently, only threads with IonBuilders can be paused.
+ MOZ_ASSERT(thisThread.ionBuilder());
+ if (!thread ||
+ IonBuilderHasHigherPriority(thisThread.ionBuilder(), thread->ionBuilder()))
+ {
+ thread = &thisThread;
+ }
+ }
+ }
+ return thread;
+}
+
+bool
+GlobalHelperThreadState::pendingIonCompileHasSufficientPriority(
+ const AutoLockHelperThreadState& lock)
+{
+ // Can't compile anything if there are no scripts to compile.
+ if (!canStartIonCompile(lock))
+ return false;
+
+ // Count the number of threads currently compiling scripts, and look for
+ // the thread with the lowest priority.
+ HelperThread* lowestPriorityThread = lowestPriorityUnpausedIonCompileAtThreshold(lock);
+
+ // If the number of threads building scripts is less than the maximum, the
+ // compilation can start immediately.
+ if (!lowestPriorityThread)
+ return true;
+
+ // If there is a builder in the worklist with higher priority than some
+ // builder currently being compiled, then that current compilation can be
+ // paused, so allow the compilation.
+ if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(lock),
+ lowestPriorityThread->ionBuilder()))
+ return true;
+
+ // Compilation will have to wait until one of the active compilations finishes.
+ return false;
+}
+
+bool
+GlobalHelperThreadState::canStartParseTask(const AutoLockHelperThreadState& lock)
+{
+ return !parseWorklist(lock).empty() && checkTaskThreadLimit<ParseTask*>(maxParseThreads());
+}
+
+bool
+GlobalHelperThreadState::canStartCompressionTask(const AutoLockHelperThreadState& lock)
+{
+ return !compressionWorklist(lock).empty() &&
+ checkTaskThreadLimit<SourceCompressionTask*>(maxCompressionThreads());
+}
+
+bool
+GlobalHelperThreadState::canStartGCHelperTask(const AutoLockHelperThreadState& lock)
+{
+ return !gcHelperWorklist(lock).empty() &&
+ checkTaskThreadLimit<GCHelperState*>(maxGCHelperThreads());
+}
+
+bool
+GlobalHelperThreadState::canStartGCParallelTask(const AutoLockHelperThreadState& lock)
+{
+ return !gcParallelWorklist(lock).empty() &&
+ checkTaskThreadLimit<GCParallelTask*>(maxGCParallelThreads());
+}
+
+js::GCParallelTask::~GCParallelTask()
+{
+ // Only most-derived classes' destructors may do the join: base class
+ // destructors run after those for derived classes' members, so a join in a
+ // base class can't ensure that the task is done using the members. All we
+ // can do now is check that someone has previously stopped the task.
+#ifdef DEBUG
+ AutoLockHelperThreadState helperLock;
+ MOZ_ASSERT(state == NotStarted);
+#endif
+}
+
+bool
+js::GCParallelTask::startWithLockHeld(AutoLockHelperThreadState& lock)
+{
+ // Tasks cannot be started twice.
+ MOZ_ASSERT(state == NotStarted);
+
+ // If we do the shutdown GC before running anything, we may never
+ // have initialized the helper threads. Just use the serial path
+ // since we cannot safely intialize them at this point.
+ if (!HelperThreadState().threads)
+ return false;
+
+ if (!HelperThreadState().gcParallelWorklist(lock).append(this))
+ return false;
+ state = Dispatched;
+
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+
+ return true;
+}
+
+bool
+js::GCParallelTask::start()
+{
+ AutoLockHelperThreadState helperLock;
+ return startWithLockHeld(helperLock);
+}
+
+void
+js::GCParallelTask::joinWithLockHeld(AutoLockHelperThreadState& locked)
+{
+ if (state == NotStarted)
+ return;
+
+ while (state != Finished)
+ HelperThreadState().wait(locked, GlobalHelperThreadState::CONSUMER);
+ state = NotStarted;
+ cancel_ = false;
+}
+
+void
+js::GCParallelTask::join()
+{
+ AutoLockHelperThreadState helperLock;
+ joinWithLockHeld(helperLock);
+}
+
+void
+js::GCParallelTask::runFromMainThread(JSRuntime* rt)
+{
+ MOZ_ASSERT(state == NotStarted);
+ MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt));
+ uint64_t timeStart = PRMJ_Now();
+ run();
+ duration_ = PRMJ_Now() - timeStart;
+}
+
+void
+js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
+{
+ {
+ AutoUnlockHelperThreadState parallelSection(locked);
+ gc::AutoSetThreadIsPerformingGC performingGC;
+ uint64_t timeStart = PRMJ_Now();
+ run();
+ duration_ = PRMJ_Now() - timeStart;
+ }
+
+ state = Finished;
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+}
+
+bool
+js::GCParallelTask::isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const
+{
+ return state == Dispatched;
+}
+
+bool
+js::GCParallelTask::isRunning() const
+{
+ AutoLockHelperThreadState helperLock;
+ return isRunningWithLockHeld(helperLock);
+}
+
+void
+HelperThread::handleGCParallelWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartGCParallelTask(locked));
+ MOZ_ASSERT(idle());
+
+ TraceLoggerThread* logger = TraceLoggerForCurrentThread();
+ AutoTraceLog logCompile(logger, TraceLogger_GC);
+
+ currentTask.emplace(HelperThreadState().gcParallelWorklist(locked).popCopy());
+ gcParallelTask()->runFromHelperThread(locked);
+ currentTask.reset();
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+}
+
+static void
+LeaveParseTaskZone(JSRuntime* rt, ParseTask* task)
+{
+ // Mark the zone as no longer in use by an ExclusiveContext, and available
+ // to be collected by the GC.
+ task->cx->leaveCompartment(task->cx->compartment());
+ rt->clearUsedByExclusiveThread(task->cx->zone());
+}
+
+ParseTask*
+GlobalHelperThreadState::removeFinishedParseTask(ParseTaskKind kind, void* token)
+{
+ // The token is a ParseTask* which should be in the finished list.
+ // Find and remove its entry.
+
+ AutoLockHelperThreadState lock;
+ ParseTaskVector& finished = parseFinishedList(lock);
+
+ for (size_t i = 0; i < finished.length(); i++) {
+ if (finished[i] == token) {
+ ParseTask* parseTask = finished[i];
+ remove(finished, &i);
+ MOZ_ASSERT(parseTask);
+ MOZ_ASSERT(parseTask->kind == kind);
+ return parseTask;
+ }
+ }
+
+ MOZ_CRASH("Invalid ParseTask token");
+}
+
+JSScript*
+GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind, void* token)
+{
+ MOZ_ASSERT(cx->compartment());
+
+ ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
+
+ // Make sure we have all the constructors we need for the prototype
+ // remapping below, since we can't GC while that's happening.
+ Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>());
+ if (!EnsureParserCreatedClasses(cx, kind)) {
+ LeaveParseTaskZone(cx, parseTask);
+ return nullptr;
+ }
+
+ mergeParseTaskCompartment(cx, parseTask, global, cx->compartment());
+
+ RootedScript script(cx, parseTask->script);
+ releaseAssertSameCompartment(cx, script);
+
+ if (!parseTask->finish(cx))
+ return nullptr;
+
+ // Report out of memory errors eagerly, or errors could be malformed.
+ if (parseTask->outOfMemory) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ // Report any error or warnings generated during the parse, and inform the
+ // debugger about the compiled scripts.
+ for (size_t i = 0; i < parseTask->errors.length(); i++)
+ parseTask->errors[i]->throwError(cx);
+ if (parseTask->overRecursed)
+ ReportOverRecursed(cx);
+ if (cx->isExceptionPending())
+ return nullptr;
+
+ if (!script) {
+ // No error was reported, but no script produced. Assume we hit out of
+ // memory.
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ // The Debugger only needs to be told about the topmost script that was compiled.
+ Debugger::onNewScript(cx, script);
+
+ return script;
+}
+
+JSScript*
+GlobalHelperThreadState::finishScriptParseTask(JSContext* cx, void* token)
+{
+ JSScript* script = finishParseTask(cx, ParseTaskKind::Script, token);
+ MOZ_ASSERT_IF(script, script->isGlobalCode());
+ return script;
+}
+
+JSObject*
+GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, void* token)
+{
+ JSScript* script = finishParseTask(cx, ParseTaskKind::Module, token);
+ if (!script)
+ return nullptr;
+
+ MOZ_ASSERT(script->module());
+
+ RootedModuleObject module(cx, script->module());
+ module->fixEnvironmentsAfterCompartmentMerge(cx);
+ if (!ModuleObject::Freeze(cx, module))
+ return nullptr;
+
+ return module;
+}
+
+void
+GlobalHelperThreadState::cancelParseTask(JSContext* cx, ParseTaskKind kind, void* token)
+{
+ ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
+ LeaveParseTaskZone(cx, parseTask);
+}
+
+JSObject*
+GlobalObject::getStarGeneratorFunctionPrototype()
+{
+ const Value& v = getReservedSlot(STAR_GENERATOR_FUNCTION_PROTO);
+ return v.isObject() ? &v.toObject() : nullptr;
+}
+
+void
+GlobalHelperThreadState::mergeParseTaskCompartment(JSContext* cx, ParseTask* parseTask,
+ Handle<GlobalObject*> global,
+ JSCompartment* dest)
+{
+ // After we call LeaveParseTaskZone() it's not safe to GC until we have
+ // finished merging the contents of the parse task's compartment into the
+ // destination compartment. Finish any ongoing incremental GC first and
+ // assert that no allocation can occur.
+ gc::FinishGC(cx);
+ JS::AutoAssertNoGC nogc(cx);
+
+ LeaveParseTaskZone(cx, parseTask);
+
+ {
+ // Generator functions don't have Function.prototype as prototype but a
+ // different function object, so the IdentifyStandardPrototype trick
+ // below won't work. Just special-case it.
+ GlobalObject* parseGlobal = &parseTask->exclusiveContextGlobal->as<GlobalObject>();
+ JSObject* parseTaskStarGenFunctionProto = parseGlobal->getStarGeneratorFunctionPrototype();
+
+ // Module objects don't have standard prototypes either.
+ JSObject* moduleProto = parseGlobal->maybeGetModulePrototype();
+ JSObject* importEntryProto = parseGlobal->maybeGetImportEntryPrototype();
+ JSObject* exportEntryProto = parseGlobal->maybeGetExportEntryPrototype();
+
+ // Point the prototypes of any objects in the script's compartment to refer
+ // to the corresponding prototype in the new compartment. This will briefly
+ // create cross compartment pointers, which will be fixed by the
+ // MergeCompartments call below.
+ for (auto group = parseTask->cx->zone()->cellIter<ObjectGroup>(); !group.done(); group.next()) {
+ TaggedProto proto(group->proto());
+ if (!proto.isObject())
+ continue;
+
+ JSObject* protoObj = proto.toObject();
+
+ JSObject* newProto;
+ JSProtoKey key = JS::IdentifyStandardPrototype(protoObj);
+ if (key != JSProto_Null) {
+ MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array ||
+ key == JSProto_Function || key == JSProto_RegExp ||
+ key == JSProto_Iterator);
+ newProto = GetBuiltinPrototypePure(global, key);
+ } else if (protoObj == parseTaskStarGenFunctionProto) {
+ newProto = global->getStarGeneratorFunctionPrototype();
+ } else if (protoObj == moduleProto) {
+ newProto = global->getModulePrototype();
+ } else if (protoObj == importEntryProto) {
+ newProto = global->getImportEntryPrototype();
+ } else if (protoObj == exportEntryProto) {
+ newProto = global->getExportEntryPrototype();
+ } else {
+ continue;
+ }
+
+ group->setProtoUnchecked(TaggedProto(newProto));
+ }
+ }
+
+ // Move the parsed script and all its contents into the desired compartment.
+ gc::MergeCompartments(parseTask->cx->compartment(), dest);
+}
+
+void
+HelperThread::destroy()
+{
+ if (thread.isSome()) {
+ {
+ AutoLockHelperThreadState lock;
+ terminate = true;
+
+ /* Notify all helpers, to ensure that this thread wakes up. */
+ HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, lock);
+ }
+
+ thread->join();
+ thread.reset();
+ }
+
+ threadData.reset();
+}
+
+/* static */
+void
+HelperThread::ThreadMain(void* arg)
+{
+ ThisThread::SetName("JS Helper");
+
+ //See bug 1104658.
+ //Set the FPU control word to be the same as the main thread's, or math
+ //computations on this thread may use incorrect precision rules during
+ //Ion compilation.
+ FIX_FPU();
+
+ static_cast<HelperThread*>(arg)->threadLoop();
+}
+
+void
+HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked));
+ MOZ_ASSERT(idle());
+
+ currentTask.emplace(HelperThreadState().wasmWorklist(locked).popCopy());
+ bool success = false;
+
+ wasm::IonCompileTask* task = wasmTask();
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+ success = wasm::CompileFunction(task);
+ }
+
+ // On success, try to move work to the finished list.
+ if (success)
+ success = HelperThreadState().wasmFinishedList(locked).append(task);
+
+ // On failure, note the failure for harvesting by the parent.
+ if (!success)
+ HelperThreadState().noteWasmFailure(locked);
+
+ // Notify the main thread in case it's waiting.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+ currentTask.reset();
+}
+
+void
+HelperThread::handlePromiseTaskWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartPromiseTask(locked));
+ MOZ_ASSERT(idle());
+
+ PromiseTask* task = HelperThreadState().promiseTasks(locked).popCopy();
+ currentTask.emplace(task);
+
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+
+ task->execute();
+
+ if (!task->runtime()->finishAsyncTaskCallback(task)) {
+ // We cannot simply delete the task now because the PromiseTask must
+ // be destroyed on its runtime's thread. Add it to a list of tasks
+ // to delete before the next GC.
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!task->runtime()->promiseTasksToDestroy.lock()->append(task))
+ oomUnsafe.crash("handlePromiseTaskWorkload");
+ }
+ }
+
+ // Notify the main thread in case it's waiting.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+ currentTask.reset();
+}
+
+void
+HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartIonCompile(locked));
+ MOZ_ASSERT(idle());
+
+ // Find the IonBuilder in the worklist with the highest priority, and
+ // remove it from the worklist.
+ jit::IonBuilder* builder =
+ HelperThreadState().highestPriorityPendingIonCompile(locked, /* remove = */ true);
+
+ // If there are now too many threads with active IonBuilders, indicate to
+ // the one with the lowest priority that it should pause. Note that due to
+ // builder priorities changing since pendingIonCompileHasSufficientPriority
+ // was called, the builder we are pausing may actually be higher priority
+ // than the one we are about to start. Oh well.
+ HelperThread* other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold(locked);
+ if (other) {
+ MOZ_ASSERT(other->ionBuilder() && !other->pause);
+ other->pause = true;
+ }
+
+ currentTask.emplace(builder);
+ builder->setPauseFlag(&pause);
+
+ JSRuntime* rt = builder->script()->compartment()->runtimeFromAnyThread();
+
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+
+ TraceLoggerThread* logger = TraceLoggerForCurrentThread();
+ TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, builder->script());
+ AutoTraceLog logScript(logger, event);
+ AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
+
+ PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
+ builder->script()->runtimeFromAnyThread());
+ jit::JitContext jctx(jit::CompileRuntime::get(rt),
+ jit::CompileCompartment::get(builder->script()->compartment()),
+ &builder->alloc());
+ builder->setBackgroundCodegen(jit::CompileBackEnd(builder));
+ }
+
+ FinishOffThreadIonCompile(builder, locked);
+ currentTask.reset();
+ pause = false;
+
+ // Ping the main thread so that the compiled code can be incorporated
+ // at the next interrupt callback. Don't interrupt Ion code for this, as
+ // this incorporation can be delayed indefinitely without affecting
+ // performance as long as the main thread is actually executing Ion code.
+ rt->requestInterrupt(JSRuntime::RequestInterruptCanWait);
+
+ // Notify the main thread in case it is waiting for the compilation to finish.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+
+ // When finishing Ion compilation jobs, we can start unpausing compilation
+ // threads that were paused to restrict the number of active compilations.
+ // Only unpause one at a time, to make sure we don't exceed the restriction.
+ // Since threads are currently only paused for Ion compilations, this
+ // strategy will eventually unpause all paused threads, regardless of how
+ // many there are, since each thread we unpause will eventually finish and
+ // end up back here.
+ if (HelperThread* other = HelperThreadState().highestPriorityPausedIonCompile(locked)) {
+ MOZ_ASSERT(other->ionBuilder() && other->pause);
+
+ // Only unpause the other thread if there isn't a higher priority
+ // builder which this thread or another can start on.
+ jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile(locked);
+ if (!builder || IonBuilderHasHigherPriority(other->ionBuilder(), builder)) {
+ other->pause = false;
+
+ // Notify all paused threads, to make sure the one we just
+ // unpaused wakes up.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, locked);
+ }
+ }
+}
+
+static HelperThread*
+CurrentHelperThread()
+{
+ auto threadId = ThisThread::GetId();
+ HelperThread* thread = nullptr;
+ for (auto& thisThread : *HelperThreadState().threads) {
+ if (thisThread.thread.isSome() && threadId == thisThread.thread->get_id()) {
+ thread = &thisThread;
+ break;
+ }
+ }
+ MOZ_ASSERT(thread);
+ return thread;
+}
+
+void
+js::PauseCurrentHelperThread()
+{
+ TraceLoggerThread* logger = TraceLoggerForCurrentThread();
+ AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
+
+ HelperThread* thread = CurrentHelperThread();
+
+ AutoLockHelperThreadState lock;
+ while (thread->pause)
+ HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE);
+}
+
+void
+ExclusiveContext::setHelperThread(HelperThread* thread)
+{
+ helperThread_ = thread;
+ perThreadData = thread->threadData.ptr();
+}
+
+bool
+ExclusiveContext::addPendingCompileError(frontend::CompileError** error)
+{
+ UniquePtr<frontend::CompileError> errorPtr(new_<frontend::CompileError>());
+ if (!errorPtr)
+ return false;
+ if (!helperThread()->parseTask()->errors.append(errorPtr.get()))
+ return false;
+ *error = errorPtr.release();
+ return true;
+}
+
+void
+ExclusiveContext::addPendingOverRecursed()
+{
+ if (helperThread()->parseTask())
+ helperThread()->parseTask()->overRecursed = true;
+}
+
+void
+ExclusiveContext::addPendingOutOfMemory()
+{
+ // Keep in sync with recoverFromOutOfMemory.
+ if (helperThread()->parseTask())
+ helperThread()->parseTask()->outOfMemory = true;
+}
+
+void
+HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit)
+{
+ MOZ_ASSERT(HelperThreadState().canStartParseTask(locked));
+ MOZ_ASSERT(idle());
+
+ currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy());
+ ParseTask* task = parseTask();
+ task->cx->setHelperThread(this);
+
+ for (size_t i = 0; i < ArrayLength(task->cx->nativeStackLimit); i++)
+ task->cx->nativeStackLimit[i] = stackLimit;
+
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+ PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
+ task->exclusiveContextGlobal->runtimeFromAnyThread());
+ task->parse();
+ }
+
+ // The callback is invoked while we are still off the main thread.
+ task->callback(task, task->callbackData);
+
+ // FinishOffThreadScript will need to be called on the script to
+ // migrate it into the correct compartment.
+ {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!HelperThreadState().parseFinishedList(locked).append(task))
+ oomUnsafe.crash("handleParseWorkload");
+ }
+
+ currentTask.reset();
+
+ // Notify the main thread in case it is waiting for the parse/emit to finish.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+}
+
+void
+HelperThread::handleCompressionWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartCompressionTask(locked));
+ MOZ_ASSERT(idle());
+
+ currentTask.emplace(HelperThreadState().compressionWorklist(locked).popCopy());
+ SourceCompressionTask* task = compressionTask();
+ task->helperThread = this;
+
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+
+ TraceLoggerThread* logger = TraceLoggerForCurrentThread();
+ AutoTraceLog logCompile(logger, TraceLogger_CompressSource);
+
+ task->result = task->work();
+ }
+
+ task->helperThread = nullptr;
+ currentTask.reset();
+
+ // Notify the main thread in case it is waiting for the compression to finish.
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+}
+
+bool
+js::StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task)
+{
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().compressionWorklist(lock).append(task)) {
+ if (JSContext* maybecx = cx->maybeJSContext())
+ ReportOutOfMemory(maybecx);
+ return false;
+ }
+
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+ return true;
+}
+
+bool
+js::StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task)
+{
+ // Execute synchronously if there are no helper threads.
+ if (!CanUseExtraThreads())
+ return task->executeAndFinish(cx);
+
+ // If we fail to start, by interface contract, it is because the JSContext
+ // is in the process of shutting down. Since promise handlers are not
+ // necessarily run while shutting down *anyway*, we simply ignore the error.
+ // This is symmetric with the handling of errors in finishAsyncTaskCallback
+ // which, since it is off the JSContext's owner thread, cannot report an
+ // error anyway.
+ if (!cx->startAsyncTaskCallback(cx, task.get())) {
+ MOZ_ASSERT(!cx->isExceptionPending());
+ return true;
+ }
+
+ // Per interface contract, after startAsyncTaskCallback succeeds,
+ // finishAsyncTaskCallback *must* be called on all paths.
+
+ AutoLockHelperThreadState lock;
+
+ if (!HelperThreadState().promiseTasks(lock).append(task.get())) {
+ Unused << cx->finishAsyncTaskCallback(task.get());
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ Unused << task.release();
+
+ HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+ return true;
+}
+
+bool
+GlobalHelperThreadState::compressionInProgress(SourceCompressionTask* task,
+ const AutoLockHelperThreadState& lock)
+{
+ for (size_t i = 0; i < compressionWorklist(lock).length(); i++) {
+ if (compressionWorklist(lock)[i] == task)
+ return true;
+ }
+ for (auto& thread : *threads) {
+ if (thread.compressionTask() == task)
+ return true;
+ }
+ return false;
+}
+
+bool
+SourceCompressionTask::complete()
+{
+ if (!active())
+ return true;
+
+ {
+ AutoLockHelperThreadState lock;
+ while (HelperThreadState().compressionInProgress(this, lock))
+ HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
+ }
+
+ if (result == Success) {
+ MOZ_ASSERT(resultString);
+ ss->setCompressedSource(mozilla::Move(*resultString), ss->length());
+ } else {
+ if (result == OOM)
+ ReportOutOfMemory(cx);
+ }
+
+ ss = nullptr;
+ MOZ_ASSERT(!active());
+
+ return result != OOM;
+}
+
+SourceCompressionTask*
+GlobalHelperThreadState::compressionTaskForSource(ScriptSource* ss,
+ const AutoLockHelperThreadState& lock)
+{
+ for (size_t i = 0; i < compressionWorklist(lock).length(); i++) {
+ SourceCompressionTask* task = compressionWorklist(lock)[i];
+ if (task->source() == ss)
+ return task;
+ }
+ for (auto& thread : *threads) {
+ SourceCompressionTask* task = thread.compressionTask();
+ if (task && task->source() == ss)
+ return task;
+ }
+ return nullptr;
+}
+
+void
+GlobalHelperThreadState::trace(JSTracer* trc)
+{
+ AutoLockHelperThreadState lock;
+ for (auto builder : ionWorklist(lock))
+ builder->trace(trc);
+ for (auto builder : ionFinishedList(lock))
+ builder->trace(trc);
+
+ if (HelperThreadState().threads) {
+ for (auto& helper : *HelperThreadState().threads) {
+ if (auto builder = helper.ionBuilder())
+ builder->trace(trc);
+ }
+ }
+
+ jit::IonBuilder* builder = trc->runtime()->ionLazyLinkList().getFirst();
+ while (builder) {
+ builder->trace(trc);
+ builder = builder->getNext();
+ }
+
+ for (auto parseTask : parseWorklist_)
+ parseTask->trace(trc);
+ for (auto parseTask : parseFinishedList_)
+ parseTask->trace(trc);
+ for (auto parseTask : parseWaitingOnGC_)
+ parseTask->trace(trc);
+}
+
+void
+HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
+{
+ MOZ_ASSERT(HelperThreadState().canStartGCHelperTask(locked));
+ MOZ_ASSERT(idle());
+
+ currentTask.emplace(HelperThreadState().gcHelperWorklist(locked).popCopy());
+ GCHelperState* task = gcHelperTask();
+
+ {
+ AutoUnlockHelperThreadState unlock(locked);
+ task->work();
+ }
+
+ currentTask.reset();
+ HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+}
+
+void
+HelperThread::threadLoop()
+{
+ MOZ_ASSERT(CanUseExtraThreads());
+
+ JS::AutoSuppressGCAnalysis nogc;
+ AutoLockHelperThreadState lock;
+
+ js::TlsPerThreadData.set(threadData.ptr());
+
+ // Compute the thread's stack limit, for over-recursed checks.
+ uintptr_t stackLimit = GetNativeStackBase();
+#if JS_STACK_GROWTH_DIRECTION > 0
+ stackLimit += HELPER_STACK_QUOTA;
+#else
+ stackLimit -= HELPER_STACK_QUOTA;
+#endif
+
+ while (true) {
+ MOZ_ASSERT(idle());
+
+ // Block until a task is available. Save the value of whether we are
+ // going to do an Ion compile, in case the value returned by the method
+ // changes.
+ bool ionCompile = false;
+ while (true) {
+ if (terminate)
+ return;
+ if ((ionCompile = HelperThreadState().pendingIonCompileHasSufficientPriority(lock)) ||
+ HelperThreadState().canStartWasmCompile(lock) ||
+ HelperThreadState().canStartPromiseTask(lock) ||
+ HelperThreadState().canStartParseTask(lock) ||
+ HelperThreadState().canStartCompressionTask(lock) ||
+ HelperThreadState().canStartGCHelperTask(lock) ||
+ HelperThreadState().canStartGCParallelTask(lock))
+ {
+ break;
+ }
+ HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
+ }
+
+ if (ionCompile) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_ION);
+ handleIonWorkload(lock);
+ } else if (HelperThreadState().canStartWasmCompile(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS);
+ handleWasmWorkload(lock);
+ } else if (HelperThreadState().canStartPromiseTask(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_PROMISE_TASK);
+ handlePromiseTaskWorkload(lock);
+ } else if (HelperThreadState().canStartParseTask(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
+ handleParseWorkload(lock, stackLimit);
+ } else if (HelperThreadState().canStartCompressionTask(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
+ handleCompressionWorkload(lock);
+ } else if (HelperThreadState().canStartGCHelperTask(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
+ handleGCHelperWorkload(lock);
+ } else if (HelperThreadState().canStartGCParallelTask(lock)) {
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
+ handleGCParallelWorkload(lock);
+ } else {
+ MOZ_CRASH("No task to perform");
+ }
+ }
+}
diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h
new file mode 100644
index 000000000..55a51dc8d
--- /dev/null
+++ b/js/src/vm/HelperThreads.h
@@ -0,0 +1,655 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Definitions for managing off-main-thread work using a process wide list
+ * of worklist items and pool of threads. Worklist items are engine internal,
+ * and are distinct from e.g. web workers.
+ */
+
+#ifndef vm_HelperThreads_h
+#define vm_HelperThreads_h
+
+#include "mozilla/GuardObjects.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/Variant.h"
+
+#include "jscntxt.h"
+
+#include "frontend/TokenStream.h"
+#include "jit/Ion.h"
+#include "threading/ConditionVariable.h"
+#include "vm/MutexIDs.h"
+
+namespace JS {
+struct Zone;
+} // namespace JS
+
+namespace js {
+
+class AutoLockHelperThreadState;
+class AutoUnlockHelperThreadState;
+class PromiseTask;
+struct HelperThread;
+struct ParseTask;
+namespace jit {
+ class IonBuilder;
+} // namespace jit
+namespace wasm {
+ class FuncIR;
+ class FunctionCompileResults;
+ class IonCompileTask;
+ typedef Vector<IonCompileTask*, 0, SystemAllocPolicy> IonCompileTaskPtrVector;
+} // namespace wasm
+
+enum class ParseTaskKind
+{
+ Script,
+ Module
+};
+
+// Per-process state for off thread work items.
+class GlobalHelperThreadState
+{
+ friend class AutoLockHelperThreadState;
+ friend class AutoUnlockHelperThreadState;
+
+ public:
+ // Number of CPUs to treat this machine as having when creating threads.
+ // May be accessed without locking.
+ size_t cpuCount;
+
+ // Number of threads to create. May be accessed without locking.
+ size_t threadCount;
+
+ typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
+ typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
+ typedef Vector<SourceCompressionTask*, 0, SystemAllocPolicy> SourceCompressionTaskVector;
+ typedef Vector<GCHelperState*, 0, SystemAllocPolicy> GCHelperStateVector;
+ typedef Vector<GCParallelTask*, 0, SystemAllocPolicy> GCParallelTaskVector;
+ typedef Vector<PromiseTask*, 0, SystemAllocPolicy> PromiseTaskVector;
+
+ // List of available threads, or null if the thread state has not been initialized.
+ using HelperThreadVector = Vector<HelperThread, 0, SystemAllocPolicy>;
+ UniquePtr<HelperThreadVector> threads;
+
+ private:
+ // The lists below are all protected by |lock|.
+
+ // Ion compilation worklist and finished jobs.
+ IonBuilderVector ionWorklist_, ionFinishedList_;
+
+ // wasm worklist and finished jobs.
+ wasm::IonCompileTaskPtrVector wasmWorklist_, wasmFinishedList_;
+
+ public:
+ // For now, only allow a single parallel wasm compilation to happen at a
+ // time. This avoids race conditions on wasmWorklist/wasmFinishedList/etc.
+ mozilla::Atomic<bool> wasmCompilationInProgress;
+
+ private:
+ // Async tasks that, upon completion, are dispatched back to the JSContext's
+ // owner thread via embedding callbacks instead of a finished list.
+ PromiseTaskVector promiseTasks_;
+
+ // Script parsing/emitting worklist and finished jobs.
+ ParseTaskVector parseWorklist_, parseFinishedList_;
+
+ // Parse tasks waiting for an atoms-zone GC to complete.
+ ParseTaskVector parseWaitingOnGC_;
+
+ // Source compression worklist.
+ SourceCompressionTaskVector compressionWorklist_;
+
+ // Runtimes which have sweeping / allocating work to do.
+ GCHelperStateVector gcHelperWorklist_;
+
+ // GC tasks needing to be done in parallel.
+ GCParallelTaskVector gcParallelWorklist_;
+
+ ParseTask* removeFinishedParseTask(ParseTaskKind kind, void* token);
+
+ public:
+ size_t maxIonCompilationThreads() const;
+ size_t maxUnpausedIonCompilationThreads() const;
+ size_t maxWasmCompilationThreads() const;
+ size_t maxParseThreads() const;
+ size_t maxCompressionThreads() const;
+ size_t maxGCHelperThreads() const;
+ size_t maxGCParallelThreads() const;
+
+ GlobalHelperThreadState();
+
+ bool ensureInitialized();
+ void finish();
+ void finishThreads();
+
+ void lock();
+ void unlock();
+
+ enum CondVar {
+ // For notifying threads waiting for work that they may be able to make progress.
+ CONSUMER,
+
+ // For notifying threads doing work that they may be able to make progress.
+ PRODUCER,
+
+ // For notifying threads doing work which are paused that they may be
+ // able to resume making progress.
+ PAUSE
+ };
+
+ void wait(AutoLockHelperThreadState& locked, CondVar which,
+ mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
+ void notifyAll(CondVar which, const AutoLockHelperThreadState&);
+ void notifyOne(CondVar which, const AutoLockHelperThreadState&);
+
+ // Helper method for removing items from the vectors below while iterating over them.
+ template <typename T>
+ void remove(T& vector, size_t* index)
+ {
+ vector[(*index)--] = vector.back();
+ vector.popBack();
+ }
+
+ IonBuilderVector& ionWorklist(const AutoLockHelperThreadState&) {
+ return ionWorklist_;
+ }
+ IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
+ return ionFinishedList_;
+ }
+
+ wasm::IonCompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&) {
+ return wasmWorklist_;
+ }
+ wasm::IonCompileTaskPtrVector& wasmFinishedList(const AutoLockHelperThreadState&) {
+ return wasmFinishedList_;
+ }
+
+ PromiseTaskVector& promiseTasks(const AutoLockHelperThreadState&) {
+ return promiseTasks_;
+ }
+
+ ParseTaskVector& parseWorklist(const AutoLockHelperThreadState&) {
+ return parseWorklist_;
+ }
+ ParseTaskVector& parseFinishedList(const AutoLockHelperThreadState&) {
+ return parseFinishedList_;
+ }
+ ParseTaskVector& parseWaitingOnGC(const AutoLockHelperThreadState&) {
+ return parseWaitingOnGC_;
+ }
+
+ SourceCompressionTaskVector& compressionWorklist(const AutoLockHelperThreadState&) {
+ return compressionWorklist_;
+ }
+
+ GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
+ return gcHelperWorklist_;
+ }
+
+ GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
+ return gcParallelWorklist_;
+ }
+
+ bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
+ bool canStartPromiseTask(const AutoLockHelperThreadState& lock);
+ bool canStartIonCompile(const AutoLockHelperThreadState& lock);
+ bool canStartParseTask(const AutoLockHelperThreadState& lock);
+ bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
+ bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
+ bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
+
+ // Unlike the methods above, the value returned by this method can change
+ // over time, even if the helper thread state lock is held throughout.
+ bool pendingIonCompileHasSufficientPriority(const AutoLockHelperThreadState& lock);
+
+ jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
+ bool remove = false);
+ HelperThread* lowestPriorityUnpausedIonCompileAtThreshold(
+ const AutoLockHelperThreadState& lock);
+ HelperThread* highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock);
+
+ uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&) {
+ uint32_t n = numWasmFailedJobs;
+ numWasmFailedJobs = 0;
+ return n;
+ }
+ void noteWasmFailure(const AutoLockHelperThreadState&) {
+ // Be mindful to signal the main thread after calling this function.
+ numWasmFailedJobs++;
+ }
+ bool wasmFailed(const AutoLockHelperThreadState&) {
+ return bool(numWasmFailedJobs);
+ }
+
+ JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, void* token);
+ void cancelParseTask(JSContext* cx, ParseTaskKind kind, void* token);
+
+ void mergeParseTaskCompartment(JSContext* cx, ParseTask* parseTask,
+ Handle<GlobalObject*> global,
+ JSCompartment* dest);
+
+ void trace(JSTracer* trc);
+
+ private:
+ /*
+ * Number of wasm jobs that encountered failure for the active module.
+ * Their parent is logically the main thread, and this number serves for harvesting.
+ */
+ uint32_t numWasmFailedJobs;
+
+ public:
+ JSScript* finishScriptParseTask(JSContext* cx, void* token);
+ JSObject* finishModuleParseTask(JSContext* cx, void* token);
+ bool compressionInProgress(SourceCompressionTask* task, const AutoLockHelperThreadState& lock);
+ SourceCompressionTask* compressionTaskForSource(ScriptSource* ss, const AutoLockHelperThreadState& lock);
+
+ bool hasActiveThreads(const AutoLockHelperThreadState&);
+ void waitForAllThreads();
+
+ template <typename T>
+ bool checkTaskThreadLimit(size_t maxThreads) const;
+
+ private:
+
+ /*
+ * Lock protecting all mutable shared state accessed by helper threads, and
+ * used by all condition variables.
+ */
+ js::Mutex helperLock;
+
+ /* Condvars for threads waiting/notifying each other. */
+ js::ConditionVariable consumerWakeup;
+ js::ConditionVariable producerWakeup;
+ js::ConditionVariable pauseWakeup;
+
+ js::ConditionVariable& whichWakeup(CondVar which) {
+ switch (which) {
+ case CONSUMER: return consumerWakeup;
+ case PRODUCER: return producerWakeup;
+ case PAUSE: return pauseWakeup;
+ default: MOZ_CRASH("Invalid CondVar in |whichWakeup|");
+ }
+ }
+};
+
+static inline GlobalHelperThreadState&
+HelperThreadState()
+{
+ extern GlobalHelperThreadState* gHelperThreadState;
+
+ MOZ_ASSERT(gHelperThreadState);
+ return *gHelperThreadState;
+}
+
+/* Individual helper thread, one allocated per core. */
+struct HelperThread
+{
+ mozilla::Maybe<PerThreadData> threadData;
+ mozilla::Maybe<Thread> thread;
+
+ /*
+ * Indicate to a thread that it should terminate itself. This is only read
+ * or written with the helper thread state lock held.
+ */
+ bool terminate;
+
+ /*
+ * Indicate to a thread that it should pause execution. This is only
+ * written with the helper thread state lock held, but may be read from
+ * without the lock held.
+ */
+ mozilla::Atomic<bool, mozilla::Relaxed> pause;
+
+ /* The current task being executed by this thread, if any. */
+ mozilla::Maybe<mozilla::Variant<jit::IonBuilder*,
+ wasm::IonCompileTask*,
+ PromiseTask*,
+ ParseTask*,
+ SourceCompressionTask*,
+ GCHelperState*,
+ GCParallelTask*>> currentTask;
+
+ bool idle() const {
+ return currentTask.isNothing();
+ }
+
+ /* Any builder currently being compiled by Ion on this thread. */
+ jit::IonBuilder* ionBuilder() {
+ return maybeCurrentTaskAs<jit::IonBuilder*>();
+ }
+
+ /* Any wasm data currently being optimized on this thread. */
+ wasm::IonCompileTask* wasmTask() {
+ return maybeCurrentTaskAs<wasm::IonCompileTask*>();
+ }
+
+ /* Any source being parsed/emitted on this thread. */
+ ParseTask* parseTask() {
+ return maybeCurrentTaskAs<ParseTask*>();
+ }
+
+ /* Any source being compressed on this thread. */
+ SourceCompressionTask* compressionTask() {
+ return maybeCurrentTaskAs<SourceCompressionTask*>();
+ }
+
+ /* Any GC state for background sweeping or allocating being performed. */
+ GCHelperState* gcHelperTask() {
+ return maybeCurrentTaskAs<GCHelperState*>();
+ }
+
+ /* State required to perform a GC parallel task. */
+ GCParallelTask* gcParallelTask() {
+ return maybeCurrentTaskAs<GCParallelTask*>();
+ }
+
+ void destroy();
+
+ static void ThreadMain(void* arg);
+ void threadLoop();
+
+ private:
+ template <typename T>
+ T maybeCurrentTaskAs() {
+ if (currentTask.isSome() && currentTask->is<T>())
+ return currentTask->as<T>();
+
+ return nullptr;
+ }
+
+ void handleWasmWorkload(AutoLockHelperThreadState& locked);
+ void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked);
+ void handleIonWorkload(AutoLockHelperThreadState& locked);
+ void handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit);
+ void handleCompressionWorkload(AutoLockHelperThreadState& locked);
+ void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
+ void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
+};
+
+/* Methods for interacting with helper threads. */
+
+// Create data structures used by helper threads.
+bool
+CreateHelperThreadsState();
+
+// Destroy data structures used by helper threads.
+void
+DestroyHelperThreadsState();
+
+// Initialize helper threads unless already initialized.
+bool
+EnsureHelperThreadsInitialized();
+
+// This allows the JS shell to override GetCPUCount() when passed the
+// --thread-count=N option.
+void
+SetFakeCPUCount(size_t count);
+
+// Pause the current thread until it's pause flag is unset.
+void
+PauseCurrentHelperThread();
+
+/* Perform MIR optimization and LIR generation on a single function. */
+bool
+StartOffThreadWasmCompile(wasm::IonCompileTask* task);
+
+/*
+ * If helper threads are available, start executing the given PromiseTask on a
+ * helper thread, finishing back on the originating JSContext's owner thread. If
+ * no helper threads are available, the PromiseTask is synchronously executed
+ * and finished.
+ */
+bool
+StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task);
+
+/*
+ * Schedule an Ion compilation for a script, given a builder which has been
+ * generated and read everything needed from the VM state.
+ */
+bool
+StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder);
+
+struct AllCompilations {};
+struct ZonesInState { JSRuntime* runtime; JS::Zone::GCState state; };
+
+using CompilationSelector = mozilla::Variant<JSScript*,
+ JSCompartment*,
+ ZonesInState,
+ JSRuntime*,
+ AllCompilations>;
+
+/*
+ * Cancel scheduled or in progress Ion compilations.
+ */
+void
+CancelOffThreadIonCompile(CompilationSelector selector, bool discardLazyLinkList);
+
+inline void
+CancelOffThreadIonCompile(JSScript* script)
+{
+ CancelOffThreadIonCompile(CompilationSelector(script), true);
+}
+
+inline void
+CancelOffThreadIonCompile(JSCompartment* comp)
+{
+ CancelOffThreadIonCompile(CompilationSelector(comp), true);
+}
+
+inline void
+CancelOffThreadIonCompile(JSRuntime* runtime, JS::Zone::GCState state)
+{
+ CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state}), true);
+}
+
+inline void
+CancelOffThreadIonCompile(JSRuntime* runtime)
+{
+ CancelOffThreadIonCompile(CompilationSelector(runtime), true);
+}
+
+inline void
+CancelOffThreadIonCompile()
+{
+ CancelOffThreadIonCompile(CompilationSelector(AllCompilations()), false);
+}
+
+#ifdef DEBUG
+bool
+HasOffThreadIonCompile(JSCompartment* comp);
+#endif
+
+/* Cancel all scheduled, in progress or finished parses for runtime. */
+void
+CancelOffThreadParses(JSRuntime* runtime);
+
+/*
+ * Start a parse/emit cycle for a stream of source. The characters must stay
+ * alive until the compilation finishes.
+ */
+bool
+StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData);
+
+bool
+StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
+ const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData);
+
+/*
+ * Called at the end of GC to enqueue any Parse tasks that were waiting on an
+ * atoms-zone GC to finish.
+ */
+void
+EnqueuePendingParseTasksAfterGC(JSRuntime* rt);
+
+struct AutoEnqueuePendingParseTasksAfterGC {
+ const gc::GCRuntime& gc_;
+ explicit AutoEnqueuePendingParseTasksAfterGC(const gc::GCRuntime& gc) : gc_(gc) {}
+ ~AutoEnqueuePendingParseTasksAfterGC();
+};
+
+/* Start a compression job for the specified token. */
+bool
+StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task);
+
+class MOZ_RAII AutoLockHelperThreadState : public LockGuard<Mutex>
+{
+ using Base = LockGuard<Mutex>;
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ public:
+ explicit AutoLockHelperThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+ : Base(HelperThreadState().helperLock)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+};
+
+class MOZ_RAII AutoUnlockHelperThreadState : public UnlockGuard<Mutex>
+{
+ using Base = UnlockGuard<Mutex>;
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ public:
+
+ explicit AutoUnlockHelperThreadState(AutoLockHelperThreadState& locked
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : Base(locked)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+};
+
+struct ParseTask
+{
+ ParseTaskKind kind;
+ ExclusiveContext* cx;
+ OwningCompileOptions options;
+ const char16_t* chars;
+ size_t length;
+ LifoAlloc alloc;
+
+ // Rooted pointer to the global object used by 'cx'.
+ JSObject* exclusiveContextGlobal;
+
+ // Callback invoked off the main thread when the parse finishes.
+ JS::OffThreadCompileCallback callback;
+ void* callbackData;
+
+ // Holds the final script between the invocation of the callback and the
+ // point where FinishOffThreadScript is called, which will destroy the
+ // ParseTask.
+ JSScript* script;
+
+ // Holds the ScriptSourceObject generated for the script compilation.
+ ScriptSourceObject* sourceObject;
+
+ // Any errors or warnings produced during compilation. These are reported
+ // when finishing the script.
+ Vector<frontend::CompileError*> errors;
+ bool overRecursed;
+ bool outOfMemory;
+
+ ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData);
+ bool init(JSContext* cx, const ReadOnlyCompileOptions& options);
+
+ void activate(JSRuntime* rt);
+ virtual void parse() = 0;
+ bool finish(JSContext* cx);
+
+ bool runtimeMatches(JSRuntime* rt) {
+ return cx->runtimeMatches(rt);
+ }
+
+ virtual ~ParseTask();
+
+ void trace(JSTracer* trc);
+};
+
+struct ScriptParseTask : public ParseTask
+{
+ ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData);
+ void parse() override;
+};
+
+struct ModuleParseTask : public ParseTask
+{
+ ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
+ JSContext* initCx, const char16_t* chars, size_t length,
+ JS::OffThreadCompileCallback callback, void* callbackData);
+ void parse() override;
+};
+
+// Return whether, if a new parse task was started, it would need to wait for
+// an in-progress GC to complete before starting.
+extern bool
+OffThreadParsingMustWaitForGC(JSRuntime* rt);
+
+// Compression tasks are allocated on the stack by their triggering thread,
+// which will block on the compression completing as the task goes out of scope
+// to ensure it completes at the required time.
+struct SourceCompressionTask
+{
+ friend class ScriptSource;
+ friend struct HelperThread;
+
+ // Thread performing the compression.
+ HelperThread* helperThread;
+
+ private:
+ // Context from the triggering thread. Don't use this off thread!
+ ExclusiveContext* cx;
+
+ ScriptSource* ss;
+
+ // Atomic flag to indicate to a helper thread that it should abort
+ // compression on the source.
+ mozilla::Atomic<bool, mozilla::Relaxed> abort_;
+
+ // Stores the result of the compression.
+ enum ResultType {
+ OOM,
+ Aborted,
+ Success
+ } result;
+
+ mozilla::Maybe<SharedImmutableString> resultString;
+
+ public:
+ explicit SourceCompressionTask(ExclusiveContext* cx)
+ : helperThread(nullptr)
+ , cx(cx)
+ , ss(nullptr)
+ , abort_(false)
+ , result(OOM)
+ {}
+
+ ~SourceCompressionTask()
+ {
+ complete();
+ }
+
+ ResultType work();
+ bool complete();
+ void abort() { abort_ = true; }
+ bool active() const { return !!ss; }
+ ScriptSource* source() { return ss; }
+};
+
+} /* namespace js */
+
+#endif /* vm_HelperThreads_h */
diff --git a/js/src/vm/Id.cpp b/js/src/vm/Id.cpp
new file mode 100644
index 000000000..d88f4398d
--- /dev/null
+++ b/js/src/vm/Id.cpp
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/Id.h"
+#include "js/RootingAPI.h"
+
+const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) };
+const jsid JSID_EMPTY = { size_t(JSID_TYPE_SYMBOL) };
+
+static const jsid voidIdValue = JSID_VOID;
+static const jsid emptyIdValue = JSID_EMPTY;
+const JS::HandleId JSID_VOIDHANDLE = JS::HandleId::fromMarkedLocation(&voidIdValue);
+const JS::HandleId JSID_EMPTYHANDLE = JS::HandleId::fromMarkedLocation(&emptyIdValue);
+
diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp
new file mode 100644
index 000000000..05cc087cc
--- /dev/null
+++ b/js/src/vm/Initialization.cpp
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* SpiderMonkey initialization and shutdown code. */
+
+#include "js/Initialization.h"
+
+#include "mozilla/Assertions.h"
+
+#include <ctype.h>
+
+#include "jstypes.h"
+
+#include "builtin/AtomicsObject.h"
+#include "ds/MemoryProtectionExceptionHandler.h"
+#include "gc/Statistics.h"
+#include "jit/ExecutableAllocator.h"
+#include "jit/Ion.h"
+#include "js/Utility.h"
+#if ENABLE_INTL_API
+#include "unicode/uclean.h"
+#include "unicode/utypes.h"
+#endif // ENABLE_INTL_API
+#include "vm/DateTime.h"
+#include "vm/HelperThreads.h"
+#include "vm/Runtime.h"
+#include "vm/Time.h"
+#include "vm/TraceLogging.h"
+#include "wasm/WasmInstance.h"
+
+using JS::detail::InitState;
+using JS::detail::libraryInitState;
+using js::FutexRuntime;
+
+InitState JS::detail::libraryInitState;
+
+#ifdef DEBUG
+static unsigned
+MessageParameterCount(const char* format)
+{
+ unsigned numfmtspecs = 0;
+ for (const char* fmt = format; *fmt != '\0'; fmt++) {
+ if (*fmt == '{' && isdigit(fmt[1]))
+ ++numfmtspecs;
+ }
+ return numfmtspecs;
+}
+
+static void
+CheckMessageParameterCounts()
+{
+ // Assert that each message format has the correct number of braced
+ // parameters.
+# define MSG_DEF(name, count, exception, format) \
+ MOZ_ASSERT(MessageParameterCount(format) == count);
+# include "js.msg"
+# undef MSG_DEF
+}
+#endif /* DEBUG */
+
+#define RETURN_IF_FAIL(code) do { if (!code) return #code " failed"; } while (0)
+
+JS_PUBLIC_API(const char*)
+JS::detail::InitWithFailureDiagnostic(bool isDebugBuild)
+{
+ // Verify that our DEBUG setting matches the caller's.
+#ifdef DEBUG
+ MOZ_RELEASE_ASSERT(isDebugBuild);
+#else
+ MOZ_RELEASE_ASSERT(!isDebugBuild);
+#endif
+
+ MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
+ "must call JS_Init once before any JSAPI operation except "
+ "JS_SetICUMemoryFunctions");
+ MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
+ "how do we have live runtimes before JS_Init?");
+
+ PRMJ_NowInit();
+
+ // The first invocation of `ProcessCreation` creates a temporary thread
+ // and crashes if that fails, i.e. because we're out of memory. To prevent
+ // that from happening at some later time, get it out of the way during
+ // startup.
+ bool ignored;
+ mozilla::TimeStamp::ProcessCreation(ignored);
+
+#ifdef DEBUG
+ CheckMessageParameterCounts();
+#endif
+
+ using js::TlsPerThreadData;
+ RETURN_IF_FAIL(TlsPerThreadData.init());
+
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+ RETURN_IF_FAIL(js::oom::InitThreadType());
+ js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
+#endif
+
+ RETURN_IF_FAIL(js::Mutex::Init());
+
+ RETURN_IF_FAIL(js::wasm::InitInstanceStaticData());
+
+ js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works.
+ RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory());
+
+ MOZ_ALWAYS_TRUE(js::MemoryProtectionExceptionHandler::install());
+
+ RETURN_IF_FAIL(js::jit::InitializeIon());
+
+ js::DateTimeInfo::init();
+
+#if EXPOSE_INTL_API
+ UErrorCode err = U_ZERO_ERROR;
+ u_init(&err);
+ if (U_FAILURE(err))
+ return "u_init() failed";
+#endif // EXPOSE_INTL_API
+
+ RETURN_IF_FAIL(js::CreateHelperThreadsState());
+ RETURN_IF_FAIL(FutexRuntime::initialize());
+ RETURN_IF_FAIL(js::gcstats::Statistics::initialize());
+
+ libraryInitState = InitState::Running;
+ return nullptr;
+}
+
+#undef RETURN_IF_FAIL
+
+JS_PUBLIC_API(void)
+JS_ShutDown(void)
+{
+ MOZ_ASSERT(libraryInitState == InitState::Running,
+ "JS_ShutDown must only be called after JS_Init and can't race with it");
+#ifdef DEBUG
+ if (JSRuntime::hasLiveRuntimes()) {
+ // Gecko is too buggy to assert this just yet.
+ fprintf(stderr,
+ "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
+ "and everything alive inside it, that is) AT JS_ShutDown "
+ "TIME. FIX THIS!\n");
+ }
+#endif
+
+ FutexRuntime::destroy();
+
+ js::DestroyHelperThreadsState();
+
+#ifdef JS_TRACE_LOGGING
+ js::DestroyTraceLoggerThreadState();
+ js::DestroyTraceLoggerGraphState();
+#endif
+
+ js::MemoryProtectionExceptionHandler::uninstall();
+
+ js::wasm::ShutDownInstanceStaticData();
+
+ js::Mutex::ShutDown();
+
+ // The only difficult-to-address reason for the restriction that you can't
+ // call JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ
+ // NowInit initialization code, which uses PR_CallOnce to initialize the
+ // PRMJ_Now subsystem. (For reinitialization to be permitted, we'd need to
+ // "reset" the called-once status -- doable, but more trouble than it's
+ // worth now.) Initializing that subsystem from JS_Init eliminates the
+ // problem, but initialization can take a comparatively long time (15ms or
+ // so), so we really don't want to do it in JS_Init, and we really do want
+ // to do it only when PRMJ_Now is eventually called.
+ PRMJ_NowShutdown();
+
+#if EXPOSE_INTL_API
+ u_cleanup();
+#endif // EXPOSE_INTL_API
+
+ if (!JSRuntime::hasLiveRuntimes())
+ js::jit::ReleaseProcessExecutableMemory();
+
+ libraryInitState = InitState::ShutDown;
+}
+
+JS_PUBLIC_API(bool)
+JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
+{
+ MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
+ "must call JS_SetICUMemoryFunctions before any other JSAPI "
+ "operation (including JS_Init)");
+
+#if EXPOSE_INTL_API
+ UErrorCode status = U_ZERO_ERROR;
+ u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
+ return U_SUCCESS(status);
+#else
+ return true;
+#endif
+}
diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h
new file mode 100644
index 000000000..5f476c4ff
--- /dev/null
+++ b/js/src/vm/Interpreter-inl.h
@@ -0,0 +1,880 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Interpreter_inl_h
+#define vm_Interpreter_inl_h
+
+#include "vm/Interpreter.h"
+
+#include "jscompartment.h"
+#include "jsnum.h"
+#include "jsstr.h"
+
+#include "jit/Ion.h"
+#include "vm/ArgumentsObject.h"
+
+#include "jsatominlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/EnvironmentObject-inl.h"
+#include "vm/Stack-inl.h"
+#include "vm/String-inl.h"
+#include "vm/UnboxedObject-inl.h"
+
+namespace js {
+
+/*
+ * Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined
+ * by ScriptAnalysis::needsArgsObj) must check for these magic values and, when
+ * one is received, act as if the value were the function's ArgumentsObject.
+ * Additionally, it is possible that, after 'arguments' was copied into a
+ * temporary, the arguments object has been created a some other failed guard
+ * that called JSScript::argumentsOptimizationFailed. In this case, it is
+ * always valid (and necessary) to replace JS_OPTIMIZED_ARGUMENTS with the real
+ * arguments object.
+ */
+static inline bool
+IsOptimizedArguments(AbstractFramePtr frame, MutableHandleValue vp)
+{
+ if (vp.isMagic(JS_OPTIMIZED_ARGUMENTS) && frame.script()->needsArgsObj())
+ vp.setObject(frame.argsObj());
+ return vp.isMagic(JS_OPTIMIZED_ARGUMENTS);
+}
+
+/*
+ * One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply.
+ * However, this speculation must be guarded before calling 'apply' in case it
+ * is not the builtin Function.prototype.apply.
+ */
+static inline bool
+GuardFunApplyArgumentsOptimization(JSContext* cx, AbstractFramePtr frame, CallArgs& args)
+{
+ if (args.length() == 2 && IsOptimizedArguments(frame, args[1])) {
+ if (!IsNativeFunction(args.calleev(), js::fun_apply)) {
+ RootedScript script(cx, frame.script());
+ if (!JSScript::argumentsOptimizationFailed(cx, script))
+ return false;
+ args[1].setObject(frame.argsObj());
+ }
+ }
+
+ return true;
+}
+
+/*
+ * Per ES6, lexical declarations may not be accessed in any fashion until they
+ * are initialized (i.e., until the actual declaring statement is
+ * executed). The various LEXICAL opcodes need to check if the slot is an
+ * uninitialized let declaration, represented by the magic value
+ * JS_UNINITIALIZED_LEXICAL.
+ */
+static inline bool
+IsUninitializedLexical(const Value& val)
+{
+ // Use whyMagic here because JS_OPTIMIZED_ARGUMENTS could flow into here.
+ return val.isMagic() && val.whyMagic() == JS_UNINITIALIZED_LEXICAL;
+}
+
+static inline bool
+IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
+{
+ MOZ_ASSERT(shape);
+ if (obj->is<WithEnvironmentObject>())
+ return false;
+ // We check for IsImplicitDenseOrTypedArrayElement even though the shape
+ // is always a non-indexed property because proxy hooks may return a
+ // "non-native property found" shape, which happens to be encoded in the
+ // same way as the "dense element" shape. See MarkNonNativePropertyFound.
+ if (IsImplicitDenseOrTypedArrayElement(shape) ||
+ !shape->hasSlot() ||
+ !shape->hasDefaultGetter() ||
+ !shape->hasDefaultSetter())
+ {
+ return false;
+ }
+ MOZ_ASSERT(obj->as<NativeObject>().containsPure(shape));
+ return IsUninitializedLexical(obj->as<NativeObject>().getSlot(shape->slot()));
+}
+
+static inline void
+ReportUninitializedLexical(JSContext* cx, HandlePropertyName name)
+{
+ ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, name);
+}
+
+static inline void
+ReportUninitializedLexical(JSContext* cx, HandleScript script, jsbytecode* pc)
+{
+ ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script, pc);
+}
+
+static inline bool
+CheckUninitializedLexical(JSContext* cx, PropertyName* name_, HandleValue val)
+{
+ if (IsUninitializedLexical(val)) {
+ RootedPropertyName name(cx, name_);
+ ReportUninitializedLexical(cx, name);
+ return false;
+ }
+ return true;
+}
+
+static inline bool
+CheckUninitializedLexical(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue val)
+{
+ if (IsUninitializedLexical(val)) {
+ ReportUninitializedLexical(cx, script, pc);
+ return false;
+ }
+ return true;
+}
+
+static inline void
+ReportRuntimeConstAssignment(JSContext* cx, HandlePropertyName name)
+{
+ ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, name);
+}
+
+static inline void
+ReportRuntimeConstAssignment(JSContext* cx, HandleScript script, jsbytecode* pc)
+{
+ ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, pc);
+}
+
+inline bool
+GetLengthProperty(const Value& lval, MutableHandleValue vp)
+{
+ /* Optimize length accesses on strings, arrays, and arguments. */
+ if (lval.isString()) {
+ vp.setInt32(lval.toString()->length());
+ return true;
+ }
+ if (lval.isObject()) {
+ JSObject* obj = &lval.toObject();
+ if (obj->is<ArrayObject>()) {
+ vp.setNumber(obj->as<ArrayObject>().length());
+ return true;
+ }
+
+ if (obj->is<ArgumentsObject>()) {
+ ArgumentsObject* argsobj = &obj->as<ArgumentsObject>();
+ if (!argsobj->hasOverriddenLength()) {
+ uint32_t length = argsobj->initialLength();
+ MOZ_ASSERT(length < INT32_MAX);
+ vp.setInt32(int32_t(length));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+template <bool TypeOf> inline bool
+FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
+ HandleShape shape, MutableHandleValue vp)
+{
+ if (!shape) {
+ if (TypeOf) {
+ vp.setUndefined();
+ return true;
+ }
+ return ReportIsNotDefined(cx, name);
+ }
+
+ /* Take the slow path if shape was not found in a native object. */
+ if (!obj->isNative() || !obj2->isNative()) {
+ Rooted<jsid> id(cx, NameToId(name));
+ if (!GetProperty(cx, obj, obj, id, vp))
+ return false;
+ } else {
+ RootedObject normalized(cx, obj);
+ if (normalized->is<WithEnvironmentObject>() && !shape->hasDefaultGetter())
+ normalized = &normalized->as<WithEnvironmentObject>().object();
+ if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
+ /* Fast path for Object instance properties. */
+ MOZ_ASSERT(shape->hasSlot());
+ vp.set(obj2->as<NativeObject>().getSlot(shape->slot()));
+ } else {
+ if (!NativeGetExistingProperty(cx, normalized, obj2.as<NativeObject>(), shape, vp))
+ return false;
+ }
+ }
+
+ // We do our own explicit checking for |this|
+ if (name == cx->names().dotThis)
+ return true;
+
+ // NAME operations are the slow paths already, so unconditionally check
+ // for uninitialized lets.
+ return CheckUninitializedLexical(cx, name, vp);
+}
+
+inline bool
+FetchNameNoGC(JSObject* pobj, Shape* shape, MutableHandleValue vp)
+{
+ if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter())
+ return false;
+
+ vp.set(pobj->as<NativeObject>().getSlot(shape->slot()));
+ return !IsUninitializedLexical(vp);
+}
+
+inline bool
+GetIntrinsicOperation(JSContext* cx, jsbytecode* pc, MutableHandleValue vp)
+{
+ RootedPropertyName name(cx, cx->currentScript()->getName(pc));
+ return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp);
+}
+
+inline bool
+SetIntrinsicOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleValue val)
+{
+ RootedPropertyName name(cx, script->getName(pc));
+ return GlobalObject::setIntrinsicValue(cx, cx->global(), name, val);
+}
+
+inline void
+SetAliasedVarOperation(JSContext* cx, JSScript* script, jsbytecode* pc,
+ EnvironmentObject& obj, EnvironmentCoordinate ec, const Value& val,
+ MaybeCheckTDZ checkTDZ)
+{
+ MOZ_ASSERT_IF(checkTDZ, !IsUninitializedLexical(obj.aliasedBinding(ec)));
+
+ // Avoid computing the name if no type updates are needed, as this may be
+ // expensive on scopes with large numbers of variables.
+ PropertyName* name = obj.isSingleton()
+ ? EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc)
+ : nullptr;
+
+ obj.setAliasedBinding(cx, ec, name, val);
+}
+
+inline bool
+SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject env,
+ HandleValue val)
+{
+ MOZ_ASSERT(*pc == JSOP_SETNAME ||
+ *pc == JSOP_STRICTSETNAME ||
+ *pc == JSOP_SETGNAME ||
+ *pc == JSOP_STRICTSETGNAME);
+ MOZ_ASSERT_IF((*pc == JSOP_SETGNAME || *pc == JSOP_STRICTSETGNAME) &&
+ !script->hasNonSyntacticScope(),
+ env == cx->global() ||
+ env == &cx->global()->lexicalEnvironment() ||
+ env->is<RuntimeLexicalErrorObject>());
+
+ bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME;
+ RootedPropertyName name(cx, script->getName(pc));
+
+ // In strict mode, assigning to an undeclared global variable is an
+ // error. To detect this, we call NativeSetProperty directly and pass
+ // Unqualified. It stores the error, if any, in |result|.
+ bool ok;
+ ObjectOpResult result;
+ RootedId id(cx, NameToId(name));
+ RootedValue receiver(cx, ObjectValue(*env));
+ if (env->isUnqualifiedVarObj()) {
+ RootedNativeObject varobj(cx);
+ if (env->is<DebugEnvironmentProxy>())
+ varobj = &env->as<DebugEnvironmentProxy>().environment().as<NativeObject>();
+ else
+ varobj = &env->as<NativeObject>();
+ MOZ_ASSERT(!varobj->getOpsSetProperty());
+ ok = NativeSetProperty(cx, varobj, id, val, receiver, Unqualified, result);
+ } else {
+ ok = SetProperty(cx, env, id, val, receiver, result);
+ }
+ return ok && result.checkStrictErrorOrWarning(cx, env, id, strict);
+}
+
+inline bool
+DefLexicalOperation(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
+ HandleObject varObj, HandlePropertyName name, unsigned attrs)
+{
+ // Redeclaration checks should have already been done.
+ MOZ_ASSERT(CheckLexicalNameConflict(cx, lexicalEnv, varObj, name));
+ RootedId id(cx, NameToId(name));
+ RootedValue uninitialized(cx, MagicValue(JS_UNINITIALIZED_LEXICAL));
+ return NativeDefineProperty(cx, lexicalEnv, id, uninitialized, nullptr, nullptr, attrs);
+}
+
+inline bool
+DefLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvArg,
+ JSObject* varObjArg, JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(*pc == JSOP_DEFLET || *pc == JSOP_DEFCONST);
+ RootedPropertyName name(cx, script->getName(pc));
+
+ unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
+ if (*pc == JSOP_DEFCONST)
+ attrs |= JSPROP_READONLY;
+
+ Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, lexicalEnvArg);
+ RootedObject varObj(cx, varObjArg);
+ MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),
+ lexicalEnv == &cx->global()->lexicalEnvironment() && varObj == cx->global());
+
+ return DefLexicalOperation(cx, lexicalEnv, varObj, name, attrs);
+}
+
+inline void
+InitGlobalLexicalOperation(JSContext* cx, LexicalEnvironmentObject* lexicalEnvArg,
+ JSScript* script, jsbytecode* pc, HandleValue value)
+{
+ MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),
+ lexicalEnvArg == &cx->global()->lexicalEnvironment());
+ MOZ_ASSERT(*pc == JSOP_INITGLEXICAL);
+ Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, lexicalEnvArg);
+ RootedShape shape(cx, lexicalEnv->lookup(cx, script->getName(pc)));
+ MOZ_ASSERT(shape);
+ lexicalEnv->setSlotWithType(cx, shape, value);
+}
+
+inline bool
+InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs)
+{
+ if (obj->is<PlainObject>() || obj->is<JSFunction>()) {
+ unsigned propAttrs = GetInitDataPropAttrs(op);
+ return NativeDefineProperty(cx, obj.as<NativeObject>(), id, rhs, nullptr, nullptr,
+ propAttrs);
+ }
+
+ MOZ_ASSERT(obj->as<UnboxedPlainObject>().layout().lookup(id));
+ return PutProperty(cx, obj, id, rhs, false);
+}
+
+inline bool
+DefVarOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
+{
+ MOZ_ASSERT(varobj->isQualifiedVarObj());
+
+#ifdef DEBUG
+ // Per spec, it is an error to redeclare a lexical binding. This should
+ // have already been checked.
+ if (JS_HasExtensibleLexicalEnvironment(varobj)) {
+ Rooted<LexicalEnvironmentObject*> lexicalEnv(cx);
+ lexicalEnv = &JS_ExtensibleLexicalEnvironment(varobj)->as<LexicalEnvironmentObject>();
+ MOZ_ASSERT(CheckVarNameConflict(cx, lexicalEnv, dn));
+ }
+#endif
+
+ RootedShape prop(cx);
+ RootedObject obj2(cx);
+ if (!LookupProperty(cx, varobj, dn, &obj2, &prop))
+ return false;
+
+ /* Steps 8c, 8d. */
+ if (!prop || (obj2 != varobj && varobj->is<GlobalObject>())) {
+ if (!DefineProperty(cx, varobj, dn, UndefinedHandleValue, nullptr, nullptr, attrs))
+ return false;
+ }
+
+ if (varobj->is<GlobalObject>()) {
+ if (!varobj->compartment()->addToVarNames(cx, dn))
+ return false;
+ }
+
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue val,
+ MutableHandleValue res)
+{
+ /*
+ * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies
+ * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the
+ * results, -0.0 or INT32_MAX + 1, are double values.
+ */
+ int32_t i;
+ if (val.isInt32() && (i = val.toInt32()) != 0 && i != INT32_MIN) {
+ res.setInt32(-i);
+ } else {
+ double d;
+ if (!ToNumber(cx, val, &d))
+ return false;
+ res.setNumber(-d);
+ }
+
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
+ MutableHandleValue res)
+{
+ if (idval.isInt32()) {
+ res.set(idval);
+ return true;
+ }
+
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, idval, &id))
+ return false;
+
+ res.set(IdToValue(id));
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+GetObjectElementOperation(JSContext* cx, JSOp op, JS::HandleObject obj, JS::HandleObject receiver,
+ HandleValue key, MutableHandleValue res)
+{
+ MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM || op == JSOP_GETELEM_SUPER);
+ MOZ_ASSERT_IF(op == JSOP_GETELEM || op == JSOP_CALLELEM, obj == receiver);
+
+ do {
+ uint32_t index;
+ if (IsDefinitelyIndex(key, &index)) {
+ if (GetElementNoGC(cx, obj, receiver, index, res.address()))
+ break;
+
+ if (!GetElement(cx, obj, receiver, index, res))
+ return false;
+ break;
+ }
+
+ if (key.isString()) {
+ JSString* str = key.toString();
+ JSAtom* name = str->isAtom() ? &str->asAtom() : AtomizeString(cx, str);
+ if (!name)
+ return false;
+ if (name->isIndex(&index)) {
+ if (GetElementNoGC(cx, obj, receiver, index, res.address()))
+ break;
+ } else {
+ if (GetPropertyNoGC(cx, obj, receiver, name->asPropertyName(), res.address()))
+ break;
+ }
+ }
+
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, key, &id))
+ return false;
+ if (!GetProperty(cx, obj, receiver, id, res))
+ return false;
+ } while (false);
+
+ assertSameCompartmentDebugOnly(cx, res);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver,
+ HandleValue key, MutableHandleValue res)
+{
+ MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
+
+ // FIXME: Bug 1234324 We shouldn't be boxing here.
+ RootedObject boxed(cx, ToObjectFromStack(cx, receiver));
+ if (!boxed)
+ return false;
+
+ do {
+ uint32_t index;
+ if (IsDefinitelyIndex(key, &index)) {
+ if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
+ break;
+
+ if (!GetElement(cx, boxed, receiver, index, res))
+ return false;
+ break;
+ }
+
+ if (key.isString()) {
+ JSString* str = key.toString();
+ JSAtom* name = str->isAtom() ? &str->asAtom() : AtomizeString(cx, str);
+ if (!name)
+ return false;
+ if (name->isIndex(&index)) {
+ if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
+ break;
+ } else {
+ if (GetPropertyNoGC(cx, boxed, receiver, name->asPropertyName(), res.address()))
+ break;
+ }
+ }
+
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, key, &id))
+ return false;
+ if (!GetProperty(cx, boxed, receiver, id, res))
+ return false;
+ } while (false);
+
+ assertSameCompartmentDebugOnly(cx, res);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+GetElemOptimizedArguments(JSContext* cx, AbstractFramePtr frame, MutableHandleValue lref,
+ HandleValue rref, MutableHandleValue res, bool* done)
+{
+ MOZ_ASSERT(!*done);
+
+ if (IsOptimizedArguments(frame, lref)) {
+ if (rref.isInt32()) {
+ int32_t i = rref.toInt32();
+ if (i >= 0 && uint32_t(i) < frame.numActualArgs()) {
+ res.set(frame.unaliasedActual(i));
+ *done = true;
+ return true;
+ }
+ }
+
+ RootedScript script(cx, frame.script());
+ if (!JSScript::argumentsOptimizationFailed(cx, script))
+ return false;
+
+ lref.set(ObjectValue(frame.argsObj()));
+ }
+
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+GetElementOperation(JSContext* cx, JSOp op, MutableHandleValue lref, HandleValue rref,
+ MutableHandleValue res)
+{
+ MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
+
+ uint32_t index;
+ if (lref.isString() && IsDefinitelyIndex(rref, &index)) {
+ JSString* str = lref.toString();
+ if (index < str->length()) {
+ str = cx->staticStrings().getUnitStringForElement(cx, str, index);
+ if (!str)
+ return false;
+ res.setString(str);
+ return true;
+ }
+ }
+
+ if (lref.isPrimitive()) {
+ RootedValue thisv(cx, lref);
+ return GetPrimitiveElementOperation(cx, op, thisv, rref, res);
+ }
+
+ RootedObject thisv(cx, &lref.toObject());
+ return GetObjectElementOperation(cx, op, thisv, thisv, rref, res);
+}
+
+static MOZ_ALWAYS_INLINE JSString*
+TypeOfOperation(const Value& v, JSRuntime* rt)
+{
+ JSType type = js::TypeOfValue(v);
+ return TypeName(type, *rt->commonNames);
+}
+
+static inline JSString*
+TypeOfObjectOperation(JSObject* obj, JSRuntime* rt)
+{
+ JSType type = js::TypeOfObject(obj);
+ return TypeName(type, *rt->commonNames);
+}
+
+static MOZ_ALWAYS_INLINE bool
+InitElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval, HandleValue val)
+{
+ MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));
+ MOZ_ASSERT(!obj->getClass()->getGetProperty());
+ MOZ_ASSERT(!obj->getClass()->getSetProperty());
+
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, idval, &id))
+ return false;
+
+ unsigned flags = JSOp(*pc) == JSOP_INITHIDDENELEM ? 0 : JSPROP_ENUMERATE;
+ return DefineProperty(cx, obj, id, val, nullptr, nullptr, flags);
+}
+
+static MOZ_ALWAYS_INLINE bool
+InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t index, HandleValue val)
+{
+ JSOp op = JSOp(*pc);
+ MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
+
+ MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
+
+ if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);
+ return false;
+ }
+
+ /*
+ * If val is a hole, do not call DefineElement.
+ *
+ * Furthermore, if the current op is JSOP_INITELEM_INC, always call
+ * SetLengthProperty even if it is not the last element initialiser,
+ * because it may be followed by JSOP_SPREAD, which will not set the array
+ * length if nothing is spread.
+ *
+ * Alternatively, if the current op is JSOP_INITELEM_ARRAY, the length will
+ * have already been set by the earlier JSOP_NEWARRAY; JSOP_INITELEM_ARRAY
+ * cannot follow JSOP_SPREAD.
+ */
+ if (val.isMagic(JS_ELEMENTS_HOLE)) {
+ if (op == JSOP_INITELEM_INC) {
+ if (!SetLengthProperty(cx, obj, index + 1))
+ return false;
+ }
+ } else {
+ if (!DefineElement(cx, obj, index, val, nullptr, nullptr, JSPROP_ENUMERATE))
+ return false;
+ }
+
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+ProcessCallSiteObjOperation(JSContext* cx, RootedObject& cso, RootedObject& raw,
+ RootedValue& rawValue)
+{
+ bool extensible;
+ if (!IsExtensible(cx, cso, &extensible))
+ return false;
+ if (extensible) {
+ JSAtom* name = cx->names().raw;
+ if (!DefineProperty(cx, cso, name->asPropertyName(), rawValue, nullptr, nullptr, 0))
+ return false;
+ if (!FreezeObject(cx, raw))
+ return false;
+ if (!FreezeObject(cx, cso))
+ return false;
+ }
+ return true;
+}
+
+#define RELATIONAL_OP(OP) \
+ JS_BEGIN_MACRO \
+ /* Optimize for two int-tagged operands (typical loop control). */ \
+ if (lhs.isInt32() && rhs.isInt32()) { \
+ *res = lhs.toInt32() OP rhs.toInt32(); \
+ } else { \
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) \
+ return false; \
+ if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) \
+ return false; \
+ if (lhs.isString() && rhs.isString()) { \
+ JSString* l = lhs.toString(); \
+ JSString* r = rhs.toString(); \
+ int32_t result; \
+ if (!CompareStrings(cx, l, r, &result)) \
+ return false; \
+ *res = result OP 0; \
+ } else { \
+ double l, r; \
+ if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r)) \
+ return false; \
+ *res = (l OP r); \
+ } \
+ } \
+ return true; \
+ JS_END_MACRO
+
+static MOZ_ALWAYS_INLINE bool
+LessThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
+ RELATIONAL_OP(<);
+}
+
+static MOZ_ALWAYS_INLINE bool
+LessThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
+ RELATIONAL_OP(<=);
+}
+
+static MOZ_ALWAYS_INLINE bool
+GreaterThanOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
+ RELATIONAL_OP(>);
+}
+
+static MOZ_ALWAYS_INLINE bool
+GreaterThanOrEqualOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
+ RELATIONAL_OP(>=);
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitNot(JSContext* cx, HandleValue in, int* out)
+{
+ int i;
+ if (!ToInt32(cx, in, &i))
+ return false;
+ *out = ~i;
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitXor(JSContext* cx, HandleValue lhs, HandleValue rhs, int* out)
+{
+ int left, right;
+ if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ *out = left ^ right;
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitOr(JSContext* cx, HandleValue lhs, HandleValue rhs, int* out)
+{
+ int left, right;
+ if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ *out = left | right;
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitAnd(JSContext* cx, HandleValue lhs, HandleValue rhs, int* out)
+{
+ int left, right;
+ if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ *out = left & right;
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitLsh(JSContext* cx, HandleValue lhs, HandleValue rhs, int* out)
+{
+ int32_t left, right;
+ if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ *out = uint32_t(left) << (right & 31);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+BitRsh(JSContext* cx, HandleValue lhs, HandleValue rhs, int* out)
+{
+ int32_t left, right;
+ if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ *out = left >> (right & 31);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+UrshOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue out)
+{
+ uint32_t left;
+ int32_t right;
+ if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+ return false;
+ left >>= right & 31;
+ out.setNumber(uint32_t(left));
+ return true;
+}
+
+template <typename T>
+static MOZ_ALWAYS_INLINE bool
+SignExtendOperation(JSContext* cx, HandleValue in, int* out)
+{
+ int32_t i;
+ if (!ToInt32(cx, in, &i))
+ return false;
+ *out = (T)i;
+ return true;
+}
+
+#undef RELATIONAL_OP
+
+inline JSFunction*
+ReportIfNotFunction(JSContext* cx, HandleValue v, MaybeConstruct construct = NO_CONSTRUCT)
+{
+ if (v.isObject() && v.toObject().is<JSFunction>())
+ return &v.toObject().as<JSFunction>();
+
+ ReportIsNotFunction(cx, v, -1, construct);
+ return nullptr;
+}
+
+/*
+ * FastCallGuard is used to optimize calls to JS functions from natives written
+ * in C++, e.g. Array.prototype.map. If the callee is not Ion-compiled, this
+ * will just call js::Call. If the callee has a valid IonScript, however, it
+ * will enter Ion directly.
+ */
+class FastCallGuard
+{
+ InvokeArgs args_;
+ RootedFunction fun_;
+ RootedScript script_;
+
+ // Constructing a JitContext is pretty expensive due to the TLS access,
+ // so only do this if we have to.
+ bool useIon_;
+
+ public:
+ FastCallGuard(JSContext* cx, const Value& fval)
+ : args_(cx)
+ , fun_(cx)
+ , script_(cx)
+ , useIon_(jit::IsIonEnabled(cx))
+ {
+ initFunction(fval);
+ }
+
+ void initFunction(const Value& fval) {
+ if (fval.isObject() && fval.toObject().is<JSFunction>()) {
+ JSFunction* fun = &fval.toObject().as<JSFunction>();
+ if (fun->isInterpreted())
+ fun_ = fun;
+ }
+ }
+
+ InvokeArgs& args() {
+ return args_;
+ }
+
+ bool call(JSContext* cx, HandleValue callee, HandleValue thisv, MutableHandleValue rval) {
+ args_.CallArgs::setCallee(callee);
+ args_.CallArgs::setThis(thisv);
+
+ if (useIon_ && fun_) {
+ if (!script_) {
+ script_ = fun_->getOrCreateScript(cx);
+ if (!script_)
+ return false;
+ }
+ MOZ_ASSERT(fun_->nonLazyScript() == script_);
+
+ jit::MethodStatus status = jit::CanEnterUsingFastInvoke(cx, script_, args_.length());
+ if (status == jit::Method_Error)
+ return false;
+ if (status == jit::Method_Compiled) {
+ jit::JitExecStatus result = jit::FastInvoke(cx, fun_, args_);
+ if (IsErrorStatus(result))
+ return false;
+
+ MOZ_ASSERT(result == jit::JitExec_Ok);
+ rval.set(args_.CallArgs::rval());
+ return true;
+ }
+
+ MOZ_ASSERT(status == jit::Method_Skipped);
+
+ if (script_->canIonCompile()) {
+ // This script is not yet hot. Since calling into Ion is much
+ // faster here, bump the warm-up counter a bit to account for this.
+ script_->incWarmUpCounter(5);
+ }
+ }
+
+ if (!InternalCallOrConstruct(cx, args_, NO_CONSTRUCT))
+ return false;
+
+ rval.set(args_.CallArgs::rval());
+ return true;
+ }
+
+ private:
+ FastCallGuard(const FastCallGuard& other) = delete;
+ void operator=(const FastCallGuard& other) = delete;
+};
+
+} /* namespace js */
+
+#endif /* vm_Interpreter_inl_h */
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
new file mode 100644
index 000000000..3ca379d01
--- /dev/null
+++ b/js/src/vm/Interpreter.cpp
@@ -0,0 +1,5087 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JavaScript bytecode interpreter.
+ */
+
+#include "vm/Interpreter-inl.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/Sprintf.h"
+
+#include <string.h>
+
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsiter.h"
+#include "jslibmath.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsprf.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+#include "builtin/Eval.h"
+#include "jit/AtomicOperations.h"
+#include "jit/BaselineJIT.h"
+#include "jit/Ion.h"
+#include "jit/IonAnalysis.h"
+#include "vm/AsyncFunction.h"
+#include "vm/Debugger.h"
+#include "vm/GeneratorObject.h"
+#include "vm/Opcodes.h"
+#include "vm/Scope.h"
+#include "vm/Shape.h"
+#include "vm/Stopwatch.h"
+#include "vm/TraceLogging.h"
+
+#include "jsatominlines.h"
+#include "jsboolinlines.h"
+#include "jsfuninlines.h"
+#include "jsscriptinlines.h"
+
+#include "jit/JitFrames-inl.h"
+#include "vm/Debugger-inl.h"
+#include "vm/EnvironmentObject-inl.h"
+#include "vm/NativeObject-inl.h"
+#include "vm/Probes-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::NumberEqualsInt32;
+using mozilla::PodCopy;
+using JS::ForOfIterator;
+
+template <bool Eq>
+static MOZ_ALWAYS_INLINE bool
+LooseEqualityOp(JSContext* cx, InterpreterRegs& regs)
+{
+ HandleValue rval = regs.stackHandleAt(-1);
+ HandleValue lval = regs.stackHandleAt(-2);
+ bool cond;
+ if (!LooselyEqual(cx, lval, rval, &cond))
+ return false;
+ cond = (cond == Eq);
+ regs.sp--;
+ regs.sp[-1].setBoolean(cond);
+ return true;
+}
+
+bool
+js::BoxNonStrictThis(JSContext* cx, HandleValue thisv, MutableHandleValue vp)
+{
+ /*
+ * Check for SynthesizeFrame poisoning and fast constructors which
+ * didn't check their callee properly.
+ */
+ MOZ_ASSERT(!thisv.isMagic());
+
+ if (thisv.isNullOrUndefined()) {
+ vp.set(GetThisValue(cx->global()));
+ return true;
+ }
+
+ if (thisv.isObject()) {
+ vp.set(thisv);
+ return true;
+ }
+
+ JSObject* obj = PrimitiveToObject(cx, thisv);
+ if (!obj)
+ return false;
+
+ vp.setObject(*obj);
+ return true;
+}
+
+bool
+js::GetFunctionThis(JSContext* cx, AbstractFramePtr frame, MutableHandleValue res)
+{
+ MOZ_ASSERT(frame.isFunctionFrame());
+ MOZ_ASSERT(!frame.callee()->isArrow());
+
+ if (frame.thisArgument().isObject() ||
+ frame.callee()->strict() ||
+ frame.callee()->isSelfHostedBuiltin())
+ {
+ res.set(frame.thisArgument());
+ return true;
+ }
+
+ RootedValue thisv(cx, frame.thisArgument());
+ return BoxNonStrictThis(cx, thisv, res);
+}
+
+bool
+js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, MutableHandleValue res)
+{
+ RootedObject env(cx, envChain);
+ while (true) {
+ if (IsExtensibleLexicalEnvironment(env)) {
+ res.set(env->as<LexicalEnvironmentObject>().thisValue());
+ return true;
+ }
+ if (!env->enclosingEnvironment()) {
+ // This can only happen in Debugger eval frames: in that case we
+ // don't always have a global lexical env, see EvaluateInEnv.
+ MOZ_ASSERT(env->is<GlobalObject>());
+ res.set(GetThisValue(env));
+ return true;
+ }
+ env = env->enclosingEnvironment();
+ }
+
+ 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
+
+ RootedObject funObj(cx, UncheckedUnwrap(&fun.toObject()));
+ MOZ_ASSERT(funObj->as<JSFunction>().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)
+{
+ JSOp op = JSOp(*pc);
+
+ if (op == JSOP_LENGTH) {
+ if (IsOptimizedArguments(fp, lval)) {
+ vp.setInt32(fp->numActualArgs());
+ return true;
+ }
+
+ if (GetLengthProperty(lval, vp))
+ return true;
+ }
+
+ RootedPropertyName name(cx, script->getName(pc));
+
+ if (name == cx->names().callee && IsOptimizedArguments(fp, lval)) {
+ vp.setObject(fp->callee());
+ return true;
+ }
+
+ // Copy lval, because it might alias vp.
+ RootedValue v(cx, lval);
+ return GetProperty(cx, v, name, vp);
+}
+
+static inline bool
+GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHandleValue vp)
+{
+ JSObject* obj = fp->environmentChain();
+ PropertyName* name = fp->script()->getName(pc);
+
+ /*
+ * Skip along the env chain to the enclosing global object. This is
+ * used for GNAME opcodes where the bytecode emitter has determined a
+ * name access must be on the global. It also insulates us from bugs
+ * in the emitter: type inference will assume that GNAME opcodes are
+ * accessing the global object, and the inferred behavior should match
+ * the actual behavior even if the id could be found on the env chain
+ * before the global object.
+ */
+ if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope())
+ obj = &obj->global().lexicalEnvironment();
+
+ Shape* shape = nullptr;
+ JSObject* env = nullptr;
+ JSObject* pobj = nullptr;
+ if (LookupNameNoGC(cx, name, obj, &env, &pobj, &shape)) {
+ if (FetchNameNoGC(pobj, shape, vp))
+ return true;
+ }
+
+ RootedObject objRoot(cx, obj), envRoot(cx), pobjRoot(cx);
+ RootedPropertyName nameRoot(cx, name);
+ RootedShape shapeRoot(cx);
+
+ if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &shapeRoot))
+ return false;
+
+ /* Kludge to allow (typeof foo == "undefined") tests. */
+ JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
+ if (op2 == JSOP_TYPEOF)
+ return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
+
+ return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
+}
+
+static inline bool
+GetImportOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHandleValue vp)
+{
+ RootedObject obj(cx, fp->environmentChain()), env(cx), pobj(cx);
+ RootedPropertyName name(cx, fp->script()->getName(pc));
+ RootedShape shape(cx);
+
+ MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &shape));
+ MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
+ MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
+ return FetchName<false>(cx, env, pobj, name, shape, vp);
+}
+
+static bool
+SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, HandleValue rval)
+{
+ MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
+
+ RootedObject obj(cx, ToObjectFromStack(cx, lval));
+ if (!obj)
+ return false;
+
+ ObjectOpResult result;
+ return SetProperty(cx, obj, id, rval, lval, result) &&
+ result.checkStrictErrorOrWarning(cx, obj, id, op == JSOP_STRICTSETPROP);
+}
+
+static JSFunction*
+MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto)
+{
+ bool derived = op == JSOP_DERIVEDCONSTRUCTOR;
+ MOZ_ASSERT(derived == !!proto);
+
+ PropertyName* lookup = derived ? cx->names().DefaultDerivedClassConstructor
+ : cx->names().DefaultBaseClassConstructor;
+
+ RootedPropertyName selfHostedName(cx, lookup);
+ RootedAtom name(cx, atom == cx->names().empty ? nullptr : atom);
+
+ RootedFunction ctor(cx);
+ if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name,
+ /* nargs = */ !!derived,
+ proto, TenuredObject, &ctor))
+ {
+ return nullptr;
+ }
+
+ ctor->setIsConstructor();
+ ctor->setIsClassConstructor();
+ if (derived)
+ ctor->setHasRest();
+
+ MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx));
+
+ return ctor;
+}
+
+bool
+js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip, MaybeConstruct construct)
+{
+ unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
+ int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
+
+ ReportValueError(cx, error, spIndex, v, nullptr);
+ return false;
+}
+
+JSObject*
+js::ValueToCallable(JSContext* cx, HandleValue v, int numToSkip, MaybeConstruct construct)
+{
+ if (v.isObject() && v.toObject().isCallable()) {
+ return &v.toObject();
+ }
+
+ ReportIsNotFunction(cx, v, numToSkip, construct);
+ return nullptr;
+}
+
+bool
+RunState::maybeCreateThisForConstructor(JSContext* cx)
+{
+ if (isInvoke()) {
+ InvokeState& invoke = *asInvoke();
+ if (invoke.constructing() && invoke.args().thisv().isPrimitive()) {
+ RootedObject callee(cx, &invoke.args().callee());
+ if (callee->isBoundFunction()) {
+ invoke.args().setThis(MagicValue(JS_UNINITIALIZED_LEXICAL));
+ } else if (script()->isDerivedClassConstructor()) {
+ MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
+ invoke.args().setThis(MagicValue(JS_UNINITIALIZED_LEXICAL));
+ } else {
+ MOZ_ASSERT(invoke.args().thisv().isMagic(JS_IS_CONSTRUCTING));
+ RootedObject newTarget(cx, &invoke.args().newTarget().toObject());
+ NewObjectKind newKind = invoke.createSingleton() ? SingletonObject : GenericObject;
+ JSObject* obj = CreateThisForFunction(cx, callee, newTarget, newKind);
+ if (!obj)
+ return false;
+ invoke.args().setThis(ObjectValue(*obj));
+ }
+ }
+ }
+ return true;
+}
+
+static MOZ_NEVER_INLINE bool
+Interpret(JSContext* cx, RunState& state);
+
+InterpreterFrame*
+InvokeState::pushInterpreterFrame(JSContext* cx)
+{
+ return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, construct_);
+}
+
+InterpreterFrame*
+ExecuteState::pushInterpreterFrame(JSContext* cx)
+{
+ return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, newTargetValue_,
+ envChain_, evalInFrame_);
+}
+// MSVC with PGO inlines a lot of functions in RunScript, resulting in large
+// stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
+// avoid this.
+#ifdef _MSC_VER
+# pragma optimize("g", off)
+#endif
+bool
+js::RunScript(JSContext* cx, RunState& state)
+{
+ JS_CHECK_RECURSION(cx, return false);
+
+ // Since any script can conceivably GC, make sure it's safe to do so.
+ cx->runtime()->gc.verifyIsSafeToGC();
+
+ if (!Debugger::checkNoExecute(cx, state.script()))
+ return false;
+
+#if defined(MOZ_HAVE_RDTSC)
+ js::AutoStopwatch stopwatch(cx);
+#endif // defined(MOZ_HAVE_RDTSC)
+
+ SPSEntryMarker marker(cx->runtime(), state.script());
+
+ state.script()->ensureNonLazyCanonicalFunction(cx);
+
+ if (jit::IsIonEnabled(cx)) {
+ jit::MethodStatus status = jit::CanEnter(cx, state);
+ if (status == jit::Method_Error)
+ return false;
+ if (status == jit::Method_Compiled) {
+ jit::JitExecStatus status = jit::IonCannon(cx, state);
+ return !IsErrorStatus(status);
+ }
+ }
+
+ if (jit::IsBaselineEnabled(cx)) {
+ jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state);
+ if (status == jit::Method_Error)
+ return false;
+ if (status == jit::Method_Compiled) {
+ jit::JitExecStatus status = jit::EnterBaselineMethod(cx, state);
+ return !IsErrorStatus(status);
+ }
+ }
+
+ if (state.isInvoke()) {
+ InvokeState& invoke = *state.asInvoke();
+ TypeMonitorCall(cx, invoke.args(), invoke.constructing());
+ }
+
+ return Interpret(cx, state);
+}
+#ifdef _MSC_VER
+# pragma optimize("", on)
+#endif
+
+struct AutoGCIfRequested
+{
+ JSRuntime* runtime;
+ explicit AutoGCIfRequested(JSRuntime* rt) : runtime(rt) {}
+ ~AutoGCIfRequested() { runtime->gc.gcIfRequested(); }
+};
+
+/*
+ * Find a function reference and its 'this' value implicit first parameter
+ * under argc arguments on cx's stack, and call the function. Push missing
+ * required arguments, allocate declared local variables, and pop everything
+ * when done. Then push the return value.
+ *
+ * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
+ * necessary. The caller (usually the interpreter) must have performed
+ * this step already!
+ */
+bool
+js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
+{
+ MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
+ MOZ_ASSERT(!cx->zone()->types.activeAnalysis);
+
+ /* Perform GC if necessary on exit from the function. */
+ AutoGCIfRequested gcIfRequested(cx->runtime());
+
+ unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
+ if (args.calleev().isPrimitive())
+ return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
+
+ /* Invoke non-functions. */
+ if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) {
+ MOZ_ASSERT_IF(construct, !args.callee().constructHook());
+ JSNative call = args.callee().callHook();
+ if (!call)
+ return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
+ return CallJSNative(cx, call, args);
+ }
+
+ /* Invoke native functions. */
+ JSFunction* fun = &args.callee().as<JSFunction>();
+ if (construct != CONSTRUCT && fun->isClassConstructor()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
+ return false;
+ }
+
+ if (fun->isNative()) {
+ MOZ_ASSERT_IF(construct, !fun->isConstructor());
+ return CallJSNative(cx, fun->native(), args);
+ }
+
+ if (!fun->getOrCreateScript(cx))
+ return false;
+
+ /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
+ InvokeState state(cx, args, construct);
+
+ // Check to see if createSingleton flag should be set for this frame.
+ if (construct) {
+ jsbytecode* pc;
+ if (JSScript* script = cx->currentScript(&pc)) {
+ if (ObjectGroup::useSingletonForNewObject(cx, script, pc))
+ state.setCreateSingleton();
+ }
+ }
+
+ bool ok = RunScript(cx, state);
+
+ MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
+ return ok;
+}
+
+static bool
+InternalCall(JSContext* cx, const AnyInvokeArgs& args)
+{
+ MOZ_ASSERT(args.array() + args.length() == args.end(),
+ "must pass calling arguments to a calling attempt");
+
+ if (args.thisv().isObject()) {
+ // We must call the thisValue hook in case we are not called from the
+ // interpreter, where a prior bytecode has computed an appropriate
+ // |this| already. But don't do that if fval is a DOM function.
+ HandleValue fval = args.calleev();
+ if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
+ !fval.toObject().as<JSFunction>().isNative() ||
+ !fval.toObject().as<JSFunction>().jitInfo() ||
+ fval.toObject().as<JSFunction>().jitInfo()->needsOuterizedThisObject())
+ {
+ JSObject* thisObj = &args.thisv().toObject();
+ args.mutableThisv().set(GetThisValue(thisObj));
+ }
+ }
+
+ return InternalCallOrConstruct(cx, args, NO_CONSTRUCT);
+}
+
+bool
+js::CallFromStack(JSContext* cx, const CallArgs& args)
+{
+ return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args));
+}
+
+// ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.12 Call.
+bool
+js::Call(JSContext* cx, HandleValue fval, HandleValue thisv, const AnyInvokeArgs& args,
+ MutableHandleValue rval)
+{
+ // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
+ // shadowing.
+ args.CallArgs::setCallee(fval);
+ args.CallArgs::setThis(thisv);
+
+ if (!InternalCall(cx, args))
+ return false;
+
+ rval.set(args.rval());
+ return true;
+}
+
+static bool
+InternalConstruct(JSContext* cx, const AnyConstructArgs& args)
+{
+ MOZ_ASSERT(args.array() + args.length() + 1 == args.end(),
+ "must pass constructing arguments to a construction attempt");
+ MOZ_ASSERT(!JSFunction::class_.getConstruct());
+
+ // Callers are responsible for enforcing these preconditions.
+ MOZ_ASSERT(IsConstructor(args.calleev()),
+ "trying to construct a value that isn't a constructor");
+ MOZ_ASSERT(IsConstructor(args.CallArgs::newTarget()),
+ "provided new.target value must be a constructor");
+
+ MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING) || args.thisv().isObject());
+
+ JSObject& callee = args.callee();
+ if (callee.is<JSFunction>()) {
+ RootedFunction fun(cx, &callee.as<JSFunction>());
+
+ if (fun->isNative())
+ return CallJSNativeConstructor(cx, fun->native(), args);
+
+ if (!InternalCallOrConstruct(cx, args, CONSTRUCT))
+ return false;
+
+ MOZ_ASSERT(args.CallArgs::rval().isObject());
+ return true;
+ }
+
+ JSNative construct = callee.constructHook();
+ MOZ_ASSERT(construct != nullptr, "IsConstructor without a construct hook?");
+
+ return CallJSNativeConstructor(cx, construct, args);
+}
+
+// Check that |callee|, the callee in a |new| expression, is a constructor.
+static bool
+StackCheckIsConstructorCalleeNewTarget(JSContext* cx, HandleValue callee, HandleValue newTarget)
+{
+ // Calls from the stack could have any old non-constructor callee.
+ if (!IsConstructor(callee)) {
+ ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, callee, nullptr);
+ return false;
+ }
+
+ // The new.target has already been vetted by previous calls, or is the callee.
+ // We can just assert that it's a constructor.
+ MOZ_ASSERT(IsConstructor(newTarget));
+
+ return true;
+}
+
+bool
+js::ConstructFromStack(JSContext* cx, const CallArgs& args)
+{
+ if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(), args.newTarget()))
+ return false;
+
+ return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args));
+}
+
+bool
+js::Construct(JSContext* cx, HandleValue fval, const AnyConstructArgs& args, HandleValue newTarget,
+ MutableHandleObject objp)
+{
+ MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING));
+
+ // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
+ args.CallArgs::setCallee(fval);
+ args.CallArgs::newTarget().set(newTarget);
+
+ if (!InternalConstruct(cx, args))
+ return false;
+
+ MOZ_ASSERT(args.CallArgs::rval().isObject());
+ objp.set(&args.CallArgs::rval().toObject());
+ return true;
+}
+
+bool
+js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval, HandleValue thisv,
+ const AnyConstructArgs& args, HandleValue newTarget,
+ MutableHandleValue rval)
+{
+ args.CallArgs::setCallee(fval);
+
+ MOZ_ASSERT(thisv.isObject());
+ args.CallArgs::setThis(thisv);
+
+ args.CallArgs::newTarget().set(newTarget);
+
+ if (!InternalConstruct(cx, args))
+ return false;
+
+ rval.set(args.CallArgs::rval());
+ return true;
+}
+
+bool
+js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter, MutableHandleValue rval)
+{
+ // Invoke could result in another try to get or set the same id again, see
+ // bug 355497.
+ JS_CHECK_RECURSION(cx, return false);
+
+ FixedInvokeArgs<0> args(cx);
+
+ return Call(cx, getter, thisv, args, rval);
+}
+
+bool
+js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter, HandleValue v)
+{
+ JS_CHECK_RECURSION(cx, return false);
+
+ FixedInvokeArgs<1> args(cx);
+
+ args[0].set(v);
+
+ RootedValue ignored(cx);
+ return Call(cx, setter, thisv, args, &ignored);
+}
+
+bool
+js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& envChainArg,
+ const Value& newTargetValue, AbstractFramePtr evalInFrame,
+ Value* result)
+{
+ MOZ_ASSERT_IF(script->isGlobalCode(),
+ IsGlobalLexicalEnvironment(&envChainArg) ||
+ !IsSyntacticEnvironment(&envChainArg));
+#ifdef DEBUG
+ RootedObject terminatingEnv(cx, &envChainArg);
+ while (IsSyntacticEnvironment(terminatingEnv))
+ terminatingEnv = terminatingEnv->enclosingEnvironment();
+ MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
+ script->hasNonSyntacticScope());
+#endif
+
+ if (script->treatAsRunOnce()) {
+ if (script->hasRunOnce()) {
+ JS_ReportErrorASCII(cx, "Trying to execute a run-once script multiple times");
+ return false;
+ }
+
+ script->setHasRunOnce();
+ }
+
+ if (script->isEmpty()) {
+ if (result)
+ result->setUndefined();
+ return true;
+ }
+
+ probes::StartExecution(script);
+ ExecuteState state(cx, script, newTargetValue, envChainArg, evalInFrame, result);
+ bool ok = RunScript(cx, state);
+ probes::StopExecution(script);
+
+ return ok;
+}
+
+bool
+js::Execute(JSContext* cx, HandleScript script, JSObject& envChainArg, Value* rval)
+{
+ /* The env chain is something we control, so we know it can't
+ have any outer objects on it. */
+ RootedObject envChain(cx, &envChainArg);
+ MOZ_ASSERT(!IsWindowProxy(envChain));
+
+ if (script->module()) {
+ MOZ_RELEASE_ASSERT(envChain == script->module()->environment(),
+ "Module scripts can only be executed in the module's environment");
+ } else {
+ MOZ_RELEASE_ASSERT(IsGlobalLexicalEnvironment(envChain) || script->hasNonSyntacticScope(),
+ "Only global scripts with non-syntactic envs can be executed with "
+ "interesting envchains");
+ }
+
+ /* Ensure the env chain is all same-compartment and terminates in a global. */
+#ifdef DEBUG
+ JSObject* s = envChain;
+ do {
+ assertSameCompartment(cx, s);
+ MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
+ } while ((s = s->enclosingEnvironment()));
+#endif
+
+ return ExecuteKernel(cx, script, *envChain, NullValue(),
+ NullFramePtr() /* evalInFrame */, rval);
+}
+
+/*
+ * ES6 (4-25-16) 12.10.4 InstanceofOperator
+ */
+extern bool
+js::InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
+{
+ /* Step 1. is handled by caller. */
+
+ /* Step 2. */
+ RootedValue hasInstance(cx);
+ RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance));
+ if (!GetProperty(cx, obj, obj, id, &hasInstance))
+ return false;
+
+ if (!hasInstance.isNullOrUndefined()) {
+ if (!IsCallable(hasInstance))
+ return ReportIsNotFunction(cx, hasInstance);
+
+ /* Step 3. */
+ RootedValue rval(cx);
+ if (!Call(cx, hasInstance, obj, v, &rval))
+ return false;
+ *bp = ToBoolean(rval);
+ return true;
+ }
+
+ /* Step 4. */
+ if (!obj->isCallable()) {
+ RootedValue val(cx, ObjectValue(*obj));
+ return ReportIsNotFunction(cx, val);
+ }
+
+ /* Step 5. */
+ return OrdinaryHasInstance(cx, obj, v, bp);
+}
+
+bool
+js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp)
+{
+ const Class* clasp = obj->getClass();
+ RootedValue local(cx, v);
+ if (JSHasInstanceOp hasInstance = clasp->getHasInstance())
+ return hasInstance(cx, obj, &local, bp);
+ return js::InstanceOfOperator(cx, obj, local, bp);
+}
+
+static inline bool
+EqualGivenSameType(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal)
+{
+ MOZ_ASSERT(SameType(lval, rval));
+
+ if (lval.isString())
+ return EqualStrings(cx, lval.toString(), rval.toString(), equal);
+ if (lval.isDouble()) {
+ *equal = (lval.toDouble() == rval.toDouble());
+ return true;
+ }
+ if (lval.isGCThing()) { // objects or symbols
+ *equal = (lval.toGCThing() == rval.toGCThing());
+ return true;
+ }
+ *equal = lval.get().payloadAsRawUint32() == rval.get().payloadAsRawUint32();
+ MOZ_ASSERT_IF(lval.isUndefined() || lval.isNull(), *equal);
+ return true;
+}
+
+static inline bool
+LooselyEqualBooleanAndOther(JSContext* cx, HandleValue lval, HandleValue rval, bool* result)
+{
+ MOZ_ASSERT(!rval.isBoolean());
+ RootedValue lvalue(cx, Int32Value(lval.toBoolean() ? 1 : 0));
+
+ // The tail-call would end up in Step 3.
+ if (rval.isNumber()) {
+ *result = (lvalue.toNumber() == rval.toNumber());
+ return true;
+ }
+ // The tail-call would end up in Step 6.
+ if (rval.isString()) {
+ double num;
+ if (!StringToNumber(cx, rval.toString(), &num))
+ return false;
+ *result = (lvalue.toNumber() == num);
+ return true;
+ }
+
+ return LooselyEqual(cx, lvalue, rval, result);
+}
+
+// ES6 draft rev32 7.2.12 Abstract Equality Comparison
+bool
+js::LooselyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* result)
+{
+ // Step 3.
+ if (SameType(lval, rval))
+ return EqualGivenSameType(cx, lval, rval, result);
+
+ // Handle int32 x double.
+ if (lval.isNumber() && rval.isNumber()) {
+ *result = (lval.toNumber() == rval.toNumber());
+ return true;
+ }
+
+ // Step 4. This a bit more complex, because of the undefined emulating object.
+ if (lval.isNullOrUndefined()) {
+ // We can return early here, because null | undefined is only equal to the same set.
+ *result = rval.isNullOrUndefined() ||
+ (rval.isObject() && EmulatesUndefined(&rval.toObject()));
+ return true;
+ }
+
+ // Step 5.
+ if (rval.isNullOrUndefined()) {
+ MOZ_ASSERT(!lval.isNullOrUndefined());
+ *result = lval.isObject() && EmulatesUndefined(&lval.toObject());
+ return true;
+ }
+
+ // Step 6.
+ if (lval.isNumber() && rval.isString()) {
+ double num;
+ if (!StringToNumber(cx, rval.toString(), &num))
+ return false;
+ *result = (lval.toNumber() == num);
+ return true;
+ }
+
+ // Step 7.
+ if (lval.isString() && rval.isNumber()) {
+ double num;
+ if (!StringToNumber(cx, lval.toString(), &num))
+ return false;
+ *result = (num == rval.toNumber());
+ return true;
+ }
+
+ // Step 8.
+ if (lval.isBoolean())
+ return LooselyEqualBooleanAndOther(cx, lval, rval, result);
+
+ // Step 9.
+ if (rval.isBoolean())
+ return LooselyEqualBooleanAndOther(cx, rval, lval, result);
+
+ // Step 10.
+ if ((lval.isString() || lval.isNumber() || lval.isSymbol()) && rval.isObject()) {
+ RootedValue rvalue(cx, rval);
+ if (!ToPrimitive(cx, &rvalue))
+ return false;
+ return LooselyEqual(cx, lval, rvalue, result);
+ }
+
+ // Step 11.
+ if (lval.isObject() && (rval.isString() || rval.isNumber() || rval.isSymbol())) {
+ RootedValue lvalue(cx, lval);
+ if (!ToPrimitive(cx, &lvalue))
+ return false;
+ return LooselyEqual(cx, lvalue, rval, result);
+ }
+
+ // Step 12.
+ *result = false;
+ return true;
+}
+
+bool
+js::StrictlyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal)
+{
+ if (SameType(lval, rval))
+ return EqualGivenSameType(cx, lval, rval, equal);
+
+ if (lval.isNumber() && rval.isNumber()) {
+ *equal = (lval.toNumber() == rval.toNumber());
+ return true;
+ }
+
+ *equal = false;
+ return true;
+}
+
+static inline bool
+IsNegativeZero(const Value& v)
+{
+ return v.isDouble() && mozilla::IsNegativeZero(v.toDouble());
+}
+
+static inline bool
+IsNaN(const Value& v)
+{
+ return v.isDouble() && mozilla::IsNaN(v.toDouble());
+}
+
+bool
+js::SameValue(JSContext* cx, HandleValue v1, HandleValue v2, bool* same)
+{
+ if (IsNegativeZero(v1)) {
+ *same = IsNegativeZero(v2);
+ return true;
+ }
+ if (IsNegativeZero(v2)) {
+ *same = false;
+ return true;
+ }
+ if (IsNaN(v1) && IsNaN(v2)) {
+ *same = true;
+ return true;
+ }
+ return StrictlyEqual(cx, v1, v2, same);
+}
+
+JSType
+js::TypeOfObject(JSObject* obj)
+{
+ if (EmulatesUndefined(obj))
+ return JSTYPE_VOID;
+ if (obj->isCallable())
+ return JSTYPE_FUNCTION;
+ return JSTYPE_OBJECT;
+}
+
+JSType
+js::TypeOfValue(const Value& v)
+{
+ if (v.isNumber())
+ return JSTYPE_NUMBER;
+ if (v.isString())
+ return JSTYPE_STRING;
+ if (v.isNull())
+ return JSTYPE_OBJECT;
+ if (v.isUndefined())
+ return JSTYPE_VOID;
+ if (v.isObject())
+ return TypeOfObject(&v.toObject());
+ if (v.isBoolean())
+ return JSTYPE_BOOLEAN;
+ MOZ_ASSERT(v.isSymbol());
+ return JSTYPE_SYMBOL;
+}
+
+/*
+ * Enter the new with environment using an object at sp[-1] and associate the
+ * depth of the with block with sp + stackIndex.
+ */
+bool
+js::EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val,
+ Handle<WithScope*> scope)
+{
+ RootedObject obj(cx);
+ if (val.isObject()) {
+ obj = &val.toObject();
+ } else {
+ obj = ToObject(cx, val);
+ if (!obj)
+ return false;
+ }
+
+ RootedObject envChain(cx, frame.environmentChain());
+ WithEnvironmentObject* withobj = WithEnvironmentObject::create(cx, obj, envChain, scope);
+ if (!withobj)
+ return false;
+
+ frame.pushOnEnvironmentChain(*withobj);
+ return true;
+}
+
+static void
+PopEnvironment(JSContext* cx, EnvironmentIter& ei)
+{
+ switch (ei.scope().kind()) {
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda:
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopLexical(cx, ei);
+ if (ei.scope().hasEnvironment())
+ ei.initialFrame().popOffEnvironmentChain<LexicalEnvironmentObject>();
+ break;
+ case ScopeKind::With:
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopWith(ei.initialFrame());
+ ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
+ break;
+ case ScopeKind::Function:
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopCall(cx, ei.initialFrame());
+ if (ei.scope().hasEnvironment())
+ ei.initialFrame().popOffEnvironmentChain<CallObject>();
+ break;
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar:
+ case ScopeKind::StrictEval:
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopVar(cx, ei);
+ if (ei.scope().hasEnvironment())
+ ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
+ break;
+ case ScopeKind::Eval:
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ case ScopeKind::Module:
+ break;
+ }
+}
+
+// Unwind environment chain and iterator to match the env corresponding to
+// the given bytecode position.
+void
+js::UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc)
+{
+ if (!ei.withinInitialFrame())
+ return;
+
+ RootedScope scope(cx, ei.initialFrame().script()->innermostScope(pc));
+
+#ifdef DEBUG
+ // A frame's environment chain cannot be unwound to anything enclosing the
+ // body scope of a script. This includes the parameter defaults
+ // environment and the decl env object. These environments, once pushed
+ // onto the environment chain, are expected to be there for the duration
+ // of the frame.
+ //
+ // Attempting to unwind to the parameter defaults code in a script is a
+ // bug; that section of code has no try-catch blocks.
+ JSScript* script = ei.initialFrame().script();
+ for (uint32_t i = 0; i < script->bodyScopeIndex(); i++)
+ MOZ_ASSERT(scope != script->getScope(i));
+#endif
+
+ for (; ei.maybeScope() != scope; ei++)
+ PopEnvironment(cx, ei);
+}
+
+// Unwind all environments. This is needed because block scopes may cover the
+// first bytecode at a script's main(). e.g.,
+//
+// function f() { { let i = 0; } }
+//
+// will have no pc location distinguishing the first block scope from the
+// outermost function scope.
+void
+js::UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei)
+{
+ for (; ei.withinInitialFrame(); ei++)
+ PopEnvironment(cx, ei);
+}
+
+// Compute the pc needed to unwind the environment to the beginning of a try
+// block. We cannot unwind to *after* the JSOP_TRY, because that might be the
+// first opcode of an inner scope, with the same problem as above. e.g.,
+//
+// try { { let x; } }
+//
+// will have no pc location distinguishing the try block scope from the inner
+// let block scope.
+jsbytecode*
+js::UnwindEnvironmentToTryPc(JSScript* script, JSTryNote* tn)
+{
+ jsbytecode* pc = script->main() + tn->start;
+ if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY) {
+ pc -= JSOP_TRY_LENGTH;
+ MOZ_ASSERT(*pc == JSOP_TRY);
+ }
+ return pc;
+}
+
+static bool
+ForcedReturn(JSContext* cx, EnvironmentIter& ei, InterpreterRegs& regs, bool frameOk = true)
+{
+ bool ok = Debugger::onLeaveFrame(cx, regs.fp(), regs.pc, frameOk);
+ // Point the frame to the end of the script, regardless of error. The
+ // caller must jump to the correct continuation depending on 'ok'.
+ regs.setToEndOfScript();
+ return ok;
+}
+
+static bool
+ForcedReturn(JSContext* cx, InterpreterRegs& regs)
+{
+ EnvironmentIter ei(cx, regs.fp(), regs.pc);
+ return ForcedReturn(cx, ei, regs);
+}
+
+static void
+SettleOnTryNote(JSContext* cx, JSTryNote* tn, EnvironmentIter& ei, InterpreterRegs& regs)
+{
+ // Unwind the environment to the beginning of the JSOP_TRY.
+ UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
+
+ // Set pc to the first bytecode after the the try note to point
+ // to the beginning of catch or finally.
+ regs.pc = regs.fp()->script()->main() + tn->start + tn->length;
+ regs.sp = regs.spForStackDepth(tn->stackDepth);
+}
+
+class InterpreterFrameStackDepthOp
+{
+ const InterpreterRegs& regs_;
+ public:
+ explicit InterpreterFrameStackDepthOp(const InterpreterRegs& regs)
+ : regs_(regs)
+ { }
+ uint32_t operator()() { return regs_.stackDepth(); }
+};
+
+class TryNoteIterInterpreter : public TryNoteIter<InterpreterFrameStackDepthOp>
+{
+ public:
+ TryNoteIterInterpreter(JSContext* cx, const InterpreterRegs& regs)
+ : TryNoteIter(cx, regs.fp()->script(), regs.pc, InterpreterFrameStackDepthOp(regs))
+ { }
+};
+
+static void
+UnwindIteratorsForUncatchableException(JSContext* cx, const InterpreterRegs& regs)
+{
+ // c.f. the regular (catchable) TryNoteIterInterpreter loop in
+ // ProcessTryNotes.
+ for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
+ JSTryNote* tn = *tni;
+ if (tn->kind == JSTRY_FOR_IN) {
+ Value* sp = regs.spForStackDepth(tn->stackDepth);
+ UnwindIteratorForUncatchableException(cx, &sp[-1].toObject());
+ }
+ }
+}
+
+enum HandleErrorContinuation
+{
+ SuccessfulReturnContinuation,
+ ErrorReturnContinuation,
+ CatchContinuation,
+ FinallyContinuation
+};
+
+static HandleErrorContinuation
+ProcessTryNotes(JSContext* cx, EnvironmentIter& ei, InterpreterRegs& regs)
+{
+ for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
+ JSTryNote* tn = *tni;
+
+ switch (tn->kind) {
+ case JSTRY_CATCH:
+ /* Catch cannot intercept the closing of a generator. */
+ if (cx->isClosingGenerator())
+ break;
+ SettleOnTryNote(cx, tn, ei, regs);
+ return CatchContinuation;
+
+ case JSTRY_FINALLY:
+ SettleOnTryNote(cx, tn, ei, regs);
+ return FinallyContinuation;
+
+ case JSTRY_FOR_IN: {
+ /* This is similar to JSOP_ENDITER in the interpreter loop. */
+ DebugOnly<jsbytecode*> pc = regs.fp()->script()->main() + tn->start + tn->length;
+ MOZ_ASSERT(JSOp(*pc) == JSOP_ENDITER);
+ Value* sp = regs.spForStackDepth(tn->stackDepth);
+ RootedObject obj(cx, &sp[-1].toObject());
+ if (!UnwindIteratorForException(cx, obj)) {
+ // We should only settle on the note only if
+ // UnwindIteratorForException itself threw, as
+ // onExceptionUnwind should be called anew with the new
+ // location of the throw (the iterator). Indeed, we must
+ // settle to avoid infinitely handling the same exception.
+ SettleOnTryNote(cx, tn, ei, regs);
+ return ErrorReturnContinuation;
+ }
+ break;
+ }
+
+ case JSTRY_FOR_OF:
+ case JSTRY_LOOP:
+ break;
+
+ default:
+ MOZ_CRASH("Invalid try note");
+ }
+ }
+
+ return SuccessfulReturnContinuation;
+}
+
+bool
+js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame, bool ok)
+{
+ /*
+ * Propagate the exception or error to the caller unless the exception
+ * is an asynchronous return from a generator.
+ */
+ if (cx->isClosingGenerator()) {
+ cx->clearPendingException();
+ ok = true;
+ SetReturnValueForClosingGenerator(cx, frame);
+ }
+ return ok;
+}
+
+static HandleErrorContinuation
+HandleError(JSContext* cx, InterpreterRegs& regs)
+{
+ MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
+
+ if (regs.fp()->script()->hasScriptCounts()) {
+ PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
+ // If we failed to allocate, then skip the increment and continue to
+ // handle the exception.
+ if (counts)
+ counts->numExec()++;
+ }
+
+ EnvironmentIter ei(cx, regs.fp(), regs.pc);
+ bool ok = false;
+
+ again:
+ if (cx->isExceptionPending()) {
+ /* Call debugger throw hooks. */
+ if (!cx->isClosingGenerator()) {
+ JSTrapStatus status = Debugger::onExceptionUnwind(cx, regs.fp());
+ switch (status) {
+ case JSTRAP_ERROR:
+ goto again;
+
+ case JSTRAP_CONTINUE:
+ case JSTRAP_THROW:
+ break;
+
+ case JSTRAP_RETURN:
+ UnwindIteratorsForUncatchableException(cx, regs);
+ if (!ForcedReturn(cx, ei, regs))
+ return ErrorReturnContinuation;
+ return SuccessfulReturnContinuation;
+
+ default:
+ MOZ_CRASH("Bad Debugger::onExceptionUnwind status");
+ }
+ }
+
+ HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
+ switch (res) {
+ case SuccessfulReturnContinuation:
+ break;
+ case ErrorReturnContinuation:
+ goto again;
+ case CatchContinuation:
+ case FinallyContinuation:
+ // No need to increment the PCCounts number of execution here, as
+ // the interpreter increments any PCCounts if present.
+ MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
+ regs.fp()->script()->maybeGetPCCounts(regs.pc));
+ return res;
+ }
+
+ ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
+ ok = Debugger::onLeaveFrame(cx, regs.fp(), regs.pc, ok);
+ } else {
+ // We may be propagating a forced return from the interrupt
+ // callback, which cannot easily force a return.
+ if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
+ cx->clearPropagatingForcedReturn();
+ if (!ForcedReturn(cx, ei, regs))
+ return ErrorReturnContinuation;
+ return SuccessfulReturnContinuation;
+ }
+
+ UnwindIteratorsForUncatchableException(cx, regs);
+ }
+
+ // After this point, we will pop the frame regardless. Settle the frame on
+ // the end of the script.
+ regs.setToEndOfScript();
+
+ return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
+}
+
+#define REGS (activation.regs())
+#define PUSH_COPY(v) do { *REGS.sp++ = (v); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
+#define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
+#define PUSH_NULL() REGS.sp++->setNull()
+#define PUSH_UNDEFINED() REGS.sp++->setUndefined()
+#define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
+#define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
+#define PUSH_INT32(i) REGS.sp++->setInt32(i)
+#define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
+#define PUSH_STRING(s) do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
+#define PUSH_OBJECT(obj) do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
+#define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0)
+#define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
+#define POP_COPY_TO(v) (v) = *--REGS.sp
+#define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
+
+#define FETCH_OBJECT(cx, n, obj) \
+ JS_BEGIN_MACRO \
+ HandleValue val = REGS.stackHandleAt(n); \
+ obj = ToObjectFromStack((cx), (val)); \
+ if (!obj) \
+ goto error; \
+ JS_END_MACRO
+
+/*
+ * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
+ * remain distinct for the decompiler.
+ */
+JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
+
+/* See TRY_BRANCH_AFTER_COND. */
+JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
+JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
+
+/*
+ * Compute the implicit |this| parameter for a call expression where the callee
+ * funval was resolved from an unqualified name reference to a property on obj
+ * (an object on the env chain).
+ *
+ * We can avoid computing |this| eagerly and push the implicit callee-coerced
+ * |this| value, undefined, if either of these conditions hold:
+ *
+ * 1. The nominal |this|, obj, is a global object.
+ *
+ * 2. The nominal |this|, obj, has one of LexicalEnvironment or Call class (this
+ * is what IsCacheableEnvironment tests). Such objects-as-envs must be
+ * censored with undefined.
+ *
+ * Otherwise, we bind |this| to the result of GetThisValue(). Only names inside
+ * |with| statements and embedding-specific environment objects fall into this
+ * category.
+ *
+ * If the callee is a strict mode function, then code implementing JSOP_THIS
+ * in the interpreter and JITs will leave undefined as |this|. If funval is a
+ * function not in strict mode, JSOP_THIS code replaces undefined with funval's
+ * global.
+ */
+static inline Value
+ComputeImplicitThis(JSObject* obj)
+{
+ if (obj->is<GlobalObject>())
+ return UndefinedValue();
+
+ if (IsCacheableEnvironment(obj))
+ return UndefinedValue();
+
+ return GetThisValue(obj);
+}
+
+static MOZ_ALWAYS_INLINE bool
+AddOperation(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ if (lhs.isInt32() && rhs.isInt32()) {
+ int32_t l = lhs.toInt32(), r = rhs.toInt32();
+ int32_t t;
+ if (MOZ_LIKELY(SafeAdd(l, r, &t))) {
+ res.setInt32(t);
+ return true;
+ }
+ }
+
+ if (!ToPrimitive(cx, lhs))
+ return false;
+ if (!ToPrimitive(cx, rhs))
+ return false;
+
+ bool lIsString, rIsString;
+ if ((lIsString = lhs.isString()) | (rIsString = rhs.isString())) {
+ JSString* lstr;
+ if (lIsString) {
+ lstr = lhs.toString();
+ } else {
+ lstr = ToString<CanGC>(cx, lhs);
+ if (!lstr)
+ return false;
+ }
+
+ JSString* rstr;
+ if (rIsString) {
+ rstr = rhs.toString();
+ } else {
+ // Save/restore lstr in case of GC activity under ToString.
+ lhs.setString(lstr);
+ rstr = ToString<CanGC>(cx, rhs);
+ if (!rstr)
+ return false;
+ lstr = lhs.toString();
+ }
+ JSString* str = ConcatStrings<NoGC>(cx, lstr, rstr);
+ if (!str) {
+ RootedString nlstr(cx, lstr), nrstr(cx, rstr);
+ str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
+ if (!str)
+ return false;
+ }
+ res.setString(str);
+ } else {
+ double l, r;
+ if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r))
+ return false;
+ res.setNumber(l + r);
+ }
+
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+SubOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ res.setNumber(d1 - d2);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+MulOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ res.setNumber(d1 * d2);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+DivOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
+{
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+ res.setNumber(NumberDiv(d1, d2));
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+ModOperation(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
+{
+ int32_t l, r;
+ if (lhs.isInt32() && rhs.isInt32() &&
+ (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
+ int32_t mod = l % r;
+ res.setInt32(mod);
+ return true;
+ }
+
+ double d1, d2;
+ if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+ return false;
+
+ res.setNumber(NumberMod(d1, d2));
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
+ HandleValue receiver, bool strict,
+ JSScript* script = nullptr, jsbytecode* pc = nullptr)
+{
+ // receiver != obj happens only at super[expr], where we expect to find the property
+ // People probably aren't building hashtables with |super| anyway.
+ TypeScript::MonitorAssign(cx, obj, id);
+
+ if (obj->isNative() && JSID_IS_INT(id)) {
+ uint32_t length = obj->as<NativeObject>().getDenseInitializedLength();
+ int32_t i = JSID_TO_INT(id);
+ if ((uint32_t)i >= length) {
+ // Annotate script if provided with information (e.g. baseline)
+ if (script && script->hasBaselineScript() && IsSetElemPC(pc))
+ script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
+ }
+ }
+
+ if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
+ return false;
+
+ ObjectOpResult result;
+ return SetProperty(cx, obj, id, value, receiver, result) &&
+ result.checkStrictErrorOrWarning(cx, obj, id, strict);
+}
+
+/*
+ * Get the innermost enclosing function that has a 'this' binding.
+ *
+ * Implements ES6 12.3.5.2 GetSuperConstructor() steps 1-3, including
+ * the loop in ES6 8.3.2 GetThisEnvironment(). Our implementation of
+ * ES6 12.3.5.3 MakeSuperPropertyReference() also uses this code.
+ */
+static JSFunction&
+GetSuperEnvFunction(JSContext* cx, InterpreterRegs& regs)
+{
+ JSObject* env = regs.fp()->environmentChain();
+ Scope* scope = regs.fp()->script()->innermostScope(regs.pc);
+ for (EnvironmentIter ei(cx, env, scope); ei; ei++) {
+ if (ei.hasSyntacticEnvironment() && ei.scope().is<FunctionScope>()) {
+ JSFunction& callee = ei.environment().as<CallObject>().callee();
+
+ // Arrow functions don't have the information we're looking for,
+ // their enclosing scopes do. Nevertheless, they might have call
+ // objects. Skip them to find what we came for.
+ if (callee.isArrow())
+ continue;
+
+ return callee;
+ }
+ }
+ MOZ_CRASH("unexpected env chain for GetSuperEnvFunction");
+}
+
+
+/*
+ * As an optimization, the interpreter creates a handful of reserved Rooted<T>
+ * variables at the beginning, thus inserting them into the Rooted list once
+ * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it
+ * within a local scope, resetting the value to nullptr (or the appropriate
+ * equivalent for T) at scope end. This avoids inserting/removing the Rooted
+ * from the rooter list, while preventing stale values from being kept alive
+ * unnecessarily.
+ */
+
+template<typename T>
+class ReservedRootedBase {
+};
+
+template<typename T>
+class ReservedRooted : public ReservedRootedBase<T>
+{
+ Rooted<T>* savedRoot;
+
+ public:
+ ReservedRooted(Rooted<T>* root, const T& ptr) : savedRoot(root) {
+ *root = ptr;
+ }
+
+ explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
+ *root = JS::GCPolicy<T>::initial();
+ }
+
+ ~ReservedRooted() {
+ *savedRoot = JS::GCPolicy<T>::initial();
+ }
+
+ void set(const T& p) const { *savedRoot = p; }
+ operator Handle<T>() { return *savedRoot; }
+ operator Rooted<T>&() { return *savedRoot; }
+ MutableHandle<T> operator&() { return &*savedRoot; }
+
+ DECLARE_NONPOINTER_ACCESSOR_METHODS(savedRoot->get())
+ DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(savedRoot->get())
+ DECLARE_POINTER_CONSTREF_OPS(T)
+ DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
+};
+
+template <>
+class ReservedRootedBase<Value> : public ValueOperations<ReservedRooted<Value>>
+{};
+
+template <>
+class ReservedRootedBase<Scope*> : public ScopeCastOperation<ReservedRooted<Scope*>>
+{};
+
+static MOZ_NEVER_INLINE bool
+Interpret(JSContext* cx, RunState& state)
+{
+/*
+ * Define macros for an interpreter loop. Opcode dispatch may be either by a
+ * switch statement or by indirect goto (aka a threaded interpreter), depending
+ * on compiler support.
+ *
+ * Threaded interpretation appears to be well-supported by GCC 3 and higher.
+ * IBM's C compiler when run with the right options (e.g., -qlanglvl=extended)
+ * also supports threading. Ditto the SunPro C compiler.
+ */
+#if (defined(__GNUC__) || \
+ (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) || \
+ __SUNPRO_C >= 0x570)
+// Non-standard but faster indirect-goto-based dispatch.
+# define INTERPRETER_LOOP()
+# define CASE(OP) label_##OP:
+# define DEFAULT() label_default:
+# define DISPATCH_TO(OP) goto* addresses[(OP)]
+
+# define LABEL(X) (&&label_##X)
+
+ // Use addresses instead of offsets to optimize for runtime speed over
+ // load-time relocation overhead.
+ static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
+# define OPCODE_LABEL(op, ...) LABEL(op),
+ FOR_EACH_OPCODE(OPCODE_LABEL)
+# undef OPCODE_LABEL
+# define TRAILING_LABEL(v) \
+ ((v) == EnableInterruptsPseudoOpcode \
+ ? LABEL(EnableInterruptsPseudoOpcode) \
+ : LABEL(default)),
+ FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
+# undef TRAILING_LABEL
+ };
+#else
+// Portable switch-based dispatch.
+# define INTERPRETER_LOOP() the_switch: switch (switchOp)
+# define CASE(OP) case OP:
+# define DEFAULT() default:
+# define DISPATCH_TO(OP) \
+ JS_BEGIN_MACRO \
+ switchOp = (OP); \
+ goto the_switch; \
+ JS_END_MACRO
+
+ // This variable is effectively a parameter to the_switch.
+ jsbytecode switchOp;
+#endif
+
+ /*
+ * Increment REGS.pc by N, load the opcode at that position,
+ * and jump to the code to execute it.
+ *
+ * When Debugger puts a script in single-step mode, all js::Interpret
+ * invocations that might be presently running that script must have
+ * interrupts enabled. It's not practical to simply check
+ * script->stepModeEnabled() at each point some callee could have changed
+ * it, because there are so many places js::Interpret could possibly cause
+ * JavaScript to run: each place an object might be coerced to a primitive
+ * or a number, for example. So instead, we expose a simple mechanism to
+ * let Debugger tweak the affected js::Interpret frames when an onStep
+ * handler is added: calling activation.enableInterruptsUnconditionally()
+ * will enable interrupts, and activation.opMask() is or'd with the opcode
+ * to implement a simple alternate dispatch.
+ */
+#define ADVANCE_AND_DISPATCH(N) \
+ JS_BEGIN_MACRO \
+ REGS.pc += (N); \
+ SANITY_CHECKS(); \
+ DISPATCH_TO(*REGS.pc | activation.opMask()); \
+ JS_END_MACRO
+
+ /*
+ * Shorthand for the common sequence at the end of a fixed-size opcode.
+ */
+#define END_CASE(OP) ADVANCE_AND_DISPATCH(OP##_LENGTH);
+
+ /*
+ * Prepare to call a user-supplied branch handler, and abort the script
+ * if it returns false.
+ */
+#define CHECK_BRANCH() \
+ JS_BEGIN_MACRO \
+ if (!CheckForInterrupt(cx)) \
+ goto error; \
+ JS_END_MACRO
+
+ /*
+ * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
+ * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
+ * is the backedge of a loop.
+ */
+#define BRANCH(n) \
+ JS_BEGIN_MACRO \
+ int32_t nlen = (n); \
+ if (nlen <= 0) \
+ CHECK_BRANCH(); \
+ ADVANCE_AND_DISPATCH(nlen); \
+ JS_END_MACRO
+
+ /*
+ * Initialize code coverage vectors.
+ */
+#define INIT_COVERAGE() \
+ JS_BEGIN_MACRO \
+ if (!script->hasScriptCounts()) { \
+ if (cx->compartment()->collectCoverageForDebug()) { \
+ if (!script->initScriptCounts(cx)) \
+ goto error; \
+ } \
+ } \
+ JS_END_MACRO
+
+ /*
+ * Increment the code coverage counter associated with the given pc.
+ */
+#define COUNT_COVERAGE_PC(PC) \
+ JS_BEGIN_MACRO \
+ if (script->hasScriptCounts()) { \
+ PCCounts* counts = script->maybeGetPCCounts(PC); \
+ MOZ_ASSERT(counts); \
+ counts->numExec()++; \
+ } \
+ JS_END_MACRO
+
+#define COUNT_COVERAGE_MAIN() \
+ JS_BEGIN_MACRO \
+ jsbytecode* main = script->main(); \
+ if (!BytecodeIsJumpTarget(JSOp(*main))) \
+ COUNT_COVERAGE_PC(main); \
+ JS_END_MACRO
+
+#define COUNT_COVERAGE() \
+ JS_BEGIN_MACRO \
+ MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
+ COUNT_COVERAGE_PC(REGS.pc); \
+ JS_END_MACRO
+
+#define LOAD_DOUBLE(PCOFF, dbl) \
+ ((dbl) = script->getConst(GET_UINT32_INDEX(REGS.pc + (PCOFF))).toDouble())
+
+#define SET_SCRIPT(s) \
+ JS_BEGIN_MACRO \
+ script = (s); \
+ if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts()) \
+ activation.enableInterruptsUnconditionally(); \
+ JS_END_MACRO
+
+#define SANITY_CHECKS() \
+ JS_BEGIN_MACRO \
+ js::gc::MaybeVerifyBarriers(cx); \
+ JS_END_MACRO
+
+ gc::MaybeVerifyBarriers(cx, true);
+ MOZ_ASSERT(!cx->zone()->types.activeAnalysis);
+
+ InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
+ if (!entryFrame)
+ return false;
+
+ ActivationEntryMonitor entryMonitor(cx, entryFrame);
+ InterpreterActivation activation(state, cx, entryFrame);
+
+ /* The script is used frequently, so keep a local copy. */
+ RootedScript script(cx);
+ SET_SCRIPT(REGS.fp()->script());
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, script);
+ TraceLogStartEvent(logger, scriptEvent);
+ TraceLogStartEvent(logger, TraceLogger_Interpreter);
+
+ /*
+ * Pool of rooters for use in this interpreter frame. References to these
+ * are used for local variables within interpreter cases. This avoids
+ * creating new rooters each time an interpreter case is entered, and also
+ * correctness pitfalls due to incorrect compilation of destructor calls
+ * around computed gotos.
+ */
+ RootedValue rootValue0(cx), rootValue1(cx);
+ RootedString rootString0(cx), rootString1(cx);
+ RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
+ RootedNativeObject rootNativeObject0(cx);
+ RootedFunction rootFunction0(cx);
+ RootedPropertyName rootName0(cx);
+ RootedId rootId0(cx);
+ RootedShape rootShape0(cx);
+ RootedScript rootScript0(cx);
+ Rooted<Scope*> rootScope0(cx);
+ DebugOnly<uint32_t> blockDepth;
+
+ /* State communicated between non-local jumps: */
+ bool interpReturnOK;
+ bool frameHalfInitialized;
+
+ if (!activation.entryFrame()->prologue(cx))
+ goto prologue_error;
+
+ switch (Debugger::onEnterFrame(cx, activation.entryFrame())) {
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ if (!ForcedReturn(cx, REGS))
+ goto error;
+ goto successful_return_continuation;
+ case JSTRAP_THROW:
+ case JSTRAP_ERROR:
+ goto error;
+ default:
+ MOZ_CRASH("bad Debugger::onEnterFrame status");
+ }
+
+ // Increment the coverage for the main entry point.
+ INIT_COVERAGE();
+ COUNT_COVERAGE_MAIN();
+
+ // Enter the interpreter loop starting at the current pc.
+ ADVANCE_AND_DISPATCH(0);
+
+INTERPRETER_LOOP() {
+
+CASE(EnableInterruptsPseudoOpcode)
+{
+ bool moreInterrupts = false;
+ jsbytecode op = *REGS.pc;
+
+ if (!script->hasScriptCounts() && cx->compartment()->collectCoverageForDebug()) {
+ if (!script->initScriptCounts(cx))
+ goto error;
+ }
+
+ if (script->isDebuggee()) {
+ if (script->stepModeEnabled()) {
+ RootedValue rval(cx);
+ JSTrapStatus status = JSTRAP_CONTINUE;
+ status = Debugger::onSingleStep(cx, &rval);
+ switch (status) {
+ case JSTRAP_ERROR:
+ goto error;
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ REGS.fp()->setReturnValue(rval);
+ if (!ForcedReturn(cx, REGS))
+ goto error;
+ goto successful_return_continuation;
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ goto error;
+ default:;
+ }
+ moreInterrupts = true;
+ }
+
+ if (script->hasAnyBreakpointsOrStepMode())
+ moreInterrupts = true;
+
+ if (script->hasBreakpointsAt(REGS.pc)) {
+ RootedValue rval(cx);
+ JSTrapStatus status = Debugger::onTrap(cx, &rval);
+ switch (status) {
+ case JSTRAP_ERROR:
+ goto error;
+ case JSTRAP_RETURN:
+ REGS.fp()->setReturnValue(rval);
+ if (!ForcedReturn(cx, REGS))
+ goto error;
+ goto successful_return_continuation;
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ goto error;
+ default:
+ break;
+ }
+ MOZ_ASSERT(status == JSTRAP_CONTINUE);
+ MOZ_ASSERT(rval.isInt32() && rval.toInt32() == op);
+ }
+ }
+
+ MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
+ if (!moreInterrupts)
+ activation.clearInterruptsMask();
+
+ /* Commence executing the actual opcode. */
+ SANITY_CHECKS();
+ DISPATCH_TO(op);
+}
+
+/* Various 1-byte no-ops. */
+CASE(JSOP_NOP)
+CASE(JSOP_NOP_DESTRUCTURING)
+CASE(JSOP_UNUSED182)
+CASE(JSOP_UNUSED183)
+CASE(JSOP_UNUSED187)
+CASE(JSOP_UNUSED192)
+CASE(JSOP_UNUSED209)
+CASE(JSOP_UNUSED210)
+CASE(JSOP_UNUSED211)
+CASE(JSOP_UNUSED219)
+CASE(JSOP_UNUSED220)
+CASE(JSOP_UNUSED221)
+CASE(JSOP_UNUSED222)
+CASE(JSOP_UNUSED223)
+CASE(JSOP_CONDSWITCH)
+{
+ MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
+ ADVANCE_AND_DISPATCH(1);
+}
+
+CASE(JSOP_TRY)
+CASE(JSOP_JUMPTARGET)
+CASE(JSOP_LOOPHEAD)
+{
+ MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
+ COUNT_COVERAGE();
+ ADVANCE_AND_DISPATCH(1);
+}
+
+CASE(JSOP_LABEL)
+END_CASE(JSOP_LABEL)
+
+CASE(JSOP_LOOPENTRY)
+ COUNT_COVERAGE();
+ // Attempt on-stack replacement with Baseline code.
+ if (jit::IsBaselineEnabled(cx)) {
+ jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp(), false);
+ if (status == jit::Method_Error)
+ goto error;
+ if (status == jit::Method_Compiled) {
+ bool wasSPS = REGS.fp()->hasPushedSPSFrame();
+
+ jit::JitExecStatus maybeOsr;
+ {
+ SPSBaselineOSRMarker spsOSR(cx->runtime(), wasSPS);
+ maybeOsr = jit::EnterBaselineAtBranch(cx, REGS.fp(), REGS.pc);
+ }
+
+ // We failed to call into baseline at all, so treat as an error.
+ if (maybeOsr == jit::JitExec_Aborted)
+ goto error;
+
+ interpReturnOK = (maybeOsr == jit::JitExec_Ok);
+
+ // Pop the SPS frame pushed by the interpreter. (The compiled version of the
+ // function popped a copy of the frame pushed by the OSR trampoline.)
+ if (wasSPS)
+ cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
+
+ if (activation.entryFrame() != REGS.fp())
+ goto jit_return_pop_frame;
+ goto leave_on_safe_point;
+ }
+ }
+END_CASE(JSOP_LOOPENTRY)
+
+CASE(JSOP_LINENO)
+END_CASE(JSOP_LINENO)
+
+CASE(JSOP_FORCEINTERPRETER)
+END_CASE(JSOP_FORCEINTERPRETER)
+
+CASE(JSOP_UNDEFINED)
+ // If this ever changes, change what JSOP_GIMPLICITTHIS does too.
+ PUSH_UNDEFINED();
+END_CASE(JSOP_UNDEFINED)
+
+CASE(JSOP_POP)
+ REGS.sp--;
+END_CASE(JSOP_POP)
+
+CASE(JSOP_POPN)
+ MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
+ REGS.sp -= GET_UINT16(REGS.pc);
+END_CASE(JSOP_POPN)
+
+CASE(JSOP_DUPAT)
+{
+ MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
+ unsigned i = GET_UINT24(REGS.pc);
+ const Value& rref = REGS.sp[-int(i + 1)];
+ PUSH_COPY(rref);
+}
+END_CASE(JSOP_DUPAT)
+
+CASE(JSOP_SETRVAL)
+ POP_RETURN_VALUE();
+END_CASE(JSOP_SETRVAL)
+
+CASE(JSOP_GETRVAL)
+ PUSH_COPY(REGS.fp()->returnValue());
+END_CASE(JSOP_GETRVAL)
+
+CASE(JSOP_ENTERWITH)
+{
+ ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
+ REGS.sp--;
+ ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
+
+ if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>()))
+ goto error;
+}
+END_CASE(JSOP_ENTERWITH)
+
+CASE(JSOP_LEAVEWITH)
+ REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
+END_CASE(JSOP_LEAVEWITH)
+
+CASE(JSOP_RETURN)
+ POP_RETURN_VALUE();
+ /* FALL THROUGH */
+
+CASE(JSOP_RETRVAL)
+{
+ /*
+ * When the inlined frame exits with an exception or an error, ok will be
+ * false after the inline_return label.
+ */
+ CHECK_BRANCH();
+
+ successful_return_continuation:
+ interpReturnOK = true;
+
+ return_continuation:
+ frameHalfInitialized = false;
+
+ prologue_return_continuation:
+
+ if (activation.entryFrame() != REGS.fp()) {
+ // Stop the engine. (No details about which engine exactly, could be
+ // interpreter, Baseline or IonMonkey.)
+ TraceLogStopEvent(logger, TraceLogger_Engine);
+ TraceLogStopEvent(logger, TraceLogger_Scripts);
+
+ if (MOZ_LIKELY(!frameHalfInitialized)) {
+ interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
+
+ REGS.fp()->epilogue(cx, REGS.pc);
+ }
+
+ jit_return_pop_frame:
+
+ activation.popInlineFrame(REGS.fp());
+ SET_SCRIPT(REGS.fp()->script());
+
+ jit_return:
+
+ MOZ_ASSERT(CodeSpec[*REGS.pc].format & JOF_INVOKE);
+
+ /* Resume execution in the calling frame. */
+ if (MOZ_LIKELY(interpReturnOK)) {
+ TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
+
+ ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
+ }
+
+ goto error;
+ } else {
+ MOZ_ASSERT(REGS.stackDepth() == 0);
+ }
+ goto exit;
+}
+
+CASE(JSOP_DEFAULT)
+ REGS.sp--;
+ /* FALL THROUGH */
+CASE(JSOP_GOTO)
+{
+ BRANCH(GET_JUMP_OFFSET(REGS.pc));
+}
+
+CASE(JSOP_IFEQ)
+{
+ bool cond = ToBoolean(REGS.stackHandleAt(-1));
+ REGS.sp--;
+ if (!cond)
+ BRANCH(GET_JUMP_OFFSET(REGS.pc));
+}
+END_CASE(JSOP_IFEQ)
+
+CASE(JSOP_IFNE)
+{
+ bool cond = ToBoolean(REGS.stackHandleAt(-1));
+ REGS.sp--;
+ if (cond)
+ BRANCH(GET_JUMP_OFFSET(REGS.pc));
+}
+END_CASE(JSOP_IFNE)
+
+CASE(JSOP_OR)
+{
+ bool cond = ToBoolean(REGS.stackHandleAt(-1));
+ if (cond)
+ ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
+}
+END_CASE(JSOP_OR)
+
+CASE(JSOP_AND)
+{
+ bool cond = ToBoolean(REGS.stackHandleAt(-1));
+ if (!cond)
+ ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
+}
+END_CASE(JSOP_AND)
+
+#define FETCH_ELEMENT_ID(n, id) \
+ JS_BEGIN_MACRO \
+ if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) \
+ goto error; \
+ JS_END_MACRO
+
+#define TRY_BRANCH_AFTER_COND(cond,spdec) \
+ JS_BEGIN_MACRO \
+ MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1); \
+ unsigned diff_ = (unsigned) GET_UINT8(REGS.pc) - (unsigned) JSOP_IFEQ; \
+ if (diff_ <= 1) { \
+ REGS.sp -= (spdec); \
+ if ((cond) == (diff_ != 0)) { \
+ ++REGS.pc; \
+ BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
+ } \
+ ADVANCE_AND_DISPATCH(1 + JSOP_IFEQ_LENGTH); \
+ } \
+ JS_END_MACRO
+
+CASE(JSOP_IN)
+{
+ HandleValue rref = REGS.stackHandleAt(-1);
+ if (!rref.isObject()) {
+ ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, nullptr);
+ goto error;
+ }
+ bool found;
+ {
+ ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
+ ReservedRooted<jsid> id(&rootId0);
+ FETCH_ELEMENT_ID(-2, id);
+ if (!HasProperty(cx, obj, id, &found))
+ goto error;
+ }
+ TRY_BRANCH_AFTER_COND(found, 2);
+ REGS.sp--;
+ REGS.sp[-1].setBoolean(found);
+}
+END_CASE(JSOP_IN)
+
+CASE(JSOP_ITER)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 1);
+ uint8_t flags = GET_UINT8(REGS.pc);
+ HandleValue val = REGS.stackHandleAt(-1);
+ ReservedRooted<JSObject*> iter(&rootObject0);
+ iter.set(ValueToIterator(cx, flags, val));
+ if (!iter)
+ goto error;
+ REGS.sp[-1].setObject(*iter);
+}
+END_CASE(JSOP_ITER)
+
+CASE(JSOP_MOREITER)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 1);
+ MOZ_ASSERT(REGS.sp[-1].isObject());
+ PUSH_NULL();
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+ if (!IteratorMore(cx, obj, REGS.stackHandleAt(-1)))
+ goto error;
+}
+END_CASE(JSOP_MOREITER)
+
+CASE(JSOP_ISNOITER)
+{
+ bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
+ PUSH_BOOLEAN(b);
+}
+END_CASE(JSOP_ISNOITER)
+
+CASE(JSOP_ENDITER)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 1);
+ COUNT_COVERAGE();
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
+ bool ok = CloseIterator(cx, obj);
+ REGS.sp--;
+ if (!ok)
+ goto error;
+}
+END_CASE(JSOP_ENDITER)
+
+CASE(JSOP_DUP)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 1);
+ const Value& rref = REGS.sp[-1];
+ PUSH_COPY(rref);
+}
+END_CASE(JSOP_DUP)
+
+CASE(JSOP_DUP2)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+ const Value& lref = REGS.sp[-2];
+ const Value& rref = REGS.sp[-1];
+ PUSH_COPY(lref);
+ PUSH_COPY(rref);
+}
+END_CASE(JSOP_DUP2)
+
+CASE(JSOP_SWAP)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+ Value& lref = REGS.sp[-2];
+ Value& rref = REGS.sp[-1];
+ lref.swap(rref);
+}
+END_CASE(JSOP_SWAP)
+
+CASE(JSOP_PICK)
+{
+ unsigned i = GET_UINT8(REGS.pc);
+ MOZ_ASSERT(REGS.stackDepth() >= i + 1);
+ Value lval = REGS.sp[-int(i + 1)];
+ memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
+ REGS.sp[-1] = lval;
+}
+END_CASE(JSOP_PICK)
+
+CASE(JSOP_BINDGNAME)
+CASE(JSOP_BINDNAME)
+{
+ JSOp op = JSOp(*REGS.pc);
+ ReservedRooted<JSObject*> envChain(&rootObject0);
+ if (op == JSOP_BINDNAME || script->hasNonSyntacticScope())
+ envChain.set(REGS.fp()->environmentChain());
+ else
+ envChain.set(&REGS.fp()->global().lexicalEnvironment());
+ ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
+
+ /* Assigning to an undeclared name adds a property to the global object. */
+ ReservedRooted<JSObject*> env(&rootObject1);
+ if (!LookupNameUnqualified(cx, name, envChain, &env))
+ goto error;
+
+ PUSH_OBJECT(*env);
+
+ static_assert(JSOP_BINDNAME_LENGTH == JSOP_BINDGNAME_LENGTH,
+ "We're sharing the END_CASE so the lengths better match");
+}
+END_CASE(JSOP_BINDNAME)
+
+CASE(JSOP_BINDVAR)
+{
+ PUSH_OBJECT(REGS.fp()->varObj());
+}
+END_CASE(JSOP_BINDVAR)
+
+#define BITWISE_OP(OP) \
+ JS_BEGIN_MACRO \
+ int32_t i, j; \
+ if (!ToInt32(cx, REGS.stackHandleAt(-2), &i)) \
+ goto error; \
+ if (!ToInt32(cx, REGS.stackHandleAt(-1), &j)) \
+ goto error; \
+ i = i OP j; \
+ REGS.sp--; \
+ REGS.sp[-1].setInt32(i); \
+ JS_END_MACRO
+
+CASE(JSOP_BITOR)
+ BITWISE_OP(|);
+END_CASE(JSOP_BITOR)
+
+CASE(JSOP_BITXOR)
+ BITWISE_OP(^);
+END_CASE(JSOP_BITXOR)
+
+CASE(JSOP_BITAND)
+ BITWISE_OP(&);
+END_CASE(JSOP_BITAND)
+
+#undef BITWISE_OP
+
+CASE(JSOP_EQ)
+ if (!LooseEqualityOp<true>(cx, REGS))
+ goto error;
+END_CASE(JSOP_EQ)
+
+CASE(JSOP_NE)
+ if (!LooseEqualityOp<false>(cx, REGS))
+ goto error;
+END_CASE(JSOP_NE)
+
+#define STRICT_EQUALITY_OP(OP, COND) \
+ JS_BEGIN_MACRO \
+ HandleValue lval = REGS.stackHandleAt(-2); \
+ HandleValue rval = REGS.stackHandleAt(-1); \
+ bool equal; \
+ if (!StrictlyEqual(cx, lval, rval, &equal)) \
+ goto error; \
+ (COND) = equal OP true; \
+ REGS.sp--; \
+ JS_END_MACRO
+
+CASE(JSOP_STRICTEQ)
+{
+ bool cond;
+ STRICT_EQUALITY_OP(==, cond);
+ REGS.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_STRICTEQ)
+
+CASE(JSOP_STRICTNE)
+{
+ bool cond;
+ STRICT_EQUALITY_OP(!=, cond);
+ REGS.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_STRICTNE)
+
+CASE(JSOP_CASE)
+{
+ bool cond;
+ STRICT_EQUALITY_OP(==, cond);
+ if (cond) {
+ REGS.sp--;
+ BRANCH(GET_JUMP_OFFSET(REGS.pc));
+ }
+}
+END_CASE(JSOP_CASE)
+
+#undef STRICT_EQUALITY_OP
+
+CASE(JSOP_LT)
+{
+ bool cond;
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!LessThanOperation(cx, lval, rval, &cond))
+ goto error;
+ TRY_BRANCH_AFTER_COND(cond, 2);
+ REGS.sp[-2].setBoolean(cond);
+ REGS.sp--;
+}
+END_CASE(JSOP_LT)
+
+CASE(JSOP_LE)
+{
+ bool cond;
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!LessThanOrEqualOperation(cx, lval, rval, &cond))
+ goto error;
+ TRY_BRANCH_AFTER_COND(cond, 2);
+ REGS.sp[-2].setBoolean(cond);
+ REGS.sp--;
+}
+END_CASE(JSOP_LE)
+
+CASE(JSOP_GT)
+{
+ bool cond;
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!GreaterThanOperation(cx, lval, rval, &cond))
+ goto error;
+ TRY_BRANCH_AFTER_COND(cond, 2);
+ REGS.sp[-2].setBoolean(cond);
+ REGS.sp--;
+}
+END_CASE(JSOP_GT)
+
+CASE(JSOP_GE)
+{
+ bool cond;
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond))
+ goto error;
+ TRY_BRANCH_AFTER_COND(cond, 2);
+ REGS.sp[-2].setBoolean(cond);
+ REGS.sp--;
+}
+END_CASE(JSOP_GE)
+
+#define SIGNED_SHIFT_OP(OP) \
+ JS_BEGIN_MACRO \
+ int32_t i, j; \
+ if (!ToInt32(cx, REGS.stackHandleAt(-2), &i)) \
+ goto error; \
+ if (!ToInt32(cx, REGS.stackHandleAt(-1), &j)) \
+ goto error; \
+ i = i OP (j & 31); \
+ REGS.sp--; \
+ REGS.sp[-1].setInt32(i); \
+ JS_END_MACRO
+
+CASE(JSOP_LSH)
+ SIGNED_SHIFT_OP(<<);
+END_CASE(JSOP_LSH)
+
+CASE(JSOP_RSH)
+ SIGNED_SHIFT_OP(>>);
+END_CASE(JSOP_RSH)
+
+#undef SIGNED_SHIFT_OP
+
+CASE(JSOP_URSH)
+{
+ HandleValue lval = REGS.stackHandleAt(-2);
+ HandleValue rval = REGS.stackHandleAt(-1);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!UrshOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_URSH)
+
+CASE(JSOP_ADD)
+{
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!AddOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_ADD)
+
+CASE(JSOP_SUB)
+{
+ ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!SubOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_SUB)
+
+CASE(JSOP_MUL)
+{
+ ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!MulOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_MUL)
+
+CASE(JSOP_DIV)
+{
+ ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!DivOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_DIV)
+
+CASE(JSOP_MOD)
+{
+ ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!ModOperation(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_MOD)
+
+CASE(JSOP_POW)
+{
+ ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ if (!math_pow_handle(cx, lval, rval, res))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_POW)
+
+CASE(JSOP_NOT)
+{
+ bool cond = ToBoolean(REGS.stackHandleAt(-1));
+ REGS.sp--;
+ PUSH_BOOLEAN(!cond);
+}
+END_CASE(JSOP_NOT)
+
+CASE(JSOP_BITNOT)
+{
+ int32_t i;
+ HandleValue value = REGS.stackHandleAt(-1);
+ if (!BitNot(cx, value, &i))
+ goto error;
+ REGS.sp[-1].setInt32(i);
+}
+END_CASE(JSOP_BITNOT)
+
+CASE(JSOP_NEG)
+{
+ ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-1);
+ if (!NegOperation(cx, script, REGS.pc, val, res))
+ goto error;
+}
+END_CASE(JSOP_NEG)
+
+CASE(JSOP_POS)
+ if (!ToNumber(cx, REGS.stackHandleAt(-1)))
+ goto error;
+END_CASE(JSOP_POS)
+
+CASE(JSOP_DELNAME)
+{
+ ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
+ ReservedRooted<JSObject*> envObj(&rootObject0, REGS.fp()->environmentChain());
+
+ PUSH_BOOLEAN(true);
+ MutableHandleValue res = REGS.stackHandleAt(-1);
+ if (!DeleteNameOperation(cx, name, envObj, res))
+ goto error;
+}
+END_CASE(JSOP_DELNAME)
+
+CASE(JSOP_DELPROP)
+CASE(JSOP_STRICTDELPROP)
+{
+ static_assert(JSOP_DELPROP_LENGTH == JSOP_STRICTDELPROP_LENGTH,
+ "delprop and strictdelprop must be the same size");
+ ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
+ ReservedRooted<JSObject*> obj(&rootObject0);
+ FETCH_OBJECT(cx, -1, obj);
+
+ ObjectOpResult result;
+ if (!DeleteProperty(cx, obj, id, result))
+ goto error;
+ if (!result && JSOp(*REGS.pc) == JSOP_STRICTDELPROP) {
+ result.reportError(cx, obj, id);
+ goto error;
+ }
+ MutableHandleValue res = REGS.stackHandleAt(-1);
+ res.setBoolean(result.ok());
+}
+END_CASE(JSOP_DELPROP)
+
+CASE(JSOP_DELELEM)
+CASE(JSOP_STRICTDELELEM)
+{
+ static_assert(JSOP_DELELEM_LENGTH == JSOP_STRICTDELELEM_LENGTH,
+ "delelem and strictdelelem must be the same size");
+ /* Fetch the left part and resolve it to a non-null object. */
+ ReservedRooted<JSObject*> obj(&rootObject0);
+ FETCH_OBJECT(cx, -2, obj);
+
+ ReservedRooted<Value> propval(&rootValue0, REGS.sp[-1]);
+
+ ObjectOpResult result;
+ ReservedRooted<jsid> id(&rootId0);
+ if (!ToPropertyKey(cx, propval, &id))
+ goto error;
+ if (!DeleteProperty(cx, obj, id, result))
+ goto error;
+ if (!result && JSOp(*REGS.pc) == JSOP_STRICTDELELEM) {
+ result.reportError(cx, obj, id);
+ goto error;
+ }
+
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+ res.setBoolean(result.ok());
+ REGS.sp--;
+}
+END_CASE(JSOP_DELELEM)
+
+CASE(JSOP_TOID)
+{
+ /*
+ * Increment or decrement requires use to lookup the same property twice,
+ * 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<Value> idval(&rootValue1, REGS.sp[-1]);
+ MutableHandleValue res = REGS.stackHandleAt(-1);
+ if (!ToIdOperation(cx, script, REGS.pc, idval, res))
+ goto error;
+}
+END_CASE(JSOP_TOID)
+
+CASE(JSOP_TYPEOFEXPR)
+CASE(JSOP_TYPEOF)
+{
+ REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
+}
+END_CASE(JSOP_TYPEOF)
+
+CASE(JSOP_VOID)
+ REGS.sp[-1].setUndefined();
+END_CASE(JSOP_VOID)
+
+CASE(JSOP_FUNCTIONTHIS)
+ PUSH_NULL();
+ if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1)))
+ goto error;
+END_CASE(JSOP_FUNCTIONTHIS)
+
+CASE(JSOP_GLOBALTHIS)
+{
+ if (script->hasNonSyntacticScope()) {
+ PUSH_NULL();
+ if (!GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(), REGS.stackHandleAt(-1)))
+ goto error;
+ } else {
+ PUSH_COPY(cx->global()->lexicalEnvironment().thisValue());
+ }
+}
+END_CASE(JSOP_GLOBALTHIS)
+
+CASE(JSOP_CHECKISOBJ)
+{
+ if (!REGS.sp[-1].isObject()) {
+ MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
+ goto error;
+ }
+}
+END_CASE(JSOP_CHECKISOBJ)
+
+CASE(JSOP_CHECKTHIS)
+{
+ if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
+ MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx, REGS.fp()));
+ goto error;
+ }
+}
+END_CASE(JSOP_CHECKTHIS)
+
+CASE(JSOP_CHECKTHISREINIT)
+{
+ if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
+ goto error;
+ }
+}
+END_CASE(JSOP_CHECKTHISREINIT)
+
+CASE(JSOP_CHECKRETURN)
+{
+ if (!REGS.fp()->checkReturn(cx, REGS.stackHandleAt(-1)))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_CHECKRETURN)
+
+CASE(JSOP_GETPROP)
+CASE(JSOP_LENGTH)
+CASE(JSOP_CALLPROP)
+{
+ MutableHandleValue lval = REGS.stackHandleAt(-1);
+ if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval))
+ goto error;
+
+ TypeScript::Monitor(cx, script, REGS.pc, lval);
+ assertSameCompartmentDebugOnly(cx, lval);
+}
+END_CASE(JSOP_GETPROP)
+
+CASE(JSOP_GETPROP_SUPER)
+{
+ ReservedRooted<JSObject*> receiver(&rootObject0);
+ FETCH_OBJECT(cx, -2, receiver);
+ ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
+ MutableHandleValue rref = REGS.stackHandleAt(-2);
+
+ if (!GetProperty(cx, obj, receiver, script->getName(REGS.pc), rref))
+ goto error;
+
+ REGS.sp--;
+}
+END_CASE(JSOP_GETPROP_SUPER)
+
+CASE(JSOP_GETXPROP)
+{
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
+ ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!GetPropertyForNameLookup(cx, obj, id, rval))
+ goto error;
+
+ TypeScript::Monitor(cx, script, REGS.pc, rval);
+ assertSameCompartmentDebugOnly(cx, rval);
+}
+END_CASE(JSOP_GETXPROP)
+
+CASE(JSOP_SETINTRINSIC)
+{
+ HandleValue value = REGS.stackHandleAt(-1);
+
+ if (!SetIntrinsicOperation(cx, script, REGS.pc, value))
+ goto error;
+}
+END_CASE(JSOP_SETINTRINSIC)
+
+CASE(JSOP_SETGNAME)
+CASE(JSOP_STRICTSETGNAME)
+CASE(JSOP_SETNAME)
+CASE(JSOP_STRICTSETNAME)
+{
+ static_assert(JSOP_SETNAME_LENGTH == JSOP_STRICTSETNAME_LENGTH,
+ "setname and strictsetname must be the same size");
+ static_assert(JSOP_SETGNAME_LENGTH == JSOP_STRICTSETGNAME_LENGTH,
+ "setganem adn strictsetgname must be the same size");
+ static_assert(JSOP_SETNAME_LENGTH == JSOP_SETGNAME_LENGTH,
+ "We're sharing the END_CASE so the lengths better match");
+
+ ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-2].toObject());
+ HandleValue value = REGS.stackHandleAt(-1);
+
+ if (!SetNameOperation(cx, script, REGS.pc, env, value))
+ goto error;
+
+ REGS.sp[-2] = REGS.sp[-1];
+ REGS.sp--;
+}
+END_CASE(JSOP_SETNAME)
+
+CASE(JSOP_SETPROP)
+CASE(JSOP_STRICTSETPROP)
+{
+ static_assert(JSOP_SETPROP_LENGTH == JSOP_STRICTSETPROP_LENGTH,
+ "setprop and strictsetprop must be the same size");
+ HandleValue lval = REGS.stackHandleAt(-2);
+ HandleValue rval = REGS.stackHandleAt(-1);
+
+ ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
+ if (!SetPropertyOperation(cx, JSOp(*REGS.pc), lval, id, rval))
+ goto error;
+
+ REGS.sp[-2] = REGS.sp[-1];
+ REGS.sp--;
+}
+END_CASE(JSOP_SETPROP)
+
+CASE(JSOP_SETPROP_SUPER)
+CASE(JSOP_STRICTSETPROP_SUPER)
+{
+ static_assert(JSOP_SETPROP_SUPER_LENGTH == JSOP_STRICTSETPROP_SUPER_LENGTH,
+ "setprop-super and strictsetprop-super must be the same size");
+
+
+ ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+ ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
+ ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
+
+ ObjectOpResult result;
+ if (!SetProperty(cx, obj, id, rval, receiver, result))
+ goto error;
+
+ bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETPROP_SUPER;
+ if (!result.checkStrictErrorOrWarning(cx, obj, id, strict))
+ goto error;
+
+ REGS.sp[-3] = REGS.sp[-1];
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_SETPROP_SUPER)
+
+CASE(JSOP_GETELEM)
+CASE(JSOP_CALLELEM)
+{
+ MutableHandleValue lval = REGS.stackHandleAt(-2);
+ HandleValue rval = REGS.stackHandleAt(-1);
+ MutableHandleValue res = REGS.stackHandleAt(-2);
+
+ bool done = false;
+ if (!GetElemOptimizedArguments(cx, REGS.fp(), lval, rval, res, &done))
+ goto error;
+
+ if (!done) {
+ if (!GetElementOperation(cx, JSOp(*REGS.pc), lval, rval, res))
+ goto error;
+ }
+
+ TypeScript::Monitor(cx, script, REGS.pc, res);
+ REGS.sp--;
+}
+END_CASE(JSOP_GETELEM)
+
+CASE(JSOP_GETELEM_SUPER)
+{
+ HandleValue rval = REGS.stackHandleAt(-3);
+ ReservedRooted<JSObject*> receiver(&rootObject0);
+ FETCH_OBJECT(cx, -2, receiver);
+ ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-1].toObject());
+
+ MutableHandleValue res = REGS.stackHandleAt(-3);
+
+ // Since we have asserted that obj has to be an object, it cannot be
+ // either optimized arguments, or indeed any primitive. This simplifies
+ // our task some.
+ if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, rval, res))
+ goto error;
+
+ TypeScript::Monitor(cx, script, REGS.pc, res);
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_GETELEM_SUPER)
+
+CASE(JSOP_SETELEM)
+CASE(JSOP_STRICTSETELEM)
+{
+ static_assert(JSOP_SETELEM_LENGTH == JSOP_STRICTSETELEM_LENGTH,
+ "setelem and strictsetelem must be the same size");
+ HandleValue receiver = REGS.stackHandleAt(-3);
+ ReservedRooted<JSObject*> obj(&rootObject0);
+ obj = ToObjectFromStack(cx, receiver);
+ if (!obj)
+ goto error;
+ ReservedRooted<jsid> id(&rootId0);
+ FETCH_ELEMENT_ID(-2, id);
+ HandleValue value = REGS.stackHandleAt(-1);
+ if (!SetObjectElementOperation(cx, obj, id, value, receiver, *REGS.pc == JSOP_STRICTSETELEM))
+ goto error;
+ REGS.sp[-3] = value;
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_SETELEM)
+
+CASE(JSOP_SETELEM_SUPER)
+CASE(JSOP_STRICTSETELEM_SUPER)
+{
+ static_assert(JSOP_SETELEM_SUPER_LENGTH == JSOP_STRICTSETELEM_SUPER_LENGTH,
+ "setelem-super and strictsetelem-super must be the same size");
+
+ ReservedRooted<jsid> id(&rootId0);
+ FETCH_ELEMENT_ID(-4, id);
+ ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
+ ReservedRooted<JSObject*> obj(&rootObject1, &REGS.sp[-2].toObject());
+ HandleValue value = REGS.stackHandleAt(-1);
+
+ bool strict = JSOp(*REGS.pc) == JSOP_STRICTSETELEM_SUPER;
+ if (!SetObjectElementOperation(cx, obj, id, value, receiver, strict))
+ goto error;
+ REGS.sp[-4] = value;
+ REGS.sp -= 3;
+}
+END_CASE(JSOP_SETELEM_SUPER)
+
+CASE(JSOP_EVAL)
+CASE(JSOP_STRICTEVAL)
+{
+ static_assert(JSOP_EVAL_LENGTH == JSOP_STRICTEVAL_LENGTH,
+ "eval and stricteval must be the same size");
+
+ CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
+ if (REGS.fp()->environmentChain()->global().valueIsEval(args.calleev())) {
+ if (!DirectEval(cx, args.get(0), args.rval()))
+ goto error;
+ } else {
+ if (!CallFromStack(cx, args))
+ goto error;
+ }
+
+ REGS.sp = args.spAfterCall();
+ TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
+}
+END_CASE(JSOP_EVAL)
+
+CASE(JSOP_SPREADNEW)
+CASE(JSOP_SPREADCALL)
+CASE(JSOP_SPREADSUPERCALL)
+ if (REGS.fp()->hasPushedSPSFrame())
+ cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
+ /* FALL THROUGH */
+
+CASE(JSOP_SPREADEVAL)
+CASE(JSOP_STRICTSPREADEVAL)
+{
+ static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
+ "spreadeval and strictspreadeval must be the same size");
+ bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW || JSOp(*REGS.pc) == JSOP_SPREADSUPERCALL;;
+
+ MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
+
+ HandleValue callee = REGS.stackHandleAt(-3 - construct);
+ HandleValue thisv = REGS.stackHandleAt(-2 - construct);
+ HandleValue arr = REGS.stackHandleAt(-1 - construct);
+ MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
+
+ RootedValue& newTarget = rootValue0;
+ if (construct)
+ newTarget = REGS.sp[-1];
+ else
+ newTarget = NullValue();
+
+ if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr, newTarget, ret))
+ goto error;
+
+ REGS.sp -= 2 + construct;
+}
+END_CASE(JSOP_SPREADCALL)
+
+CASE(JSOP_FUNAPPLY)
+{
+ CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
+ if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args))
+ goto error;
+ /* FALL THROUGH */
+}
+
+CASE(JSOP_NEW)
+CASE(JSOP_CALL)
+CASE(JSOP_CALLITER)
+CASE(JSOP_SUPERCALL)
+CASE(JSOP_FUNCALL)
+{
+ if (REGS.fp()->hasPushedSPSFrame())
+ cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
+
+ MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
+ unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
+
+ MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
+ CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct);
+
+ JSFunction* maybeFun;
+ bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
+
+ /* Don't bother trying to fast-path calls to scripted non-constructors. */
+ if (!isFunction || !maybeFun->isInterpreted() || !maybeFun->isConstructor() ||
+ (!construct && maybeFun->isClassConstructor()))
+ {
+ if (construct) {
+ if (!ConstructFromStack(cx, args))
+ goto error;
+ } else {
+ if (*REGS.pc == JSOP_CALLITER && args.calleev().isPrimitive()) {
+ MOZ_ASSERT(args.length() == 0, "thisv must be on top of the stack");
+ ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
+ goto error;
+ }
+ if (!CallFromStack(cx, args))
+ goto error;
+ }
+ Value* newsp = args.spAfterCall();
+ TypeScript::Monitor(cx, script, REGS.pc, newsp[-1]);
+ REGS.sp = newsp;
+ ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
+ }
+
+ {
+ MOZ_ASSERT(maybeFun);
+ ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
+ ReservedRooted<JSScript*> funScript(&rootScript0, fun->getOrCreateScript(cx));
+ if (!funScript)
+ goto error;
+
+ bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc);
+
+ TypeMonitorCall(cx, args, construct);
+
+ mozilla::Maybe<InvokeState> state;
+ state.emplace(cx, args, construct);
+
+ if (createSingleton)
+ state->setCreateSingleton();
+
+ if (!createSingleton && jit::IsIonEnabled(cx)) {
+ jit::MethodStatus status = jit::CanEnter(cx, state.ref());
+ if (status == jit::Method_Error)
+ goto error;
+ if (status == jit::Method_Compiled) {
+ jit::JitExecStatus exec = jit::IonCannon(cx, state.ref());
+ interpReturnOK = !IsErrorStatus(exec);
+ if (interpReturnOK)
+ CHECK_BRANCH();
+ REGS.sp = args.spAfterCall();
+ goto jit_return;
+ }
+ }
+
+ if (jit::IsBaselineEnabled(cx)) {
+ jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state.ref());
+ if (status == jit::Method_Error)
+ goto error;
+ if (status == jit::Method_Compiled) {
+ jit::JitExecStatus exec = jit::EnterBaselineMethod(cx, state.ref());
+ interpReturnOK = !IsErrorStatus(exec);
+ if (interpReturnOK)
+ CHECK_BRANCH();
+ REGS.sp = args.spAfterCall();
+ goto jit_return;
+ }
+ }
+
+ state.reset();
+ funScript = fun->nonLazyScript();
+
+ if (!activation.pushInlineFrame(args, funScript, construct))
+ goto error;
+
+ if (createSingleton)
+ REGS.fp()->setCreateSingleton();
+ }
+
+ SET_SCRIPT(REGS.fp()->script());
+
+ {
+ TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
+ TraceLogStartEvent(logger, event);
+ TraceLogStartEvent(logger, TraceLogger_Interpreter);
+ }
+
+ if (!REGS.fp()->prologue(cx))
+ goto prologue_error;
+
+ switch (Debugger::onEnterFrame(cx, REGS.fp())) {
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ if (!ForcedReturn(cx, REGS))
+ goto error;
+ goto successful_return_continuation;
+ case JSTRAP_THROW:
+ case JSTRAP_ERROR:
+ goto error;
+ default:
+ MOZ_CRASH("bad Debugger::onEnterFrame status");
+ }
+
+ // Increment the coverage for the main entry point.
+ INIT_COVERAGE();
+ COUNT_COVERAGE_MAIN();
+
+ /* Load first op and dispatch it (safe since JSOP_RETRVAL). */
+ ADVANCE_AND_DISPATCH(0);
+}
+
+CASE(JSOP_OPTIMIZE_SPREADCALL)
+{
+ ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
+
+ bool optimized = false;
+ if (!OptimizeSpreadCall(cx, val, &optimized))
+ goto error;
+
+ PUSH_BOOLEAN(optimized);
+}
+END_CASE(JSOP_OPTIMIZE_SPREADCALL)
+
+CASE(JSOP_THROWMSG)
+{
+ JS_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT16(REGS.pc)));
+ goto error;
+}
+END_CASE(JSOP_THROWMSG)
+
+CASE(JSOP_IMPLICITTHIS)
+CASE(JSOP_GIMPLICITTHIS)
+{
+ JSOp op = JSOp(*REGS.pc);
+ if (op == JSOP_IMPLICITTHIS || script->hasNonSyntacticScope()) {
+ ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
+ ReservedRooted<JSObject*> envObj(&rootObject0, REGS.fp()->environmentChain());
+ ReservedRooted<JSObject*> env(&rootObject1);
+ if (!LookupNameWithGlobalDefault(cx, name, envObj, &env))
+ goto error;
+
+ Value v = ComputeImplicitThis(env);
+ PUSH_COPY(v);
+ } else {
+ // Treat it like JSOP_UNDEFINED.
+ PUSH_UNDEFINED();
+ }
+ static_assert(JSOP_IMPLICITTHIS_LENGTH == JSOP_GIMPLICITTHIS_LENGTH,
+ "We're sharing the END_CASE so the lengths better match");
+}
+END_CASE(JSOP_IMPLICITTHIS)
+
+CASE(JSOP_GETGNAME)
+CASE(JSOP_GETNAME)
+{
+ ReservedRooted<Value> rval(&rootValue0);
+ if (!GetNameOperation(cx, REGS.fp(), REGS.pc, &rval))
+ goto error;
+
+ PUSH_COPY(rval);
+ TypeScript::Monitor(cx, script, REGS.pc, rval);
+ static_assert(JSOP_GETNAME_LENGTH == JSOP_GETGNAME_LENGTH,
+ "We're sharing the END_CASE so the lengths better match");
+}
+END_CASE(JSOP_GETNAME)
+
+CASE(JSOP_GETIMPORT)
+{
+ PUSH_NULL();
+ MutableHandleValue rval = REGS.stackHandleAt(-1);
+ if (!GetImportOperation(cx, REGS.fp(), REGS.pc, rval))
+ goto error;
+
+ TypeScript::Monitor(cx, script, REGS.pc, rval);
+}
+END_CASE(JSOP_GETIMPORT)
+
+CASE(JSOP_GETINTRINSIC)
+{
+ ReservedRooted<Value> rval(&rootValue0);
+ if (!GetIntrinsicOperation(cx, REGS.pc, &rval))
+ goto error;
+
+ PUSH_COPY(rval);
+ TypeScript::Monitor(cx, script, REGS.pc, rval);
+}
+END_CASE(JSOP_GETINTRINSIC)
+
+CASE(JSOP_UINT16)
+ PUSH_INT32((int32_t) GET_UINT16(REGS.pc));
+END_CASE(JSOP_UINT16)
+
+CASE(JSOP_UINT24)
+ PUSH_INT32((int32_t) GET_UINT24(REGS.pc));
+END_CASE(JSOP_UINT24)
+
+CASE(JSOP_INT8)
+ PUSH_INT32(GET_INT8(REGS.pc));
+END_CASE(JSOP_INT8)
+
+CASE(JSOP_INT32)
+ PUSH_INT32(GET_INT32(REGS.pc));
+END_CASE(JSOP_INT32)
+
+CASE(JSOP_DOUBLE)
+{
+ double dbl;
+ LOAD_DOUBLE(0, dbl);
+ PUSH_DOUBLE(dbl);
+}
+END_CASE(JSOP_DOUBLE)
+
+CASE(JSOP_STRING)
+ PUSH_STRING(script->getAtom(REGS.pc));
+END_CASE(JSOP_STRING)
+
+CASE(JSOP_TOSTRING)
+{
+ MutableHandleValue oper = REGS.stackHandleAt(-1);
+
+ if (!oper.isString()) {
+ JSString* operString = ToString<CanGC>(cx, oper);
+ if (!operString)
+ goto error;
+ oper.setString(operString);
+ }
+}
+END_CASE(JSOP_TOSTRING)
+
+CASE(JSOP_SYMBOL)
+ PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
+END_CASE(JSOP_SYMBOL)
+
+CASE(JSOP_OBJECT)
+{
+ ReservedRooted<JSObject*> ref(&rootObject0, script->getObject(REGS.pc));
+ if (cx->compartment()->creationOptions().cloneSingletons()) {
+ JSObject* obj = DeepCloneObjectLiteral(cx, ref, TenuredObject);
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+ } else {
+ cx->compartment()->behaviors().setSingletonsAsValues();
+ PUSH_OBJECT(*ref);
+ }
+}
+END_CASE(JSOP_OBJECT)
+
+CASE(JSOP_CALLSITEOBJ)
+{
+
+ ReservedRooted<JSObject*> cso(&rootObject0, script->getObject(REGS.pc));
+ ReservedRooted<JSObject*> raw(&rootObject1, script->getObject(GET_UINT32_INDEX(REGS.pc) + 1));
+ ReservedRooted<Value> rawValue(&rootValue0, ObjectValue(*raw));
+
+ if (!ProcessCallSiteObjOperation(cx, cso, raw, rawValue))
+ goto error;
+
+ PUSH_OBJECT(*cso);
+}
+END_CASE(JSOP_CALLSITEOBJ)
+
+CASE(JSOP_REGEXP)
+{
+ /*
+ * Push a regexp object cloned from the regexp literal object mapped by the
+ * bytecode at pc.
+ */
+ JSObject* obj = CloneRegExpObject(cx, script->getRegExp(REGS.pc));
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_REGEXP)
+
+CASE(JSOP_ZERO)
+ PUSH_INT32(0);
+END_CASE(JSOP_ZERO)
+
+CASE(JSOP_ONE)
+ PUSH_INT32(1);
+END_CASE(JSOP_ONE)
+
+CASE(JSOP_NULL)
+ PUSH_NULL();
+END_CASE(JSOP_NULL)
+
+CASE(JSOP_FALSE)
+ PUSH_BOOLEAN(false);
+END_CASE(JSOP_FALSE)
+
+CASE(JSOP_TRUE)
+ PUSH_BOOLEAN(true);
+END_CASE(JSOP_TRUE)
+
+CASE(JSOP_TABLESWITCH)
+{
+ jsbytecode* pc2 = REGS.pc;
+ int32_t len = GET_JUMP_OFFSET(pc2);
+
+ /*
+ * ECMAv2+ forbids conversion of discriminant, so we will skip to the
+ * default case if the discriminant isn't already an int jsval. (This
+ * opcode is emitted only for dense int-domain switches.)
+ */
+ const Value& rref = *--REGS.sp;
+ int32_t i;
+ if (rref.isInt32()) {
+ i = rref.toInt32();
+ } else {
+ /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
+ if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i))
+ ADVANCE_AND_DISPATCH(len);
+ }
+
+ pc2 += JUMP_OFFSET_LEN;
+ int32_t low = GET_JUMP_OFFSET(pc2);
+ pc2 += JUMP_OFFSET_LEN;
+ int32_t high = GET_JUMP_OFFSET(pc2);
+
+ i -= low;
+ if ((uint32_t)i < (uint32_t)(high - low + 1)) {
+ pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
+ int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
+ if (off)
+ len = off;
+ }
+ ADVANCE_AND_DISPATCH(len);
+}
+
+CASE(JSOP_ARGUMENTS)
+ if (!script->ensureHasAnalyzedArgsUsage(cx))
+ goto error;
+ if (script->needsArgsObj()) {
+ ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
+ if (!obj)
+ goto error;
+ PUSH_COPY(ObjectValue(*obj));
+ } else {
+ PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
+ }
+END_CASE(JSOP_ARGUMENTS)
+
+CASE(JSOP_RUNONCE)
+{
+ if (!RunOnceScriptPrologue(cx, script))
+ goto error;
+}
+END_CASE(JSOP_RUNONCE)
+
+CASE(JSOP_REST)
+{
+ ReservedRooted<JSObject*> rest(&rootObject0, REGS.fp()->createRestParameter(cx));
+ if (!rest)
+ goto error;
+ PUSH_COPY(ObjectValue(*rest));
+}
+END_CASE(JSOP_REST)
+
+CASE(JSOP_GETALIASEDVAR)
+{
+ EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
+ ReservedRooted<Value> val(&rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
+#ifdef DEBUG
+ // Only the .this slot can hold the TDZ MagicValue.
+ if (IsUninitializedLexical(val)) {
+ PropertyName* name = EnvironmentCoordinateName(cx->caches.envCoordinateNameCache,
+ script, REGS.pc);
+ MOZ_ASSERT(name == cx->names().dotThis);
+ JSOp next = JSOp(*GetNextPc(REGS.pc));
+ MOZ_ASSERT(next == JSOP_CHECKTHIS || next == JSOP_CHECKRETURN || next == JSOP_CHECKTHISREINIT);
+ }
+#endif
+ PUSH_COPY(val);
+ TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
+}
+END_CASE(JSOP_GETALIASEDVAR)
+
+CASE(JSOP_SETALIASEDVAR)
+{
+ EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
+ EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
+ SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1], CheckTDZ);
+}
+END_CASE(JSOP_SETALIASEDVAR)
+
+CASE(JSOP_THROWSETCONST)
+CASE(JSOP_THROWSETALIASEDCONST)
+CASE(JSOP_THROWSETCALLEE)
+{
+ ReportRuntimeConstAssignment(cx, script, REGS.pc);
+ goto error;
+}
+END_CASE(JSOP_THROWSETCONST)
+
+CASE(JSOP_CHECKLEXICAL)
+{
+ uint32_t i = GET_LOCALNO(REGS.pc);
+ ReservedRooted<Value> val(&rootValue0, REGS.fp()->unaliasedLocal(i));
+ if (!CheckUninitializedLexical(cx, script, REGS.pc, val))
+ goto error;
+}
+END_CASE(JSOP_CHECKLEXICAL)
+
+CASE(JSOP_INITLEXICAL)
+{
+ uint32_t i = GET_LOCALNO(REGS.pc);
+ REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
+}
+END_CASE(JSOP_INITLEXICAL)
+
+CASE(JSOP_CHECKALIASEDLEXICAL)
+{
+ EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
+ ReservedRooted<Value> val(&rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
+ if (!CheckUninitializedLexical(cx, script, REGS.pc, val))
+ goto error;
+}
+END_CASE(JSOP_CHECKALIASEDLEXICAL)
+
+CASE(JSOP_INITALIASEDLEXICAL)
+{
+ EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
+ EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
+ SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1], DontCheckTDZ);
+}
+END_CASE(JSOP_INITALIASEDLEXICAL)
+
+CASE(JSOP_INITGLEXICAL)
+{
+ LexicalEnvironmentObject* lexicalEnv;
+ if (script->hasNonSyntacticScope())
+ lexicalEnv = &REGS.fp()->extensibleLexicalEnvironment();
+ else
+ lexicalEnv = &cx->global()->lexicalEnvironment();
+ HandleValue value = REGS.stackHandleAt(-1);
+ InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
+}
+END_CASE(JSOP_INITGLEXICAL)
+
+CASE(JSOP_UNINITIALIZED)
+ PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL);
+END_CASE(JSOP_UNINITIALIZED)
+
+CASE(JSOP_GETARG)
+{
+ unsigned i = GET_ARGNO(REGS.pc);
+ if (script->argsObjAliasesFormals())
+ PUSH_COPY(REGS.fp()->argsObj().arg(i));
+ else
+ PUSH_COPY(REGS.fp()->unaliasedFormal(i));
+}
+END_CASE(JSOP_GETARG)
+
+CASE(JSOP_SETARG)
+{
+ unsigned i = GET_ARGNO(REGS.pc);
+ if (script->argsObjAliasesFormals())
+ REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
+ else
+ REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
+}
+END_CASE(JSOP_SETARG)
+
+CASE(JSOP_GETLOCAL)
+{
+ uint32_t i = GET_LOCALNO(REGS.pc);
+ PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
+
+#ifdef DEBUG
+ // Derived class constructors store the TDZ Value in the .this slot
+ // before a super() call.
+ if (IsUninitializedLexical(REGS.sp[-1])) {
+ MOZ_ASSERT(script->isDerivedClassConstructor());
+ JSOp next = JSOp(*GetNextPc(REGS.pc));
+ MOZ_ASSERT(next == JSOP_CHECKTHIS || next == JSOP_CHECKRETURN || next == JSOP_CHECKTHISREINIT);
+ }
+#endif
+
+ /*
+ * Skip the same-compartment assertion if the local will be immediately
+ * popped. We do not guarantee sync for dead locals when coming in from the
+ * method JIT, and a GETLOCAL followed by POP is not considered to be
+ * a use of the variable.
+ */
+ if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
+ assertSameCompartmentDebugOnly(cx, REGS.sp[-1]);
+}
+END_CASE(JSOP_GETLOCAL)
+
+CASE(JSOP_SETLOCAL)
+{
+ uint32_t i = GET_LOCALNO(REGS.pc);
+
+ MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
+
+ REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
+}
+END_CASE(JSOP_SETLOCAL)
+
+CASE(JSOP_DEFVAR)
+{
+ /* ES5 10.5 step 8 (with subsequent errata). */
+ unsigned attrs = JSPROP_ENUMERATE;
+ if (!REGS.fp()->isEvalFrame())
+ attrs |= JSPROP_PERMANENT;
+
+ /* Step 8b. */
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.fp()->varObj());
+ ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
+
+ if (!DefVarOperation(cx, obj, name, attrs))
+ goto error;
+}
+END_CASE(JSOP_DEFVAR)
+
+CASE(JSOP_DEFCONST)
+CASE(JSOP_DEFLET)
+{
+ LexicalEnvironmentObject* lexicalEnv;
+ JSObject* varObj;
+ if (script->hasNonSyntacticScope()) {
+ lexicalEnv = &REGS.fp()->extensibleLexicalEnvironment();
+ varObj = &REGS.fp()->varObj();
+ } else {
+ lexicalEnv = &cx->global()->lexicalEnvironment();
+ varObj = cx->global();
+ }
+ if (!DefLexicalOperation(cx, lexicalEnv, varObj, script, REGS.pc))
+ goto error;
+}
+END_CASE(JSOP_DEFLET)
+
+CASE(JSOP_DEFFUN)
+{
+ /*
+ * A top-level function defined in Global or Eval code (see ECMA-262
+ * Ed. 3), or else a SpiderMonkey extension: a named function statement in
+ * a compound statement (not at the top statement level of global code, or
+ * at the top level of a function body).
+ */
+ ReservedRooted<JSFunction*> fun(&rootFunction0, &REGS.sp[-1].toObject().as<JSFunction>());
+ if (!DefFunOperation(cx, script, REGS.fp()->environmentChain(), fun))
+ goto error;
+ REGS.sp--;
+}
+END_CASE(JSOP_DEFFUN)
+
+CASE(JSOP_LAMBDA)
+{
+ /* Load the specified function object literal. */
+ ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
+ JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
+ if (!obj)
+ goto error;
+
+ MOZ_ASSERT(obj->staticPrototype());
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_LAMBDA)
+
+CASE(JSOP_LAMBDA_ARROW)
+{
+ /* Load the specified function object literal. */
+ ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
+ ReservedRooted<Value> newTarget(&rootValue1, REGS.sp[-1]);
+ JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->environmentChain(), newTarget);
+ if (!obj)
+ goto error;
+
+ MOZ_ASSERT(obj->staticPrototype());
+ REGS.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_LAMBDA_ARROW)
+
+CASE(JSOP_TOASYNC)
+{
+ ReservedRooted<JSFunction*> unwrapped(&rootFunction0,
+ &REGS.sp[-1].toObject().as<JSFunction>());
+ JSObject* wrapped = WrapAsyncFunction(cx, unwrapped);
+ if (!wrapped)
+ goto error;
+
+ REGS.sp[-1].setObject(*wrapped);
+}
+END_CASE(JSOP_TOASYNC)
+
+CASE(JSOP_CALLEE)
+ MOZ_ASSERT(REGS.fp()->isFunctionFrame());
+ PUSH_COPY(REGS.fp()->calleev());
+END_CASE(JSOP_CALLEE)
+
+CASE(JSOP_INITPROP_GETTER)
+CASE(JSOP_INITHIDDENPROP_GETTER)
+CASE(JSOP_INITPROP_SETTER)
+CASE(JSOP_INITHIDDENPROP_SETTER)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+ ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
+ ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
+
+ if (!InitGetterSetterOperation(cx, REGS.pc, obj, name, val))
+ goto error;
+
+ REGS.sp--;
+}
+END_CASE(JSOP_INITPROP_GETTER)
+
+CASE(JSOP_INITELEM_GETTER)
+CASE(JSOP_INITHIDDENELEM_GETTER)
+CASE(JSOP_INITELEM_SETTER)
+CASE(JSOP_INITHIDDENELEM_SETTER)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 3);
+
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
+ ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
+ ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
+
+ if (!InitGetterSetterOperation(cx, REGS.pc, obj, idval, val))
+ goto error;
+
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_INITELEM_GETTER)
+
+CASE(JSOP_HOLE)
+ PUSH_MAGIC(JS_ELEMENTS_HOLE);
+END_CASE(JSOP_HOLE)
+
+CASE(JSOP_NEWINIT)
+{
+ uint8_t i = GET_UINT8(REGS.pc);
+ MOZ_ASSERT(i == JSProto_Array || i == JSProto_Object);
+
+ JSObject* obj;
+ if (i == JSProto_Array)
+ obj = NewArrayOperation(cx, script, REGS.pc, 0);
+ else
+ obj = NewObjectOperation(cx, script, REGS.pc);
+
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_NEWINIT)
+
+CASE(JSOP_NEWARRAY)
+CASE(JSOP_SPREADCALLARRAY)
+{
+ uint32_t length = GET_UINT32(REGS.pc);
+ JSObject* obj = NewArrayOperation(cx, script, REGS.pc, length);
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_NEWARRAY)
+
+CASE(JSOP_NEWARRAY_COPYONWRITE)
+{
+ ReservedRooted<JSObject*> baseobj(&rootObject0, ObjectGroup::getOrFixupCopyOnWriteObject(cx, script, REGS.pc));
+ if (!baseobj)
+ goto error;
+
+ ReservedRooted<JSObject*> obj(&rootObject1, NewDenseCopyOnWriteArray(cx, ((RootedObject&)(baseobj)).as<ArrayObject>(), gc::DefaultHeap));
+ if (!obj)
+ goto error;
+
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_NEWARRAY_COPYONWRITE)
+
+CASE(JSOP_NEWOBJECT)
+{
+ JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_NEWOBJECT)
+
+CASE(JSOP_MUTATEPROTO)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+
+ if (REGS.sp[-1].isObjectOrNull()) {
+ ReservedRooted<JSObject*> newProto(&rootObject1, REGS.sp[-1].toObjectOrNull());
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+ MOZ_ASSERT(obj->is<PlainObject>());
+
+ if (!SetPrototype(cx, obj, newProto))
+ goto error;
+ }
+
+ REGS.sp--;
+}
+END_CASE(JSOP_MUTATEPROTO)
+
+CASE(JSOP_INITPROP)
+CASE(JSOP_INITLOCKEDPROP)
+CASE(JSOP_INITHIDDENPROP)
+{
+ static_assert(JSOP_INITPROP_LENGTH == JSOP_INITLOCKEDPROP_LENGTH,
+ "initprop and initlockedprop must be the same size");
+ static_assert(JSOP_INITPROP_LENGTH == JSOP_INITHIDDENPROP_LENGTH,
+ "initprop and inithiddenprop must be the same size");
+ /* Load the property's initial value into rval. */
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+ ReservedRooted<Value> rval(&rootValue0, REGS.sp[-1]);
+
+ /* Load the object being initialized into lval/obj. */
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+
+ PropertyName* name = script->getName(REGS.pc);
+
+ RootedId& id = rootId0;
+ id = NameToId(name);
+
+ if (!InitPropertyOperation(cx, JSOp(*REGS.pc), obj, id, rval))
+ goto error;
+
+ REGS.sp--;
+}
+END_CASE(JSOP_INITPROP)
+
+CASE(JSOP_INITELEM)
+CASE(JSOP_INITHIDDENELEM)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 3);
+ HandleValue val = REGS.stackHandleAt(-1);
+ HandleValue id = REGS.stackHandleAt(-2);
+
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
+
+ if (!InitElemOperation(cx, REGS.pc, obj, id, val))
+ goto error;
+
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_INITELEM)
+
+CASE(JSOP_INITELEM_ARRAY)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 2);
+ HandleValue val = REGS.stackHandleAt(-1);
+
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
+
+ uint32_t index = GET_UINT32(REGS.pc);
+ if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
+ goto error;
+
+ REGS.sp--;
+}
+END_CASE(JSOP_INITELEM_ARRAY)
+
+CASE(JSOP_INITELEM_INC)
+{
+ MOZ_ASSERT(REGS.stackDepth() >= 3);
+ HandleValue val = REGS.stackHandleAt(-1);
+
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
+
+ uint32_t index = REGS.sp[-2].toInt32();
+ if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
+ goto error;
+
+ REGS.sp[-2].setInt32(index + 1);
+ REGS.sp--;
+}
+END_CASE(JSOP_INITELEM_INC)
+
+CASE(JSOP_GOSUB)
+{
+ PUSH_BOOLEAN(false);
+ int32_t i = script->pcToOffset(REGS.pc) + JSOP_GOSUB_LENGTH;
+ int32_t len = GET_JUMP_OFFSET(REGS.pc);
+ PUSH_INT32(i);
+ ADVANCE_AND_DISPATCH(len);
+}
+
+CASE(JSOP_RETSUB)
+{
+ /* Pop [exception or hole, retsub pc-index]. */
+ Value rval, lval;
+ POP_COPY_TO(rval);
+ POP_COPY_TO(lval);
+ MOZ_ASSERT(lval.isBoolean());
+ if (lval.toBoolean()) {
+ /*
+ * Exception was pending during finally, throw it *before* we adjust
+ * pc, because pc indexes into script->trynotes. This turns out not to
+ * be necessary, but it seems clearer. And it points out a FIXME:
+ * 350509, due to Igor Bukanov.
+ */
+ cx->setPendingException(rval);
+ goto error;
+ }
+ MOZ_ASSERT(rval.isInt32());
+
+ /* Increment the PC by this much. */
+ int32_t len = rval.toInt32() - int32_t(script->pcToOffset(REGS.pc));
+ ADVANCE_AND_DISPATCH(len);
+}
+
+CASE(JSOP_EXCEPTION)
+{
+ PUSH_NULL();
+ MutableHandleValue res = REGS.stackHandleAt(-1);
+ if (!GetAndClearException(cx, res))
+ goto error;
+}
+END_CASE(JSOP_EXCEPTION)
+
+CASE(JSOP_FINALLY)
+ CHECK_BRANCH();
+END_CASE(JSOP_FINALLY)
+
+CASE(JSOP_THROWING)
+{
+ ReservedRooted<Value> v(&rootValue0);
+ POP_COPY_TO(v);
+ MOZ_ALWAYS_TRUE(ThrowingOperation(cx, v));
+}
+END_CASE(JSOP_THROWING)
+
+CASE(JSOP_THROW)
+{
+ CHECK_BRANCH();
+ ReservedRooted<Value> v(&rootValue0);
+ POP_COPY_TO(v);
+ JS_ALWAYS_FALSE(Throw(cx, v));
+ /* let the code at error try to catch the exception. */
+ goto error;
+}
+
+CASE(JSOP_INSTANCEOF)
+{
+ ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
+ if (HandleValue(rref).isPrimitive()) {
+ ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
+ goto error;
+ }
+ ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
+ bool cond = false;
+ if (!HasInstance(cx, obj, REGS.stackHandleAt(-2), &cond))
+ goto error;
+ REGS.sp--;
+ REGS.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_INSTANCEOF)
+
+CASE(JSOP_DEBUGGER)
+{
+ RootedValue rval(cx);
+ switch (Debugger::onDebuggerStatement(cx, REGS.fp())) {
+ case JSTRAP_ERROR:
+ goto error;
+ case JSTRAP_CONTINUE:
+ break;
+ case JSTRAP_RETURN:
+ if (!ForcedReturn(cx, REGS))
+ goto error;
+ goto successful_return_continuation;
+ case JSTRAP_THROW:
+ goto error;
+ default:;
+ }
+}
+END_CASE(JSOP_DEBUGGER)
+
+CASE(JSOP_PUSHLEXICALENV)
+{
+ ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
+
+ // Create block environment and push on scope chain.
+ if (!REGS.fp()->pushLexicalEnvironment(cx, scope.as<LexicalScope>()))
+ goto error;
+}
+END_CASE(JSOP_PUSHLEXICALENV)
+
+CASE(JSOP_POPLEXICALENV)
+{
+#ifdef DEBUG
+ // Pop block from scope chain.
+ Scope* scope = script->lookupScope(REGS.pc);
+ MOZ_ASSERT(scope);
+ MOZ_ASSERT(scope->is<LexicalScope>());
+ MOZ_ASSERT(scope->as<LexicalScope>().hasEnvironment());
+#endif
+
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
+
+ // Pop block from scope chain.
+ REGS.fp()->popOffEnvironmentChain<LexicalEnvironmentObject>();
+}
+END_CASE(JSOP_POPLEXICALENV)
+
+CASE(JSOP_DEBUGLEAVELEXICALENV)
+{
+ MOZ_ASSERT(script->lookupScope(REGS.pc));
+ MOZ_ASSERT(script->lookupScope(REGS.pc)->is<LexicalScope>());
+ MOZ_ASSERT(!script->lookupScope(REGS.pc)->as<LexicalScope>().hasEnvironment());
+
+ // FIXME: This opcode should not be necessary. The debugger shouldn't need
+ // help from bytecode to do its job. See bug 927782.
+
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
+}
+END_CASE(JSOP_DEBUGLEAVELEXICALENV)
+
+CASE(JSOP_FRESHENLEXICALENV)
+{
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
+
+ if (!REGS.fp()->freshenLexicalEnvironment(cx))
+ goto error;
+}
+END_CASE(JSOP_FRESHENLEXICALENV)
+
+CASE(JSOP_RECREATELEXICALENV)
+{
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
+
+ if (!REGS.fp()->recreateLexicalEnvironment(cx))
+ goto error;
+}
+END_CASE(JSOP_RECREATELEXICALENV)
+
+CASE(JSOP_PUSHVARENV)
+{
+ ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
+
+ if (!REGS.fp()->pushVarEnvironment(cx, scope))
+ goto error;
+}
+END_CASE(JSOP_PUSHVARENV)
+
+CASE(JSOP_POPVARENV)
+{
+#ifdef DEBUG
+ Scope* scope = script->lookupScope(REGS.pc);
+ MOZ_ASSERT(scope);
+ MOZ_ASSERT(scope->is<VarScope>());
+ MOZ_ASSERT(scope->as<VarScope>().hasEnvironment());
+#endif
+
+ if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
+ DebugEnvironments::onPopVar(cx, REGS.fp(), REGS.pc);
+
+ REGS.fp()->popOffEnvironmentChain<VarEnvironmentObject>();
+}
+END_CASE(JSOP_POPVARENV)
+
+CASE(JSOP_GENERATOR)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(REGS.stackDepth() == 0);
+ JSObject* obj = GeneratorObject::create(cx, REGS.fp());
+ if (!obj)
+ goto error;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_GENERATOR)
+
+CASE(JSOP_INITIALYIELD)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(REGS.fp()->isFunctionFrame());
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
+ POP_RETURN_VALUE();
+ MOZ_ASSERT(REGS.stackDepth() == 0);
+ if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc))
+ goto error;
+ goto successful_return_continuation;
+}
+
+CASE(JSOP_YIELD)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(REGS.fp()->isFunctionFrame());
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
+ if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc,
+ REGS.spForStackDepth(0), REGS.stackDepth() - 2))
+ {
+ goto error;
+ }
+
+ REGS.sp--;
+ POP_RETURN_VALUE();
+
+ goto successful_return_continuation;
+}
+
+CASE(JSOP_RESUME)
+{
+ {
+ ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-2].toObject());
+ ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
+ // popInlineFrame expects there to be an additional value on the stack
+ // to pop off, so leave "gen" on the stack.
+
+ GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(REGS.pc);
+ bool ok = GeneratorObject::resume(cx, activation, gen, val, resumeKind);
+ SET_SCRIPT(REGS.fp()->script());
+
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, script);
+ TraceLogStartEvent(logger, scriptEvent);
+ TraceLogStartEvent(logger, TraceLogger_Interpreter);
+
+ if (!ok)
+ goto error;
+ }
+ ADVANCE_AND_DISPATCH(0);
+}
+
+CASE(JSOP_DEBUGAFTERYIELD)
+{
+ // No-op in the interpreter, as GeneratorObject::resume takes care of
+ // fixing up InterpreterFrames.
+ MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
+}
+END_CASE(JSOP_DEBUGAFTERYIELD)
+
+CASE(JSOP_FINALYIELDRVAL)
+{
+ ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-1].toObject());
+ REGS.sp--;
+
+ if (!GeneratorObject::finalSuspend(cx, gen)) {
+ interpReturnOK = false;
+ goto return_continuation;
+ }
+
+ goto successful_return_continuation;
+}
+
+CASE(JSOP_ARRAYPUSH)
+{
+ ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
+ if (!NewbornArrayPush(cx, obj, REGS.sp[-2]))
+ goto error;
+ REGS.sp -= 2;
+}
+END_CASE(JSOP_ARRAYPUSH)
+
+CASE(JSOP_CLASSHERITAGE)
+{
+ ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
+
+ ReservedRooted<Value> objProto(&rootValue1);
+ ReservedRooted<JSObject*> funcProto(&rootObject0);
+ if (val.isNull()) {
+ objProto = NullValue();
+ if (!GetBuiltinPrototype(cx, JSProto_Function, &funcProto))
+ goto error;
+ } else {
+ if (!IsConstructor(val)) {
+ ReportIsNotFunction(cx, val, 0, CONSTRUCT);
+ goto error;
+ }
+
+ funcProto = &val.toObject();
+
+ if (!GetProperty(cx, funcProto, funcProto, cx->names().prototype, &objProto))
+ goto error;
+
+ if (!objProto.isObjectOrNull()) {
+ ReportValueError(cx, JSMSG_PROTO_NOT_OBJORNULL, -1, objProto, nullptr);
+ goto error;
+ }
+ }
+
+ REGS.sp[-1].setObject(*funcProto);
+ PUSH_COPY(objProto);
+}
+END_CASE(JSOP_CLASSHERITAGE)
+
+CASE(JSOP_FUNWITHPROTO)
+{
+ ReservedRooted<JSObject*> proto(&rootObject1, &REGS.sp[-1].toObject());
+
+ /* Load the specified function object literal. */
+ ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
+
+ JSObject* obj = CloneFunctionObjectIfNotSingleton(cx, fun, REGS.fp()->environmentChain(),
+ proto, GenericObject);
+ if (!obj)
+ goto error;
+
+ REGS.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_FUNWITHPROTO)
+
+CASE(JSOP_OBJWITHPROTO)
+{
+ ReservedRooted<JSObject*> proto(&rootObject0, REGS.sp[-1].toObjectOrNull());
+
+ JSObject* obj = NewObjectWithGivenProto<PlainObject>(cx, proto);
+ if (!obj)
+ goto error;
+
+ REGS.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_OBJWITHPROTO)
+
+CASE(JSOP_INITHOMEOBJECT)
+{
+ unsigned skipOver = GET_UINT8(REGS.pc);
+ MOZ_ASSERT(REGS.stackDepth() >= skipOver + 2);
+
+ /* Load the function to be initialized */
+ ReservedRooted<JSFunction*> func(&rootFunction0, &REGS.sp[-1].toObject().as<JSFunction>());
+ MOZ_ASSERT(func->allowSuperProperty());
+
+ /* Load the home object */
+ ReservedRooted<JSObject*> obj(&rootObject0);
+ obj = &REGS.sp[int(-2 - skipOver)].toObject();
+ MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() || obj->is<JSFunction>());
+
+ func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, ObjectValue(*obj));
+}
+END_CASE(JSOP_INITHOMEOBJECT)
+
+CASE(JSOP_SUPERBASE)
+{
+ JSFunction& superEnvFunc = GetSuperEnvFunction(cx, REGS);
+ MOZ_ASSERT(superEnvFunc.allowSuperProperty());
+ MOZ_ASSERT(superEnvFunc.nonLazyScript()->needsHomeObject());
+ const Value& homeObjVal = superEnvFunc.getExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT);
+
+ ReservedRooted<JSObject*> homeObj(&rootObject0, &homeObjVal.toObject());
+ ReservedRooted<JSObject*> superBase(&rootObject1);
+ if (!GetPrototype(cx, homeObj, &superBase))
+ goto error;
+
+ if (!superBase) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
+ "null", "object");
+ goto error;
+ }
+ PUSH_OBJECT(*superBase);
+}
+END_CASE(JSOP_SUPERBASE)
+
+CASE(JSOP_NEWTARGET)
+ PUSH_COPY(REGS.fp()->newTarget());
+ MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
+END_CASE(JSOP_NEWTARGET)
+
+CASE(JSOP_SUPERFUN)
+{
+ ReservedRooted<JSObject*> superEnvFunc(&rootObject0, &GetSuperEnvFunction(cx, REGS));
+ MOZ_ASSERT(superEnvFunc->as<JSFunction>().isClassConstructor());
+ MOZ_ASSERT(superEnvFunc->as<JSFunction>().nonLazyScript()->isDerivedClassConstructor());
+
+ ReservedRooted<JSObject*> superFun(&rootObject1);
+
+ if (!GetPrototype(cx, superEnvFunc, &superFun))
+ goto error;
+
+ ReservedRooted<Value> superFunVal(&rootValue0, UndefinedValue());
+ if (!superFun)
+ superFunVal = NullValue();
+ else if (!superFun->isConstructor())
+ superFunVal = ObjectValue(*superFun);
+
+ if (superFunVal.isObjectOrNull()) {
+ ReportIsNotFunction(cx, superFunVal, JSDVG_IGNORE_STACK, CONSTRUCT);
+ goto error;
+ }
+
+ PUSH_OBJECT(*superFun);
+}
+END_CASE(JSOP_SUPERFUN)
+
+CASE(JSOP_DERIVEDCONSTRUCTOR)
+{
+ MOZ_ASSERT(REGS.sp[-1].isObject());
+ ReservedRooted<JSObject*> proto(&rootObject0, &REGS.sp[-1].toObject());
+
+ JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
+ proto);
+ if (!constructor)
+ goto error;
+
+ REGS.sp[-1].setObject(*constructor);
+}
+END_CASE(JSOP_DERIVEDCONSTRUCTOR)
+
+CASE(JSOP_CLASSCONSTRUCTOR)
+{
+ JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
+ nullptr);
+ if (!constructor)
+ goto error;
+ PUSH_OBJECT(*constructor);
+}
+END_CASE(JSOP_CLASSCONSTRUCTOR)
+
+CASE(JSOP_CHECKOBJCOERCIBLE)
+{
+ ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
+ if (checkVal.isNullOrUndefined() && !ToObjectFromStack(cx, checkVal))
+ goto error;
+}
+END_CASE(JSOP_CHECKOBJCOERCIBLE)
+
+CASE(JSOP_DEBUGCHECKSELFHOSTED)
+{
+#ifdef DEBUG
+ ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
+ if (!Debug_CheckSelfHosted(cx, checkVal))
+ goto error;
+#endif
+}
+END_CASE(JSOP_DEBUGCHECKSELFHOSTED)
+
+CASE(JSOP_IS_CONSTRUCTING)
+ PUSH_MAGIC(JS_IS_CONSTRUCTING);
+END_CASE(JSOP_IS_CONSTRUCTING)
+
+DEFAULT()
+{
+ char numBuf[12];
+ SprintfLiteral(numBuf, "%d", *REGS.pc);
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_BYTECODE, numBuf);
+ goto error;
+}
+
+} /* interpreter loop */
+
+ MOZ_CRASH("Interpreter loop exited via fallthrough");
+
+ error:
+ switch (HandleError(cx, REGS)) {
+ case SuccessfulReturnContinuation:
+ goto successful_return_continuation;
+
+ case ErrorReturnContinuation:
+ interpReturnOK = false;
+ goto return_continuation;
+
+ case CatchContinuation:
+ ADVANCE_AND_DISPATCH(0);
+
+ case FinallyContinuation: {
+ /*
+ * Push (true, exception) pair for finally to indicate that [retsub]
+ * should rethrow the exception.
+ */
+ ReservedRooted<Value> exception(&rootValue0);
+ if (!cx->getPendingException(&exception)) {
+ interpReturnOK = false;
+ goto return_continuation;
+ }
+ PUSH_BOOLEAN(true);
+ PUSH_COPY(exception);
+ cx->clearPendingException();
+ }
+ ADVANCE_AND_DISPATCH(0);
+ }
+
+ MOZ_CRASH("Invalid HandleError continuation");
+
+ exit:
+ if (MOZ_LIKELY(!frameHalfInitialized)) {
+ interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
+
+ REGS.fp()->epilogue(cx, REGS.pc);
+ }
+
+ gc::MaybeVerifyBarriers(cx, true);
+
+ TraceLogStopEvent(logger, TraceLogger_Engine);
+ TraceLogStopEvent(logger, scriptEvent);
+
+ /*
+ * This path is used when it's guaranteed the method can be finished
+ * inside the JIT.
+ */
+ leave_on_safe_point:
+
+ if (interpReturnOK)
+ state.setReturnValue(activation.entryFrame()->returnValue());
+
+ return interpReturnOK;
+
+ prologue_error:
+ interpReturnOK = false;
+ frameHalfInitialized = true;
+ goto prologue_return_continuation;
+}
+
+bool
+js::Throw(JSContext* cx, HandleValue v)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ cx->setPendingException(v);
+ return false;
+}
+
+bool
+js::ThrowingOperation(JSContext* cx, HandleValue v)
+{
+ // Like js::Throw, but returns |true| instead of |false| to continue
+ // execution instead of calling the (JIT) exception handler.
+
+ MOZ_ASSERT(!cx->isExceptionPending());
+ cx->setPendingException(v);
+ return true;
+}
+
+bool
+js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
+{
+ if (name == cx->names().length) {
+ // Fast path for strings, arrays and arguments.
+ if (GetLengthProperty(v, vp))
+ return true;
+ }
+
+ // Optimize common cases like (2).toString() or "foo".valueOf() to not
+ // create a wrapper object.
+ if (v.isPrimitive() && !v.isNullOrUndefined()) {
+ NativeObject* proto;
+ if (v.isNumber()) {
+ proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
+ } else if (v.isString()) {
+ proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
+ } else if (v.isBoolean()) {
+ proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
+ } else {
+ MOZ_ASSERT(v.isSymbol());
+ proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
+ }
+ if (!proto)
+ return false;
+
+ if (GetPropertyPure(cx, proto, NameToId(name), vp.address()))
+ return true;
+ }
+
+ RootedValue receiver(cx, v);
+ RootedObject obj(cx, ToObjectFromStack(cx, v));
+ if (!obj)
+ return false;
+
+ return GetProperty(cx, obj, receiver, name, vp);
+}
+
+bool
+js::GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name,
+ MutableHandleValue vp)
+{
+ RootedShape shape(cx);
+ RootedObject obj(cx), pobj(cx);
+ if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
+ return false;
+
+ if (!shape)
+ return ReportIsNotDefined(cx, name);
+
+ if (!GetProperty(cx, obj, obj, name, vp))
+ return false;
+
+ // We do our own explicit checking for |this|
+ if (name == cx->names().dotThis)
+ return true;
+
+ // See note in FetchName.
+ return CheckUninitializedLexical(cx, name, vp);
+}
+
+/*
+ * Alternate form for NAME opcodes followed immediately by a TYPEOF,
+ * which do not report an exception on (typeof foo == "undefined") tests.
+ */
+bool
+js::GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject envChain, HandlePropertyName name,
+ MutableHandleValue vp)
+{
+ RootedShape shape(cx);
+ RootedObject obj(cx), pobj(cx);
+ if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
+ return false;
+
+ if (!shape) {
+ vp.set(UndefinedValue());
+ return true;
+ }
+
+ if (!GetProperty(cx, obj, obj, name, vp))
+ return false;
+
+ // See note in FetchName.
+ return CheckUninitializedLexical(cx, name, vp);
+}
+
+JSObject*
+js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent)
+{
+ MOZ_ASSERT(!fun->isArrow());
+
+ RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent));
+ if (!clone)
+ return nullptr;
+
+ MOZ_ASSERT(fun->global() == clone->global());
+ return clone;
+}
+
+JSObject*
+js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue newTargetv)
+{
+ MOZ_ASSERT(fun->isArrow());
+
+ RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, nullptr,
+ TenuredObject));
+ if (!clone)
+ return nullptr;
+
+ MOZ_ASSERT(clone->as<JSFunction>().isArrow());
+ clone->as<JSFunction>().setExtendedSlot(0, newTargetv);
+
+ MOZ_ASSERT(fun->global() == clone->global());
+ return clone;
+}
+
+bool
+js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
+ HandleFunction fun)
+{
+ /*
+ * We define the function as a property of the variable object and not the
+ * current scope chain even for the case of function expression statements
+ * and functions defined by eval inside let or with blocks.
+ */
+ RootedObject parent(cx, envChain);
+ while (!parent->isQualifiedVarObj())
+ parent = parent->enclosingEnvironment();
+
+ /* ES5 10.5 (NB: with subsequent errata). */
+ RootedPropertyName name(cx, fun->name()->asPropertyName());
+
+ RootedShape shape(cx);
+ RootedObject pobj(cx);
+ if (!LookupProperty(cx, parent, name, &pobj, &shape))
+ return false;
+
+ RootedValue rval(cx, ObjectValue(*fun));
+
+ /*
+ * ECMA requires functions defined when entering Eval code to be
+ * impermanent.
+ */
+ unsigned attrs = script->isActiveEval()
+ ? JSPROP_ENUMERATE
+ : JSPROP_ENUMERATE | JSPROP_PERMANENT;
+
+ /* Steps 5d, 5f. */
+ if (!shape || pobj != parent) {
+ if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
+ return false;
+
+ return parent->is<GlobalObject>() ? parent->compartment()->addToVarNames(cx, name) : true;
+ }
+
+ /*
+ * Step 5e.
+ *
+ * A DebugEnvironmentProxy is okay here, and sometimes necessary. If
+ * Debugger.Frame.prototype.eval defines a function with the same name as an
+ * extant variable in the frame, the DebugEnvironmentProxy takes care of storing
+ * the function in the stack frame (for non-aliased variables) or on the
+ * scope object (for aliased).
+ */
+ MOZ_ASSERT(parent->isNative() || parent->is<DebugEnvironmentProxy>());
+ if (parent->is<GlobalObject>()) {
+ if (shape->configurable()) {
+ if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
+ return false;
+ } else {
+ MOZ_ASSERT(shape->isDataDescriptor());
+ MOZ_ASSERT(shape->writable());
+ MOZ_ASSERT(shape->enumerable());
+ }
+
+ // Careful: the presence of a shape, even one appearing to derive from
+ // a variable declaration, doesn't mean it's in [[VarNames]].
+ if (!parent->compartment()->addToVarNames(cx, name))
+ return false;
+ }
+
+ /*
+ * Non-global properties, and global properties which we aren't simply
+ * redefining, must be set. First, this preserves their attributes.
+ * Second, this will produce warnings and/or errors as necessary if the
+ * specified Call object property is not writable (const).
+ */
+
+ /* Step 5f. */
+ RootedId id(cx, NameToId(name));
+ return PutProperty(cx, parent, id, rval, script->strict());
+}
+
+bool
+js::ThrowMsgOperation(JSContext* cx, const unsigned errorNum)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNum);
+ return false;
+}
+
+bool
+js::GetAndClearException(JSContext* cx, MutableHandleValue res)
+{
+ if (!cx->getPendingException(res))
+ return false;
+ cx->clearPendingException();
+
+ // Allow interrupting deeply nested exception handling.
+ return CheckForInterrupt(cx);
+}
+
+template <bool strict>
+bool
+js::DeletePropertyJit(JSContext* cx, HandleValue v, HandlePropertyName name, bool* bp)
+{
+ RootedObject obj(cx, ToObjectFromStack(cx, v));
+ if (!obj)
+ return false;
+
+ RootedId id(cx, NameToId(name));
+ ObjectOpResult result;
+ if (!DeleteProperty(cx, obj, id, result))
+ return false;
+
+ if (strict) {
+ if (!result)
+ return result.reportError(cx, obj, id);
+ *bp = true;
+ } else {
+ *bp = result.ok();
+ }
+ return true;
+}
+
+template bool js::DeletePropertyJit<true> (JSContext* cx, HandleValue val, HandlePropertyName name,
+ bool* bp);
+template bool js::DeletePropertyJit<false>(JSContext* cx, HandleValue val, HandlePropertyName name,
+ bool* bp);
+
+template <bool strict>
+bool
+js::DeleteElementJit(JSContext* cx, HandleValue val, HandleValue index, bool* bp)
+{
+ RootedObject obj(cx, ToObjectFromStack(cx, val));
+ if (!obj)
+ return false;
+
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, index, &id))
+ return false;
+ ObjectOpResult result;
+ if (!DeleteProperty(cx, obj, id, result))
+ return false;
+
+ if (strict) {
+ if (!result)
+ return result.reportError(cx, obj, id);
+ *bp = true;
+ } else {
+ *bp = result.ok();
+ }
+ return true;
+}
+
+template bool js::DeleteElementJit<true> (JSContext*, HandleValue, HandleValue, bool* succeeded);
+template bool js::DeleteElementJit<false>(JSContext*, HandleValue, HandleValue, bool* succeeded);
+
+bool
+js::GetElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp)
+{
+ return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp);
+}
+
+bool
+js::CallElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res)
+{
+ return GetElementOperation(cx, JSOP_CALLELEM, lref, rref, res);
+}
+
+bool
+js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ bool strict)
+{
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, index, &id))
+ return false;
+ RootedValue receiver(cx, ObjectValue(*obj));
+ return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
+}
+
+bool
+js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ bool strict, HandleScript script, jsbytecode* pc)
+{
+ MOZ_ASSERT(pc);
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, index, &id))
+ return false;
+ RootedValue receiver(cx, ObjectValue(*obj));
+ return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script, pc);
+}
+
+bool
+js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ HandleValue receiver, bool strict, HandleScript script, jsbytecode* pc)
+{
+ MOZ_ASSERT(pc);
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, index, &id))
+ return false;
+ return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script, pc);
+}
+
+bool
+js::InitElementArray(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t index, HandleValue value)
+{
+ return InitArrayElemOperation(cx, pc, obj, index, value);
+}
+
+bool
+js::AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return AddOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::SubValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return SubOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::MulValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return MulOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::DivValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return DivOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::ModValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return ModOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::UrshValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res)
+{
+ return UrshOperation(cx, lhs, rhs, res);
+}
+
+bool
+js::AtomicIsLockFree(JSContext* cx, HandleValue in, int* out)
+{
+ int i;
+ if (!ToInt32(cx, in, &i))
+ return false;
+ *out = js::jit::AtomicOperations::isLockfree(i);
+ return true;
+}
+
+bool
+js::DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject scopeObj,
+ MutableHandleValue res)
+{
+ RootedObject scope(cx), pobj(cx);
+ RootedShape shape(cx);
+ if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape))
+ return false;
+
+ if (!scope) {
+ // Return true for non-existent names.
+ res.setBoolean(true);
+ return true;
+ }
+
+ ObjectOpResult result;
+ RootedId id(cx, NameToId(name));
+ if (!DeleteProperty(cx, scope, id, result))
+ return false;
+
+ bool status = result.ok();
+ res.setBoolean(status);
+
+ if (status) {
+ // Deleting a name from the global object removes it from [[VarNames]].
+ if (pobj == scope && scope->is<GlobalObject>())
+ scope->compartment()->removeFromVarNames(name);
+ }
+
+ return true;
+}
+
+bool
+js::ImplicitThisOperation(JSContext* cx, HandleObject scopeObj, HandlePropertyName name,
+ MutableHandleValue res)
+{
+ RootedObject obj(cx);
+ if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj))
+ return false;
+
+ res.set(ComputeImplicitThis(obj));
+ return true;
+}
+
+bool
+js::RunOnceScriptPrologue(JSContext* cx, HandleScript script)
+{
+ MOZ_ASSERT(script->treatAsRunOnce());
+
+ if (!script->hasRunOnce()) {
+ script->setHasRunOnce();
+ return true;
+ }
+
+ // Force instantiation of the script's function's group to ensure the flag
+ // is preserved in type information.
+ if (!script->functionNonDelazifying()->getGroup(cx))
+ return false;
+
+ MarkObjectGroupFlags(cx, script->functionNonDelazifying(), OBJECT_FLAG_RUNONCE_INVALIDATED);
+ return true;
+}
+
+unsigned
+js::GetInitDataPropAttrs(JSOp op)
+{
+ switch (op) {
+ case JSOP_INITPROP:
+ return JSPROP_ENUMERATE;
+ case JSOP_INITLOCKEDPROP:
+ return JSPROP_PERMANENT | JSPROP_READONLY;
+ case JSOP_INITHIDDENPROP:
+ // Non-enumerable, but writable and configurable
+ return 0;
+ default:;
+ }
+ MOZ_CRASH("Unknown data initprop");
+}
+
+bool
+js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleId id,
+ HandleObject val)
+{
+ MOZ_ASSERT(val->isCallable());
+ GetterOp getter;
+ SetterOp setter;
+ unsigned attrs = JSPROP_SHARED;
+
+ JSOp op = JSOp(*pc);
+
+ if (!IsHiddenInitOp(op))
+ attrs |= JSPROP_ENUMERATE;
+
+ if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER ||
+ op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER)
+ {
+ getter = CastAsGetterOp(val);
+ setter = nullptr;
+ attrs |= JSPROP_GETTER;
+ } else {
+ MOZ_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER ||
+ op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER);
+ getter = nullptr;
+ setter = CastAsSetterOp(val);
+ attrs |= JSPROP_SETTER;
+ }
+
+ RootedValue scratch(cx);
+ return DefineProperty(cx, obj, id, scratch, getter, setter, attrs);
+}
+
+bool
+js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj,
+ HandlePropertyName name, HandleObject val)
+{
+ RootedId id(cx, NameToId(name));
+ return InitGetterSetterOperation(cx, pc, obj, id, val);
+}
+
+bool
+js::InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval,
+ HandleObject val)
+{
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, idval, &id))
+ return false;
+
+ return InitGetterSetterOperation(cx, pc, obj, id, val);
+}
+
+bool
+js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue thisv,
+ HandleValue callee, HandleValue arr, HandleValue newTarget, MutableHandleValue res)
+{
+ RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
+ uint32_t length = aobj->length();
+ JSOp op = JSOp(*pc);
+ bool constructing = op == JSOP_SPREADNEW || op == JSOP_SPREADSUPERCALL;
+
+ // {Construct,Invoke}Args::init does this too, but this gives us a better
+ // error message.
+ if (length > ARGS_LENGTH_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
+ : JSMSG_TOO_MANY_FUN_SPREADARGS);
+ return false;
+ }
+
+ // Do our own checks for the callee being a function, as Invoke uses the
+ // expression decompiler to decompile the callee stack operand based on
+ // the number of arguments. Spread operations have the callee at sp - 3
+ // when not constructing, and sp - 4 when constructing.
+ if (callee.isPrimitive()) {
+ return ReportIsNotFunction(cx, callee, 2 + constructing,
+ constructing ? CONSTRUCT : NO_CONSTRUCT);
+ }
+
+ if (MOZ_UNLIKELY(!callee.toObject().is<JSFunction>()) && !callee.toObject().callHook()) {
+ return ReportIsNotFunction(cx, callee, 2 + constructing,
+ constructing ? CONSTRUCT : NO_CONSTRUCT);
+ }
+
+#ifdef DEBUG
+ // The object must be an array with dense elements and no holes. Baseline's
+ // optimized spread call stubs rely on this.
+ MOZ_ASSERT(!aobj->isIndexed());
+ MOZ_ASSERT(aobj->getDenseInitializedLength() == aobj->length());
+ for (size_t i = 0; i < aobj->length(); i++)
+ MOZ_ASSERT(!aobj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE));
+#endif
+
+ if (constructing) {
+ if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget))
+ return false;
+
+ ConstructArgs cargs(cx);
+ if (!cargs.init(cx, length))
+ return false;
+
+ if (!GetElements(cx, aobj, length, cargs.array()))
+ return false;
+
+ RootedObject obj(cx);
+ if (!Construct(cx, callee, cargs, newTarget, &obj))
+ return false;
+ res.setObject(*obj);
+ } else {
+ InvokeArgs args(cx);
+ if (!args.init(cx, length))
+ return false;
+
+ if (!GetElements(cx, aobj, length, args.array()))
+ return false;
+
+ if ((op == JSOP_SPREADEVAL || op == JSOP_STRICTSPREADEVAL) &&
+ cx->global()->valueIsEval(callee))
+ {
+ if (!DirectEval(cx, args.get(0), res))
+ return false;
+ } else {
+ MOZ_ASSERT(op == JSOP_SPREADCALL ||
+ op == JSOP_SPREADEVAL ||
+ op == JSOP_STRICTSPREADEVAL,
+ "bad spread opcode");
+
+ if (!Call(cx, callee, thisv, args, res))
+ return false;
+ }
+ }
+
+ TypeScript::Monitor(cx, script, pc, res);
+ return true;
+}
+
+bool
+js::OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized)
+{
+ // Optimize spread call by skipping spread operation when following
+ // conditions are met:
+ // * the argument is an array
+ // * the array has no hole
+ // * array[@@iterator] is not modified
+ // * the array's prototype is Array.prototype
+ // * Array.prototype[@@iterator] is not modified
+ // * %ArrayIteratorPrototype%.next is not modified
+ if (!arg.isObject()) {
+ *optimized = false;
+ return true;
+ }
+
+ RootedObject obj(cx, &arg.toObject());
+ if (!IsPackedArray(obj)) {
+ *optimized = false;
+ return true;
+ }
+
+ ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
+ if (!stubChain)
+ return false;
+
+ return stubChain->tryOptimizeArray(cx, obj.as<ArrayObject>(), optimized);
+}
+
+JSObject*
+js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
+ NewObjectKind newKind /* = GenericObject */)
+{
+ MOZ_ASSERT(newKind != SingletonObject);
+
+ RootedObjectGroup group(cx);
+ if (ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Object)) {
+ newKind = SingletonObject;
+ } else {
+ group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Object);
+ if (!group)
+ return nullptr;
+ if (group->maybePreliminaryObjects()) {
+ group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
+ if (group->maybeUnboxedLayout())
+ group->maybeUnboxedLayout()->setAllocationSite(script, pc);
+ }
+
+ if (group->shouldPreTenure() || group->maybePreliminaryObjects())
+ newKind = TenuredObject;
+
+ if (group->maybeUnboxedLayout())
+ return UnboxedPlainObject::create(cx, group, newKind);
+ }
+
+ RootedObject obj(cx);
+
+ if (*pc == JSOP_NEWOBJECT) {
+ RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
+ obj = CopyInitializerObject(cx, baseObject, newKind);
+ } else {
+ MOZ_ASSERT(*pc == JSOP_NEWINIT);
+ MOZ_ASSERT(GET_UINT8(pc) == JSProto_Object);
+ obj = NewBuiltinClassInstance<PlainObject>(cx, newKind);
+ }
+
+ if (!obj)
+ return nullptr;
+
+ if (newKind == SingletonObject) {
+ if (!JSObject::setSingleton(cx, obj))
+ return nullptr;
+ } else {
+ obj->setGroup(group);
+
+ if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
+ preliminaryObjects->registerNewObject(obj);
+ }
+
+ return obj;
+}
+
+JSObject*
+js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject)
+{
+ // This is an optimized version of NewObjectOperation for use when the
+ // object is not a singleton and has had its preliminary objects analyzed,
+ // with the template object a copy of the object to create.
+ MOZ_ASSERT(!templateObject->isSingleton());
+
+ NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
+
+ if (templateObject->group()->maybeUnboxedLayout()) {
+ RootedObjectGroup group(cx, templateObject->group());
+ return UnboxedPlainObject::create(cx, group, newKind);
+ }
+
+ JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
+ if (!obj)
+ return nullptr;
+
+ obj->setGroup(templateObject->group());
+ return obj;
+}
+
+JSObject*
+js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32_t length,
+ NewObjectKind newKind /* = GenericObject */)
+{
+ MOZ_ASSERT(newKind != SingletonObject);
+
+ RootedObjectGroup group(cx);
+ if (ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Array)) {
+ newKind = SingletonObject;
+ } else {
+ group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
+ if (!group)
+ return nullptr;
+ if (group->maybePreliminaryObjects())
+ group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
+
+ if (group->shouldPreTenure() || group->maybePreliminaryObjects())
+ newKind = TenuredObject;
+
+ if (group->maybeUnboxedLayout())
+ return UnboxedArrayObject::create(cx, group, length, newKind);
+ }
+
+ ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
+ if (!obj)
+ return nullptr;
+
+ if (newKind == SingletonObject) {
+ MOZ_ASSERT(obj->isSingleton());
+ } else {
+ obj->setGroup(group);
+
+ if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
+ preliminaryObjects->registerNewObject(obj);
+ }
+
+ return obj;
+}
+
+JSObject*
+js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject)
+{
+ MOZ_ASSERT(!templateObject->isSingleton());
+
+ NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
+
+ if (templateObject->is<UnboxedArrayObject>()) {
+ uint32_t length = templateObject->as<UnboxedArrayObject>().length();
+ RootedObjectGroup group(cx, templateObject->group());
+ return UnboxedArrayObject::create(cx, group, length, newKind);
+ }
+
+ ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(),
+ nullptr, newKind);
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(obj->lastProperty() == templateObject->as<ArrayObject>().lastProperty());
+ obj->setGroup(templateObject->group());
+ return obj;
+}
+
+void
+js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleId id)
+{
+ MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
+ errorNumber == JSMSG_BAD_CONST_ASSIGN);
+ JSAutoByteString printable;
+ if (ValueToPrintable(cx, IdToValue(id), &printable))
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, printable.ptr());
+}
+
+void
+js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandlePropertyName name)
+{
+ RootedId id(cx, NameToId(name));
+ ReportRuntimeLexicalError(cx, errorNumber, id);
+}
+
+void
+js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
+ HandleScript script, jsbytecode* pc)
+{
+ JSOp op = JSOp(*pc);
+ MOZ_ASSERT(op == JSOP_CHECKLEXICAL ||
+ op == JSOP_CHECKALIASEDLEXICAL ||
+ op == JSOP_THROWSETCONST ||
+ op == JSOP_THROWSETALIASEDCONST ||
+ op == JSOP_THROWSETCALLEE ||
+ op == JSOP_GETIMPORT);
+
+ RootedPropertyName name(cx);
+
+ if (op == JSOP_THROWSETCALLEE) {
+ name = script->functionNonDelazifying()->name()->asPropertyName();
+ } else if (IsLocalOp(op)) {
+ name = FrameSlotName(script, pc)->asPropertyName();
+ } else if (IsAtomOp(op)) {
+ name = script->getName(pc);
+ } else {
+ MOZ_ASSERT(IsAliasedVarOp(op));
+ name = EnvironmentCoordinateName(cx->caches.envCoordinateNameCache, script, pc);
+ }
+
+ ReportRuntimeLexicalError(cx, errorNumber, name);
+}
+
+void
+js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, const char* redeclKind)
+{
+ JSAutoByteString printable;
+ if (AtomToPrintableString(cx, name, &printable)) {
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_REDECLARED_VAR,
+ redeclKind, printable.ptr());
+ }
+}
+
+bool
+js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
+{
+ switch (kind) {
+ case CheckIsObjectKind::IteratorNext:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NEXT_RETURNED_PRIMITIVE);
+ break;
+ case CheckIsObjectKind::GetIterator:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE);
+ break;
+ default:
+ MOZ_CRASH("Unknown kind");
+ }
+ return false;
+}
+
+bool
+js::ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame)
+{
+ RootedFunction fun(cx);
+ if (frame.isFunctionFrame()) {
+ fun = frame.callee();
+ } else {
+ Scope* startingScope;
+ if (frame.isDebuggerEvalFrame()) {
+ AbstractFramePtr evalInFramePrev = frame.asInterpreterFrame()->evalInFramePrev();
+ startingScope = evalInFramePrev.script()->bodyScope();
+ } else {
+ MOZ_ASSERT(frame.isEvalFrame());
+ MOZ_ASSERT(frame.script()->isDirectEvalInFunction());
+ startingScope = frame.script()->enclosingScope();
+ }
+
+ for (ScopeIter si(startingScope); si; si++) {
+ if (si.scope()->is<FunctionScope>()) {
+ fun = si.scope()->as<FunctionScope>().canonicalFunction();
+ break;
+ }
+ }
+ MOZ_ASSERT(fun);
+ }
+
+ if (fun->isDerivedClassConstructor()) {
+ const char* name = "anonymous";
+ JSAutoByteString str;
+ if (fun->name()) {
+ if (!AtomToPrintableString(cx, fun->name(), &str))
+ return false;
+ name = str.ptr();
+ }
+
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_THIS, name);
+ return false;
+ }
+
+ MOZ_ASSERT(fun->isArrow());
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_THIS_ARROW);
+ return false;
+}
diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h
new file mode 100644
index 000000000..1ffe1fdca
--- /dev/null
+++ b/js/src/vm/Interpreter.h
@@ -0,0 +1,582 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Interpreter_h
+#define vm_Interpreter_h
+
+/*
+ * JS interpreter interface.
+ */
+
+#include "jsiter.h"
+#include "jspubtd.h"
+
+#include "frontend/ParseNode.h"
+
+#include "vm/Stack.h"
+
+namespace js {
+
+class EnvironmentIter;
+
+/*
+ * Convert null/undefined |thisv| into the current global object for the
+ * compartment, and replace other primitives with boxed versions.
+ */
+extern bool
+BoxNonStrictThis(JSContext* cx, HandleValue thisv, MutableHandleValue vp);
+
+extern bool
+GetFunctionThis(JSContext* cx, AbstractFramePtr frame, MutableHandleValue res);
+
+extern bool
+GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain, MutableHandleValue res);
+
+/*
+ * numToSkip is the number of stack values the expression decompiler should skip
+ * before it reaches |v|. If it's -1, the decompiler will search the stack.
+ */
+extern bool
+ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
+ MaybeConstruct construct = NO_CONSTRUCT);
+
+/* See ReportIsNotFunction comment for the meaning of numToSkip. */
+extern JSObject*
+ValueToCallable(JSContext* cx, HandleValue v, int numToSkip = -1,
+ MaybeConstruct construct = NO_CONSTRUCT);
+
+/*
+ * Call or construct arguments that are stored in rooted memory.
+ *
+ * NOTE: Any necessary |GetThisValue| computation must have been performed on
+ * |args.thisv()|, likely by the interpreter when pushing |this| onto the
+ * stack. If you're not sure whether |GetThisValue| processing has been
+ * performed, use |Invoke|.
+ */
+extern bool
+InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
+ MaybeConstruct construct);
+
+/*
+ * These helpers take care of the infinite-recursion check necessary for
+ * getter/setter calls.
+ */
+extern bool
+CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter, MutableHandleValue rval);
+
+extern bool
+CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter, HandleValue rval);
+
+// ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.12 Call(F, V, argumentsList).
+// All parameters are required, hopefully forcing callers to be careful not to
+// (say) blindly pass callee as |newTarget| when a different value should have
+// been passed. Behavior is unspecified if any element of |args| isn't initialized.
+//
+// |rval| is written to *only* after |fval| and |thisv| have been consumed, so
+// |rval| *may* alias either argument.
+extern bool
+Call(JSContext* cx, HandleValue fval, HandleValue thisv, const AnyInvokeArgs& args,
+ MutableHandleValue rval);
+
+inline bool
+Call(JSContext* cx, HandleValue fval, HandleValue thisv, MutableHandleValue rval)
+{
+ FixedInvokeArgs<0> args(cx);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+inline bool
+Call(JSContext* cx, HandleValue fval, JSObject* thisObj, MutableHandleValue rval)
+{
+ RootedValue thisv(cx, ObjectOrNullValue(thisObj));
+ FixedInvokeArgs<0> args(cx);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+inline bool
+Call(JSContext* cx, HandleValue fval, HandleValue thisv, HandleValue arg0, MutableHandleValue rval)
+{
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(arg0);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+inline bool
+Call(JSContext* cx, HandleValue fval, JSObject* thisObj, HandleValue arg0,
+ MutableHandleValue rval)
+{
+ RootedValue thisv(cx, ObjectOrNullValue(thisObj));
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(arg0);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+inline bool
+Call(JSContext* cx, HandleValue fval, HandleValue thisv,
+ HandleValue arg0, HandleValue arg1, MutableHandleValue rval)
+{
+ FixedInvokeArgs<2> args(cx);
+ args[0].set(arg0);
+ args[1].set(arg1);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+inline bool
+Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
+ HandleValue arg0, HandleValue arg1, MutableHandleValue rval)
+{
+ RootedValue thisv(cx, ObjectOrNullValue(thisObj));
+ FixedInvokeArgs<2> args(cx);
+ args[0].set(arg0);
+ args[1].set(arg1);
+ return Call(cx, fval, thisv, args, rval);
+}
+
+// Perform the above Call() operation using the given arguments. Similar to
+// ConstructFromStack() below, this handles |!IsCallable(args.calleev())|.
+//
+// This internal operation is intended only for use with arguments known to be
+// on the JS stack, or at least in carefully-rooted memory. The vast majority of
+// potential users should instead use InvokeArgs in concert with Call().
+extern bool
+CallFromStack(JSContext* cx, const CallArgs& args);
+
+// ES6 7.3.13 Construct(F, argumentsList, newTarget). All parameters are
+// required, hopefully forcing callers to be careful not to (say) blindly pass
+// callee as |newTarget| when a different value should have been passed.
+// Behavior is unspecified if any element of |args| isn't initialized.
+//
+// |rval| is written to *only* after |fval| and |newTarget| have been consumed,
+// so |rval| *may* alias either argument.
+//
+// NOTE: As with the ES6 spec operation, it's the caller's responsibility to
+// ensure |fval| and |newTarget| are both |IsConstructor|.
+extern bool
+Construct(JSContext* cx, HandleValue fval, const AnyConstructArgs& args, HandleValue newTarget,
+ MutableHandleObject objp);
+
+// Check that in the given |args|, which must be |args.isConstructing()|, that
+// |IsConstructor(args.callee())|. If this is not the case, throw a TypeError.
+// Otherwise, the user must ensure that, additionally, |IsConstructor(args.newTarget())|.
+// (If |args| comes directly from the interpreter stack, as set up by JSOP_NEW,
+// this comes for free.) Then perform a Construct() operation using |args|.
+//
+// This internal operation is intended only for use with arguments known to be
+// on the JS stack, or at least in carefully-rooted memory. The vast majority of
+// potential users should instead use ConstructArgs in concert with Construct().
+extern bool
+ConstructFromStack(JSContext* cx, const CallArgs& args);
+
+// Call Construct(fval, args, newTarget), but use the given |thisv| as |this|
+// during construction of |fval|.
+//
+// |rval| is written to *only* after |fval|, |thisv|, and |newTarget| have been
+// consumed, so |rval| *may* alias any of these arguments.
+//
+// This method exists only for very rare cases where a |this| was created
+// caller-side for construction of |fval|: basically only for JITs using
+// |CreateThis|. If that's not you, use Construct()!
+extern bool
+InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval, HandleValue thisv,
+ const AnyConstructArgs& args, HandleValue newTarget,
+ MutableHandleValue rval);
+
+/*
+ * Executes a script with the given scopeChain/this. The 'type' indicates
+ * whether this is eval code or global code. To support debugging, the
+ * evalFrame parameter can point to an arbitrary frame in the context's call
+ * stack to simulate executing an eval in that frame.
+ */
+extern bool
+ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChain,
+ const Value& newTargetVal, AbstractFramePtr evalInFrame, Value* result);
+
+/* Execute a script with the given scopeChain as global code. */
+extern bool
+Execute(JSContext* cx, HandleScript script, JSObject& scopeChain, Value* rval);
+
+class ExecuteState;
+class InvokeState;
+
+// RunState is passed to RunScript and RunScript then either passes it to the
+// interpreter or to the JITs. RunState contains all information we need to
+// construct an interpreter or JIT frame.
+class RunState
+{
+ protected:
+ enum Kind { Execute, Invoke };
+ Kind kind_;
+
+ RootedScript script_;
+
+ explicit RunState(JSContext* cx, Kind kind, JSScript* script)
+ : kind_(kind),
+ script_(cx, script)
+ { }
+
+ public:
+ bool isExecute() const { return kind_ == Execute; }
+ bool isInvoke() const { return kind_ == Invoke; }
+
+ ExecuteState* asExecute() const {
+ MOZ_ASSERT(isExecute());
+ return (ExecuteState*)this;
+ }
+ InvokeState* asInvoke() const {
+ MOZ_ASSERT(isInvoke());
+ return (InvokeState*)this;
+ }
+
+ JS::HandleScript script() const { return script_; }
+
+ virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx) = 0;
+ virtual void setReturnValue(const Value& v) = 0;
+
+ bool maybeCreateThisForConstructor(JSContext* cx);
+
+ private:
+ RunState(const RunState& other) = delete;
+ RunState(const ExecuteState& other) = delete;
+ RunState(const InvokeState& other) = delete;
+ void operator=(const RunState& other) = delete;
+};
+
+// Eval or global script.
+class ExecuteState : public RunState
+{
+ RootedValue newTargetValue_;
+ RootedObject envChain_;
+
+ AbstractFramePtr evalInFrame_;
+ Value* result_;
+
+ public:
+ ExecuteState(JSContext* cx, JSScript* script, const Value& newTargetValue,
+ JSObject& envChain, AbstractFramePtr evalInFrame, Value* result)
+ : RunState(cx, Execute, script),
+ newTargetValue_(cx, newTargetValue),
+ envChain_(cx, &envChain),
+ evalInFrame_(evalInFrame),
+ result_(result)
+ { }
+
+ Value newTarget() { return newTargetValue_; }
+ JSObject* environmentChain() const { return envChain_; }
+ bool isDebuggerEval() const { return !!evalInFrame_; }
+
+ virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx);
+
+ virtual void setReturnValue(const Value& v) {
+ if (result_)
+ *result_ = v;
+ }
+};
+
+// Data to invoke a function.
+class InvokeState final : public RunState
+{
+ const CallArgs& args_;
+ MaybeConstruct construct_;
+ bool createSingleton_;
+
+ public:
+ InvokeState(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
+ : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
+ args_(args),
+ construct_(construct),
+ createSingleton_(false)
+ { }
+
+ bool createSingleton() const { return createSingleton_; }
+ void setCreateSingleton() { createSingleton_ = true; }
+
+ bool constructing() const { return construct_; }
+ const CallArgs& args() const { return args_; }
+
+ virtual InterpreterFrame* pushInterpreterFrame(JSContext* cx);
+
+ virtual void setReturnValue(const Value& v) {
+ args_.rval().set(v);
+ }
+};
+
+extern bool
+RunScript(JSContext* cx, RunState& state);
+
+extern bool
+StrictlyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal);
+
+extern bool
+LooselyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal);
+
+/* === except that NaN is the same as NaN and -0 is not the same as +0. */
+extern bool
+SameValue(JSContext* cx, HandleValue v1, HandleValue v2, bool* same);
+
+extern JSType
+TypeOfObject(JSObject* obj);
+
+extern JSType
+TypeOfValue(const Value& v);
+
+extern bool
+InstanceOfOperator(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);
+
+extern bool
+HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp);
+
+// Unwind environment chain and iterator to match the scope corresponding to
+// the given bytecode position.
+extern void
+UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc);
+
+// Unwind all environments.
+extern void
+UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei);
+
+// Compute the pc needed to unwind the scope to the beginning of the block
+// pointed to by the try note.
+extern jsbytecode*
+UnwindEnvironmentToTryPc(JSScript* script, JSTryNote* tn);
+
+template <class StackDepthOp>
+class MOZ_STACK_CLASS TryNoteIter
+{
+ RootedScript script_;
+ uint32_t pcOffset_;
+ JSTryNote* tn_;
+ JSTryNote* tnEnd_;
+ StackDepthOp getStackDepth_;
+
+ void settle() {
+ for (; tn_ != tnEnd_; ++tn_) {
+ /* If pc is out of range, try the next one. */
+ if (pcOffset_ - tn_->start >= tn_->length)
+ continue;
+
+ /*
+ * We have a note that covers the exception pc but we must check
+ * whether the interpreter has already executed the corresponding
+ * handler. This is possible when the executed bytecode implements
+ * break or return from inside a for-in loop.
+ *
+ * In this case the emitter generates additional [enditer] and [gosub]
+ * opcodes to close all outstanding iterators and execute the finally
+ * blocks. If such an [enditer] throws an exception, its pc can still
+ * be inside several nested for-in loops and try-finally statements
+ * even if we have already closed the corresponding iterators and
+ * invoked the finally blocks.
+ *
+ * To address this, we make [enditer] always decrease the stack even
+ * when its implementation throws an exception. Thus already executed
+ * [enditer] and [gosub] opcodes will have try notes with the stack
+ * depth exceeding the current one and this condition is what we use to
+ * filter them out.
+ */
+ if (tn_->stackDepth <= getStackDepth_())
+ break;
+ }
+ }
+
+ public:
+ TryNoteIter(JSContext* cx, JSScript* script, jsbytecode* pc,
+ StackDepthOp getStackDepth)
+ : script_(cx, script),
+ pcOffset_(pc - script->main()),
+ getStackDepth_(getStackDepth)
+ {
+ if (script->hasTrynotes()) {
+ tn_ = script->trynotes()->vector;
+ tnEnd_ = tn_ + script->trynotes()->length;
+ } else {
+ tn_ = tnEnd_ = nullptr;
+ }
+ settle();
+ }
+
+ void operator++() {
+ ++tn_;
+ settle();
+ }
+
+ bool done() const { return tn_ == tnEnd_; }
+ JSTryNote* operator*() const { return tn_; }
+};
+
+bool
+HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame, bool ok);
+
+/************************************************************************/
+
+bool
+Throw(JSContext* cx, HandleValue v);
+
+bool
+ThrowingOperation(JSContext* cx, HandleValue v);
+
+bool
+GetProperty(JSContext* cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
+
+bool
+GetEnvironmentName(JSContext* cx, HandleObject obj, HandlePropertyName name,
+ MutableHandleValue vp);
+
+bool
+GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject obj, HandlePropertyName name,
+ MutableHandleValue vp);
+
+JSObject*
+Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
+
+JSObject*
+LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue newTargetv);
+
+bool
+GetElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
+
+bool
+CallElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
+
+bool
+SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ bool strict);
+bool
+SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ bool strict, HandleScript script, jsbytecode* pc);
+
+bool
+SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value,
+ HandleValue receiver, bool strict, HandleScript script, jsbytecode* pc);
+
+bool
+InitElementArray(JSContext* cx, jsbytecode* pc,
+ HandleObject obj, uint32_t index, HandleValue value);
+
+bool
+AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+SubValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+MulValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+DivValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+ModValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+UrshValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res);
+
+bool
+AtomicIsLockFree(JSContext* cx, HandleValue in, int* out);
+
+template <bool strict>
+bool
+DeletePropertyJit(JSContext* ctx, HandleValue val, HandlePropertyName name, bool* bv);
+
+template <bool strict>
+bool
+DeleteElementJit(JSContext* cx, HandleValue val, HandleValue index, bool* bv);
+
+bool
+DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain, HandleFunction funArg);
+
+bool
+ThrowMsgOperation(JSContext* cx, const unsigned errorNum);
+
+bool
+GetAndClearException(JSContext* cx, MutableHandleValue res);
+
+bool
+DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject scopeObj,
+ MutableHandleValue res);
+
+bool
+ImplicitThisOperation(JSContext* cx, HandleObject scopeObj, HandlePropertyName name,
+ MutableHandleValue res);
+
+bool
+RunOnceScriptPrologue(JSContext* cx, HandleScript script);
+
+bool
+InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleId id,
+ HandleObject val);
+
+bool
+InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandlePropertyName name,
+ HandleObject val);
+
+unsigned
+GetInitDataPropAttrs(JSOp op);
+
+bool
+EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val,
+ Handle<WithScope*> scope);
+
+
+bool
+InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval,
+ HandleObject val);
+
+bool
+SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue thisv,
+ HandleValue callee, HandleValue arr, HandleValue newTarget, MutableHandleValue res);
+
+bool
+OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized);
+
+JSObject*
+NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
+ NewObjectKind newKind = GenericObject);
+
+JSObject*
+NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject);
+
+JSObject*
+NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32_t length,
+ NewObjectKind newKind = GenericObject);
+
+JSObject*
+NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject);
+
+void
+ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleId id);
+
+void
+ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandlePropertyName name);
+
+void
+ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleScript script, jsbytecode* pc);
+
+// The parser only reports redeclarations that occurs within a single
+// script. Due to the extensibility of the global lexical scope, we also check
+// for redeclarations during runtime in JSOP_DEF{VAR,LET,CONST}.
+void
+ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, const char* redeclKind);
+
+enum class CheckIsObjectKind : uint8_t {
+ IteratorNext,
+ GetIterator
+};
+
+bool
+ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind);
+
+bool
+ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
+
+bool
+DefaultClassConstructor(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/JSONParser.cpp b/js/src/vm/JSONParser.cpp
new file mode 100644
index 000000000..01883bb15
--- /dev/null
+++ b/js/src/vm/JSONParser.cpp
@@ -0,0 +1,801 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/JSONParser.h"
+
+#include "mozilla/Range.h"
+#include "mozilla/RangedPtr.h"
+#include "mozilla/Sprintf.h"
+
+#include <ctype.h>
+
+#include "jsarray.h"
+#include "jscompartment.h"
+#include "jsnum.h"
+#include "jsprf.h"
+
+#include "vm/StringBuffer.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+using mozilla::RangedPtr;
+
+JSONParserBase::~JSONParserBase()
+{
+ for (size_t i = 0; i < stack.length(); i++) {
+ if (stack[i].state == FinishArrayElement)
+ js_delete(&stack[i].elements());
+ else
+ js_delete(&stack[i].properties());
+ }
+
+ for (size_t i = 0; i < freeElements.length(); i++)
+ js_delete(freeElements[i]);
+
+ for (size_t i = 0; i < freeProperties.length(); i++)
+ js_delete(freeProperties[i]);
+}
+
+void
+JSONParserBase::trace(JSTracer* trc)
+{
+ for (size_t i = 0; i < stack.length(); i++) {
+ if (stack[i].state == FinishArrayElement) {
+ ElementVector& elements = stack[i].elements();
+ for (size_t j = 0; j < elements.length(); j++)
+ TraceRoot(trc, &elements[j], "JSONParser element");
+ } else {
+ PropertyVector& properties = stack[i].properties();
+ for (size_t j = 0; j < properties.length(); j++) {
+ TraceRoot(trc, &properties[j].value, "JSONParser property value");
+ TraceRoot(trc, &properties[j].id, "JSONParser property id");
+ }
+ }
+ }
+}
+
+template <typename CharT>
+void
+JSONParser<CharT>::getTextPosition(uint32_t* column, uint32_t* line)
+{
+ CharPtr ptr = begin;
+ uint32_t col = 1;
+ uint32_t row = 1;
+ for (; ptr < current; ptr++) {
+ if (*ptr == '\n' || *ptr == '\r') {
+ ++row;
+ col = 1;
+ // \r\n is treated as a single newline.
+ if (ptr + 1 < current && *ptr == '\r' && *(ptr + 1) == '\n')
+ ++ptr;
+ } else {
+ ++col;
+ }
+ }
+ *column = col;
+ *line = row;
+}
+
+template <typename CharT>
+void
+JSONParser<CharT>::error(const char* msg)
+{
+ if (errorHandling == RaiseError) {
+ uint32_t column = 1, line = 1;
+ getTextPosition(&column, &line);
+
+ const size_t MaxWidth = sizeof("4294967295");
+ char columnNumber[MaxWidth];
+ SprintfLiteral(columnNumber, "%" PRIu32, column);
+ char lineNumber[MaxWidth];
+ SprintfLiteral(lineNumber, "%" PRIu32, line);
+
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_JSON_BAD_PARSE,
+ msg, lineNumber, columnNumber);
+ }
+}
+
+bool
+JSONParserBase::errorReturn()
+{
+ return errorHandling == NoError;
+}
+
+template <typename CharT>
+template <JSONParserBase::StringType ST>
+JSONParserBase::Token
+JSONParser<CharT>::readString()
+{
+ MOZ_ASSERT(current < end);
+ MOZ_ASSERT(*current == '"');
+
+ /*
+ * JSONString:
+ * /^"([^\u0000-\u001F"\\]|\\(["/\\bfnrt]|u[0-9a-fA-F]{4}))*"$/
+ */
+
+ if (++current == end) {
+ error("unterminated string literal");
+ return token(Error);
+ }
+
+ /*
+ * Optimization: if the source contains no escaped characters, create the
+ * string directly from the source text.
+ */
+ CharPtr start = current;
+ for (; current < end; current++) {
+ if (*current == '"') {
+ size_t length = current - start;
+ current++;
+ JSFlatString* str = (ST == JSONParser::PropertyName)
+ ? AtomizeChars(cx, start.get(), length)
+ : NewStringCopyN<CanGC>(cx, start.get(), length);
+ if (!str)
+ return token(OOM);
+ return stringToken(str);
+ }
+
+ if (*current == '\\')
+ break;
+
+ if (*current <= 0x001F) {
+ error("bad control character in string literal");
+ return token(Error);
+ }
+ }
+
+ /*
+ * Slow case: string contains escaped characters. Copy a maximal sequence
+ * of unescaped characters into a temporary buffer, then an escaped
+ * character, and repeat until the entire string is consumed.
+ */
+ StringBuffer buffer(cx);
+ do {
+ if (start < current && !buffer.append(start.get(), current.get()))
+ return token(OOM);
+
+ if (current >= end)
+ break;
+
+ char16_t c = *current++;
+ if (c == '"') {
+ JSFlatString* str = (ST == JSONParser::PropertyName)
+ ? buffer.finishAtom()
+ : buffer.finishString();
+ if (!str)
+ return token(OOM);
+ return stringToken(str);
+ }
+
+ if (c != '\\') {
+ --current;
+ error("bad character in string literal");
+ return token(Error);
+ }
+
+ if (current >= end)
+ break;
+
+ switch (*current++) {
+ case '"': c = '"'; break;
+ case '/': c = '/'; break;
+ case '\\': c = '\\'; break;
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+
+ case 'u':
+ if (end - current < 4 ||
+ !(JS7_ISHEX(current[0]) &&
+ JS7_ISHEX(current[1]) &&
+ JS7_ISHEX(current[2]) &&
+ JS7_ISHEX(current[3])))
+ {
+ // Point to the first non-hexadecimal character (which may be
+ // missing).
+ if (current == end || !JS7_ISHEX(current[0]))
+ ; // already at correct location
+ else if (current + 1 == end || !JS7_ISHEX(current[1]))
+ current += 1;
+ else if (current + 2 == end || !JS7_ISHEX(current[2]))
+ current += 2;
+ else if (current + 3 == end || !JS7_ISHEX(current[3]))
+ current += 3;
+ else
+ MOZ_CRASH("logic error determining first erroneous character");
+
+ error("bad Unicode escape");
+ return token(Error);
+ }
+ c = (JS7_UNHEX(current[0]) << 12)
+ | (JS7_UNHEX(current[1]) << 8)
+ | (JS7_UNHEX(current[2]) << 4)
+ | (JS7_UNHEX(current[3]));
+ current += 4;
+ break;
+
+ default:
+ current--;
+ error("bad escaped character");
+ return token(Error);
+ }
+ if (!buffer.append(c))
+ return token(OOM);
+
+ start = current;
+ for (; current < end; current++) {
+ if (*current == '"' || *current == '\\' || *current <= 0x001F)
+ break;
+ }
+ } while (current < end);
+
+ error("unterminated string");
+ return token(Error);
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::readNumber()
+{
+ MOZ_ASSERT(current < end);
+ MOZ_ASSERT(JS7_ISDEC(*current) || *current == '-');
+
+ /*
+ * JSONNumber:
+ * /^-?(0|[1-9][0-9]+)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?$/
+ */
+
+ bool negative = *current == '-';
+
+ /* -? */
+ if (negative && ++current == end) {
+ error("no number after minus sign");
+ return token(Error);
+ }
+
+ const CharPtr digitStart = current;
+
+ /* 0|[1-9][0-9]+ */
+ if (!JS7_ISDEC(*current)) {
+ error("unexpected non-digit");
+ return token(Error);
+ }
+ if (*current++ != '0') {
+ for (; current < end; current++) {
+ if (!JS7_ISDEC(*current))
+ break;
+ }
+ }
+
+ /* Fast path: no fractional or exponent part. */
+ if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
+ mozilla::Range<const CharT> chars(digitStart.get(), current - digitStart);
+ if (chars.length() < strlen("9007199254740992")) {
+ // If the decimal number is shorter than the length of 2**53, (the
+ // largest number a double can represent with integral precision),
+ // parse it using a decimal-only parser. This comparison is
+ // conservative but faster than a fully-precise check.
+ double d = ParseDecimalNumber(chars);
+ return numberToken(negative ? -d : d);
+ }
+
+ double d;
+ const CharT* dummy;
+ if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
+ return token(OOM);
+ MOZ_ASSERT(current == dummy);
+ return numberToken(negative ? -d : d);
+ }
+
+ /* (\.[0-9]+)? */
+ if (current < end && *current == '.') {
+ if (++current == end) {
+ error("missing digits after decimal point");
+ return token(Error);
+ }
+ if (!JS7_ISDEC(*current)) {
+ error("unterminated fractional number");
+ return token(Error);
+ }
+ while (++current < end) {
+ if (!JS7_ISDEC(*current))
+ break;
+ }
+ }
+
+ /* ([eE][\+\-]?[0-9]+)? */
+ if (current < end && (*current == 'e' || *current == 'E')) {
+ if (++current == end) {
+ error("missing digits after exponent indicator");
+ return token(Error);
+ }
+ if (*current == '+' || *current == '-') {
+ if (++current == end) {
+ error("missing digits after exponent sign");
+ return token(Error);
+ }
+ }
+ if (!JS7_ISDEC(*current)) {
+ error("exponent part is missing a number");
+ return token(Error);
+ }
+ while (++current < end) {
+ if (!JS7_ISDEC(*current))
+ break;
+ }
+ }
+
+ double d;
+ const CharT* finish;
+ if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d))
+ return token(OOM);
+ MOZ_ASSERT(current == finish);
+ return numberToken(negative ? -d : d);
+}
+
+static inline bool
+IsJSONWhitespace(char16_t c)
+{
+ return c == '\t' || c == '\r' || c == '\n' || c == ' ';
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advance()
+{
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("unexpected end of data");
+ return token(Error);
+ }
+
+ switch (*current) {
+ case '"':
+ return readString<LiteralValue>();
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return readNumber();
+
+ case 't':
+ if (end - current < 4 || current[1] != 'r' || current[2] != 'u' || current[3] != 'e') {
+ error("unexpected keyword");
+ return token(Error);
+ }
+ current += 4;
+ return token(True);
+
+ case 'f':
+ if (end - current < 5 ||
+ current[1] != 'a' || current[2] != 'l' || current[3] != 's' || current[4] != 'e')
+ {
+ error("unexpected keyword");
+ return token(Error);
+ }
+ current += 5;
+ return token(False);
+
+ case 'n':
+ if (end - current < 4 || current[1] != 'u' || current[2] != 'l' || current[3] != 'l') {
+ error("unexpected keyword");
+ return token(Error);
+ }
+ current += 4;
+ return token(Null);
+
+ case '[':
+ current++;
+ return token(ArrayOpen);
+ case ']':
+ current++;
+ return token(ArrayClose);
+
+ case '{':
+ current++;
+ return token(ObjectOpen);
+ case '}':
+ current++;
+ return token(ObjectClose);
+
+ case ',':
+ current++;
+ return token(Comma);
+
+ case ':':
+ current++;
+ return token(Colon);
+
+ default:
+ error("unexpected character");
+ return token(Error);
+ }
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advanceAfterObjectOpen()
+{
+ MOZ_ASSERT(current[-1] == '{');
+
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("end of data while reading object contents");
+ return token(Error);
+ }
+
+ if (*current == '"')
+ return readString<PropertyName>();
+
+ if (*current == '}') {
+ current++;
+ return token(ObjectClose);
+ }
+
+ error("expected property name or '}'");
+ return token(Error);
+}
+
+template <typename CharT>
+static inline void
+AssertPastValue(const RangedPtr<const CharT> current)
+{
+ /*
+ * We're past an arbitrary JSON value, so the previous character is
+ * *somewhat* constrained, even if this assertion is pretty broad. Don't
+ * knock it till you tried it: this assertion *did* catch a bug once.
+ */
+ MOZ_ASSERT((current[-1] == 'l' &&
+ current[-2] == 'l' &&
+ current[-3] == 'u' &&
+ current[-4] == 'n') ||
+ (current[-1] == 'e' &&
+ current[-2] == 'u' &&
+ current[-3] == 'r' &&
+ current[-4] == 't') ||
+ (current[-1] == 'e' &&
+ current[-2] == 's' &&
+ current[-3] == 'l' &&
+ current[-4] == 'a' &&
+ current[-5] == 'f') ||
+ current[-1] == '}' ||
+ current[-1] == ']' ||
+ current[-1] == '"' ||
+ JS7_ISDEC(current[-1]));
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advanceAfterArrayElement()
+{
+ AssertPastValue(current);
+
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("end of data when ',' or ']' was expected");
+ return token(Error);
+ }
+
+ if (*current == ',') {
+ current++;
+ return token(Comma);
+ }
+
+ if (*current == ']') {
+ current++;
+ return token(ArrayClose);
+ }
+
+ error("expected ',' or ']' after array element");
+ return token(Error);
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advancePropertyName()
+{
+ MOZ_ASSERT(current[-1] == ',');
+
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("end of data when property name was expected");
+ return token(Error);
+ }
+
+ if (*current == '"')
+ return readString<PropertyName>();
+
+ error("expected double-quoted property name");
+ return token(Error);
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advancePropertyColon()
+{
+ MOZ_ASSERT(current[-1] == '"');
+
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("end of data after property name when ':' was expected");
+ return token(Error);
+ }
+
+ if (*current == ':') {
+ current++;
+ return token(Colon);
+ }
+
+ error("expected ':' after property name in object");
+ return token(Error);
+}
+
+template <typename CharT>
+JSONParserBase::Token
+JSONParser<CharT>::advanceAfterProperty()
+{
+ AssertPastValue(current);
+
+ while (current < end && IsJSONWhitespace(*current))
+ current++;
+ if (current >= end) {
+ error("end of data after property value in object");
+ return token(Error);
+ }
+
+ if (*current == ',') {
+ current++;
+ return token(Comma);
+ }
+
+ if (*current == '}') {
+ current++;
+ return token(ObjectClose);
+ }
+
+ error("expected ',' or '}' after property value in object");
+ return token(Error);
+}
+
+inline bool
+JSONParserBase::finishObject(MutableHandleValue vp, PropertyVector& properties)
+{
+ MOZ_ASSERT(&properties == &stack.back().properties());
+
+ JSObject* obj = ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(), GenericObject);
+ if (!obj)
+ return false;
+
+ vp.setObject(*obj);
+ if (!freeProperties.append(&properties))
+ return false;
+ stack.popBack();
+
+ if (!stack.empty() && stack.back().state == FinishArrayElement) {
+ const ElementVector& elements = stack.back().elements();
+ if (!CombinePlainObjectPropertyTypes(cx, obj, elements.begin(), elements.length()))
+ return false;
+ }
+
+ return true;
+}
+
+inline bool
+JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements)
+{
+ MOZ_ASSERT(&elements == &stack.back().elements());
+
+ JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(),
+ GenericObject);
+ if (!obj)
+ return false;
+
+ vp.setObject(*obj);
+ if (!freeElements.append(&elements))
+ return false;
+ stack.popBack();
+
+ if (!stack.empty() && stack.back().state == FinishArrayElement) {
+ const ElementVector& elements = stack.back().elements();
+ if (!CombineArrayElementTypes(cx, obj, elements.begin(), elements.length()))
+ return false;
+ }
+
+ return true;
+}
+
+template <typename CharT>
+bool
+JSONParser<CharT>::parse(MutableHandleValue vp)
+{
+ RootedValue value(cx);
+ MOZ_ASSERT(stack.empty());
+
+ vp.setUndefined();
+
+ Token token;
+ ParserState state = JSONValue;
+ while (true) {
+ switch (state) {
+ case FinishObjectMember: {
+ PropertyVector& properties = stack.back().properties();
+ properties.back().value = value;
+
+ token = advanceAfterProperty();
+ if (token == ObjectClose) {
+ if (!finishObject(&value, properties))
+ return false;
+ break;
+ }
+ if (token != Comma) {
+ if (token == OOM)
+ return false;
+ if (token != Error)
+ error("expected ',' or '}' after property-value pair in object literal");
+ return errorReturn();
+ }
+ token = advancePropertyName();
+ /* FALL THROUGH */
+ }
+
+ JSONMember:
+ if (token == String) {
+ jsid id = AtomToId(atomValue());
+ PropertyVector& properties = stack.back().properties();
+ if (!properties.append(IdValuePair(id)))
+ return false;
+ token = advancePropertyColon();
+ if (token != Colon) {
+ MOZ_ASSERT(token == Error);
+ return errorReturn();
+ }
+ goto JSONValue;
+ }
+ if (token == OOM)
+ return false;
+ if (token != Error)
+ error("property names must be double-quoted strings");
+ return errorReturn();
+
+ case FinishArrayElement: {
+ ElementVector& elements = stack.back().elements();
+ if (!elements.append(value.get()))
+ return false;
+ token = advanceAfterArrayElement();
+ if (token == Comma)
+ goto JSONValue;
+ if (token == ArrayClose) {
+ if (!finishArray(&value, elements))
+ return false;
+ break;
+ }
+ MOZ_ASSERT(token == Error);
+ return errorReturn();
+ }
+
+ JSONValue:
+ case JSONValue:
+ token = advance();
+ JSONValueSwitch:
+ switch (token) {
+ case String:
+ value = stringValue();
+ break;
+ case Number:
+ value = numberValue();
+ break;
+ case True:
+ value = BooleanValue(true);
+ break;
+ case False:
+ value = BooleanValue(false);
+ break;
+ case Null:
+ value = NullValue();
+ break;
+
+ case ArrayOpen: {
+ ElementVector* elements;
+ if (!freeElements.empty()) {
+ elements = freeElements.popCopy();
+ elements->clear();
+ } else {
+ elements = cx->new_<ElementVector>(cx);
+ if (!elements)
+ return false;
+ }
+ if (!stack.append(elements))
+ return false;
+
+ token = advance();
+ if (token == ArrayClose) {
+ if (!finishArray(&value, *elements))
+ return false;
+ break;
+ }
+ goto JSONValueSwitch;
+ }
+
+ case ObjectOpen: {
+ PropertyVector* properties;
+ if (!freeProperties.empty()) {
+ properties = freeProperties.popCopy();
+ properties->clear();
+ } else {
+ properties = cx->new_<PropertyVector>(cx);
+ if (!properties)
+ return false;
+ }
+ if (!stack.append(properties))
+ return false;
+
+ token = advanceAfterObjectOpen();
+ if (token == ObjectClose) {
+ if (!finishObject(&value, *properties))
+ return false;
+ break;
+ }
+ goto JSONMember;
+ }
+
+ case ArrayClose:
+ case ObjectClose:
+ case Colon:
+ case Comma:
+ // Move the current pointer backwards so that the position
+ // reported in the error message is correct.
+ --current;
+ error("unexpected character");
+ return errorReturn();
+
+ case OOM:
+ return false;
+
+ case Error:
+ return errorReturn();
+ }
+ break;
+ }
+
+ if (stack.empty())
+ break;
+ state = stack.back().state;
+ }
+
+ for (; current < end; current++) {
+ if (!IsJSONWhitespace(*current)) {
+ error("unexpected non-whitespace character after JSON data");
+ return errorReturn();
+ }
+ }
+
+ MOZ_ASSERT(end == current);
+ MOZ_ASSERT(stack.empty());
+
+ vp.set(value);
+ return true;
+}
+
+template class js::JSONParser<Latin1Char>;
+template class js::JSONParser<char16_t>;
diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h
new file mode 100644
index 000000000..797aaca5f
--- /dev/null
+++ b/js/src/vm/JSONParser.h
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_JSONParser_h
+#define vm_JSONParser_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Range.h"
+
+#include "jspubtd.h"
+
+#include "ds/IdValuePair.h"
+#include "vm/String.h"
+
+namespace js {
+
+// JSONParser base class. JSONParser is templatized to work on either Latin1
+// or TwoByte input strings, JSONParserBase holds all state and methods that
+// can be shared between the two encodings.
+class MOZ_STACK_CLASS JSONParserBase
+{
+ public:
+ enum ErrorHandling { RaiseError, NoError };
+
+ private:
+ /* Data members */
+ Value v;
+
+ protected:
+ JSContext * const cx;
+
+ const ErrorHandling errorHandling;
+
+ enum Token { String, Number, True, False, Null,
+ ArrayOpen, ArrayClose,
+ ObjectOpen, ObjectClose,
+ Colon, Comma,
+ OOM, Error };
+
+ // State related to the parser's current position. At all points in the
+ // parse this keeps track of the stack of arrays and objects which have
+ // been started but not finished yet. The actual JS object is not
+ // allocated until the literal is closed, so that the result can be sized
+ // according to its contents and have its type and shape filled in using
+ // caches.
+
+ // State for an array that is currently being parsed. This includes all
+ // elements that have been seen so far.
+ typedef Vector<Value, 20> ElementVector;
+
+ // State for an object that is currently being parsed. This includes all
+ // the key/value pairs that have been seen so far.
+ typedef Vector<IdValuePair, 10> PropertyVector;
+
+ // Possible states the parser can be in between values.
+ enum ParserState {
+ // An array element has just being parsed.
+ FinishArrayElement,
+
+ // An object property has just been parsed.
+ FinishObjectMember,
+
+ // At the start of the parse, before any values have been processed.
+ JSONValue
+ };
+
+ // Stack element for an in progress array or object.
+ struct StackEntry {
+ ElementVector& elements() {
+ MOZ_ASSERT(state == FinishArrayElement);
+ return * static_cast<ElementVector*>(vector);
+ }
+
+ PropertyVector& properties() {
+ MOZ_ASSERT(state == FinishObjectMember);
+ return * static_cast<PropertyVector*>(vector);
+ }
+
+ explicit StackEntry(ElementVector* elements)
+ : state(FinishArrayElement), vector(elements)
+ {}
+
+ explicit StackEntry(PropertyVector* properties)
+ : state(FinishObjectMember), vector(properties)
+ {}
+
+ ParserState state;
+
+ private:
+ void* vector;
+ };
+
+ // All in progress arrays and objects being parsed, in order from outermost
+ // to innermost.
+ Vector<StackEntry, 10> stack;
+
+ // Unused element and property vectors for previous in progress arrays and
+ // objects. These vectors are not freed until the end of the parse to avoid
+ // unnecessary freeing and allocation.
+ Vector<ElementVector*, 5> freeElements;
+ Vector<PropertyVector*, 5> freeProperties;
+
+#ifdef DEBUG
+ Token lastToken;
+#endif
+
+ JSONParserBase(JSContext* cx, ErrorHandling errorHandling)
+ : cx(cx),
+ errorHandling(errorHandling),
+ stack(cx),
+ freeElements(cx),
+ freeProperties(cx)
+#ifdef DEBUG
+ , lastToken(Error)
+#endif
+ {}
+ ~JSONParserBase();
+
+ // Allow move construction for use with Rooted.
+ JSONParserBase(JSONParserBase&& other)
+ : v(other.v),
+ cx(other.cx),
+ errorHandling(other.errorHandling),
+ stack(mozilla::Move(other.stack)),
+ freeElements(mozilla::Move(other.freeElements)),
+ freeProperties(mozilla::Move(other.freeProperties))
+#ifdef DEBUG
+ , lastToken(mozilla::Move(other.lastToken))
+#endif
+ {}
+
+
+ Value numberValue() const {
+ MOZ_ASSERT(lastToken == Number);
+ MOZ_ASSERT(v.isNumber());
+ return v;
+ }
+
+ Value stringValue() const {
+ MOZ_ASSERT(lastToken == String);
+ MOZ_ASSERT(v.isString());
+ return v;
+ }
+
+ JSAtom* atomValue() const {
+ Value strval = stringValue();
+ return &strval.toString()->asAtom();
+ }
+
+ Token token(Token t) {
+ MOZ_ASSERT(t != String);
+ MOZ_ASSERT(t != Number);
+#ifdef DEBUG
+ lastToken = t;
+#endif
+ return t;
+ }
+
+ Token stringToken(JSString* str) {
+ this->v = StringValue(str);
+#ifdef DEBUG
+ lastToken = String;
+#endif
+ return String;
+ }
+
+ Token numberToken(double d) {
+ this->v = NumberValue(d);
+#ifdef DEBUG
+ lastToken = Number;
+#endif
+ return Number;
+ }
+
+ enum StringType { PropertyName, LiteralValue };
+
+ bool errorReturn();
+
+ bool finishObject(MutableHandleValue vp, PropertyVector& properties);
+ bool finishArray(MutableHandleValue vp, ElementVector& elements);
+
+ void trace(JSTracer* trc);
+
+ private:
+ JSONParserBase(const JSONParserBase& other) = delete;
+ void operator=(const JSONParserBase& other) = delete;
+};
+
+template <typename CharT>
+class MOZ_STACK_CLASS JSONParser : public JSONParserBase
+{
+ private:
+ typedef mozilla::RangedPtr<const CharT> CharPtr;
+
+ CharPtr current;
+ const CharPtr begin, end;
+
+ public:
+ /* Public API */
+
+ /* Create a parser for the provided JSON data. */
+ JSONParser(JSContext* cx, mozilla::Range<const CharT> data,
+ ErrorHandling errorHandling = RaiseError)
+ : JSONParserBase(cx, errorHandling),
+ current(data.begin()),
+ begin(current),
+ end(data.end())
+ {
+ MOZ_ASSERT(current <= end);
+ }
+
+ /* Allow move construction for use with Rooted. */
+ JSONParser(JSONParser&& other)
+ : JSONParserBase(mozilla::Move(other)),
+ current(other.current),
+ begin(other.begin),
+ end(other.end)
+ {}
+
+ /*
+ * Parse the JSON data specified at construction time. If it parses
+ * successfully, store the prescribed value in *vp and return true. If an
+ * internal error (e.g. OOM) occurs during parsing, return false.
+ * Otherwise, if invalid input was specifed but no internal error occurred,
+ * behavior depends upon the error handling specified at construction: if
+ * error handling is RaiseError then throw a SyntaxError and return false,
+ * otherwise return true and set *vp to |undefined|. (JSON syntax can't
+ * represent |undefined|, so the JSON data couldn't have specified it.)
+ */
+ bool parse(MutableHandleValue vp);
+
+ static void trace(JSONParser<CharT>* parser, JSTracer* trc) { parser->trace(trc); }
+ void trace(JSTracer* trc) { JSONParserBase::trace(trc); }
+
+ private:
+ template<StringType ST> Token readString();
+
+ Token readNumber();
+
+ Token advance();
+ Token advancePropertyName();
+ Token advancePropertyColon();
+ Token advanceAfterProperty();
+ Token advanceAfterObjectOpen();
+ Token advanceAfterArrayElement();
+
+ void error(const char* msg);
+
+ void getTextPosition(uint32_t* column, uint32_t* line);
+
+ private:
+ JSONParser(const JSONParser& other) = delete;
+ void operator=(const JSONParser& other) = delete;
+};
+
+template <typename CharT>
+struct RootedBase<JSONParser<CharT>> {
+ bool parse(MutableHandleValue vp) {
+ return static_cast<Rooted<JSONParser<CharT>>*>(this)->get().parse(vp);
+ }
+};
+
+} /* namespace js */
+
+#endif /* vm_JSONParser_h */
diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h
new file mode 100644
index 000000000..ef37c4419
--- /dev/null
+++ b/js/src/vm/Keywords.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A higher-order macro for enumerating keyword tokens. */
+
+#ifndef vm_Keywords_h
+#define vm_Keywords_h
+
+#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \
+ macro(false, false_, TOK_FALSE) \
+ macro(true, true_, TOK_TRUE) \
+ macro(null, null, TOK_NULL) \
+ /* Keywords. */ \
+ macro(break, break_, TOK_BREAK) \
+ macro(case, case_, TOK_CASE) \
+ macro(catch, catch_, TOK_CATCH) \
+ macro(const, const_, TOK_CONST) \
+ macro(continue, continue_, TOK_CONTINUE) \
+ macro(debugger, debugger, TOK_DEBUGGER) \
+ macro(default, default_, TOK_DEFAULT) \
+ macro(delete, delete_, TOK_DELETE) \
+ macro(do, do_, TOK_DO) \
+ macro(else, else_, TOK_ELSE) \
+ macro(finally, finally_, TOK_FINALLY) \
+ macro(for, for_, TOK_FOR) \
+ macro(function, function, TOK_FUNCTION) \
+ macro(if, if_, TOK_IF) \
+ macro(in, in, TOK_IN) \
+ macro(instanceof, instanceof, TOK_INSTANCEOF) \
+ macro(new, new_, TOK_NEW) \
+ macro(return, return_, TOK_RETURN) \
+ macro(switch, switch_, TOK_SWITCH) \
+ macro(this, this_, TOK_THIS) \
+ macro(throw, throw_, TOK_THROW) \
+ macro(try, try_, TOK_TRY) \
+ macro(typeof, typeof, TOK_TYPEOF) \
+ macro(var, var, TOK_VAR) \
+ macro(void, void_, TOK_VOID) \
+ macro(while, while_, TOK_WHILE) \
+ macro(with, with, TOK_WITH) \
+ macro(import, import, TOK_IMPORT) \
+ macro(export, export, TOK_EXPORT) \
+ macro(class, class_, TOK_CLASS) \
+ macro(extends, extends, TOK_EXTENDS) \
+ macro(super, super, TOK_SUPER) \
+ /* Reserved keywords. */ \
+ macro(enum, enum_, TOK_RESERVED) \
+ /* Future reserved keywords, but only in strict mode. */ \
+ macro(implements, implements, TOK_STRICT_RESERVED) \
+ macro(interface, interface, TOK_STRICT_RESERVED) \
+ macro(package, package, TOK_STRICT_RESERVED) \
+ macro(private, private_, TOK_STRICT_RESERVED) \
+ macro(protected, protected_, TOK_STRICT_RESERVED) \
+ macro(public, public_, TOK_STRICT_RESERVED) \
+ macro(await, await, TOK_AWAIT) \
+ /* \
+ * Yield is a token inside function*. Outside of a function*, it is a \
+ * future reserved keyword in strict mode, but a keyword in JS1.7 even \
+ * when strict. Punt logic to parser. \
+ */ \
+ macro(yield, yield, TOK_YIELD)
+
+#endif /* vm_Keywords_h */
diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h
new file mode 100644
index 000000000..0fd40d0cd
--- /dev/null
+++ b/js/src/vm/MallocProvider.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Hierarchy of SpiderMonkey system memory allocators:
+ *
+ * - System {m,c,re}alloc/new/free: Overridden by jemalloc in most
+ * environments. Do not use these functions directly.
+ *
+ * - js_{m,c,re}alloc/new/free: Wraps the system allocators and adds a
+ * failure injection framework for use by the fuzzers as well as templated,
+ * typesafe variants. See js/public/Utility.h.
+ *
+ * - AllocPolicy: An interface for the js allocators, for use with templates.
+ * These allocators are for system memory whose lifetime is not associated
+ * with a GC thing. See js/src/jsalloc.h.
+ *
+ * - SystemAllocPolicy: No extra functionality over bare allocators.
+ *
+ * - TempAllocPolicy: Adds automatic error reporting to the provided
+ * JSContext when allocations fail.
+ *
+ * - RuntimeAllocPolicy: Forwards to the JSRuntime MallocProvider.
+ *
+ * - ZoneAllocPolicy: Forwards to the Zone MallocProvider.
+ *
+ * - MallocProvider. A mixin base class that handles automatically updating
+ * the GC's state in response to allocations that are tied to a GC lifetime
+ * or are for a particular GC purpose. These allocators must only be used
+ * for memory that will be freed when a GC thing is swept.
+ *
+ * - gc::Zone: Automatically triggers zone GC.
+ * - JSRuntime: Automatically triggers full GC.
+ * - ThreadsafeContext > ExclusiveContext > JSContext:
+ * Dispatches directly to the runtime.
+ */
+
+#ifndef vm_MallocProvider_h
+#define vm_MallocProvider_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Likely.h"
+
+#include "js/UniquePtr.h"
+#include "js/Utility.h"
+
+namespace js {
+
+template<class Client>
+struct MallocProvider
+{
+ template <class T>
+ T* maybe_pod_malloc(size_t numElems) {
+ T* p = js_pod_malloc<T>(numElems);
+ if (MOZ_LIKELY(p))
+ client()->updateMallocCounter(numElems * sizeof(T));
+ return p;
+ }
+
+ template <class T>
+ T* maybe_pod_calloc(size_t numElems) {
+ T* p = js_pod_calloc<T>(numElems);
+ if (MOZ_LIKELY(p))
+ client()->updateMallocCounter(numElems * sizeof(T));
+ return p;
+ }
+
+ template <class T>
+ T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
+ T* p = js_pod_realloc(prior, oldSize, newSize);
+ if (MOZ_LIKELY(p)) {
+ // For compatibility we do not account for realloc that decreases
+ // previously allocated memory.
+ if (newSize > oldSize)
+ client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
+ }
+ return p;
+ }
+
+ template <class T>
+ T* pod_malloc() {
+ return pod_malloc<T>(1);
+ }
+
+ template <class T>
+ T* pod_malloc(size_t numElems) {
+ T* p = maybe_pod_malloc<T>(numElems);
+ if (MOZ_LIKELY(p))
+ return p;
+ size_t bytes;
+ if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
+ client()->reportAllocationOverflow();
+ return nullptr;
+ }
+ p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes);
+ if (p)
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+
+ template <class T, class U>
+ T* pod_malloc_with_extra(size_t numExtra) {
+ size_t bytes;
+ if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
+ client()->reportAllocationOverflow();
+ return nullptr;
+ }
+ T* p = static_cast<T*>(js_malloc(bytes));
+ if (MOZ_LIKELY(p)) {
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+ p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes);
+ if (p)
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+
+ template <class T>
+ UniquePtr<T[], JS::FreePolicy>
+ make_pod_array(size_t numElems) {
+ return UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems));
+ }
+
+ template <class T>
+ T* pod_calloc() {
+ return pod_calloc<T>(1);
+ }
+
+ template <class T>
+ T* pod_calloc(size_t numElems) {
+ T* p = maybe_pod_calloc<T>(numElems);
+ if (MOZ_LIKELY(p))
+ return p;
+ size_t bytes;
+ if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
+ client()->reportAllocationOverflow();
+ return nullptr;
+ }
+ p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
+ if (p)
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+
+ template <class T, class U>
+ T* pod_calloc_with_extra(size_t numExtra) {
+ size_t bytes;
+ if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
+ client()->reportAllocationOverflow();
+ return nullptr;
+ }
+ T* p = static_cast<T*>(js_calloc(bytes));
+ if (p) {
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+ p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
+ if (p)
+ client()->updateMallocCounter(bytes);
+ return p;
+ }
+
+ template <class T>
+ UniquePtr<T[], JS::FreePolicy>
+ make_zeroed_pod_array(size_t numElems)
+ {
+ return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
+ }
+
+ template <class T>
+ T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
+ T* p = maybe_pod_realloc(prior, oldSize, newSize);
+ if (MOZ_LIKELY(p))
+ return p;
+ size_t bytes;
+ if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) {
+ client()->reportAllocationOverflow();
+ return nullptr;
+ }
+ p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior);
+ if (p && newSize > oldSize)
+ client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
+ return p;
+ }
+
+ JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
+ JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
+
+ private:
+ Client* client() { return static_cast<Client*>(this); }
+};
+
+} /* namespace js */
+
+#endif /* vm_MallocProvider_h */
diff --git a/js/src/vm/MatchPairs.h b/js/src/vm/MatchPairs.h
new file mode 100644
index 000000000..14dee5c66
--- /dev/null
+++ b/js/src/vm/MatchPairs.h
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_MatchPairs_h
+#define vm_MatchPairs_h
+
+#include "jsalloc.h"
+
+#include "ds/LifoAlloc.h"
+#include "js/Vector.h"
+
+/*
+ * RegExp match results are succinctly represented by pairs of integer
+ * indices delimiting (start, limit] segments of the input string.
+ *
+ * The pair count for a given RegExp match is the capturing parentheses
+ * count plus one for the "0 capturing paren" whole text match.
+ */
+
+namespace js {
+
+struct MatchPair
+{
+ int32_t start;
+ int32_t limit;
+
+ MatchPair()
+ : start(-1), limit(-1)
+ { }
+
+ MatchPair(int32_t start, int32_t limit)
+ : start(start), limit(limit)
+ { }
+
+ size_t length() const { MOZ_ASSERT(!isUndefined()); return limit - start; }
+ bool isEmpty() const { return length() == 0; }
+ bool isUndefined() const { return start < 0; }
+
+ void displace(size_t amount) {
+ start += (start < 0) ? 0 : amount;
+ limit += (limit < 0) ? 0 : amount;
+ }
+
+ inline bool check() const {
+ MOZ_ASSERT(limit >= start);
+ MOZ_ASSERT_IF(start < 0, start == -1);
+ MOZ_ASSERT_IF(limit < 0, limit == -1);
+ return true;
+ }
+};
+
+/* Base class for RegExp execution output. */
+class MatchPairs
+{
+ protected:
+ /* Length of pairs_. */
+ uint32_t pairCount_;
+
+ /* Raw pointer into an allocated MatchPair buffer. */
+ MatchPair* pairs_;
+
+ protected:
+ /* Not used directly: use ScopedMatchPairs or VectorMatchPairs. */
+ MatchPairs()
+ : pairCount_(0), pairs_(nullptr)
+ { }
+
+ protected:
+ /* Functions used by friend classes. */
+ friend class RegExpShared;
+ friend class RegExpStatics;
+
+ /* MatchPair buffer allocator: set pairs_ and pairCount_. */
+ virtual bool allocOrExpandArray(size_t pairCount) = 0;
+
+ bool initArrayFrom(MatchPairs& copyFrom);
+ void forgetArray() { pairs_ = nullptr; }
+
+ void checkAgainst(size_t inputLength) {
+#ifdef DEBUG
+ for (size_t i = 0; i < pairCount_; i++) {
+ const MatchPair& p = (*this)[i];
+ MOZ_ASSERT(p.check());
+ if (p.isUndefined())
+ continue;
+ MOZ_ASSERT(size_t(p.limit) <= inputLength);
+ }
+#endif
+ }
+
+ public:
+ /* Querying functions in the style of RegExpStatics. */
+ bool empty() const { return pairCount_ == 0; }
+ size_t pairCount() const { MOZ_ASSERT(pairCount_ > 0); return pairCount_; }
+ size_t parenCount() const { return pairCount_ - 1; }
+
+ static size_t offsetOfPairs() { return offsetof(MatchPairs, pairs_); }
+ static size_t offsetOfPairCount() { return offsetof(MatchPairs, pairCount_); }
+
+ int32_t* pairsRaw() { return reinterpret_cast<int32_t*>(pairs_); }
+
+ public:
+ size_t length() const { return pairCount_; }
+
+ const MatchPair& operator[](size_t i) const {
+ MOZ_ASSERT(i < pairCount_);
+ return pairs_[i];
+ }
+ MatchPair& operator[](size_t i) {
+ MOZ_ASSERT(i < pairCount_);
+ return pairs_[i];
+ }
+};
+
+/* MatchPairs allocated into temporary storage, removed when out of scope. */
+class ScopedMatchPairs : public MatchPairs
+{
+ LifoAllocScope lifoScope_;
+
+ public:
+ /* Constructs an implicit LifoAllocScope. */
+ explicit ScopedMatchPairs(LifoAlloc* lifoAlloc)
+ : lifoScope_(lifoAlloc)
+ { }
+
+ protected:
+ bool allocOrExpandArray(size_t pairCount);
+};
+
+/*
+ * MatchPairs allocated into permanent storage, for RegExpStatics.
+ * The Vector of MatchPairs is reusable by Vector expansion.
+ */
+class VectorMatchPairs : public MatchPairs
+{
+ Vector<MatchPair, 10, SystemAllocPolicy> vec_;
+
+ public:
+ VectorMatchPairs() {
+ vec_.clear();
+ }
+
+ protected:
+ friend class RegExpStatics;
+ bool allocOrExpandArray(size_t pairCount);
+};
+
+} /* namespace js */
+
+#endif /* vm_MatchPairs_h */
diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp
new file mode 100644
index 000000000..1012e808e
--- /dev/null
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -0,0 +1,959 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/MemoryMetrics.h"
+
+#include "mozilla/DebugOnly.h"
+
+#include "jsapi.h"
+#include "jscompartment.h"
+#include "jsgc.h"
+#include "jsobj.h"
+#include "jsscript.h"
+
+#include "gc/Heap.h"
+#include "jit/BaselineJIT.h"
+#include "jit/Ion.h"
+#include "vm/ArrayObject.h"
+#include "vm/Runtime.h"
+#include "vm/Shape.h"
+#include "vm/String.h"
+#include "vm/Symbol.h"
+#include "vm/WrapperObject.h"
+#include "wasm/WasmInstance.h"
+#include "wasm/WasmJS.h"
+#include "wasm/WasmModule.h"
+
+using mozilla::DebugOnly;
+using mozilla::MallocSizeOf;
+using mozilla::Move;
+using mozilla::PodCopy;
+using mozilla::PodEqual;
+
+using namespace js;
+
+using JS::RuntimeStats;
+using JS::ObjectPrivateVisitor;
+using JS::ZoneStats;
+using JS::CompartmentStats;
+
+namespace js {
+
+JS_FRIEND_API(size_t)
+MemoryReportingSundriesThreshold()
+{
+ return 8 * 1024;
+}
+
+template <typename CharT>
+static uint32_t
+HashStringChars(JSString* s)
+{
+ ScopedJSFreePtr<CharT> ownedChars;
+ const CharT* chars;
+ JS::AutoCheckCannotGC nogc;
+ if (s->isLinear()) {
+ chars = s->asLinear().chars<CharT>(nogc);
+ } else {
+ // Slowest hash function evar!
+ if (!s->asRope().copyChars<CharT>(/* tcx */ nullptr, ownedChars))
+ MOZ_CRASH("oom");
+ chars = ownedChars;
+ }
+
+ return mozilla::HashString(chars, s->length());
+}
+
+/* static */ HashNumber
+InefficientNonFlatteningStringHashPolicy::hash(const Lookup& l)
+{
+ return l->hasLatin1Chars()
+ ? HashStringChars<Latin1Char>(l)
+ : HashStringChars<char16_t>(l);
+}
+
+template <typename Char1, typename Char2>
+static bool
+EqualStringsPure(JSString* s1, JSString* s2)
+{
+ if (s1->length() != s2->length())
+ return false;
+
+ const Char1* c1;
+ ScopedJSFreePtr<Char1> ownedChars1;
+ JS::AutoCheckCannotGC nogc;
+ if (s1->isLinear()) {
+ c1 = s1->asLinear().chars<Char1>(nogc);
+ } else {
+ if (!s1->asRope().copyChars<Char1>(/* tcx */ nullptr, ownedChars1))
+ MOZ_CRASH("oom");
+ c1 = ownedChars1;
+ }
+
+ const Char2* c2;
+ ScopedJSFreePtr<Char2> ownedChars2;
+ if (s2->isLinear()) {
+ c2 = s2->asLinear().chars<Char2>(nogc);
+ } else {
+ if (!s2->asRope().copyChars<Char2>(/* tcx */ nullptr, ownedChars2))
+ MOZ_CRASH("oom");
+ c2 = ownedChars2;
+ }
+
+ return EqualChars(c1, c2, s1->length());
+}
+
+/* static */ bool
+InefficientNonFlatteningStringHashPolicy::match(const JSString* const& k, const Lookup& l)
+{
+ // We can't use js::EqualStrings, because that flattens our strings.
+ JSString* s1 = const_cast<JSString*>(k);
+ if (k->hasLatin1Chars()) {
+ return l->hasLatin1Chars()
+ ? EqualStringsPure<Latin1Char, Latin1Char>(s1, l)
+ : EqualStringsPure<Latin1Char, char16_t>(s1, l);
+ }
+
+ return l->hasLatin1Chars()
+ ? EqualStringsPure<char16_t, Latin1Char>(s1, l)
+ : EqualStringsPure<char16_t, char16_t>(s1, l);
+}
+
+/* static */ HashNumber
+CStringHashPolicy::hash(const Lookup& l)
+{
+ return mozilla::HashString(l);
+}
+
+/* static */ bool
+CStringHashPolicy::match(const char* const& k, const Lookup& l)
+{
+ return strcmp(k, l) == 0;
+}
+
+} // namespace js
+
+namespace JS {
+
+NotableStringInfo::NotableStringInfo()
+ : StringInfo(),
+ buffer(0),
+ length(0)
+{
+}
+
+template <typename CharT>
+static void
+StoreStringChars(char* buffer, size_t bufferSize, JSString* str)
+{
+ const CharT* chars;
+ ScopedJSFreePtr<CharT> ownedChars;
+ JS::AutoCheckCannotGC nogc;
+ if (str->isLinear()) {
+ chars = str->asLinear().chars<CharT>(nogc);
+ } else {
+ if (!str->asRope().copyChars<CharT>(/* tcx */ nullptr, ownedChars))
+ MOZ_CRASH("oom");
+ chars = ownedChars;
+ }
+
+ // We might truncate |str| even if it's much shorter than 1024 chars, if
+ // |str| contains unicode chars. Since this is just for a memory reporter,
+ // we don't care.
+ PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0);
+}
+
+NotableStringInfo::NotableStringInfo(JSString* str, const StringInfo& info)
+ : StringInfo(info),
+ length(str->length())
+{
+ size_t bufferSize = Min(str->length() + 1, size_t(MAX_SAVED_CHARS));
+ buffer = js_pod_malloc<char>(bufferSize);
+ if (!buffer) {
+ MOZ_CRASH("oom");
+ }
+
+ if (str->hasLatin1Chars())
+ StoreStringChars<Latin1Char>(buffer, bufferSize, str);
+ else
+ StoreStringChars<char16_t>(buffer, bufferSize, str);
+}
+
+NotableStringInfo::NotableStringInfo(NotableStringInfo&& info)
+ : StringInfo(Move(info)),
+ length(info.length)
+{
+ buffer = info.buffer;
+ info.buffer = nullptr;
+}
+
+NotableStringInfo& NotableStringInfo::operator=(NotableStringInfo&& info)
+{
+ MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
+ this->~NotableStringInfo();
+ new (this) NotableStringInfo(Move(info));
+ return *this;
+}
+
+NotableClassInfo::NotableClassInfo()
+ : ClassInfo(),
+ className_(nullptr)
+{
+}
+
+NotableClassInfo::NotableClassInfo(const char* className, const ClassInfo& info)
+ : ClassInfo(info)
+{
+ size_t bytes = strlen(className) + 1;
+ className_ = js_pod_malloc<char>(bytes);
+ if (!className_)
+ MOZ_CRASH("oom");
+ PodCopy(className_, className, bytes);
+}
+
+NotableClassInfo::NotableClassInfo(NotableClassInfo&& info)
+ : ClassInfo(Move(info))
+{
+ className_ = info.className_;
+ info.className_ = nullptr;
+}
+
+NotableClassInfo& NotableClassInfo::operator=(NotableClassInfo&& info)
+{
+ MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
+ this->~NotableClassInfo();
+ new (this) NotableClassInfo(Move(info));
+ return *this;
+}
+
+NotableScriptSourceInfo::NotableScriptSourceInfo()
+ : ScriptSourceInfo(),
+ filename_(nullptr)
+{
+}
+
+NotableScriptSourceInfo::NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info)
+ : ScriptSourceInfo(info)
+{
+ size_t bytes = strlen(filename) + 1;
+ filename_ = js_pod_malloc<char>(bytes);
+ if (!filename_)
+ MOZ_CRASH("oom");
+ PodCopy(filename_, filename, bytes);
+}
+
+NotableScriptSourceInfo::NotableScriptSourceInfo(NotableScriptSourceInfo&& info)
+ : ScriptSourceInfo(Move(info))
+{
+ filename_ = info.filename_;
+ info.filename_ = nullptr;
+}
+
+NotableScriptSourceInfo& NotableScriptSourceInfo::operator=(NotableScriptSourceInfo&& info)
+{
+ MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
+ this->~NotableScriptSourceInfo();
+ new (this) NotableScriptSourceInfo(Move(info));
+ return *this;
+}
+
+
+} // namespace JS
+
+typedef HashSet<ScriptSource*, DefaultHasher<ScriptSource*>, SystemAllocPolicy> SourceSet;
+
+struct StatsClosure
+{
+ RuntimeStats* rtStats;
+ ObjectPrivateVisitor* opv;
+ SourceSet seenSources;
+ wasm::Metadata::SeenSet wasmSeenMetadata;
+ wasm::ShareableBytes::SeenSet wasmSeenBytes;
+ wasm::Table::SeenSet wasmSeenTables;
+ bool anonymize;
+
+ StatsClosure(RuntimeStats* rt, ObjectPrivateVisitor* v, bool anon)
+ : rtStats(rt),
+ opv(v),
+ anonymize(anon)
+ {}
+
+ bool init() {
+ return seenSources.init() &&
+ wasmSeenMetadata.init() &&
+ wasmSeenBytes.init() &&
+ wasmSeenTables.init();
+ }
+};
+
+static void
+DecommittedArenasChunkCallback(JSRuntime* rt, void* data, gc::Chunk* chunk)
+{
+ // This case is common and fast to check. Do it first.
+ if (chunk->decommittedArenas.isAllClear())
+ return;
+
+ size_t n = 0;
+ for (size_t i = 0; i < gc::ArenasPerChunk; i++) {
+ if (chunk->decommittedArenas.get(i))
+ n += gc::ArenaSize;
+ }
+ MOZ_ASSERT(n > 0);
+ *static_cast<size_t*>(data) += n;
+}
+
+static void
+StatsZoneCallback(JSRuntime* rt, void* data, Zone* zone)
+{
+ // Append a new CompartmentStats to the vector.
+ RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
+
+ // CollectRuntimeStats reserves enough space.
+ MOZ_ALWAYS_TRUE(rtStats->zoneStatsVector.growBy(1));
+ ZoneStats& zStats = rtStats->zoneStatsVector.back();
+ if (!zStats.initStrings(rt))
+ MOZ_CRASH("oom");
+ rtStats->initExtraZoneStats(zone, &zStats);
+ rtStats->currZoneStats = &zStats;
+
+ zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
+ &zStats.typePool,
+ &zStats.baselineStubsOptimized,
+ &zStats.uniqueIdMap,
+ &zStats.shapeTables);
+}
+
+static void
+StatsCompartmentCallback(JSContext* cx, void* data, JSCompartment* compartment)
+{
+ // Append a new CompartmentStats to the vector.
+ RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
+
+ // CollectRuntimeStats reserves enough space.
+ MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
+ CompartmentStats& cStats = rtStats->compartmentStatsVector.back();
+ if (!cStats.initClasses(cx))
+ MOZ_CRASH("oom");
+ rtStats->initExtraCompartmentStats(compartment, &cStats);
+
+ compartment->setCompartmentStats(&cStats);
+
+ // Measure the compartment object itself, and things hanging off it.
+ compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
+ &cStats.typeInferenceAllocationSiteTables,
+ &cStats.typeInferenceArrayTypeTables,
+ &cStats.typeInferenceObjectTypeTables,
+ &cStats.compartmentObject,
+ &cStats.compartmentTables,
+ &cStats.innerViewsTable,
+ &cStats.lazyArrayBuffersTable,
+ &cStats.objectMetadataTable,
+ &cStats.crossCompartmentWrappersTable,
+ &cStats.regexpCompartment,
+ &cStats.savedStacksSet,
+ &cStats.varNamesSet,
+ &cStats.nonSyntacticLexicalScopesTable,
+ &cStats.jitCompartment,
+ &cStats.privateData);
+}
+
+static void
+StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena,
+ JS::TraceKind traceKind, size_t thingSize)
+{
+ RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
+
+ // The admin space includes (a) the header fields and (b) the padding
+ // between the end of the header fields and the first GC thing.
+ size_t allocationSpace = gc::Arena::thingsSpan(arena->getAllocKind());
+ rtStats->currZoneStats->gcHeapArenaAdmin += gc::ArenaSize - allocationSpace;
+
+ // We don't call the callback on unused things. So we compute the
+ // unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
+ // We do this by setting arenaUnused to maxArenaUnused here, and then
+ // subtracting thingSize for every used cell, in StatsCellCallback().
+ rtStats->currZoneStats->unusedGCThings.addToKind(traceKind, allocationSpace);
+}
+
+// FineGrained is used for normal memory reporting. CoarseGrained is used by
+// AddSizeOfTab(), which aggregates all the measurements into a handful of
+// high-level numbers, which means that fine-grained reporting would be a waste
+// of effort.
+enum Granularity {
+ FineGrained,
+ CoarseGrained
+};
+
+static void
+AddClassInfo(Granularity granularity, CompartmentStats& cStats, const char* className,
+ JS::ClassInfo& info)
+{
+ if (granularity == FineGrained) {
+ if (!className)
+ className = "<no class name>";
+ CompartmentStats::ClassesHashMap::AddPtr p = cStats.allClasses->lookupForAdd(className);
+ if (!p) {
+ bool ok = cStats.allClasses->add(p, className, info);
+ // Ignore failure -- we just won't record the
+ // object/shape/base-shape as notable.
+ (void)ok;
+ } else {
+ p->value().add(info);
+ }
+ }
+}
+
+template <Granularity granularity>
+static void
+CollectScriptSourceStats(StatsClosure* closure, ScriptSource* ss)
+{
+ RuntimeStats* rtStats = closure->rtStats;
+
+ SourceSet::AddPtr entry = closure->seenSources.lookupForAdd(ss);
+ if (entry)
+ return;
+
+ bool ok = closure->seenSources.add(entry, ss);
+ (void)ok; // Not much to be done on failure.
+
+ JS::ScriptSourceInfo info; // This zeroes all the sizes.
+ ss->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &info);
+
+ rtStats->runtime.scriptSourceInfo.add(info);
+
+ if (granularity == FineGrained) {
+ const char* filename = ss->filename();
+ if (!filename)
+ filename = "<no filename>";
+
+ JS::RuntimeSizes::ScriptSourcesHashMap::AddPtr p =
+ rtStats->runtime.allScriptSources->lookupForAdd(filename);
+ if (!p) {
+ bool ok = rtStats->runtime.allScriptSources->add(p, filename, info);
+ // Ignore failure -- we just won't record the script source as notable.
+ (void)ok;
+ } else {
+ p->value().add(info);
+ }
+ }
+}
+
+
+// The various kinds of hashing are expensive, and the results are unused when
+// doing coarse-grained measurements. Skipping them more than doubles the
+// profile speed for complex pages such as gmail.com.
+template <Granularity granularity>
+static void
+StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKind,
+ size_t thingSize)
+{
+ StatsClosure* closure = static_cast<StatsClosure*>(data);
+ RuntimeStats* rtStats = closure->rtStats;
+ ZoneStats* zStats = rtStats->currZoneStats;
+ switch (traceKind) {
+ case JS::TraceKind::Object: {
+ JSObject* obj = static_cast<JSObject*>(thing);
+ CompartmentStats& cStats = obj->compartment()->compartmentStats();
+ JS::ClassInfo info; // This zeroes all the sizes.
+ info.objectsGCHeap += thingSize;
+
+ obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info);
+
+ // These classes require special handling due to shared resources which
+ // we must be careful not to report twice.
+ if (obj->is<WasmModuleObject>()) {
+ wasm::Module& module = obj->as<WasmModuleObject>().module();
+ if (ScriptSource* ss = module.metadata().maybeScriptSource())
+ CollectScriptSourceStats<granularity>(closure, ss);
+ module.addSizeOfMisc(rtStats->mallocSizeOf_,
+ &closure->wasmSeenMetadata,
+ &closure->wasmSeenBytes,
+ &info.objectsNonHeapCodeWasm,
+ &info.objectsMallocHeapMisc);
+ } else if (obj->is<WasmInstanceObject>()) {
+ wasm::Instance& instance = obj->as<WasmInstanceObject>().instance();
+ if (ScriptSource* ss = instance.metadata().maybeScriptSource())
+ CollectScriptSourceStats<granularity>(closure, ss);
+ instance.addSizeOfMisc(rtStats->mallocSizeOf_,
+ &closure->wasmSeenMetadata,
+ &closure->wasmSeenBytes,
+ &closure->wasmSeenTables,
+ &info.objectsNonHeapCodeWasm,
+ &info.objectsMallocHeapMisc);
+ }
+
+ cStats.classInfo.add(info);
+
+ const Class* clasp = obj->getClass();
+ const char* className = clasp->name;
+ AddClassInfo(granularity, cStats, className, info);
+
+ if (ObjectPrivateVisitor* opv = closure->opv) {
+ nsISupports* iface;
+ if (opv->getISupports_(obj, &iface) && iface)
+ cStats.objectsPrivate += opv->sizeOfIncludingThis(iface);
+ }
+ break;
+ }
+
+ case JS::TraceKind::Script: {
+ JSScript* script = static_cast<JSScript*>(thing);
+ CompartmentStats& cStats = script->compartment()->compartmentStats();
+ cStats.scriptsGCHeap += thingSize;
+ cStats.scriptsMallocHeapData += script->sizeOfData(rtStats->mallocSizeOf_);
+ cStats.typeInferenceTypeScripts += script->sizeOfTypeScript(rtStats->mallocSizeOf_);
+ jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_, &cStats.baselineData,
+ &cStats.baselineStubsFallback);
+ cStats.ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_);
+ CollectScriptSourceStats<granularity>(closure, script->scriptSource());
+ break;
+ }
+
+ case JS::TraceKind::String: {
+ JSString* str = static_cast<JSString*>(thing);
+
+ JS::StringInfo info;
+ if (str->hasLatin1Chars()) {
+ info.gcHeapLatin1 = thingSize;
+ info.mallocHeapLatin1 = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ } else {
+ info.gcHeapTwoByte = thingSize;
+ info.mallocHeapTwoByte = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ }
+ info.numCopies = 1;
+
+ zStats->stringInfo.add(info);
+
+ // The primary use case for anonymization is automated crash submission
+ // (to help detect OOM crashes). In that case, we don't want to pay the
+ // memory cost required to do notable string detection.
+ if (granularity == FineGrained && !closure->anonymize) {
+ ZoneStats::StringsHashMap::AddPtr p = zStats->allStrings->lookupForAdd(str);
+ if (!p) {
+ bool ok = zStats->allStrings->add(p, str, info);
+ // Ignore failure -- we just won't record the string as notable.
+ (void)ok;
+ } else {
+ p->value().add(info);
+ }
+ }
+ break;
+ }
+
+ case JS::TraceKind::Symbol:
+ zStats->symbolsGCHeap += thingSize;
+ break;
+
+ case JS::TraceKind::BaseShape: {
+ JS::ShapeInfo info; // This zeroes all the sizes.
+ info.shapesGCHeapBase += thingSize;
+ // No malloc-heap measurements.
+
+ zStats->shapeInfo.add(info);
+ break;
+ }
+
+ case JS::TraceKind::JitCode: {
+ zStats->jitCodesGCHeap += thingSize;
+ // The code for a script is counted in ExecutableAllocator::sizeOfCode().
+ break;
+ }
+
+ case JS::TraceKind::LazyScript: {
+ LazyScript* lazy = static_cast<LazyScript*>(thing);
+ zStats->lazyScriptsGCHeap += thingSize;
+ zStats->lazyScriptsMallocHeap += lazy->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ break;
+ }
+
+ case JS::TraceKind::Shape: {
+ Shape* shape = static_cast<Shape*>(thing);
+
+ JS::ShapeInfo info; // This zeroes all the sizes.
+ if (shape->inDictionary())
+ info.shapesGCHeapDict += thingSize;
+ else
+ info.shapesGCHeapTree += thingSize;
+ shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info);
+ zStats->shapeInfo.add(info);
+ break;
+ }
+
+ case JS::TraceKind::ObjectGroup: {
+ ObjectGroup* group = static_cast<ObjectGroup*>(thing);
+ zStats->objectGroupsGCHeap += thingSize;
+ zStats->objectGroupsMallocHeap += group->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ break;
+ }
+
+ case JS::TraceKind::Scope: {
+ Scope* scope = static_cast<Scope*>(thing);
+ zStats->scopesGCHeap += thingSize;
+ zStats->scopesMallocHeap += scope->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ break;
+ }
+
+ default:
+ MOZ_CRASH("invalid traceKind in StatsCellCallback");
+ }
+
+ // Yes, this is a subtraction: see StatsArenaCallback() for details.
+ zStats->unusedGCThings.addToKind(traceKind, -thingSize);
+}
+
+bool
+ZoneStats::initStrings(JSRuntime* rt)
+{
+ isTotals = false;
+ allStrings = rt->new_<StringsHashMap>();
+ if (!allStrings || !allStrings->init()) {
+ js_delete(allStrings);
+ allStrings = nullptr;
+ return false;
+ }
+ return true;
+}
+
+bool
+CompartmentStats::initClasses(JSRuntime* rt)
+{
+ isTotals = false;
+ allClasses = rt->new_<ClassesHashMap>();
+ if (!allClasses || !allClasses->init()) {
+ js_delete(allClasses);
+ allClasses = nullptr;
+ return false;
+ }
+ return true;
+}
+
+static bool
+FindNotableStrings(ZoneStats& zStats)
+{
+ using namespace JS;
+
+ // We should only run FindNotableStrings once per ZoneStats object.
+ MOZ_ASSERT(zStats.notableStrings.empty());
+
+ for (ZoneStats::StringsHashMap::Range r = zStats.allStrings->all(); !r.empty(); r.popFront()) {
+
+ JSString* str = r.front().key();
+ StringInfo& info = r.front().value();
+
+ if (!info.isNotable())
+ continue;
+
+ if (!zStats.notableStrings.growBy(1))
+ return false;
+
+ zStats.notableStrings.back() = NotableStringInfo(str, info);
+
+ // We're moving this string from a non-notable to a notable bucket, so
+ // subtract it out of the non-notable tallies.
+ zStats.stringInfo.subtract(info);
+ }
+ // Delete |allStrings| now, rather than waiting for zStats's destruction,
+ // to reduce peak memory consumption during reporting.
+ js_delete(zStats.allStrings);
+ zStats.allStrings = nullptr;
+ return true;
+}
+
+static bool
+FindNotableClasses(CompartmentStats& cStats)
+{
+ using namespace JS;
+
+ // We should only run FindNotableClasses once per ZoneStats object.
+ MOZ_ASSERT(cStats.notableClasses.empty());
+
+ for (CompartmentStats::ClassesHashMap::Range r = cStats.allClasses->all();
+ !r.empty();
+ r.popFront())
+ {
+ const char* className = r.front().key();
+ ClassInfo& info = r.front().value();
+
+ // If this class isn't notable, or if we can't grow the notableStrings
+ // vector, skip this string.
+ if (!info.isNotable())
+ continue;
+
+ if (!cStats.notableClasses.growBy(1))
+ return false;
+
+ cStats.notableClasses.back() = NotableClassInfo(className, info);
+
+ // We're moving this class from a non-notable to a notable bucket, so
+ // subtract it out of the non-notable tallies.
+ cStats.classInfo.subtract(info);
+ }
+ // Delete |allClasses| now, rather than waiting for zStats's destruction,
+ // to reduce peak memory consumption during reporting.
+ js_delete(cStats.allClasses);
+ cStats.allClasses = nullptr;
+ return true;
+}
+
+static bool
+FindNotableScriptSources(JS::RuntimeSizes& runtime)
+{
+ using namespace JS;
+
+ // We should only run FindNotableScriptSources once per RuntimeSizes.
+ MOZ_ASSERT(runtime.notableScriptSources.empty());
+
+ for (RuntimeSizes::ScriptSourcesHashMap::Range r = runtime.allScriptSources->all();
+ !r.empty();
+ r.popFront())
+ {
+ const char* filename = r.front().key();
+ ScriptSourceInfo& info = r.front().value();
+
+ if (!info.isNotable())
+ continue;
+
+ if (!runtime.notableScriptSources.growBy(1))
+ return false;
+
+ runtime.notableScriptSources.back() = NotableScriptSourceInfo(filename, info);
+
+ // We're moving this script source from a non-notable to a notable
+ // bucket, so subtract its sizes from the non-notable tallies.
+ runtime.scriptSourceInfo.subtract(info);
+ }
+ // Delete |allScriptSources| now, rather than waiting for zStats's
+ // destruction, to reduce peak memory consumption during reporting.
+ js_delete(runtime.allScriptSources);
+ runtime.allScriptSources = nullptr;
+ return true;
+}
+
+static bool
+CollectRuntimeStatsHelper(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv,
+ bool anonymize, IterateCellCallback statsCellCallback)
+{
+ JSRuntime* rt = cx;
+ if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments))
+ return false;
+
+ if (!rtStats->zoneStatsVector.reserve(rt->gc.zones.length()))
+ return false;
+
+ rtStats->gcHeapChunkTotal =
+ size_t(JS_GetGCParameter(cx, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
+
+ rtStats->gcHeapUnusedChunks =
+ size_t(JS_GetGCParameter(cx, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize;
+
+ IterateChunks(cx, &rtStats->gcHeapDecommittedArenas,
+ DecommittedArenasChunkCallback);
+
+ // Take the per-compartment measurements.
+ StatsClosure closure(rtStats, opv, anonymize);
+ if (!closure.init())
+ return false;
+ IterateZonesCompartmentsArenasCells(cx, &closure,
+ StatsZoneCallback,
+ StatsCompartmentCallback,
+ StatsArenaCallback,
+ statsCellCallback);
+
+ // Take the "explicit/js/runtime/" measurements.
+ rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
+
+ if (!FindNotableScriptSources(rtStats->runtime))
+ return false;
+
+ JS::ZoneStatsVector& zs = rtStats->zoneStatsVector;
+ ZoneStats& zTotals = rtStats->zTotals;
+
+ // We don't look for notable strings for zTotals. So we first sum all the
+ // zones' measurements to get the totals. Then we find the notable strings
+ // within each zone.
+ for (size_t i = 0; i < zs.length(); i++)
+ zTotals.addSizes(zs[i]);
+
+ for (size_t i = 0; i < zs.length(); i++)
+ if (!FindNotableStrings(zs[i]))
+ return false;
+
+ MOZ_ASSERT(!zTotals.allStrings);
+
+ JS::CompartmentStatsVector& cs = rtStats->compartmentStatsVector;
+ CompartmentStats& cTotals = rtStats->cTotals;
+
+ // As with the zones, we sum all compartments first, and then get the
+ // notable classes within each zone.
+ for (size_t i = 0; i < cs.length(); i++)
+ cTotals.addSizes(cs[i]);
+
+ for (size_t i = 0; i < cs.length(); i++) {
+ if (!FindNotableClasses(cs[i]))
+ return false;
+ }
+
+ MOZ_ASSERT(!cTotals.allClasses);
+
+ rtStats->gcHeapGCThings = rtStats->zTotals.sizeOfLiveGCThings() +
+ rtStats->cTotals.sizeOfLiveGCThings();
+
+#ifdef DEBUG
+ // Check that the in-arena measurements look ok.
+ size_t totalArenaSize = rtStats->zTotals.gcHeapArenaAdmin +
+ rtStats->zTotals.unusedGCThings.totalSize() +
+ rtStats->gcHeapGCThings;
+ MOZ_ASSERT(totalArenaSize % gc::ArenaSize == 0);
+#endif
+
+ for (CompartmentsIter comp(rt, WithAtoms); !comp.done(); comp.next())
+ comp->nullCompartmentStats();
+
+ size_t numDirtyChunks =
+ (rtStats->gcHeapChunkTotal - rtStats->gcHeapUnusedChunks) / gc::ChunkSize;
+ size_t perChunkAdmin =
+ sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
+ rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
+
+ // |gcHeapUnusedArenas| is the only thing left. Compute it in terms of
+ // all the others. See the comment in RuntimeStats for explanation.
+ rtStats->gcHeapUnusedArenas = rtStats->gcHeapChunkTotal -
+ rtStats->gcHeapDecommittedArenas -
+ rtStats->gcHeapUnusedChunks -
+ rtStats->zTotals.unusedGCThings.totalSize() -
+ rtStats->gcHeapChunkAdmin -
+ rtStats->zTotals.gcHeapArenaAdmin -
+ rtStats->gcHeapGCThings;
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS::CollectRuntimeStats(JSContext* cx, RuntimeStats *rtStats, ObjectPrivateVisitor *opv,
+ bool anonymize)
+{
+ return CollectRuntimeStatsHelper(cx, rtStats, opv, anonymize, StatsCellCallback<FineGrained>);
+}
+
+JS_PUBLIC_API(size_t)
+JS::SystemCompartmentCount(JSContext* cx)
+{
+ size_t n = 0;
+ for (CompartmentsIter comp(cx, WithAtoms); !comp.done(); comp.next()) {
+ if (comp->isSystem())
+ ++n;
+ }
+ return n;
+}
+
+JS_PUBLIC_API(size_t)
+JS::UserCompartmentCount(JSContext* cx)
+{
+ size_t n = 0;
+ for (CompartmentsIter comp(cx, WithAtoms); !comp.done(); comp.next()) {
+ if (!comp->isSystem())
+ ++n;
+ }
+ return n;
+}
+
+JS_PUBLIC_API(size_t)
+JS::PeakSizeOfTemporary(const JSContext* cx)
+{
+ return cx->JSRuntime::tempLifoAlloc.peakSizeOfExcludingThis();
+}
+
+namespace JS {
+
+class SimpleJSRuntimeStats : public JS::RuntimeStats
+{
+ public:
+ explicit SimpleJSRuntimeStats(MallocSizeOf mallocSizeOf)
+ : JS::RuntimeStats(mallocSizeOf)
+ {}
+
+ virtual void initExtraZoneStats(JS::Zone* zone, JS::ZoneStats* zStats)
+ override
+ {}
+
+ virtual void initExtraCompartmentStats(
+ JSCompartment* c, JS::CompartmentStats* cStats) override
+ {}
+};
+
+JS_PUBLIC_API(bool)
+AddSizeOfTab(JSContext* cx, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor* opv,
+ TabSizes* sizes)
+{
+ SimpleJSRuntimeStats rtStats(mallocSizeOf);
+
+ JS::Zone* zone = GetObjectZone(obj);
+
+ if (!rtStats.compartmentStatsVector.reserve(zone->compartments.length()))
+ return false;
+
+ if (!rtStats.zoneStatsVector.reserve(1))
+ return false;
+
+ // Take the per-compartment measurements. No need to anonymize because
+ // these measurements will be aggregated.
+ StatsClosure closure(&rtStats, opv, /* anonymize = */ false);
+ if (!closure.init())
+ return false;
+ IterateZoneCompartmentsArenasCells(cx, zone, &closure,
+ StatsZoneCallback,
+ StatsCompartmentCallback,
+ StatsArenaCallback,
+ StatsCellCallback<CoarseGrained>);
+
+ MOZ_ASSERT(rtStats.zoneStatsVector.length() == 1);
+ rtStats.zTotals.addSizes(rtStats.zoneStatsVector[0]);
+
+ for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++)
+ rtStats.cTotals.addSizes(rtStats.compartmentStatsVector[i]);
+
+ for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
+ comp->nullCompartmentStats();
+
+ rtStats.zTotals.addToTabSizes(sizes);
+ rtStats.cTotals.addToTabSizes(sizes);
+
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+AddServoSizeOf(JSContext* cx, MallocSizeOf mallocSizeOf, ObjectPrivateVisitor *opv,
+ ServoSizes *sizes)
+{
+ SimpleJSRuntimeStats rtStats(mallocSizeOf);
+
+ // No need to anonymize because the results will be aggregated.
+ if (!CollectRuntimeStatsHelper(cx, &rtStats, opv, /* anonymize = */ false,
+ StatsCellCallback<CoarseGrained>))
+ return false;
+
+#ifdef DEBUG
+ size_t gcHeapTotalOriginal = sizes->gcHeapUsed +
+ sizes->gcHeapUnused +
+ sizes->gcHeapAdmin +
+ sizes->gcHeapDecommitted;
+#endif
+
+ rtStats.addToServoSizes(sizes);
+ rtStats.zTotals.addToServoSizes(sizes);
+ rtStats.cTotals.addToServoSizes(sizes);
+
+#ifdef DEBUG
+ size_t gcHeapTotal = sizes->gcHeapUsed +
+ sizes->gcHeapUnused +
+ sizes->gcHeapAdmin +
+ sizes->gcHeapDecommitted;
+ MOZ_ASSERT(rtStats.gcHeapChunkTotal == gcHeapTotal - gcHeapTotalOriginal);
+#endif
+
+ return true;
+}
+
+} // namespace JS
diff --git a/js/src/vm/Monitor.h b/js/src/vm/Monitor.h
new file mode 100644
index 000000000..c5ce9b843
--- /dev/null
+++ b/js/src/vm/Monitor.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Monitor_h
+#define vm_Monitor_h
+
+#include "mozilla/DebugOnly.h"
+
+#include <stddef.h>
+
+#include "js/Utility.h"
+
+namespace js {
+
+// A base class used for types intended to be used in a parallel
+// fashion. Combines a lock and a condition variable. You can
+// acquire the lock or signal the condition variable using the
+// |AutoLockMonitor| type.
+
+class Monitor
+{
+ protected:
+ friend class AutoLockMonitor;
+ friend class AutoUnlockMonitor;
+
+ Mutex lock_;
+ ConditionVariable condVar_;
+
+ public:
+ explicit Monitor(const MutexId& id)
+ : lock_(id)
+ { }
+};
+
+class AutoLockMonitor : public LockGuard<Mutex>
+{
+ private:
+ using Base = LockGuard<Mutex>;
+ Monitor& monitor;
+
+ public:
+ explicit AutoLockMonitor(Monitor& monitor)
+ : Base(monitor.lock_)
+ , monitor(monitor)
+ { }
+
+ bool isFor(Monitor& other) const {
+ return monitor.lock_ == other.lock_;
+ }
+
+ void wait(ConditionVariable& condVar) {
+ condVar.wait(*this);
+ }
+
+ void wait() {
+ wait(monitor.condVar_);
+ }
+
+ void notify(ConditionVariable& condVar) {
+ condVar.notify_one();
+ }
+
+ void notify() {
+ notify(monitor.condVar_);
+ }
+
+ void notifyAll(ConditionVariable& condVar) {
+ condVar.notify_all();
+ }
+
+ void notifyAll() {
+ notifyAll(monitor.condVar_);
+ }
+};
+
+class AutoUnlockMonitor
+{
+ private:
+ Monitor& monitor;
+
+ public:
+ explicit AutoUnlockMonitor(Monitor& monitor)
+ : monitor(monitor)
+ {
+ monitor.lock_.unlock();
+ }
+
+ ~AutoUnlockMonitor() {
+ monitor.lock_.lock();
+ }
+
+ bool isFor(Monitor& other) const {
+ return monitor.lock_ == other.lock_;
+ }
+};
+
+} // namespace js
+
+#endif /* vm_Monitor_h */
diff --git a/js/src/vm/MutexIDs.h b/js/src/vm/MutexIDs.h
new file mode 100644
index 000000000..fbf689f89
--- /dev/null
+++ b/js/src/vm/MutexIDs.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_MutexIDs_h
+#define vm_MutexIDs_h
+
+#include "threading/Mutex.h"
+
+// Central definition point for mutex ordering.
+
+#define FOR_EACH_MUTEX(_) \
+ _(TestMutex, 100) \
+ _(ShellContextWatchdog, 100) \
+ _(ShellWorkerThreads, 100) \
+ _(ShellArrayBufferMailbox, 100) \
+ \
+ _(RuntimeExclusiveAccess, 200) \
+ \
+ _(GlobalHelperThreadState, 300) \
+ \
+ _(ShellAsyncTasks, 350) \
+ \
+ _(GCLock, 400) \
+ \
+ _(SharedImmutableStringsCache, 500) \
+ _(FutexRuntime, 500) \
+ _(PromiseTaskPtrVector, 500) \
+ _(SPSProfilerStrings, 500) \
+ _(ProtectedRegionTree, 500) \
+ _(WasmSigIdSet, 500) \
+ _(ShellOffThreadState, 500) \
+ _(SimulatorCacheLock, 500) \
+ _(Arm64SimulatorLock, 500) \
+ _(IonSpewer, 500) \
+ _(PerfSpewer, 500) \
+ _(TraceLoggerThreadState, 500) \
+ _(ProcessExecutableRegion, 500) \
+ \
+ _(TraceLoggerGraphState, 600)
+
+namespace js {
+namespace mutexid {
+
+#define DEFINE_MUTEX_ID(name, order) \
+static const MutexId name { #name, order };
+FOR_EACH_MUTEX(DEFINE_MUTEX_ID)
+#undef DEFINE_MUTEX_ID
+
+} // namespace mutexid
+} // namespace js
+
+#endif // vm_MutexIDs_h
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
new file mode 100644
index 000000000..48a42a8db
--- /dev/null
+++ b/js/src/vm/NativeObject-inl.h
@@ -0,0 +1,612 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_NativeObject_inl_h
+#define vm_NativeObject_inl_h
+
+#include "vm/NativeObject.h"
+
+#include "jscntxt.h"
+
+#include "builtin/TypedObject.h"
+#include "proxy/Proxy.h"
+#include "vm/ProxyObject.h"
+#include "vm/TypedArrayObject.h"
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+inline uint8_t*
+NativeObject::fixedData(size_t nslots) const
+{
+ MOZ_ASSERT(ClassCanHaveFixedData(getClass()));
+ MOZ_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
+ return reinterpret_cast<uint8_t*>(&fixedSlots()[nslots]);
+}
+
+inline void
+NativeObject::removeLastProperty(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(canRemoveLastProperty());
+ JS_ALWAYS_TRUE(setLastProperty(cx, lastProperty()->previous()));
+}
+
+inline bool
+NativeObject::canRemoveLastProperty()
+{
+ /*
+ * Check that the information about the object stored in the last
+ * property's base shape is consistent with that stored in the previous
+ * shape. If not consistent, then the last property cannot be removed as it
+ * will induce a change in the object itself, and the object must be
+ * converted to dictionary mode instead. See BaseShape comment in jsscope.h
+ */
+ MOZ_ASSERT(!inDictionaryMode());
+ Shape* previous = lastProperty()->previous().get();
+ return previous->getObjectFlags() == lastProperty()->getObjectFlags();
+}
+
+inline void
+NativeObject::setShouldConvertDoubleElements()
+{
+ MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
+ getElementsHeader()->setShouldConvertDoubleElements();
+}
+
+inline void
+NativeObject::clearShouldConvertDoubleElements()
+{
+ MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
+ getElementsHeader()->clearShouldConvertDoubleElements();
+}
+
+inline void
+NativeObject::setDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val)
+{
+ // Avoid a slow AddTypePropertyId call if the type is the same as the type
+ // of the previous element.
+ TypeSet::Type thisType = TypeSet::GetValueType(val);
+ if (index == 0 || TypeSet::GetValueType(elements_[index - 1]) != thisType)
+ AddTypePropertyId(cx, this, JSID_VOID, thisType);
+ setDenseElementMaybeConvertDouble(index, val);
+}
+
+inline void
+NativeObject::initDenseElementWithType(ExclusiveContext* cx, uint32_t index, const Value& val)
+{
+ MOZ_ASSERT(!shouldConvertDoubleElements());
+ if (val.isMagic(JS_ELEMENTS_HOLE))
+ markDenseElementsNotPacked(cx);
+ else
+ AddTypePropertyId(cx, this, JSID_VOID, val);
+ initDenseElement(index, val);
+}
+
+inline void
+NativeObject::setDenseElementHole(ExclusiveContext* cx, uint32_t index)
+{
+ MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED);
+ setDenseElement(index, MagicValue(JS_ELEMENTS_HOLE));
+}
+
+/* static */ inline void
+NativeObject::removeDenseElementForSparseIndex(ExclusiveContext* cx,
+ HandleNativeObject obj, uint32_t index)
+{
+ MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_NON_PACKED | OBJECT_FLAG_SPARSE_INDEXES);
+ if (obj->containsDenseElement(index))
+ obj->setDenseElementUnchecked(index, MagicValue(JS_ELEMENTS_HOLE));
+}
+
+inline bool
+NativeObject::writeToIndexWouldMarkNotPacked(uint32_t index)
+{
+ return getElementsHeader()->initializedLength < index;
+}
+
+inline void
+NativeObject::markDenseElementsNotPacked(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(isNative());
+ MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED);
+}
+
+inline void
+NativeObject::ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext* cx, uint32_t index,
+ uint32_t extra)
+{
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+
+ /*
+ * Ensure that the array's contents have been initialized up to index, and
+ * mark the elements through 'index + extra' as initialized in preparation
+ * for a write.
+ */
+ MOZ_ASSERT(index + extra <= getDenseCapacity());
+ uint32_t& initlen = getElementsHeader()->initializedLength;
+
+ if (initlen < index + extra) {
+ size_t offset = initlen;
+ for (HeapSlot* sp = elements_ + initlen;
+ sp != elements_ + (index + extra);
+ sp++, offset++)
+ {
+ sp->init(this, HeapSlot::Element, offset, MagicValue(JS_ELEMENTS_HOLE));
+ }
+ initlen = index + extra;
+ }
+}
+
+inline void
+NativeObject::ensureDenseInitializedLength(ExclusiveContext* cx, uint32_t index, uint32_t extra)
+{
+ if (writeToIndexWouldMarkNotPacked(index))
+ markDenseElementsNotPacked(cx);
+ ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
+}
+
+DenseElementResult
+NativeObject::extendDenseElements(ExclusiveContext* cx,
+ uint32_t requiredCapacity, uint32_t extra)
+{
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+
+ /*
+ * Don't grow elements for non-extensible objects or watched objects. Dense
+ * elements can be added/written with no extensible or watchpoint checks as
+ * long as there is capacity for them.
+ */
+ if (!nonProxyIsExtensible() || watched()) {
+ MOZ_ASSERT(getDenseCapacity() == 0);
+ return DenseElementResult::Incomplete;
+ }
+
+ /*
+ * Don't grow elements for objects which already have sparse indexes.
+ * This avoids needing to count non-hole elements in willBeSparseElements
+ * every time a new index is added.
+ */
+ if (isIndexed())
+ return DenseElementResult::Incomplete;
+
+ /*
+ * We use the extra argument also as a hint about number of non-hole
+ * elements to be inserted.
+ */
+ if (requiredCapacity > MIN_SPARSE_INDEX &&
+ willBeSparseElements(requiredCapacity, extra)) {
+ return DenseElementResult::Incomplete;
+ }
+
+ if (!growElements(cx, requiredCapacity))
+ return DenseElementResult::Failure;
+
+ return DenseElementResult::Success;
+}
+
+inline DenseElementResult
+NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t extra)
+{
+ MOZ_ASSERT(isNative());
+
+ if (writeToIndexWouldMarkNotPacked(index))
+ markDenseElementsNotPacked(cx);
+
+ if (!maybeCopyElementsForWrite(cx))
+ return DenseElementResult::Failure;
+
+ uint32_t currentCapacity = getDenseCapacity();
+
+ uint32_t requiredCapacity;
+ if (extra == 1) {
+ /* Optimize for the common case. */
+ if (index < currentCapacity) {
+ ensureDenseInitializedLengthNoPackedCheck(cx, index, 1);
+ return DenseElementResult::Success;
+ }
+ requiredCapacity = index + 1;
+ if (requiredCapacity == 0) {
+ /* Overflow. */
+ return DenseElementResult::Incomplete;
+ }
+ } else {
+ requiredCapacity = index + extra;
+ if (requiredCapacity < index) {
+ /* Overflow. */
+ return DenseElementResult::Incomplete;
+ }
+ if (requiredCapacity <= currentCapacity) {
+ ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
+ return DenseElementResult::Success;
+ }
+ }
+
+ DenseElementResult result = extendDenseElements(cx, requiredCapacity, extra);
+ if (result != DenseElementResult::Success)
+ return result;
+
+ ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
+ return DenseElementResult::Success;
+}
+
+inline Value
+NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
+{
+ if (is<TypedArrayObject>())
+ return as<TypedArrayObject>().getElement(idx);
+ return getDenseElement(idx);
+}
+
+/* static */ inline NativeObject*
+NativeObject::copy(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
+ HandleNativeObject templateObject)
+{
+ RootedShape shape(cx, templateObject->lastProperty());
+ RootedObjectGroup group(cx, templateObject->group());
+ MOZ_ASSERT(!templateObject->denseElementsAreCopyOnWrite());
+
+ JSObject* baseObj = create(cx, kind, heap, shape, group);
+ if (!baseObj)
+ return nullptr;
+ NativeObject* obj = &baseObj->as<NativeObject>();
+
+ size_t span = shape->slotSpan();
+ if (span) {
+ uint32_t numFixed = templateObject->numFixedSlots();
+ const Value* fixed = &templateObject->getSlot(0);
+ // Only copy elements which are registered in the shape, even if the
+ // number of fixed slots is larger.
+ if (span < numFixed)
+ numFixed = span;
+ obj->copySlotRange(0, fixed, numFixed);
+
+ if (numFixed < span) {
+ uint32_t numSlots = span - numFixed;
+ const Value* slots = &templateObject->getSlot(numFixed);
+ obj->copySlotRange(numFixed, slots, numSlots);
+ }
+ }
+
+ return obj;
+}
+
+inline void
+NativeObject::setSlotWithType(ExclusiveContext* cx, Shape* shape,
+ const Value& value, bool overwriting)
+{
+ setSlot(shape->slot(), value);
+
+ if (overwriting)
+ shape->setOverwritten();
+
+ AddTypePropertyId(cx, this, shape->propid(), value);
+}
+
+inline void
+NativeObject::updateShapeAfterMovingGC()
+{
+ Shape* shape = shape_.unbarrieredGet();
+ if (IsForwarded(shape))
+ shape_.unsafeSet(Forwarded(shape));
+}
+
+/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
+static inline PlainObject*
+CopyInitializerObject(JSContext* cx, HandlePlainObject baseobj, NewObjectKind newKind = GenericObject)
+{
+ MOZ_ASSERT(!baseobj->inDictionaryMode());
+
+ gc::AllocKind allocKind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
+ allocKind = gc::GetBackgroundAllocKind(allocKind);
+ MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured().getAllocKind());
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, allocKind, newKind));
+ if (!obj)
+ return nullptr;
+
+ if (!obj->setLastProperty(cx, baseobj->lastProperty()))
+ return nullptr;
+
+ return obj;
+}
+
+inline NativeObject*
+NewNativeObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp,
+ Handle<TaggedProto> proto,
+ gc::AllocKind allocKind, NewObjectKind newKind)
+{
+ return MaybeNativeObject(NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind,
+ newKind));
+}
+
+inline NativeObject*
+NewNativeObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp,
+ Handle<TaggedProto> proto,
+ NewObjectKind newKind = GenericObject)
+{
+ return MaybeNativeObject(NewObjectWithGivenTaggedProto(cx, clasp, proto, newKind));
+}
+
+inline NativeObject*
+NewNativeObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp,
+ HandleObject proto,
+ gc::AllocKind allocKind, NewObjectKind newKind)
+{
+ return MaybeNativeObject(NewObjectWithGivenProto(cx, clasp, proto, allocKind, newKind));
+}
+
+inline NativeObject*
+NewNativeObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp,
+ HandleObject proto,
+ NewObjectKind newKind = GenericObject)
+{
+ return MaybeNativeObject(NewObjectWithGivenProto(cx, clasp, proto, newKind));
+}
+
+inline NativeObject*
+NewNativeObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
+ gc::AllocKind allocKind,
+ NewObjectKind newKind = GenericObject)
+{
+ return MaybeNativeObject(NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind));
+}
+
+inline NativeObject*
+NewNativeObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
+ NewObjectKind newKind = GenericObject)
+{
+ return MaybeNativeObject(NewObjectWithClassProto(cx, clasp, proto, newKind));
+}
+
+/*
+ * Call obj's resolve hook.
+ *
+ * cx and id are the parameters initially passed to the ongoing lookup;
+ * propp and recursedp are its out parameters.
+ *
+ * There are four possible outcomes:
+ *
+ * - On failure, report an error or exception and return false.
+ *
+ * - If we are already resolving a property of obj, set *recursedp = true,
+ * and return true.
+ *
+ * - If the resolve hook finds or defines the sought property, set propp
+ * appropriately, set *recursedp = false, and return true.
+ *
+ * - Otherwise no property was resolved. Set propp to nullptr and
+ * *recursedp = false and return true.
+ */
+static MOZ_ALWAYS_INLINE bool
+CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleShape propp,
+ bool* recursedp)
+{
+ // Avoid recursion on (obj, id) already being resolved on cx.
+ AutoResolving resolving(cx, obj, id);
+ if (resolving.alreadyStarted()) {
+ // Already resolving id in obj, suppress recursion.
+ *recursedp = true;
+ return true;
+ }
+ *recursedp = false;
+
+ bool resolved = false;
+ if (!obj->getClass()->getResolve()(cx, obj, id, &resolved))
+ return false;
+
+ if (!resolved)
+ return true;
+
+ // Assert the mayResolve hook, if there is one, returns true for this
+ // property.
+ MOZ_ASSERT_IF(obj->getClass()->getMayResolve(),
+ obj->getClass()->getMayResolve()(cx->names(), id, obj));
+
+ if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
+ MarkDenseOrTypedArrayElementFound<CanGC>(propp);
+ return true;
+ }
+
+ MOZ_ASSERT(!obj->is<TypedArrayObject>());
+
+ propp.set(obj->lookup(cx, id));
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
+{
+ MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
+
+ if (!clasp->getResolve()) {
+ // Sanity check: we should only have a mayResolve hook if we have a
+ // resolve hook.
+ MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
+ return false;
+ }
+
+ if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
+ // Tell the analysis our mayResolve hooks won't trigger GC.
+ JS::AutoSuppressGCAnalysis nogc;
+ if (!mayResolve(names, id, maybeObj))
+ return false;
+ }
+
+ return true;
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE bool
+LookupOwnPropertyInline(ExclusiveContext* cx,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<jsid, allowGC>::HandleType id,
+ typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp,
+ bool* donep)
+{
+ // Check for a native dense element.
+ if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
+ MarkDenseOrTypedArrayElementFound<allowGC>(propp);
+ *donep = true;
+ return true;
+ }
+
+ // Check for a typed array element. Integer lookups always finish here
+ // so that integer properties on the prototype are ignored even for out
+ // of bounds accesses.
+ if (obj->template is<TypedArrayObject>()) {
+ uint64_t index;
+ if (IsTypedArrayIndex(id, &index)) {
+ if (index < obj->template as<TypedArrayObject>().length()) {
+ MarkDenseOrTypedArrayElementFound<allowGC>(propp);
+ } else {
+ propp.set(nullptr);
+ }
+ *donep = true;
+ return true;
+ }
+ }
+
+ // Check for a native property.
+ if (Shape* shape = obj->lookup(cx, id)) {
+ propp.set(shape);
+ *donep = true;
+ return true;
+ }
+
+ // id was not found in obj. Try obj's resolve hook, if any.
+ if (obj->getClass()->getResolve()) {
+ if (!cx->shouldBeJSContext() || !allowGC)
+ return false;
+
+ bool recursed;
+ if (!CallResolveOp(cx->asJSContext(),
+ MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
+ MaybeRooted<jsid, allowGC>::toHandle(id),
+ MaybeRooted<Shape*, allowGC>::toMutableHandle(propp),
+ &recursed))
+ {
+ return false;
+ }
+
+ if (recursed) {
+ propp.set(nullptr);
+ *donep = true;
+ return true;
+ }
+
+ if (propp) {
+ *donep = true;
+ return true;
+ }
+ }
+
+ propp.set(nullptr);
+ *donep = false;
+ return true;
+}
+
+/*
+ * Simplified version of LookupOwnPropertyInline that doesn't call resolve
+ * hooks.
+ */
+static inline void
+NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ MutableHandleShape result)
+{
+ // Check for a native dense element.
+ if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
+ MarkDenseOrTypedArrayElementFound<CanGC>(result);
+ return;
+ }
+
+ // Check for a typed array element.
+ if (obj->is<TypedArrayObject>()) {
+ uint64_t index;
+ if (IsTypedArrayIndex(id, &index)) {
+ if (index < obj->as<TypedArrayObject>().length())
+ MarkDenseOrTypedArrayElementFound<CanGC>(result);
+ else
+ result.set(nullptr);
+ return;
+ }
+ }
+
+ // Check for a native property.
+ result.set(obj->lookup(cx, id));
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE bool
+LookupPropertyInline(ExclusiveContext* cx,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<jsid, allowGC>::HandleType id,
+ typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
+ typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+{
+ /* NB: The logic of this procedure is implicitly reflected in
+ * BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
+ * If this changes, please remember to update the logic there as well.
+ */
+
+ /* Search scopes starting with obj and following the prototype link. */
+ typename MaybeRooted<NativeObject*, allowGC>::RootType current(cx, obj);
+
+ while (true) {
+ bool done;
+ if (!LookupOwnPropertyInline<allowGC>(cx, current, id, propp, &done))
+ return false;
+ if (done) {
+ if (propp)
+ objp.set(current);
+ else
+ objp.set(nullptr);
+ return true;
+ }
+
+ typename MaybeRooted<JSObject*, allowGC>::RootType proto(cx, current->staticPrototype());
+
+ if (!proto)
+ break;
+ if (!proto->isNative()) {
+ if (!cx->shouldBeJSContext() || !allowGC)
+ return false;
+ return LookupProperty(cx->asJSContext(),
+ MaybeRooted<JSObject*, allowGC>::toHandle(proto),
+ MaybeRooted<jsid, allowGC>::toHandle(id),
+ MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
+ MaybeRooted<Shape*, allowGC>::toMutableHandle(propp));
+ }
+
+ current = &proto->template as<NativeObject>();
+ }
+
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+}
+
+inline bool
+ThrowIfNotConstructing(JSContext *cx, const CallArgs &args, const char *builtinName)
+{
+ if (args.isConstructing())
+ return true;
+ return JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
+ JSMSG_BUILTIN_CTOR_NO_NEW, builtinName);
+}
+
+inline bool
+IsPackedArray(JSObject* obj)
+{
+ return obj->is<ArrayObject>() && !obj->hasLazyGroup() &&
+ !obj->group()->hasAllFlags(OBJECT_FLAG_NON_PACKED) &&
+ obj->as<ArrayObject>().getDenseInitializedLength() == obj->as<ArrayObject>().length();
+}
+
+} // namespace js
+
+#endif /* vm_NativeObject_inl_h */
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
new file mode 100644
index 000000000..21f73f4a9
--- /dev/null
+++ b/js/src/vm/NativeObject.cpp
@@ -0,0 +1,2564 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/NativeObject-inl.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Casting.h"
+
+#include "jswatchpoint.h"
+
+#include "gc/Marking.h"
+#include "js/Value.h"
+#include "vm/Debugger.h"
+#include "vm/TypedArrayCommon.h"
+
+#include "jsobjinlines.h"
+
+#include "gc/Nursery-inl.h"
+#include "vm/ArrayObject-inl.h"
+#include "vm/EnvironmentObject-inl.h"
+#include "vm/Shape-inl.h"
+
+using namespace js;
+
+using JS::AutoCheckCannotGC;
+using JS::GenericNaN;
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::PodCopy;
+using mozilla::RoundUpPow2;
+
+static const ObjectElements emptyElementsHeader(0, 0);
+
+/* Objects with no elements share one empty set of elements. */
+HeapSlot* const js::emptyObjectElements =
+ reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeader) + sizeof(ObjectElements));
+
+static const ObjectElements emptyElementsHeaderShared(0, 0, ObjectElements::SharedMemory::IsShared);
+
+/* Objects with no elements share one empty set of elements. */
+HeapSlot* const js::emptyObjectElementsShared =
+ reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
+
+
+#ifdef DEBUG
+
+bool
+NativeObject::canHaveNonEmptyElements()
+{
+ return !this->is<TypedArrayObject>();
+}
+
+#endif // DEBUG
+
+/* static */ bool
+ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr)
+{
+ /*
+ * This function is infallible, but has a fallible interface so that it can
+ * be called directly from Ion code. Only arrays can have their dense
+ * elements converted to doubles, and arrays never have empty elements.
+ */
+ HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr;
+ MOZ_ASSERT(elementsHeapPtr != emptyObjectElements &&
+ elementsHeapPtr != emptyObjectElementsShared);
+
+ ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr);
+ MOZ_ASSERT(!header->shouldConvertDoubleElements());
+
+ // Note: the elements can be mutated in place even for copy on write
+ // arrays. See comment on ObjectElements.
+ Value* vp = (Value*) elementsPtr;
+ for (size_t i = 0; i < header->initializedLength; i++) {
+ if (vp[i].isInt32())
+ vp[i].setDouble(vp[i].toInt32());
+ }
+
+ header->setShouldConvertDoubleElements();
+ return true;
+}
+
+/* static */ bool
+ObjectElements::MakeElementsCopyOnWrite(ExclusiveContext* cx, NativeObject* obj)
+{
+ static_assert(sizeof(HeapSlot) >= sizeof(GCPtrObject),
+ "there must be enough room for the owner object pointer at "
+ "the end of the elements");
+ if (!obj->ensureElements(cx, obj->getDenseInitializedLength() + 1))
+ return false;
+
+ ObjectElements* header = obj->getElementsHeader();
+
+ // Note: this method doesn't update type information to indicate that the
+ // elements might be copy on write. Handling this is left to the caller.
+ MOZ_ASSERT(!header->isCopyOnWrite());
+ MOZ_ASSERT(!header->isFrozen());
+ header->flags |= COPY_ON_WRITE;
+
+ header->ownerObject().init(obj);
+ return true;
+}
+
+/* static */ bool
+ObjectElements::FreezeElements(ExclusiveContext* cx, HandleNativeObject obj)
+{
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ if (obj->hasEmptyElements())
+ return true;
+
+ ObjectElements* header = obj->getElementsHeader();
+
+ // Note: this method doesn't update type information to indicate that the
+ // elements might be frozen. Handling this is left to the caller.
+ header->freeze();
+
+ return true;
+}
+
+#ifdef DEBUG
+void
+js::NativeObject::checkShapeConsistency()
+{
+ static int throttle = -1;
+ if (throttle < 0) {
+ if (const char* var = getenv("JS_CHECK_SHAPE_THROTTLE"))
+ throttle = atoi(var);
+ if (throttle < 0)
+ throttle = 0;
+ }
+ if (throttle == 0)
+ return;
+
+ MOZ_ASSERT(isNative());
+
+ Shape* shape = lastProperty();
+ Shape* prev = nullptr;
+
+ AutoCheckCannotGC nogc;
+ if (inDictionaryMode()) {
+ if (ShapeTable* table = shape->maybeTable(nogc)) {
+ for (uint32_t fslot = table->freeList();
+ fslot != SHAPE_INVALID_SLOT;
+ fslot = getSlot(fslot).toPrivateUint32())
+ {
+ MOZ_ASSERT(fslot < slotSpan());
+ }
+
+ for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
+ MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable());
+
+ ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(shape->propid(),
+ nogc);
+ MOZ_ASSERT(entry.shape() == shape);
+ }
+ }
+
+ shape = lastProperty();
+ for (int n = throttle; --n >= 0 && shape; shape = shape->parent) {
+ MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan());
+ if (!prev) {
+ MOZ_ASSERT(lastProperty() == shape);
+ MOZ_ASSERT(shape->listp == &shape_);
+ } else {
+ MOZ_ASSERT(shape->listp == &prev->parent);
+ }
+ prev = shape;
+ }
+ } else {
+ for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
+ if (ShapeTable* table = shape->maybeTable(nogc)) {
+ MOZ_ASSERT(shape->parent);
+ for (Shape::Range<NoGC> r(shape); !r.empty(); r.popFront()) {
+ ShapeTable::Entry& entry =
+ table->search<MaybeAdding::NotAdding>(r.front().propid(), nogc);
+ MOZ_ASSERT(entry.shape() == &r.front());
+ }
+ }
+ if (prev) {
+ MOZ_ASSERT(prev->maybeSlot() >= shape->maybeSlot());
+ shape->kids.checkConsistency(prev);
+ }
+ prev = shape;
+ }
+ }
+}
+#endif
+
+void
+js::NativeObject::initializeSlotRange(uint32_t start, uint32_t length)
+{
+ /*
+ * No bounds check, as this is used when the object's shape does not
+ * reflect its allocated slots (updateSlotsForSpan).
+ */
+ HeapSlot* fixedStart;
+ HeapSlot* fixedEnd;
+ HeapSlot* slotsStart;
+ HeapSlot* slotsEnd;
+ getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+
+ uint32_t offset = start;
+ for (HeapSlot* sp = fixedStart; sp < fixedEnd; sp++)
+ sp->init(this, HeapSlot::Slot, offset++, UndefinedValue());
+ for (HeapSlot* sp = slotsStart; sp < slotsEnd; sp++)
+ sp->init(this, HeapSlot::Slot, offset++, UndefinedValue());
+}
+
+void
+js::NativeObject::initSlotRange(uint32_t start, const Value* vector, uint32_t length)
+{
+ HeapSlot* fixedStart;
+ HeapSlot* fixedEnd;
+ HeapSlot* slotsStart;
+ HeapSlot* slotsEnd;
+ getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+ for (HeapSlot* sp = fixedStart; sp < fixedEnd; sp++)
+ sp->init(this, HeapSlot::Slot, start++, *vector++);
+ for (HeapSlot* sp = slotsStart; sp < slotsEnd; sp++)
+ sp->init(this, HeapSlot::Slot, start++, *vector++);
+}
+
+void
+js::NativeObject::copySlotRange(uint32_t start, const Value* vector, uint32_t length)
+{
+ HeapSlot* fixedStart;
+ HeapSlot* fixedEnd;
+ HeapSlot* slotsStart;
+ HeapSlot* slotsEnd;
+ getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+ for (HeapSlot* sp = fixedStart; sp < fixedEnd; sp++)
+ sp->set(this, HeapSlot::Slot, start++, *vector++);
+ for (HeapSlot* sp = slotsStart; sp < slotsEnd; sp++)
+ sp->set(this, HeapSlot::Slot, start++, *vector++);
+}
+
+#ifdef DEBUG
+bool
+js::NativeObject::slotInRange(uint32_t slot, SentinelAllowed sentinel) const
+{
+ uint32_t capacity = numFixedSlots() + numDynamicSlots();
+ if (sentinel == SENTINEL_ALLOWED)
+ return slot <= capacity;
+ return slot < capacity;
+}
+#endif /* DEBUG */
+
+Shape*
+js::NativeObject::lookup(ExclusiveContext* cx, jsid id)
+{
+ MOZ_ASSERT(isNative());
+ return Shape::search(cx, lastProperty(), id);
+}
+
+Shape*
+js::NativeObject::lookupPure(jsid id)
+{
+ MOZ_ASSERT(isNative());
+ return Shape::searchNoHashify(lastProperty(), id);
+}
+
+uint32_t
+js::NativeObject::numFixedSlotsForCompilation() const
+{
+ // This is an alternative method for getting the number of fixed slots in an
+ // object. It requires more logic and memory accesses than numFixedSlots()
+ // but is safe to be called from the compilation thread, even if the main
+ // thread is actively mutating the VM.
+
+ // The compiler does not have access to nursery things.
+ MOZ_ASSERT(!IsInsideNursery(this));
+
+ if (this->is<ArrayObject>())
+ return 0;
+
+ gc::AllocKind kind = asTenured().getAllocKind();
+ return gc::GetGCKindSlots(kind, getClass());
+}
+
+uint32_t
+js::NativeObject::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class* clasp)
+{
+ if (span <= nfixed)
+ return 0;
+ span -= nfixed;
+
+ // Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood
+ // the dynamic slots need to get increased again. ArrayObjects ignore
+ // this because slots are uncommon in that case.
+ if (clasp != &ArrayObject::class_ && span <= SLOT_CAPACITY_MIN)
+ return SLOT_CAPACITY_MIN;
+
+ uint32_t slots = mozilla::RoundUpPow2(span);
+ MOZ_ASSERT(slots >= span);
+ return slots;
+}
+
+inline bool
+NativeObject::updateSlotsForSpan(ExclusiveContext* cx, size_t oldSpan, size_t newSpan)
+{
+ MOZ_ASSERT(oldSpan != newSpan);
+
+ size_t oldCount = dynamicSlotsCount(numFixedSlots(), oldSpan, getClass());
+ size_t newCount = dynamicSlotsCount(numFixedSlots(), newSpan, getClass());
+
+ if (oldSpan < newSpan) {
+ if (oldCount < newCount && !growSlots(cx, oldCount, newCount))
+ return false;
+
+ if (newSpan == oldSpan + 1)
+ initSlotUnchecked(oldSpan, UndefinedValue());
+ else
+ initializeSlotRange(oldSpan, newSpan - oldSpan);
+ } else {
+ /* Trigger write barriers on the old slots before reallocating. */
+ prepareSlotRangeForOverwrite(newSpan, oldSpan);
+ invalidateSlotRange(newSpan, oldSpan - newSpan);
+
+ if (oldCount > newCount)
+ shrinkSlots(cx, oldCount, newCount);
+ }
+
+ return true;
+}
+
+bool
+NativeObject::setLastProperty(ExclusiveContext* cx, Shape* shape)
+{
+ MOZ_ASSERT(!inDictionaryMode());
+ MOZ_ASSERT(!shape->inDictionary());
+ MOZ_ASSERT(shape->zone() == zone());
+ MOZ_ASSERT(shape->numFixedSlots() == numFixedSlots());
+ MOZ_ASSERT(shape->getObjectClass() == getClass());
+
+ size_t oldSpan = lastProperty()->slotSpan();
+ size_t newSpan = shape->slotSpan();
+
+ if (oldSpan == newSpan) {
+ shape_ = shape;
+ return true;
+ }
+
+ if (!updateSlotsForSpan(cx, oldSpan, newSpan))
+ return false;
+
+ shape_ = shape;
+ return true;
+}
+
+void
+NativeObject::setLastPropertyShrinkFixedSlots(Shape* shape)
+{
+ MOZ_ASSERT(!inDictionaryMode());
+ MOZ_ASSERT(!shape->inDictionary());
+ MOZ_ASSERT(shape->zone() == zone());
+ MOZ_ASSERT(lastProperty()->slotSpan() == shape->slotSpan());
+ MOZ_ASSERT(shape->getObjectClass() == getClass());
+
+ DebugOnly<size_t> oldFixed = numFixedSlots();
+ DebugOnly<size_t> newFixed = shape->numFixedSlots();
+ MOZ_ASSERT(newFixed < oldFixed);
+ MOZ_ASSERT(shape->slotSpan() <= oldFixed);
+ MOZ_ASSERT(shape->slotSpan() <= newFixed);
+ MOZ_ASSERT(dynamicSlotsCount(oldFixed, shape->slotSpan(), getClass()) == 0);
+ MOZ_ASSERT(dynamicSlotsCount(newFixed, shape->slotSpan(), getClass()) == 0);
+
+ shape_ = shape;
+}
+
+void
+NativeObject::setLastPropertyMakeNonNative(Shape* shape)
+{
+ MOZ_ASSERT(!inDictionaryMode());
+ MOZ_ASSERT(!shape->getObjectClass()->isNative());
+ MOZ_ASSERT(shape->zone() == zone());
+ MOZ_ASSERT(shape->slotSpan() == 0);
+ MOZ_ASSERT(shape->numFixedSlots() == 0);
+
+ if (hasDynamicElements())
+ js_free(getElementsHeader());
+ if (hasDynamicSlots()) {
+ js_free(slots_);
+ slots_ = nullptr;
+ }
+
+ shape_ = shape;
+}
+
+void
+NativeObject::setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape)
+{
+ MOZ_ASSERT(getClass()->isNative());
+ MOZ_ASSERT(shape->getObjectClass()->isNative());
+ MOZ_ASSERT(!shape->inDictionary());
+
+ // This method is used to convert unboxed objects into native objects. In
+ // this case, the shape_ field was previously used to store other data and
+ // this should be treated as an initialization.
+ shape_.init(shape);
+
+ slots_ = nullptr;
+ elements_ = emptyObjectElements;
+
+ size_t oldSpan = shape->numFixedSlots();
+ size_t newSpan = shape->slotSpan();
+
+ initializeSlotRange(0, oldSpan);
+
+ // A failure at this point will leave the object as a mutant, and we
+ // can't recover.
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (oldSpan != newSpan && !updateSlotsForSpan(cx, oldSpan, newSpan))
+ oomUnsafe.crash("NativeObject::setLastPropertyMakeNative");
+}
+
+bool
+NativeObject::setSlotSpan(ExclusiveContext* cx, uint32_t span)
+{
+ MOZ_ASSERT(inDictionaryMode());
+
+ size_t oldSpan = lastProperty()->base()->slotSpan();
+ if (oldSpan == span)
+ return true;
+
+ if (!updateSlotsForSpan(cx, oldSpan, span))
+ return false;
+
+ lastProperty()->base()->setSlotSpan(span);
+ return true;
+}
+
+bool
+NativeObject::growSlots(ExclusiveContext* cx, uint32_t oldCount, uint32_t newCount)
+{
+ MOZ_ASSERT(newCount > oldCount);
+ MOZ_ASSERT_IF(!is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
+
+ /*
+ * Slot capacities are determined by the span of allocated objects. Due to
+ * the limited number of bits to store shape slots, object growth is
+ * throttled well before the slot capacity can overflow.
+ */
+ NativeObject::slotsSizeMustNotOverflow();
+ MOZ_ASSERT(newCount <= MAX_SLOTS_COUNT);
+
+ if (!oldCount) {
+ MOZ_ASSERT(!slots_);
+ slots_ = AllocateObjectBuffer<HeapSlot>(cx, this, newCount);
+ if (!slots_)
+ return false;
+ Debug_SetSlotRangeToCrashOnTouch(slots_, newCount);
+ return true;
+ }
+
+ HeapSlot* newslots = ReallocateObjectBuffer<HeapSlot>(cx, this, slots_, oldCount, newCount);
+ if (!newslots)
+ return false; /* Leave slots at its old size. */
+
+ slots_ = newslots;
+
+ Debug_SetSlotRangeToCrashOnTouch(slots_ + oldCount, newCount - oldCount);
+
+ return true;
+}
+
+/* static */ bool
+NativeObject::growSlotsDontReportOOM(ExclusiveContext* cx, NativeObject* obj, uint32_t newCount)
+{
+ if (!obj->growSlots(cx, obj->numDynamicSlots(), newCount)) {
+ cx->recoverFromOutOfMemory();
+ return false;
+ }
+ return true;
+}
+
+static void
+FreeSlots(ExclusiveContext* cx, HeapSlot* slots)
+{
+ // Note: threads without a JSContext do not have access to GGC nursery allocated things.
+ if (cx->isJSContext())
+ return cx->asJSContext()->runtime()->gc.nursery.freeBuffer(slots);
+ js_free(slots);
+}
+
+void
+NativeObject::shrinkSlots(ExclusiveContext* cx, uint32_t oldCount, uint32_t newCount)
+{
+ MOZ_ASSERT(newCount < oldCount);
+
+ if (newCount == 0) {
+ FreeSlots(cx, slots_);
+ slots_ = nullptr;
+ return;
+ }
+
+ MOZ_ASSERT_IF(!is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
+
+ HeapSlot* newslots = ReallocateObjectBuffer<HeapSlot>(cx, this, slots_, oldCount, newCount);
+ if (!newslots) {
+ cx->recoverFromOutOfMemory();
+ return; /* Leave slots at its old size. */
+ }
+
+ slots_ = newslots;
+}
+
+/* static */ bool
+NativeObject::sparsifyDenseElement(ExclusiveContext* cx, HandleNativeObject obj, uint32_t index)
+{
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ RootedValue value(cx, obj->getDenseElement(index));
+ MOZ_ASSERT(!value.isMagic(JS_ELEMENTS_HOLE));
+
+ removeDenseElementForSparseIndex(cx, obj, index);
+
+ uint32_t slot = obj->slotSpan();
+
+ RootedId id(cx, INT_TO_JSID(index));
+
+ AutoKeepShapeTables keep(cx);
+ ShapeTable::Entry* entry = nullptr;
+ if (obj->inDictionaryMode()) {
+ ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, keep);
+ if (!table)
+ return false;
+ entry = &table->search<MaybeAdding::Adding>(id, keep);
+ }
+
+ // NOTE: We don't use addDataProperty because we don't want the
+ // extensibility check if we're, for example, sparsifying frozen objects..
+ if (!addPropertyInternal(cx, obj, id, nullptr, nullptr, slot,
+ obj->getElementsHeader()->elementAttributes(),
+ 0, entry, true, keep)) {
+ obj->setDenseElementUnchecked(index, value);
+ return false;
+ }
+
+ MOZ_ASSERT(slot == obj->slotSpan() - 1);
+ obj->initSlot(slot, value);
+
+ return true;
+}
+
+/* static */ bool
+NativeObject::sparsifyDenseElements(js::ExclusiveContext* cx, HandleNativeObject obj)
+{
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ uint32_t initialized = obj->getDenseInitializedLength();
+
+ /* Create new properties with the value of non-hole dense elements. */
+ for (uint32_t i = 0; i < initialized; i++) {
+ if (obj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE))
+ continue;
+
+ if (!sparsifyDenseElement(cx, obj, i))
+ return false;
+ }
+
+ if (initialized)
+ obj->setDenseInitializedLengthUnchecked(0);
+
+ /*
+ * Reduce storage for dense elements which are now holes. Explicitly mark
+ * the elements capacity as zero, so that any attempts to add dense
+ * elements will be caught in ensureDenseElements.
+ */
+ if (obj->getDenseCapacity()) {
+ obj->shrinkElements(cx, 0);
+ obj->getElementsHeader()->capacity = 0;
+ }
+
+ return true;
+}
+
+bool
+NativeObject::willBeSparseElements(uint32_t requiredCapacity, uint32_t newElementsHint)
+{
+ MOZ_ASSERT(isNative());
+ MOZ_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
+
+ uint32_t cap = getDenseCapacity();
+ MOZ_ASSERT(requiredCapacity >= cap);
+
+ if (requiredCapacity > MAX_DENSE_ELEMENTS_COUNT)
+ return true;
+
+ uint32_t minimalDenseCount = requiredCapacity / SPARSE_DENSITY_RATIO;
+ if (newElementsHint >= minimalDenseCount)
+ return false;
+ minimalDenseCount -= newElementsHint;
+
+ if (minimalDenseCount > cap)
+ return true;
+
+ uint32_t len = getDenseInitializedLength();
+ const Value* elems = getDenseElements();
+ for (uint32_t i = 0; i < len; i++) {
+ if (!elems[i].isMagic(JS_ELEMENTS_HOLE) && !--minimalDenseCount)
+ return false;
+ }
+ return true;
+}
+
+/* static */ DenseElementResult
+NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeObject obj)
+{
+ /*
+ * Wait until after the object goes into dictionary mode, which must happen
+ * when sparsely packing any array with more than MIN_SPARSE_INDEX elements
+ * (see PropertyTree::MAX_HEIGHT).
+ */
+ if (!obj->inDictionaryMode())
+ return DenseElementResult::Incomplete;
+
+ /*
+ * Only measure the number of indexed properties every log(n) times when
+ * populating the object.
+ */
+ uint32_t slotSpan = obj->slotSpan();
+ if (slotSpan != RoundUpPow2(slotSpan))
+ return DenseElementResult::Incomplete;
+
+ /* Watch for conditions under which an object's elements cannot be dense. */
+ if (!obj->nonProxyIsExtensible() || obj->watched())
+ return DenseElementResult::Incomplete;
+
+ /*
+ * The indexes in the object need to be sufficiently dense before they can
+ * be converted to dense mode.
+ */
+ uint32_t numDenseElements = 0;
+ uint32_t newInitializedLength = 0;
+
+ RootedShape shape(cx, obj->lastProperty());
+ while (!shape->isEmptyShape()) {
+ uint32_t index;
+ if (IdIsIndex(shape->propid(), &index)) {
+ if (shape->attributes() == JSPROP_ENUMERATE &&
+ shape->hasDefaultGetter() &&
+ shape->hasDefaultSetter())
+ {
+ numDenseElements++;
+ newInitializedLength = Max(newInitializedLength, index + 1);
+ } else {
+ /*
+ * For simplicity, only densify the object if all indexed
+ * properties can be converted to dense elements.
+ */
+ return DenseElementResult::Incomplete;
+ }
+ }
+ shape = shape->previous();
+ }
+
+ if (numDenseElements * SPARSE_DENSITY_RATIO < newInitializedLength)
+ return DenseElementResult::Incomplete;
+
+ if (newInitializedLength > MAX_DENSE_ELEMENTS_COUNT)
+ return DenseElementResult::Incomplete;
+
+ /*
+ * This object meets all necessary restrictions, convert all indexed
+ * properties into dense elements.
+ */
+
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return DenseElementResult::Failure;
+
+ if (newInitializedLength > obj->getDenseCapacity()) {
+ if (!obj->growElements(cx, newInitializedLength))
+ return DenseElementResult::Failure;
+ }
+
+ obj->ensureDenseInitializedLength(cx, newInitializedLength, 0);
+
+ RootedValue value(cx);
+
+ shape = obj->lastProperty();
+ while (!shape->isEmptyShape()) {
+ jsid id = shape->propid();
+ uint32_t index;
+ if (IdIsIndex(id, &index)) {
+ value = obj->getSlot(shape->slot());
+
+ /*
+ * When removing a property from a dictionary, the specified
+ * property will be removed from the dictionary list and the
+ * last property will then be changed due to reshaping the object.
+ * Compute the next shape in the traverse, watching for such
+ * removals from the list.
+ */
+ if (shape != obj->lastProperty()) {
+ shape = shape->previous();
+ if (!obj->removeProperty(cx, id))
+ return DenseElementResult::Failure;
+ } else {
+ if (!obj->removeProperty(cx, id))
+ return DenseElementResult::Failure;
+ shape = obj->lastProperty();
+ }
+
+ obj->setDenseElement(index, value);
+ } else {
+ shape = shape->previous();
+ }
+ }
+
+ /*
+ * All indexed properties on the object are now dense, clear the indexed
+ * flag so that we will not start using sparse indexes again if we need
+ * to grow the object.
+ */
+ if (!obj->clearFlag(cx, BaseShape::INDEXED))
+ return DenseElementResult::Failure;
+
+ return DenseElementResult::Success;
+}
+
+// Given a requested capacity (in elements) and (potentially) the length of an
+// array for which elements are being allocated, compute an actual allocation
+// amount (in elements). (Allocation amounts include space for an
+// ObjectElements instance, so a return value of |N| implies
+// |N - ObjectElements::VALUES_PER_HEADER| usable elements.)
+//
+// The requested/actual allocation distinction is meant to:
+//
+// * preserve amortized O(N) time to add N elements;
+// * minimize the number of unused elements beyond an array's length, and
+// * provide at least SLOT_CAPACITY_MIN elements no matter what (so adding
+// the first several elements to small arrays only needs one allocation).
+//
+// Note: the structure and behavior of this method follow along with
+// UnboxedArrayObject::chooseCapacityIndex. Changes to the allocation strategy
+// in one should generally be matched by the other.
+/* static */ bool
+NativeObject::goodElementsAllocationAmount(ExclusiveContext* cx, uint32_t reqCapacity,
+ uint32_t length, uint32_t* goodAmount)
+{
+ if (reqCapacity > MAX_DENSE_ELEMENTS_COUNT) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ uint32_t reqAllocated = reqCapacity + ObjectElements::VALUES_PER_HEADER;
+
+ // Handle "small" requests primarily by doubling.
+ const uint32_t Mebi = 1 << 20;
+ if (reqAllocated < Mebi) {
+ uint32_t amount = mozilla::AssertedCast<uint32_t>(RoundUpPow2(reqAllocated));
+
+ // If |amount| would be 2/3 or more of the array's length, adjust
+ // it (up or down) to be equal to the array's length. This avoids
+ // allocating excess elements that aren't likely to be needed, either
+ // in this resizing or a subsequent one. The 2/3 factor is chosen so
+ // that exceptional resizings will at most triple the capacity, as
+ // opposed to the usual doubling.
+ uint32_t goodCapacity = amount - ObjectElements::VALUES_PER_HEADER;
+ if (length >= reqCapacity && goodCapacity > (length / 3) * 2)
+ amount = length + ObjectElements::VALUES_PER_HEADER;
+
+ if (amount < SLOT_CAPACITY_MIN)
+ amount = SLOT_CAPACITY_MIN;
+
+ *goodAmount = amount;
+
+ return true;
+ }
+
+ // The almost-doubling above wastes a lot of space for larger bucket sizes.
+ // For large amounts, switch to bucket sizes that obey this formula:
+ //
+ // count(n+1) = Math.ceil(count(n) * 1.125)
+ //
+ // where |count(n)| is the size of the nth bucket, measured in 2**20 slots.
+ // These bucket sizes still preserve amortized O(N) time to add N elements,
+ // just with a larger constant factor.
+ //
+ // The bucket size table below was generated with this JavaScript (and
+ // manual reformatting):
+ //
+ // for (let n = 1, i = 0; i < 34; i++) {
+ // print('0x' + (n * (1 << 20)).toString(16) + ', ');
+ // n = Math.ceil(n * 1.125);
+ // }
+ static const uint32_t BigBuckets[] = {
+ 0x100000, 0x200000, 0x300000, 0x400000, 0x500000, 0x600000, 0x700000,
+ 0x800000, 0x900000, 0xb00000, 0xd00000, 0xf00000, 0x1100000, 0x1400000,
+ 0x1700000, 0x1a00000, 0x1e00000, 0x2200000, 0x2700000, 0x2c00000,
+ 0x3200000, 0x3900000, 0x4100000, 0x4a00000, 0x5400000, 0x5f00000,
+ 0x6b00000, 0x7900000, 0x8900000, 0x9b00000, 0xaf00000, 0xc500000,
+ 0xde00000, 0xfa00000
+ };
+ MOZ_ASSERT(BigBuckets[ArrayLength(BigBuckets) - 1] <= MAX_DENSE_ELEMENTS_ALLOCATION);
+
+ // Pick the first bucket that'll fit |reqAllocated|.
+ for (uint32_t b : BigBuckets) {
+ if (b >= reqAllocated) {
+ *goodAmount = b;
+ return true;
+ }
+ }
+
+ // Otherwise, return the maximum bucket size.
+ *goodAmount = MAX_DENSE_ELEMENTS_ALLOCATION;
+ return true;
+}
+
+bool
+NativeObject::growElements(ExclusiveContext* cx, uint32_t reqCapacity)
+{
+ MOZ_ASSERT(nonProxyIsExtensible());
+ MOZ_ASSERT(canHaveNonEmptyElements());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ if (denseElementsAreCopyOnWrite())
+ MOZ_CRASH();
+
+ uint32_t oldCapacity = getDenseCapacity();
+ MOZ_ASSERT(oldCapacity < reqCapacity);
+
+ uint32_t newAllocated = 0;
+ if (is<ArrayObject>() && !as<ArrayObject>().lengthIsWritable()) {
+ MOZ_ASSERT(reqCapacity <= as<ArrayObject>().length());
+ MOZ_ASSERT(reqCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+ // Preserve the |capacity <= length| invariant for arrays with
+ // non-writable length. See also js::ArraySetLength which initially
+ // enforces this requirement.
+ newAllocated = reqCapacity + ObjectElements::VALUES_PER_HEADER;
+ } else {
+ if (!goodElementsAllocationAmount(cx, reqCapacity, getElementsHeader()->length, &newAllocated))
+ return false;
+ }
+
+ uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
+ MOZ_ASSERT(newCapacity > oldCapacity && newCapacity >= reqCapacity);
+
+ // If newCapacity exceeds MAX_DENSE_ELEMENTS_COUNT, the array should become
+ // sparse.
+ MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+
+ uint32_t initlen = getDenseInitializedLength();
+
+ HeapSlot* oldHeaderSlots = reinterpret_cast<HeapSlot*>(getElementsHeader());
+ HeapSlot* newHeaderSlots;
+ if (hasDynamicElements()) {
+ MOZ_ASSERT(oldCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+ uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER;
+
+ newHeaderSlots = ReallocateObjectBuffer<HeapSlot>(cx, this, oldHeaderSlots, oldAllocated, newAllocated);
+ if (!newHeaderSlots)
+ return false; // Leave elements at its old size.
+ } else {
+ newHeaderSlots = AllocateObjectBuffer<HeapSlot>(cx, this, newAllocated);
+ if (!newHeaderSlots)
+ return false; // Leave elements at its old size.
+ PodCopy(newHeaderSlots, oldHeaderSlots, ObjectElements::VALUES_PER_HEADER + initlen);
+ }
+
+ ObjectElements* newheader = reinterpret_cast<ObjectElements*>(newHeaderSlots);
+ newheader->capacity = newCapacity;
+ elements_ = newheader->elements();
+
+ Debug_SetSlotRangeToCrashOnTouch(elements_ + initlen, newCapacity - initlen);
+
+ return true;
+}
+
+void
+NativeObject::shrinkElements(ExclusiveContext* cx, uint32_t reqCapacity)
+{
+ uint32_t oldCapacity = getDenseCapacity();
+ MOZ_ASSERT(reqCapacity < oldCapacity);
+
+ MOZ_ASSERT(canHaveNonEmptyElements());
+ if (denseElementsAreCopyOnWrite())
+ MOZ_CRASH();
+
+ if (!hasDynamicElements())
+ return;
+
+ uint32_t newAllocated = 0;
+ MOZ_ALWAYS_TRUE(goodElementsAllocationAmount(cx, reqCapacity, 0, &newAllocated));
+ MOZ_ASSERT(oldCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+ uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER;
+ if (newAllocated == oldAllocated)
+ return; // Leave elements at its old size.
+
+ MOZ_ASSERT(newAllocated > ObjectElements::VALUES_PER_HEADER);
+ uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
+ MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+
+ HeapSlot* oldHeaderSlots = reinterpret_cast<HeapSlot*>(getElementsHeader());
+ HeapSlot* newHeaderSlots = ReallocateObjectBuffer<HeapSlot>(cx, this, oldHeaderSlots,
+ oldAllocated, newAllocated);
+ if (!newHeaderSlots) {
+ cx->recoverFromOutOfMemory();
+ return; // Leave elements at its old size.
+ }
+
+ ObjectElements* newheader = reinterpret_cast<ObjectElements*>(newHeaderSlots);
+ newheader->capacity = newCapacity;
+ elements_ = newheader->elements();
+}
+
+/* static */ bool
+NativeObject::CopyElementsForWrite(ExclusiveContext* cx, NativeObject* obj)
+{
+ MOZ_ASSERT(obj->denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!obj->denseElementsAreFrozen());
+
+ // The original owner of a COW elements array should never be modified.
+ MOZ_ASSERT(obj->getElementsHeader()->ownerObject() != obj);
+
+ uint32_t initlen = obj->getDenseInitializedLength();
+ uint32_t newAllocated = 0;
+ if (!goodElementsAllocationAmount(cx, initlen, 0, &newAllocated))
+ return false;
+
+ uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
+
+ // COPY_ON_WRITE flags is set only if obj is a dense array.
+ MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
+
+ JSObject::writeBarrierPre(obj->getElementsHeader()->ownerObject());
+
+ HeapSlot* newHeaderSlots = AllocateObjectBuffer<HeapSlot>(cx, obj, newAllocated);
+ if (!newHeaderSlots)
+ return false;
+ ObjectElements* newheader = reinterpret_cast<ObjectElements*>(newHeaderSlots);
+ js_memcpy(newheader, obj->getElementsHeader(),
+ (ObjectElements::VALUES_PER_HEADER + initlen) * sizeof(Value));
+
+ newheader->capacity = newCapacity;
+ newheader->clearCopyOnWrite();
+ obj->elements_ = newheader->elements();
+
+ Debug_SetSlotRangeToCrashOnTouch(obj->elements_ + initlen, newCapacity - initlen);
+
+ return true;
+}
+
+/* static */ bool
+NativeObject::allocSlot(ExclusiveContext* cx, HandleNativeObject obj, uint32_t* slotp)
+{
+ uint32_t slot = obj->slotSpan();
+ MOZ_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
+
+ // If this object is in dictionary mode, try to pull a free slot from the
+ // shape table's slot-number free list. Shapes without a ShapeTable have an
+ // empty free list, because we only purge ShapeTables with an empty free
+ // list.
+ if (obj->inDictionaryMode()) {
+ AutoCheckCannotGC nogc;
+ if (ShapeTable* table = obj->lastProperty()->maybeTable(nogc)) {
+ uint32_t last = table->freeList();
+ if (last != SHAPE_INVALID_SLOT) {
+#ifdef DEBUG
+ MOZ_ASSERT(last < slot);
+ uint32_t next = obj->getSlot(last).toPrivateUint32();
+ MOZ_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
+#endif
+
+ *slotp = last;
+
+ const Value& vref = obj->getSlot(last);
+ table->setFreeList(vref.toPrivateUint32());
+ obj->setSlot(last, UndefinedValue());
+ return true;
+ }
+ }
+ }
+
+ if (slot >= SHAPE_MAXIMUM_SLOT) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ *slotp = slot;
+
+ if (obj->inDictionaryMode() && !obj->setSlotSpan(cx, slot + 1))
+ return false;
+
+ return true;
+}
+
+void
+NativeObject::freeSlot(ExclusiveContext* cx, uint32_t slot)
+{
+ MOZ_ASSERT(slot < slotSpan());
+
+ if (inDictionaryMode()) {
+ // Ensure we have a ShapeTable as it stores the object's free list (the
+ // list of available slots in dictionary objects).
+ AutoCheckCannotGC nogc;
+ if (ShapeTable* table = lastProperty()->ensureTableForDictionary(cx, nogc)) {
+ uint32_t last = table->freeList();
+
+ // Can't afford to check the whole free list, but let's check the head.
+ MOZ_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan() && last != slot);
+
+ // Place all freed slots other than reserved slots (bug 595230) on the
+ // dictionary's free list.
+ if (JSSLOT_FREE(getClass()) <= slot) {
+ MOZ_ASSERT_IF(last != SHAPE_INVALID_SLOT, last < slotSpan());
+ setSlot(slot, PrivateUint32Value(last));
+ table->setFreeList(slot);
+ return;
+ }
+ } else {
+ // OOM while creating the ShapeTable holding the free list. We can
+ // recover from it - it just means we won't be able to reuse this
+ // slot later.
+ cx->recoverFromOutOfMemory();
+ }
+ }
+ setSlot(slot, UndefinedValue());
+}
+
+Shape*
+NativeObject::addDataProperty(ExclusiveContext* cx, jsid idArg, uint32_t slot, unsigned attrs)
+{
+ MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
+ RootedNativeObject self(cx, this);
+ RootedId id(cx, idArg);
+ return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0);
+}
+
+Shape*
+NativeObject::addDataProperty(ExclusiveContext* cx, HandlePropertyName name,
+ uint32_t slot, unsigned attrs)
+{
+ MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
+ RootedNativeObject self(cx, this);
+ RootedId id(cx, NameToId(name));
+ return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0);
+}
+
+template <AllowGC allowGC>
+bool
+js::NativeLookupOwnProperty(ExclusiveContext* cx,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<jsid, allowGC>::HandleType id,
+ typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+{
+ bool done;
+ return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done);
+}
+
+template bool
+js::NativeLookupOwnProperty<CanGC>(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ MutableHandleShape propp);
+
+template bool
+js::NativeLookupOwnProperty<NoGC>(ExclusiveContext* cx, NativeObject* const& obj, const jsid& id,
+ FakeMutableHandle<Shape*> propp);
+
+/*** [[DefineOwnProperty]] ***********************************************************************/
+
+static inline bool
+CallAddPropertyHook(ExclusiveContext* cx, HandleNativeObject obj, HandleShape shape,
+ HandleValue value)
+{
+ if (JSAddPropertyOp addProperty = obj->getClass()->getAddProperty()) {
+ if (!cx->shouldBeJSContext())
+ return false;
+
+ RootedId id(cx, shape->propid());
+ if (!CallJSAddPropertyOp(cx->asJSContext(), addProperty, obj, id, value)) {
+ obj->removeProperty(cx, shape->propid());
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool
+CallAddPropertyHookDense(ExclusiveContext* cx, HandleNativeObject obj, uint32_t index,
+ HandleValue value)
+{
+ // Inline addProperty for array objects.
+ if (obj->is<ArrayObject>()) {
+ ArrayObject* arr = &obj->as<ArrayObject>();
+ uint32_t length = arr->length();
+ if (index >= length)
+ arr->setLength(cx, index + 1);
+ return true;
+ }
+
+ if (JSAddPropertyOp addProperty = obj->getClass()->getAddProperty()) {
+ if (!cx->shouldBeJSContext())
+ return false;
+
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ RootedId id(cx, INT_TO_JSID(index));
+ if (!CallJSAddPropertyOp(cx->asJSContext(), addProperty, obj, id, value)) {
+ obj->setDenseElementHole(cx, index);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+UpdateShapeTypeAndValue(ExclusiveContext* cx, HandleNativeObject obj, HandleShape shape, const Value& value)
+{
+ jsid id = shape->propid();
+ if (shape->hasSlot()) {
+ obj->setSlotWithType(cx, shape, value, /* overwriting = */ false);
+
+ // Per the acquired properties analysis, when the shape of a partially
+ // initialized object is changed to its fully initialized shape, its
+ // group can be updated as well.
+ if (TypeNewScript* newScript = obj->groupRaw()->newScript()) {
+ if (newScript->initializedShape() == shape)
+ obj->setGroup(newScript->initializedGroup());
+ }
+ }
+ if (!shape->hasSlot() || !shape->hasDefaultGetter() || !shape->hasDefaultSetter())
+ MarkTypePropertyNonData(cx, obj, id);
+ if (!shape->writable())
+ MarkTypePropertyNonWritable(cx, obj, id);
+ return true;
+}
+
+static bool
+PurgeProtoChain(ExclusiveContext* cx, JSObject* objArg, HandleId id)
+{
+ /* Root locally so we can re-assign. */
+ RootedObject obj(cx, objArg);
+
+ RootedShape shape(cx);
+ while (obj) {
+ /* Lookups will not be cached through non-native protos. */
+ if (!obj->isNative())
+ break;
+
+ shape = obj->as<NativeObject>().lookup(cx, id);
+ if (shape)
+ return obj->as<NativeObject>().shadowingShapeChange(cx, *shape);
+
+ obj = obj->staticPrototype();
+ }
+
+ return true;
+}
+
+static bool
+PurgeEnvironmentChainHelper(ExclusiveContext* cx, HandleObject objArg, HandleId id)
+{
+ /* Re-root locally so we can re-assign. */
+ RootedObject obj(cx, objArg);
+
+ MOZ_ASSERT(obj->isNative());
+ MOZ_ASSERT(obj->isDelegate());
+
+ /* Lookups on integer ids cannot be cached through prototypes. */
+ if (JSID_IS_INT(id))
+ return true;
+
+ if (!PurgeProtoChain(cx, obj->staticPrototype(), id))
+ return false;
+
+ /*
+ * We must purge the environment chain only for Call objects as they are
+ * the only kind of cacheable non-global object that can gain properties
+ * after outer properties with the same names have been cached or
+ * traced. Call objects may gain such properties via eval introducing new
+ * vars; see bug 490364.
+ */
+ if (obj->is<CallObject>()) {
+ while ((obj = obj->enclosingEnvironment()) != nullptr) {
+ if (!PurgeProtoChain(cx, obj, id))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * PurgeEnvironmentChain does nothing if obj is not itself a prototype or
+ * parent environment, else it reshapes the scope and prototype chains it
+ * links. It calls PurgeEnvironmentChainHelper, which asserts that obj is
+ * flagged as a delegate (i.e., obj has ever been on a prototype or parent
+ * chain).
+ */
+static inline bool
+PurgeEnvironmentChain(ExclusiveContext* cx, HandleObject obj, HandleId id)
+{
+ if (obj->isDelegate() && obj->isNative())
+ return PurgeEnvironmentChainHelper(cx, obj, id);
+ return true;
+}
+
+static bool
+AddOrChangeProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc)
+{
+ desc.assertComplete();
+
+ if (!PurgeEnvironmentChain(cx, obj, id))
+ return false;
+
+ // Use dense storage for new indexed properties where possible.
+ if (JSID_IS_INT(id) &&
+ !desc.getter() &&
+ !desc.setter() &&
+ desc.attributes() == JSPROP_ENUMERATE &&
+ (!obj->isIndexed() || !obj->containsPure(id)) &&
+ !obj->is<TypedArrayObject>())
+ {
+ uint32_t index = JSID_TO_INT(id);
+ DenseElementResult edResult = obj->ensureDenseElements(cx, index, 1);
+ if (edResult == DenseElementResult::Failure)
+ return false;
+ if (edResult == DenseElementResult::Success) {
+ obj->setDenseElementWithType(cx, index, desc.value());
+ if (!CallAddPropertyHookDense(cx, obj, index, desc.value()))
+ return false;
+ return true;
+ }
+ }
+
+ RootedShape shape(cx, NativeObject::putProperty(cx, obj, id, desc.getter(), desc.setter(),
+ SHAPE_INVALID_SLOT, desc.attributes(), 0));
+ if (!shape)
+ return false;
+
+ if (!UpdateShapeTypeAndValue(cx, obj, shape, desc.value()))
+ return false;
+
+ // Clear any existing dense index after adding a sparse indexed property,
+ // and investigate converting the object to dense indexes.
+ if (JSID_IS_INT(id)) {
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ uint32_t index = JSID_TO_INT(id);
+ NativeObject::removeDenseElementForSparseIndex(cx, obj, index);
+ DenseElementResult edResult =
+ NativeObject::maybeDensifySparseElements(cx, obj);
+ if (edResult == DenseElementResult::Failure)
+ return false;
+ if (edResult == DenseElementResult::Success) {
+ MOZ_ASSERT(!desc.setter());
+ return CallAddPropertyHookDense(cx, obj, index, desc.value());
+ }
+ }
+
+ return CallAddPropertyHook(cx, obj, shape, desc.value());
+}
+
+static bool IsConfigurable(unsigned attrs) { return (attrs & JSPROP_PERMANENT) == 0; }
+static bool IsEnumerable(unsigned attrs) { return (attrs & JSPROP_ENUMERATE) != 0; }
+static bool IsWritable(unsigned attrs) { return (attrs & JSPROP_READONLY) == 0; }
+
+static bool IsAccessorDescriptor(unsigned attrs) {
+ return (attrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
+}
+
+static bool IsDataDescriptor(unsigned attrs) {
+ MOZ_ASSERT((attrs & (JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY)) == 0);
+ return !IsAccessorDescriptor(attrs);
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE bool
+GetExistingProperty(JSContext* cx,
+ typename MaybeRooted<Value, allowGC>::HandleType receiver,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<Shape*, allowGC>::HandleType shape,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType vp);
+
+static bool
+GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ HandleShape shape, MutableHandleValue vp)
+{
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ vp.set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
+ return true;
+ }
+ if (!cx->shouldBeJSContext())
+ return false;
+
+ MOZ_ASSERT(shape->propid() == id);
+ MOZ_ASSERT(obj->contains(cx, shape));
+
+ RootedValue receiver(cx, ObjectValue(*obj));
+ return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp);
+}
+
+/*
+ * If ES6 draft rev 37 9.1.6.3 ValidateAndApplyPropertyDescriptor step 4 would
+ * return early, because desc is redundant with an existing own property obj[id],
+ * then set *redundant = true and return true.
+ */
+static bool
+DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ HandleShape shape, unsigned shapeAttrs,
+ Handle<PropertyDescriptor> desc, bool *redundant)
+{
+ *redundant = false;
+
+ if (desc.hasConfigurable() && desc.configurable() != ((shapeAttrs & JSPROP_PERMANENT) == 0))
+ return true;
+ if (desc.hasEnumerable() && desc.enumerable() != ((shapeAttrs & JSPROP_ENUMERATE) != 0))
+ return true;
+ if (desc.isDataDescriptor()) {
+ if ((shapeAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0)
+ return true;
+ if (desc.hasWritable() && desc.writable() != ((shapeAttrs & JSPROP_READONLY) == 0))
+ return true;
+ if (desc.hasValue()) {
+ // Get the current value of the existing property.
+ RootedValue currentValue(cx);
+ if (!IsImplicitDenseOrTypedArrayElement(shape) &&
+ shape->hasSlot() &&
+ shape->hasDefaultGetter())
+ {
+ // Inline GetExistingPropertyValue in order to omit a type
+ // correctness assertion that's too strict for this particular
+ // call site. For details, see bug 1125624 comments 13-16.
+ currentValue.set(obj->getSlot(shape->slot()));
+ } else {
+ if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ return false;
+ }
+
+ // The specification calls for SameValue here, but it seems to be a
+ // bug. See <https://bugs.ecmascript.org/show_bug.cgi?id=3508>.
+ if (desc.value() != currentValue)
+ return true;
+ }
+
+ GetterOp existingGetterOp =
+ IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->getter();
+ if (desc.getter() != existingGetterOp)
+ return true;
+
+ SetterOp existingSetterOp =
+ IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->setter();
+ if (desc.setter() != existingSetterOp)
+ return true;
+ } else {
+ if (desc.hasGetterObject()) {
+ if (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != shape->getterObject())
+ return true;
+ }
+ if (desc.hasSetterObject()) {
+ if (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != shape->setterObject())
+ return true;
+ }
+ }
+
+ *redundant = true;
+ return true;
+}
+
+bool
+js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc_,
+ ObjectOpResult& result)
+{
+ desc_.assertValid();
+
+ // Section numbers and step numbers below refer to ES6 draft rev 36
+ // (17 March 2015).
+ //
+ // This function aims to implement 9.1.6 [[DefineOwnProperty]] as well as
+ // the [[DefineOwnProperty]] methods described in 9.4.2.1 (arrays), 9.4.4.2
+ // (arguments), and 9.4.5.3 (typed array views).
+
+ // Dispense with custom behavior of exotic native objects first.
+ if (obj->is<ArrayObject>()) {
+ // 9.4.2.1 step 2. Redefining an array's length is very special.
+ Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
+ if (id == NameToId(cx->names().length)) {
+ if (!cx->shouldBeJSContext())
+ return false;
+ return ArraySetLength(cx->asJSContext(), arr, id, desc_.attributes(), desc_.value(),
+ result);
+ }
+
+ // 9.4.2.1 step 3. Don't extend a fixed-length array.
+ uint32_t index;
+ if (IdIsIndex(id, &index)) {
+ if (WouldDefinePastNonwritableLength(obj, index))
+ return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+ }
+ } else if (obj->is<TypedArrayObject>()) {
+ // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
+ uint64_t index;
+ if (IsTypedArrayIndex(id, &index)) {
+ if (!cx->shouldBeJSContext())
+ return false;
+ return DefineTypedArrayElement(cx->asJSContext(), obj, index, desc_, result);
+ }
+ } else if (obj->is<ArgumentsObject>()) {
+ if (id == NameToId(cx->names().length)) {
+ // Either we are resolving the .length property on this object, or
+ // redefining it. In the latter case only, we must set a bit. To
+ // distinguish the two cases, we note that when resolving, the
+ // property won't already exist; whereas the first time it is
+ // redefined, it will.
+ if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
+ obj->as<ArgumentsObject>().markLengthOverridden();
+ } else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
+ // Do same thing as .length for [@@iterator].
+ if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
+ obj->as<ArgumentsObject>().markIteratorOverridden();
+ } else if (JSID_IS_INT(id)) {
+ if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
+ obj->as<ArgumentsObject>().markElementOverridden();
+ }
+ }
+
+ // 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2.
+ RootedShape shape(cx);
+ if (desc_.attributes() & JSPROP_RESOLVING) {
+ // We are being called from a resolve or enumerate hook to reify a
+ // lazily-resolved property. To avoid reentering the resolve hook and
+ // recursing forever, skip the resolve hook when doing this lookup.
+ NativeLookupOwnPropertyNoResolve(cx, obj, id, &shape);
+ } else {
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ return false;
+ }
+
+ // From this point, the step numbers refer to
+ // 9.1.6.3, ValidateAndApplyPropertyDescriptor.
+ // Step 1 is a redundant assertion.
+
+ // Filling in desc: Here we make a copy of the desc_ argument. We will turn
+ // it into a complete descriptor before updating obj. The spec algorithm
+ // does not explicitly do this, but the end result is the same. Search for
+ // "fill in" below for places where the filling-in actually occurs.
+ Rooted<PropertyDescriptor> desc(cx, desc_);
+
+ // Step 2.
+ if (!shape) {
+ if (!obj->nonProxyIsExtensible())
+ return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
+
+ // Fill in missing desc fields with defaults.
+ CompletePropertyDescriptor(&desc);
+
+ if (!AddOrChangeProperty(cx, obj, id, desc))
+ return false;
+ return result.succeed();
+ }
+
+ MOZ_ASSERT(shape);
+
+ // Steps 3-4. (Step 3 is a special case of step 4.) We use shapeAttrs as a
+ // stand-in for shape in many places below, since shape might not be a
+ // pointer to a real Shape (see IsImplicitDenseOrTypedArrayElement).
+ unsigned shapeAttrs = GetShapeAttributes(obj, shape);
+ bool redundant;
+ if (!DefinePropertyIsRedundant(cx, obj, id, shape, shapeAttrs, desc, &redundant))
+ return false;
+ if (redundant) {
+ // In cases involving JSOP_NEWOBJECT and JSOP_INITPROP, obj can have a
+ // type for this property that doesn't match the value in the slot.
+ // Update the type here, even though this DefineProperty call is
+ // otherwise a no-op. (See bug 1125624 comment 13.)
+ if (!IsImplicitDenseOrTypedArrayElement(shape) && desc.hasValue()) {
+ if (!UpdateShapeTypeAndValue(cx, obj, shape, desc.value()))
+ return false;
+ }
+ return result.succeed();
+ }
+
+ // Non-standard hack: Allow redefining non-configurable properties if
+ // JSPROP_REDEFINE_NONCONFIGURABLE is set _and_ the object is a non-DOM
+ // global. The idea is that a DOM object can never have such a thing on
+ // its proto chain directly on the web, so we should be OK optimizing
+ // access to accessors found on such an object. Bug 1105518 contemplates
+ // removing this hack.
+ bool skipRedefineChecks = (desc.attributes() & JSPROP_REDEFINE_NONCONFIGURABLE) &&
+ obj->is<GlobalObject>() &&
+ !obj->getClass()->isDOMClass();
+
+ // Step 5.
+ if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks) {
+ if (desc.hasConfigurable() && desc.configurable())
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+ if (desc.hasEnumerable() && desc.enumerable() != IsEnumerable(shapeAttrs))
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+ }
+
+ // Fill in desc.[[Configurable]] and desc.[[Enumerable]] if missing.
+ if (!desc.hasConfigurable())
+ desc.setConfigurable(IsConfigurable(shapeAttrs));
+ if (!desc.hasEnumerable())
+ desc.setEnumerable(IsEnumerable(shapeAttrs));
+
+ // Steps 6-9.
+ if (desc.isGenericDescriptor()) {
+ // Step 6. No further validation is required.
+
+ // Fill in desc. A generic descriptor has none of these fields, so copy
+ // everything from shape.
+ MOZ_ASSERT(!desc.hasValue());
+ MOZ_ASSERT(!desc.hasWritable());
+ MOZ_ASSERT(!desc.hasGetterObject());
+ MOZ_ASSERT(!desc.hasSetterObject());
+ if (IsDataDescriptor(shapeAttrs)) {
+ RootedValue currentValue(cx);
+ if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ return false;
+ desc.setValue(currentValue);
+ desc.setWritable(IsWritable(shapeAttrs));
+ } else {
+ desc.setGetterObject(shape->getterObject());
+ desc.setSetterObject(shape->setterObject());
+ }
+ } else if (desc.isDataDescriptor() != IsDataDescriptor(shapeAttrs)) {
+ // Step 7.
+ if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks)
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ MOZ_ASSERT(!obj->is<TypedArrayObject>());
+ if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
+ return false;
+ shape = obj->lookup(cx, id);
+ }
+
+ // Fill in desc fields with default values (steps 7.b.i and 7.c.i).
+ CompletePropertyDescriptor(&desc);
+ } else if (desc.isDataDescriptor()) {
+ // Step 8.
+ bool frozen = !IsConfigurable(shapeAttrs) && !IsWritable(shapeAttrs);
+ if (frozen && desc.hasWritable() && desc.writable() && !skipRedefineChecks)
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ if (frozen || !desc.hasValue()) {
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ MOZ_ASSERT(!obj->is<TypedArrayObject>());
+ if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
+ return false;
+ shape = obj->lookup(cx, id);
+ }
+
+ RootedValue currentValue(cx);
+ if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ return false;
+
+ if (!desc.hasValue()) {
+ // Fill in desc.[[Value]].
+ desc.setValue(currentValue);
+ } else {
+ // Step 8.a.ii.1.
+ bool same;
+ if (!cx->shouldBeJSContext())
+ return false;
+ if (!SameValue(cx->asJSContext(), desc.value(), currentValue, &same))
+ return false;
+ if (!same && !skipRedefineChecks)
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+ }
+ }
+
+ if (!desc.hasWritable())
+ desc.setWritable(IsWritable(shapeAttrs));
+ } else {
+ // Step 9.
+ MOZ_ASSERT(shape->isAccessorDescriptor());
+ MOZ_ASSERT(desc.isAccessorDescriptor());
+
+ // The spec says to use SameValue, but since the values in
+ // question are objects, we can just compare pointers.
+ if (desc.hasSetterObject()) {
+ if (!IsConfigurable(shapeAttrs) &&
+ desc.setterObject() != shape->setterObject() &&
+ !skipRedefineChecks)
+ {
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+ }
+ } else {
+ // Fill in desc.[[Set]] from shape.
+ desc.setSetterObject(shape->setterObject());
+ }
+ if (desc.hasGetterObject()) {
+ if (!IsConfigurable(shapeAttrs) &&
+ desc.getterObject() != shape->getterObject() &&
+ !skipRedefineChecks)
+ {
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+ }
+ } else {
+ // Fill in desc.[[Get]] from shape.
+ desc.setGetterObject(shape->getterObject());
+ }
+ }
+
+ // Step 10.
+ if (!AddOrChangeProperty(cx, obj, id, desc))
+ return false;
+ return result.succeed();
+}
+
+bool
+js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
+ ObjectOpResult& result)
+{
+ Rooted<PropertyDescriptor> desc(cx);
+ desc.initFields(nullptr, value, attrs, getter, setter);
+ return NativeDefineProperty(cx, obj, id, desc, result);
+}
+
+bool
+js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
+ HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
+ ObjectOpResult& result)
+{
+ RootedId id(cx, NameToId(name));
+ return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
+}
+
+bool
+js::NativeDefineElement(ExclusiveContext* cx, HandleNativeObject obj, uint32_t index,
+ HandleValue value, GetterOp getter, SetterOp setter, unsigned attrs,
+ ObjectOpResult& result)
+{
+ RootedId id(cx);
+ if (index <= JSID_INT_MAX) {
+ id = INT_TO_JSID(index);
+ return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
+ }
+
+ AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+ if (!IndexToId(cx, index, &id))
+ return false;
+
+ return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result);
+}
+
+bool
+js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ HandleValue value, JSGetterOp getter, JSSetterOp setter,
+ unsigned attrs)
+{
+ ObjectOpResult result;
+ if (!NativeDefineProperty(cx, obj, id, value, getter, setter, attrs, result))
+ return false;
+ if (!result) {
+ // Off-main-thread callers should not get here: they must call this
+ // function only with known-valid arguments. Populating a new
+ // PlainObject with configurable properties is fine.
+ if (!cx->shouldBeJSContext())
+ return false;
+ result.reportError(cx->asJSContext(), obj, id);
+ return false;
+ }
+ return true;
+}
+
+bool
+js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
+ HandleValue value, JSGetterOp getter, JSSetterOp setter,
+ unsigned attrs)
+{
+ RootedId id(cx, NameToId(name));
+ return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs);
+}
+
+
+/*** [[HasProperty]] *****************************************************************************/
+
+// ES6 draft rev31 9.1.7.1 OrdinaryHasProperty
+bool
+js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp)
+{
+ RootedNativeObject pobj(cx, obj);
+ RootedShape shape(cx);
+
+ // This loop isn't explicit in the spec algorithm. See the comment on step
+ // 7.a. below.
+ for (;;) {
+ // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+ bool done;
+ if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
+ return false;
+
+ // Step 4.
+ if (shape) {
+ *foundp = true;
+ return true;
+ }
+
+ // Step 5-6. The check for 'done' on this next line is tricky.
+ // done can be true in exactly these unlikely-sounding cases:
+ // - We're looking up an element, and pobj is a TypedArray that
+ // doesn't have that many elements.
+ // - We're being called from a resolve hook to assign to the property
+ // being resolved.
+ // What they all have in common is we do not want to keep walking
+ // the prototype chain, and always claim that the property
+ // doesn't exist.
+ RootedObject proto(cx, done ? nullptr : pobj->staticPrototype());
+
+ // Step 8.
+ if (!proto) {
+ *foundp = false;
+ return true;
+ }
+
+ // Step 7.a. If the prototype is also native, this step is a
+ // recursive tail call, and we don't need to go through all the
+ // plumbing of HasProperty; the top of the loop is where
+ // we're going to end up anyway. But if pobj is non-native,
+ // that optimization would be incorrect.
+ if (!proto->isNative())
+ return HasProperty(cx, proto, id, foundp);
+
+ pobj = &proto->as<NativeObject>();
+ }
+}
+
+
+/*** [[GetOwnPropertyDescriptor]] ****************************************************************/
+
+bool
+js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ RootedShape shape(cx);
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ return false;
+ if (!shape) {
+ desc.object().set(nullptr);
+ return true;
+ }
+
+ desc.setAttributes(GetShapeAttributes(obj, shape));
+ if (desc.isAccessorDescriptor()) {
+ MOZ_ASSERT(desc.isShared());
+
+ // The result of GetOwnPropertyDescriptor() must be either undefined or
+ // a complete property descriptor (per ES6 draft rev 32 (2015 Feb 2)
+ // 6.1.7.3, Invariants of the Essential Internal Methods).
+ //
+ // It is an unfortunate fact that in SM, properties can exist that have
+ // JSPROP_GETTER or JSPROP_SETTER but not both. In these cases, rather
+ // than return true with desc incomplete, we fill out the missing
+ // getter or setter with a null, following CompletePropertyDescriptor.
+ if (desc.hasGetterObject()) {
+ desc.setGetterObject(shape->getterObject());
+ } else {
+ desc.setGetterObject(nullptr);
+ desc.attributesRef() |= JSPROP_GETTER;
+ }
+ if (desc.hasSetterObject()) {
+ desc.setSetterObject(shape->setterObject());
+ } else {
+ desc.setSetterObject(nullptr);
+ desc.attributesRef() |= JSPROP_SETTER;
+ }
+
+ desc.value().setUndefined();
+ } else {
+ // This is either a straight-up data property or (rarely) a
+ // property with a JSGetterOp/JSSetterOp. The latter must be
+ // reported to the caller as a plain data property, so clear
+ // desc.getter/setter, and mask away the SHARED bit.
+ desc.setGetter(nullptr);
+ desc.setSetter(nullptr);
+ desc.attributesRef() &= ~JSPROP_SHARED;
+
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
+ } else {
+ if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value()))
+ return false;
+ }
+ }
+
+ desc.object().set(obj);
+ desc.assertComplete();
+ return true;
+}
+
+
+/*** [[Get]] *************************************************************************************/
+
+static inline bool
+CallGetter(JSContext* cx, HandleObject obj, HandleValue receiver, HandleShape shape,
+ MutableHandleValue vp)
+{
+ MOZ_ASSERT(!shape->hasDefaultGetter());
+
+ if (shape->hasGetterValue()) {
+ RootedValue getter(cx, shape->getterValue());
+ return js::CallGetter(cx, receiver, getter, vp);
+ }
+
+ // In contrast to normal getters JSGetterOps always want the holder.
+ RootedId id(cx, shape->propid());
+ return CallJSGetterOp(cx, shape->getterOp(), obj, id, vp);
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE bool
+GetExistingProperty(JSContext* cx,
+ typename MaybeRooted<Value, allowGC>::HandleType receiver,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<Shape*, allowGC>::HandleType shape,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
+{
+ if (shape->hasSlot()) {
+ vp.set(obj->getSlot(shape->slot()));
+ MOZ_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) &&
+ !obj->isSingleton() &&
+ !obj->template is<EnvironmentObject>() &&
+ shape->hasDefaultGetter(),
+ ObjectGroupHasProperty(cx, obj->group(), shape->propid(), vp));
+ } else {
+ vp.setUndefined();
+ }
+ if (shape->hasDefaultGetter())
+ return true;
+
+ {
+ jsbytecode* pc;
+ JSScript* script = cx->currentScript(&pc);
+ if (script && script->hasBaselineScript()) {
+ switch (JSOp(*pc)) {
+ case JSOP_GETPROP:
+ case JSOP_CALLPROP:
+ case JSOP_LENGTH:
+ script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!allowGC)
+ return false;
+
+ if (!CallGetter(cx,
+ MaybeRooted<JSObject*, allowGC>::toHandle(obj),
+ MaybeRooted<Value, allowGC>::toHandle(receiver),
+ MaybeRooted<Shape*, allowGC>::toHandle(shape),
+ MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
+ {
+ return false;
+ }
+
+ // Ancient nonstandard extension: via the JSAPI it's possible to create a
+ // data property that has both a slot and a getter. In that case, copy the
+ // value returned by the getter back into the slot.
+ if (shape->hasSlot() && obj->contains(cx, shape))
+ obj->setSlot(shape->slot(), vp);
+
+ return true;
+}
+
+bool
+js::NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObject obj,
+ HandleShape shape, MutableHandleValue vp)
+{
+ RootedValue receiverValue(cx, ObjectValue(*receiver));
+ return GetExistingProperty<CanGC>(cx, receiverValue, obj, shape, vp);
+}
+
+/*
+ * Given pc pointing after a property accessing bytecode, return true if the
+ * access is "property-detecting" -- that is, if we shouldn't warn about it
+ * even if no such property is found and strict warnings are enabled.
+ */
+static bool
+Detecting(JSContext* cx, JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(script->containsPC(pc));
+
+ // Skip jump target opcodes.
+ while (pc < script->codeEnd() && BytecodeIsJumpTarget(JSOp(*pc)))
+ pc = GetNextPc(pc);
+
+ MOZ_ASSERT(script->containsPC(pc));
+ if (pc >= script->codeEnd())
+ return false;
+
+ // General case: a branch or equality op follows the access.
+ JSOp op = JSOp(*pc);
+ if (CodeSpec[op].format & JOF_DETECTING)
+ return true;
+
+ jsbytecode* endpc = script->codeEnd();
+
+ if (op == JSOP_NULL) {
+ // Special case #1: don't warn about (obj.prop == null).
+ if (++pc < endpc) {
+ op = JSOp(*pc);
+ return op == JSOP_EQ || op == JSOP_NE;
+ }
+ return false;
+ }
+
+ if (op == JSOP_GETGNAME || op == JSOP_GETNAME) {
+ // Special case #2: don't warn about (obj.prop == undefined).
+ JSAtom* atom = script->getAtom(GET_UINT32_INDEX(pc));
+ if (atom == cx->names().undefined &&
+ (pc += CodeSpec[op].length) < endpc) {
+ op = JSOp(*pc);
+ return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
+ }
+ }
+
+ return false;
+}
+
+enum IsNameLookup { NotNameLookup = false, NameLookup = true };
+
+/*
+ * Finish getting the property `receiver[id]` after looking at every object on
+ * the prototype chain and not finding any such property.
+ *
+ * Per the spec, this should just set the result to `undefined` and call it a
+ * day. However:
+ *
+ * 1. We add support for the nonstandard JSClass::getProperty hook.
+ *
+ * 2. This function also runs when we're evaluating an expression that's an
+ * Identifier (that is, an unqualified name lookup), so we need to figure
+ * out if that's what's happening and throw a ReferenceError if so.
+ *
+ * 3. We also emit an optional warning for this. (It's not super useful on the
+ * web, as there are too many false positives, but anecdotally useful in
+ * Gecko code.)
+ */
+static bool
+GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
+ HandleValue receiver, IsNameLookup nameLookup, MutableHandleValue vp)
+{
+ vp.setUndefined();
+
+ // Non-standard extension: Call the getProperty hook. If it sets vp to a
+ // value other than undefined, we're done. If not, fall through to the
+ // warning/error checks below.
+ if (JSGetterOp getProperty = obj->getClass()->getGetProperty()) {
+ if (!CallJSGetterOp(cx, getProperty, obj, id, vp))
+ return false;
+
+ if (!vp.isUndefined())
+ return true;
+ }
+
+ // If we are doing a name lookup, this is a ReferenceError.
+ if (nameLookup)
+ return ReportIsNotDefined(cx, id);
+
+ // Give a strict warning if foo.bar is evaluated by a script for an object
+ // foo with no property named 'bar'.
+ //
+ // Don't warn if extra warnings not enabled or for random getprop
+ // operations.
+ if (!cx->compartment()->behaviors().extraWarnings(cx))
+ return true;
+
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ if (!script)
+ return true;
+
+ if (*pc != JSOP_GETPROP && *pc != JSOP_GETELEM)
+ return true;
+
+ // Don't warn repeatedly for the same script.
+ if (script->warnedAboutUndefinedProp())
+ return true;
+
+ // Don't warn in self-hosted code (where the further presence of
+ // JS::RuntimeOptions::werror() would result in impossible-to-avoid
+ // errors to entirely-innocent client code).
+ if (script->selfHosted())
+ return true;
+
+ // We may just be checking if that object has an iterator.
+ if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
+ return true;
+
+ // Do not warn about tests like (obj[prop] == undefined).
+ pc += CodeSpec[*pc].length;
+ if (Detecting(cx, script, pc))
+ return true;
+
+ unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
+ script->setWarnedAboutUndefinedProp();
+
+ // Ok, bad undefined property reference: whine about it.
+ RootedValue val(cx, IdToValue(id));
+ return ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, JSDVG_IGNORE_STACK, val,
+ nullptr, nullptr, nullptr);
+}
+
+/* The NoGC version of GetNonexistentProperty, present only to make types line up. */
+bool
+GetNonexistentProperty(JSContext* cx, NativeObject* const& obj, const jsid& id, const Value& receiver,
+ IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
+{
+ return false;
+}
+
+static inline bool
+GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue receiver,
+ IsNameLookup nameLookup, MutableHandleValue vp)
+{
+ JS_CHECK_RECURSION(cx, return false);
+ if (nameLookup) {
+ // When nameLookup is true, GetProperty implements ES6 rev 34 (2015 Feb
+ // 20) 8.1.1.2.6 GetBindingValue, with step 3 (the call to HasProperty)
+ // and step 6 (the call to Get) fused so that only a single lookup is
+ // needed.
+ //
+ // If we get here, we've reached a non-native object. Fall back on the
+ // algorithm as specified, with two separate lookups. (Note that we
+ // throw ReferenceErrors regardless of strictness, technically a bug.)
+
+ bool found;
+ if (!HasProperty(cx, obj, id, &found))
+ return false;
+ if (!found)
+ return ReportIsNotDefined(cx, id);
+ }
+
+ return GetProperty(cx, obj, receiver, id, vp);
+}
+
+static inline bool
+GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, const Value& receiver,
+ IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
+{
+ JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
+ if (nameLookup)
+ return false;
+ return GetPropertyNoGC(cx, obj, receiver, id, vp.address());
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE bool
+NativeGetPropertyInline(JSContext* cx,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<Value, allowGC>::HandleType receiver,
+ typename MaybeRooted<jsid, allowGC>::HandleType id,
+ IsNameLookup nameLookup,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
+{
+ typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
+ typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
+
+ // This loop isn't explicit in the spec algorithm. See the comment on step
+ // 4.d below.
+ for (;;) {
+ // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+ bool done;
+ if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done))
+ return false;
+
+ if (shape) {
+ // Steps 5-8. Special case for dense elements because
+ // GetExistingProperty doesn't support those.
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
+ return true;
+ }
+ return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp);
+ }
+
+ // Steps 4.a-b. The check for 'done' on this next line is tricky.
+ // done can be true in exactly these unlikely-sounding cases:
+ // - We're looking up an element, and pobj is a TypedArray that
+ // doesn't have that many elements.
+ // - We're being called from a resolve hook to assign to the property
+ // being resolved.
+ // What they all have in common is we do not want to keep walking
+ // the prototype chain.
+ RootedObject proto(cx, done ? nullptr : pobj->staticPrototype());
+
+ // Step 4.c. The spec algorithm simply returns undefined if proto is
+ // null, but see the comment on GetNonexistentProperty.
+ if (!proto)
+ return GetNonexistentProperty(cx, obj, id, receiver, nameLookup, vp);
+
+ // Step 4.d. If the prototype is also native, this step is a
+ // recursive tail call, and we don't need to go through all the
+ // plumbing of JSObject::getGeneric; the top of the loop is where
+ // we're going to end up anyway. But if pobj is non-native,
+ // that optimization would be incorrect.
+ if (proto->getOpsGetProperty())
+ return GeneralizedGetProperty(cx, proto, id, receiver, nameLookup, vp);
+
+ pobj = &proto->as<NativeObject>();
+ }
+}
+
+bool
+js::NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp)
+{
+ return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, NotNameLookup, vp);
+}
+
+bool
+js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp)
+{
+ AutoAssertNoException noexc(cx);
+ return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, NotNameLookup, vp);
+}
+
+bool
+js::GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
+ RootedValue receiver(cx, ObjectValue(*obj));
+ if (obj->getOpsGetProperty())
+ return GeneralizedGetProperty(cx, obj, id, receiver, NameLookup, vp);
+ return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), receiver, id, NameLookup, vp);
+}
+
+
+/*** [[Set]] *************************************************************************************/
+
+static bool
+MaybeReportUndeclaredVarAssignment(JSContext* cx, HandleString propname)
+{
+ unsigned flags;
+ {
+ jsbytecode* pc;
+ JSScript* script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT);
+ if (!script)
+ return true;
+
+ // If the code is not strict and extra warnings aren't enabled, then no
+ // check is needed.
+ if (IsStrictSetPC(pc))
+ flags = JSREPORT_ERROR;
+ else if (cx->compartment()->behaviors().extraWarnings(cx))
+ flags = JSREPORT_WARNING | JSREPORT_STRICT;
+ else
+ return true;
+ }
+
+ JSAutoByteString bytes;
+ if (!bytes.encodeUtf8(cx, propname))
+ return false;
+ return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr,
+ JSMSG_UNDECLARED_VAR, bytes.ptr());
+}
+
+/*
+ * Finish assignment to a shapeful data property of a native object obj. This
+ * conforms to no standard and there is a lot of legacy baggage here.
+ */
+static bool
+NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
+ HandleValue v, HandleValue receiver, ObjectOpResult& result)
+{
+ MOZ_ASSERT(obj->isNative());
+ MOZ_ASSERT(shape->isDataDescriptor());
+
+ if (shape->hasDefaultSetter()) {
+ if (shape->hasSlot()) {
+ // The common path. Standard data property.
+
+ // Global properties declared with 'var' will be initially
+ // defined with an undefined value, so don't treat the initial
+ // assignments to such properties as overwrites.
+ bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
+ obj->setSlotWithType(cx, shape, v, overwriting);
+ return result.succeed();
+ }
+
+ // Bizarre: shared (slotless) property that's writable but has no
+ // JSSetterOp. JS code can't define such a property, but it can be done
+ // through the JSAPI. Treat it as non-writable.
+ return result.fail(JSMSG_GETTER_ONLY);
+ }
+
+ MOZ_ASSERT(!obj->is<WithEnvironmentObject>()); // See bug 1128681.
+
+ uint32_t sample = cx->runtime()->propertyRemovals;
+ RootedId id(cx, shape->propid());
+ RootedValue value(cx, v);
+ if (!CallJSSetterOp(cx, shape->setterOp(), obj, id, &value, result))
+ return false;
+
+ // Update any slot for the shape with the value produced by the setter,
+ // unless the setter deleted the shape.
+ if (shape->hasSlot() &&
+ (MOZ_LIKELY(cx->runtime()->propertyRemovals == sample) ||
+ obj->contains(cx, shape)))
+ {
+ obj->setSlot(shape->slot(), value);
+ }
+
+ return true; // result is populated by CallJSSetterOp above.
+}
+
+/*
+ * When a [[Set]] operation finds no existing property with the given id
+ * or finds a writable data property on the prototype chain, we end up here.
+ * Finish the [[Set]] by defining a new property on receiver.
+ *
+ * This implements ES6 draft rev 28, 9.1.9 [[Set]] steps 5.b-f, but it
+ * is really old code and there are a few barnacles.
+ */
+bool
+js::SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiverValue,
+ ObjectOpResult& result)
+{
+ // Step 5.b.
+ if (!receiverValue.isObject())
+ return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
+ RootedObject receiver(cx, &receiverValue.toObject());
+
+ bool existing;
+ {
+ // Steps 5.c-d.
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, receiver, id, &desc))
+ return false;
+
+ existing = !!desc.object();
+
+ // Step 5.e.
+ if (existing) {
+ // Step 5.e.i.
+ if (desc.isAccessorDescriptor())
+ return result.fail(JSMSG_OVERWRITING_ACCESSOR);
+
+ // Step 5.e.ii.
+ if (!desc.writable())
+ return result.fail(JSMSG_READ_ONLY);
+ }
+ }
+
+ // Invalidate SpiderMonkey-specific caches or bail.
+ const Class* clasp = receiver->getClass();
+
+ // Purge the property cache of now-shadowed id in receiver's environment chain.
+ if (!PurgeEnvironmentChain(cx, receiver, id))
+ return false;
+
+ // Steps 5.e.iii-iv. and 5.f.i. Define the new data property.
+ unsigned attrs =
+ existing
+ ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
+ : JSPROP_ENUMERATE;
+ JSGetterOp getter = clasp->getGetProperty();
+ JSSetterOp setter = clasp->getSetProperty();
+ MOZ_ASSERT(getter != JS_PropertyStub);
+ MOZ_ASSERT(setter != JS_StrictPropertyStub);
+ if (!DefineProperty(cx, receiver, id, v, getter, setter, attrs, result))
+ return false;
+
+ // If the receiver is native, there is one more legacy wrinkle: the class
+ // JSSetterOp is called after defining the new property.
+ if (setter && receiver->is<NativeObject>()) {
+ if (!result)
+ return true;
+
+ Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
+ if (!cx->shouldBeJSContext())
+ return false;
+ RootedValue receiverValue(cx, ObjectValue(*receiver));
+
+ // This lookup is a bit unfortunate, but not nearly the most
+ // unfortunate thing about Class getters and setters. Since the above
+ // DefineProperty call succeeded, receiver is native, and the property
+ // has a setter (and thus can't be a dense element), this lookup is
+ // guaranteed to succeed.
+ RootedShape shape(cx, nativeReceiver->lookup(cx, id));
+ MOZ_ASSERT(shape);
+ return NativeSetExistingDataProperty(cx->asJSContext(), nativeReceiver, shape, v,
+ receiverValue, result);
+ }
+
+ return true;
+}
+
+// When setting |id| for |receiver| and |obj| has no property for id, continue
+// the search up the prototype chain.
+bool
+js::SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ MOZ_ASSERT(!obj->is<ProxyObject>());
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (proto)
+ return SetProperty(cx, proto, id, v, receiver, result);
+
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+}
+
+/*
+ * Implement "the rest of" assignment to a property when no property receiver[id]
+ * was found anywhere on the prototype chain.
+ *
+ * FIXME: This should be updated to follow ES6 draft rev 28, section 9.1.9,
+ * steps 4.d.i and 5.
+ */
+static bool
+SetNonexistentProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
+ QualifiedBool qualified, ObjectOpResult& result)
+{
+ if (!qualified && receiver.isObject() && receiver.toObject().isUnqualifiedVarObj()) {
+ RootedString idStr(cx, JSID_TO_STRING(id));
+ if (!MaybeReportUndeclaredVarAssignment(cx, idStr))
+ return false;
+ }
+
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+}
+
+/*
+ * Set an existing own property obj[index] that's a dense element or typed
+ * array element.
+ */
+static bool
+SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
+ ObjectOpResult& result)
+{
+ if (obj->is<TypedArrayObject>()) {
+ double d;
+ if (!ToNumber(cx, v, &d))
+ return false;
+
+ // Silently do nothing for out-of-bounds sets, for consistency with
+ // current behavior. (ES6 currently says to throw for this in
+ // strict mode code, so we may eventually need to change.)
+ uint32_t len = obj->as<TypedArrayObject>().length();
+ if (index < len)
+ TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
+ return result.succeed();
+ }
+
+ if (WouldDefinePastNonwritableLength(obj, index))
+ return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
+
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ obj->setDenseElementWithType(cx, index, v);
+ return result.succeed();
+}
+
+/*
+ * Finish the assignment `receiver[id] = v` when an existing property (shape)
+ * has been found on a native object (pobj). This implements ES6 draft rev 32
+ * (2015 Feb 2) 9.1.9 steps 5 and 6.
+ *
+ * It is necessary to pass both id and shape because shape could be an implicit
+ * dense or typed array element (i.e. not actually a pointer to a Shape).
+ */
+static bool
+SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, HandleNativeObject pobj, HandleShape shape,
+ ObjectOpResult& result)
+{
+ // Step 5 for dense elements.
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ // Step 5.a.
+ if (pobj->getElementsHeader()->isFrozen())
+ return result.fail(JSMSG_READ_ONLY);
+
+ // Pure optimization for the common case:
+ if (receiver.isObject() && pobj == &receiver.toObject())
+ return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result);
+
+ // Steps 5.b-f.
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+ }
+
+ // Step 5 for all other properties.
+ if (shape->isDataDescriptor()) {
+ // Step 5.a.
+ if (!shape->writable())
+ return result.fail(JSMSG_READ_ONLY);
+
+ // steps 5.c-f.
+ if (receiver.isObject() && pobj == &receiver.toObject()) {
+ // Pure optimization for the common case. There's no point performing
+ // the lookup in step 5.c again, as our caller just did it for us. The
+ // result is |shape|.
+
+ // Steps 5.e.i-ii.
+ if (pobj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
+ Rooted<ArrayObject*> arr(cx, &pobj->as<ArrayObject>());
+ return ArraySetLength(cx, arr, id, shape->attributes(), v, result);
+ }
+ return NativeSetExistingDataProperty(cx, pobj, shape, v, receiver, result);
+ }
+
+ // SpiderMonkey special case: assigning to an inherited slotless
+ // property causes the setter to be called, instead of shadowing,
+ // unless the existing property is JSPROP_SHADOWABLE (see bug 552432).
+ if (!shape->hasSlot() && !shape->hasShadowable()) {
+ // Even weirder sub-special-case: inherited slotless data property
+ // with default setter. Wut.
+ if (shape->hasDefaultSetter())
+ return result.succeed();
+
+ RootedValue valCopy(cx, v);
+ return CallJSSetterOp(cx, shape->setterOp(), obj, id, &valCopy, result);
+ }
+
+ // Shadow pobj[id] by defining a new data property receiver[id].
+ // Delegate everything to SetPropertyByDefining.
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+ }
+
+ // Steps 6-11.
+ MOZ_ASSERT(shape->isAccessorDescriptor());
+ MOZ_ASSERT_IF(!shape->hasSetterObject(), shape->hasDefaultSetter());
+ if (shape->hasDefaultSetter())
+ return result.fail(JSMSG_GETTER_ONLY);
+
+ RootedValue setter(cx, ObjectValue(*shape->setterObject()));
+ if (!js::CallSetter(cx, receiver, setter, v))
+ return false;
+
+ return result.succeed();
+}
+
+bool
+js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+ HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result)
+{
+ // Fire watchpoints, if any.
+ RootedValue v(cx, value);
+ if (MOZ_UNLIKELY(obj->watched())) {
+ WatchpointMap* wpmap = cx->compartment()->watchpointMap;
+ if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v))
+ return false;
+ }
+
+ // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
+ // method for ordinary objects. We substitute our own names for these names
+ // used in the spec: O -> pobj, P -> id, ownDesc -> shape.
+ RootedShape shape(cx);
+ RootedNativeObject pobj(cx, obj);
+
+ // This loop isn't explicit in the spec algorithm. See the comment on step
+ // 4.c.i below. (There's a very similar loop in the NativeGetProperty
+ // implementation, but unfortunately not similar enough to common up.)
+ for (;;) {
+ // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+ bool done;
+ if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
+ return false;
+
+ if (shape) {
+ // Steps 5-6.
+ return SetExistingProperty(cx, obj, id, v, receiver, pobj, shape, result);
+ }
+
+ // Steps 4.a-b. The check for 'done' on this next line is tricky.
+ // done can be true in exactly these unlikely-sounding cases:
+ // - We're looking up an element, and pobj is a TypedArray that
+ // doesn't have that many elements.
+ // - We're being called from a resolve hook to assign to the property
+ // being resolved.
+ // What they all have in common is we do not want to keep walking
+ // the prototype chain.
+ RootedObject proto(cx, done ? nullptr : pobj->staticPrototype());
+ if (!proto) {
+ // Step 4.d.i (and step 5).
+ return SetNonexistentProperty(cx, id, v, receiver, qualified, result);
+ }
+
+ // Step 4.c.i. If the prototype is also native, this step is a
+ // recursive tail call, and we don't need to go through all the
+ // plumbing of SetProperty; the top of the loop is where we're going to
+ // end up anyway. But if pobj is non-native, that optimization would be
+ // incorrect.
+ if (!proto->isNative()) {
+ // Unqualified assignments are not specified to go through [[Set]]
+ // at all, but they do go through this function. So check for
+ // unqualified assignment to a nonexistent global (a strict error).
+ if (!qualified) {
+ bool found;
+ if (!HasProperty(cx, proto, id, &found))
+ return false;
+ if (!found)
+ return SetNonexistentProperty(cx, id, v, receiver, qualified, result);
+ }
+
+ return SetProperty(cx, proto, id, v, receiver, result);
+ }
+ pobj = &proto->as<NativeObject>();
+ }
+}
+
+bool
+js::NativeSetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ RootedId id(cx);
+ if (!IndexToId(cx, index, &id))
+ return false;
+ return NativeSetProperty(cx, obj, id, v, receiver, Qualified, result);
+}
+
+/*** [[Delete]] **********************************************************************************/
+
+// ES6 draft rev31 9.1.10 [[Delete]]
+bool
+js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
+ ObjectOpResult& result)
+{
+ // Steps 2-3.
+ RootedShape shape(cx);
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ return false;
+
+ // Step 4.
+ if (!shape) {
+ // If no property call the class's delProperty hook, passing succeeded
+ // as the result parameter. This always succeeds when there is no hook.
+ return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result);
+ }
+
+ cx->runtime()->gc.poke();
+
+ // Step 6. Non-configurable property.
+ if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT)
+ return result.failCantDelete();
+
+ if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result))
+ return false;
+ if (!result)
+ return true;
+
+ // Step 5.
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ // Typed array elements are non-configurable.
+ MOZ_ASSERT(!obj->is<TypedArrayObject>());
+
+ if (!obj->maybeCopyElementsForWrite(cx))
+ return false;
+
+ obj->setDenseElementHole(cx, JSID_TO_INT(id));
+ } else {
+ if (!obj->removeProperty(cx, id))
+ return false;
+ }
+
+ return SuppressDeletedProperty(cx, obj, id);
+}
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
new file mode 100644
index 000000000..d2c06eabc
--- /dev/null
+++ b/js/src/vm/NativeObject.h
@@ -0,0 +1,1552 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_NativeObject_h
+#define vm_NativeObject_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+
+#include <stdint.h>
+
+#include "jsfriendapi.h"
+#include "jsobj.h"
+#include "NamespaceImports.h"
+
+#include "gc/Barrier.h"
+#include "gc/Heap.h"
+#include "gc/Marking.h"
+#include "js/Value.h"
+#include "vm/Shape.h"
+#include "vm/ShapedObject.h"
+#include "vm/String.h"
+#include "vm/TypeInference.h"
+
+namespace js {
+
+class Shape;
+class TenuringTracer;
+
+/*
+ * To really poison a set of values, using 'magic' or 'undefined' isn't good
+ * enough since often these will just be ignored by buggy code (see bug 629974)
+ * in debug builds and crash in release builds. Instead, we use a safe-for-crash
+ * pointer.
+ */
+static MOZ_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(Value* beg, Value* end)
+{
+#ifdef DEBUG
+ for (Value* v = beg; v != end; ++v)
+ v->setObject(*reinterpret_cast<JSObject*>(0x48));
+#endif
+}
+
+static MOZ_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(Value* vec, size_t len)
+{
+#ifdef DEBUG
+ Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
+#endif
+}
+
+static MOZ_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(GCPtrValue* vec, size_t len)
+{
+#ifdef DEBUG
+ Debug_SetValueRangeToCrashOnTouch((Value*) vec, len);
+#endif
+}
+
+static MOZ_ALWAYS_INLINE void
+Debug_SetSlotRangeToCrashOnTouch(HeapSlot* vec, uint32_t len)
+{
+#ifdef DEBUG
+ Debug_SetValueRangeToCrashOnTouch((Value*) vec, len);
+#endif
+}
+
+static MOZ_ALWAYS_INLINE void
+Debug_SetSlotRangeToCrashOnTouch(HeapSlot* begin, HeapSlot* end)
+{
+#ifdef DEBUG
+ Debug_SetValueRangeToCrashOnTouch((Value*) begin, end - begin);
+#endif
+}
+
+class ArrayObject;
+
+/*
+ * ES6 20130308 draft 8.4.2.4 ArraySetLength.
+ *
+ * |id| must be "length", |attrs| are the attributes to be used for the newly-
+ * changed length property, |value| is the value for the new length, and
+ * |result| receives an error code if the change is invalid.
+ */
+extern bool
+ArraySetLength(JSContext* cx, Handle<ArrayObject*> obj, HandleId id,
+ unsigned attrs, HandleValue value, ObjectOpResult& result);
+
+/*
+ * Elements header used for native objects. The elements component of such objects
+ * offers an efficient representation for all or some of the indexed properties
+ * of the object, using a flat array of Values rather than a shape hierarchy
+ * stored in the object's slots. This structure is immediately followed by an
+ * array of elements, with the elements member in an object pointing to the
+ * beginning of that array (the end of this structure).
+ * See below for usage of this structure.
+ *
+ * The sets of properties represented by an object's elements and slots
+ * are disjoint. The elements contain only indexed properties, while the slots
+ * can contain both named and indexed properties; any indexes in the slots are
+ * distinct from those in the elements. If isIndexed() is false for an object,
+ * all indexed properties (if any) are stored in the dense elements.
+ *
+ * Indexes will be stored in the object's slots instead of its elements in
+ * the following case:
+ * - there are more than MIN_SPARSE_INDEX slots total and the load factor
+ * (COUNT / capacity) is less than 0.25
+ * - a property is defined that has non-default property attributes.
+ *
+ * We track these pieces of metadata for dense elements:
+ * - The length property as a uint32_t, accessible for array objects with
+ * ArrayObject::{length,setLength}(). This is unused for non-arrays.
+ * - The number of element slots (capacity), gettable with
+ * getDenseCapacity().
+ * - The array's initialized length, accessible with
+ * getDenseInitializedLength().
+ *
+ * Holes in the array are represented by MagicValue(JS_ELEMENTS_HOLE) values.
+ * These indicate indexes which are not dense properties of the array. The
+ * property may, however, be held by the object's properties.
+ *
+ * The capacity and length of an object's elements are almost entirely
+ * unrelated! In general the length may be greater than, less than, or equal
+ * to the capacity. The first case occurs with |new Array(100)|. The length
+ * is 100, but the capacity remains 0 (indices below length and above capacity
+ * must be treated as holes) until elements between capacity and length are
+ * set. The other two cases are common, depending upon the number of elements
+ * in an array and the underlying allocator used for element storage.
+ *
+ * The only case in which the capacity and length of an object's elements are
+ * related is when the object is an array with non-writable length. In this
+ * case the capacity is always less than or equal to the length. This permits
+ * JIT code to optimize away the check for non-writable length when assigning
+ * to possibly out-of-range elements: such code already has to check for
+ * |index < capacity|, and fallback code checks for non-writable length.
+ *
+ * The initialized length of an object specifies the number of elements that
+ * have been initialized. All elements above the initialized length are
+ * holes in the object, and the memory for all elements between the initialized
+ * length and capacity is left uninitialized. The initialized length is some
+ * value less than or equal to both the object's length and the object's
+ * capacity.
+ *
+ * There is flexibility in exactly the value the initialized length must hold,
+ * e.g. if an array has length 5, capacity 10, completely empty, it is valid
+ * for the initialized length to be any value between zero and 5, as long as
+ * the in memory values below the initialized length have been initialized with
+ * a hole value. However, in such cases we want to keep the initialized length
+ * as small as possible: if the object is known to have no hole values below
+ * its initialized length, then it is "packed" and can be accessed much faster
+ * by JIT code.
+ *
+ * Elements do not track property creation order, so enumerating the elements
+ * of an object does not necessarily visit indexes in the order they were
+ * created.
+ */
+class ObjectElements
+{
+ public:
+ enum Flags: uint32_t {
+ // Integers written to these elements must be converted to doubles.
+ CONVERT_DOUBLE_ELEMENTS = 0x1,
+
+ // Present only if these elements correspond to an array with
+ // non-writable length; never present for non-arrays.
+ NONWRITABLE_ARRAY_LENGTH = 0x2,
+
+ // These elements are shared with another object and must be copied
+ // before they can be changed. A pointer to the original owner of the
+ // elements, which is immutable, is stored immediately after the
+ // elements data. There is one case where elements can be written to
+ // before being copied: when setting the CONVERT_DOUBLE_ELEMENTS flag
+ // the shared elements may change (from ints to doubles) without
+ // making a copy first.
+ COPY_ON_WRITE = 0x4,
+
+ // For TypedArrays only: this TypedArray's storage is mapping shared
+ // memory. This is a static property of the TypedArray, set when it
+ // is created and never changed.
+ SHARED_MEMORY = 0x8,
+
+ // These elements are set to integrity level "frozen".
+ FROZEN = 0x10,
+ };
+
+ private:
+ friend class ::JSObject;
+ friend class ArrayObject;
+ friend class NativeObject;
+ friend class TenuringTracer;
+
+ friend bool js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level);
+
+ friend bool
+ ArraySetLength(JSContext* cx, Handle<ArrayObject*> obj, HandleId id,
+ unsigned attrs, HandleValue value, ObjectOpResult& result);
+
+ /* See Flags enum above. */
+ uint32_t flags;
+
+ /*
+ * Number of initialized elements. This is <= the capacity, and for arrays
+ * is <= the length. Memory for elements above the initialized length is
+ * uninitialized, but values between the initialized length and the proper
+ * length are conceptually holes.
+ */
+ uint32_t initializedLength;
+
+ /* Number of allocated slots. */
+ uint32_t capacity;
+
+ /* 'length' property of array objects, unused for other objects. */
+ uint32_t length;
+
+ bool shouldConvertDoubleElements() const {
+ return flags & CONVERT_DOUBLE_ELEMENTS;
+ }
+ void setShouldConvertDoubleElements() {
+ // Note: allow isCopyOnWrite() here, see comment above.
+ flags |= CONVERT_DOUBLE_ELEMENTS;
+ }
+ void clearShouldConvertDoubleElements() {
+ MOZ_ASSERT(!isCopyOnWrite());
+ flags &= ~CONVERT_DOUBLE_ELEMENTS;
+ }
+ bool hasNonwritableArrayLength() const {
+ return flags & NONWRITABLE_ARRAY_LENGTH;
+ }
+ void setNonwritableArrayLength() {
+ MOZ_ASSERT(!isCopyOnWrite());
+ flags |= NONWRITABLE_ARRAY_LENGTH;
+ }
+ bool isCopyOnWrite() const {
+ return flags & COPY_ON_WRITE;
+ }
+ void clearCopyOnWrite() {
+ MOZ_ASSERT(isCopyOnWrite());
+ flags &= ~COPY_ON_WRITE;
+ }
+
+ public:
+ constexpr ObjectElements(uint32_t capacity, uint32_t length)
+ : flags(0), initializedLength(0), capacity(capacity), length(length)
+ {}
+
+ enum class SharedMemory {
+ IsShared
+ };
+
+ constexpr ObjectElements(uint32_t capacity, uint32_t length, SharedMemory shmem)
+ : flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length)
+ {}
+
+ HeapSlot* elements() {
+ return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
+ }
+ const HeapSlot* elements() const {
+ return reinterpret_cast<const HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
+ }
+ static ObjectElements * fromElements(HeapSlot* elems) {
+ return reinterpret_cast<ObjectElements*>(uintptr_t(elems) - sizeof(ObjectElements));
+ }
+
+ bool isSharedMemory() const {
+ return flags & SHARED_MEMORY;
+ }
+
+ GCPtrNativeObject& ownerObject() const {
+ MOZ_ASSERT(isCopyOnWrite());
+ return *(GCPtrNativeObject*)(&elements()[initializedLength]);
+ }
+
+ static int offsetOfFlags() {
+ return int(offsetof(ObjectElements, flags)) - int(sizeof(ObjectElements));
+ }
+ static int offsetOfInitializedLength() {
+ return int(offsetof(ObjectElements, initializedLength)) - int(sizeof(ObjectElements));
+ }
+ static int offsetOfCapacity() {
+ return int(offsetof(ObjectElements, capacity)) - int(sizeof(ObjectElements));
+ }
+ static int offsetOfLength() {
+ return int(offsetof(ObjectElements, length)) - int(sizeof(ObjectElements));
+ }
+
+ static bool ConvertElementsToDoubles(JSContext* cx, uintptr_t elements);
+ static bool MakeElementsCopyOnWrite(ExclusiveContext* cx, NativeObject* obj);
+ static bool FreezeElements(ExclusiveContext* cx, HandleNativeObject obj);
+
+ bool isFrozen() const {
+ return flags & FROZEN;
+ }
+ void freeze() {
+ MOZ_ASSERT(!isFrozen());
+ MOZ_ASSERT(!isCopyOnWrite());
+ flags |= FROZEN;
+ }
+ void markNotFrozen() {
+ MOZ_ASSERT(isFrozen());
+ MOZ_ASSERT(!isCopyOnWrite());
+ flags &= ~FROZEN;
+ }
+
+ uint8_t elementAttributes() const {
+ if (isFrozen())
+ return JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY;
+ return JSPROP_ENUMERATE;
+ }
+
+ // This is enough slots to store an object of this class. See the static
+ // assertion below.
+ static const size_t VALUES_PER_HEADER = 2;
+};
+
+static_assert(ObjectElements::VALUES_PER_HEADER * sizeof(HeapSlot) == sizeof(ObjectElements),
+ "ObjectElements doesn't fit in the given number of slots");
+
+/*
+ * Shared singletons for objects with no elements.
+ * emptyObjectElementsShared is used only for TypedArrays, when the TA
+ * maps shared memory.
+ */
+extern HeapSlot* const emptyObjectElements;
+extern HeapSlot* const emptyObjectElementsShared;
+
+struct Class;
+class GCMarker;
+class Shape;
+
+class NewObjectCache;
+
+#ifdef DEBUG
+static inline bool
+IsObjectValueInCompartment(const Value& v, JSCompartment* comp);
+#endif
+
+// Operations which change an object's dense elements can either succeed, fail,
+// or be unable to complete. For native objects, the latter is used when the
+// object's elements must become sparse instead. The enum below is used for
+// such operations, and for similar operations on unboxed arrays and methods
+// that work on both kinds of objects.
+enum class DenseElementResult {
+ Failure,
+ Success,
+ Incomplete
+};
+
+/*
+ * NativeObject specifies the internal implementation of a native object.
+ *
+ * Native objects use ShapedObject::shape_ to record property information. Two
+ * native objects with the same shape are guaranteed to have the same number of
+ * fixed slots.
+ *
+ * Native objects extend the base implementation of an object with storage for
+ * the object's named properties and indexed elements.
+ *
+ * These are stored separately from one another. Objects are followed by a
+ * variable-sized array of values for inline storage, which may be used by
+ * either properties of native objects (fixed slots), by elements (fixed
+ * elements), or by other data for certain kinds of objects, such as
+ * ArrayBufferObjects and TypedArrayObjects.
+ *
+ * Named property storage can be split between fixed slots and a dynamically
+ * allocated array (the slots member). For an object with N fixed slots, shapes
+ * with slots [0..N-1] are stored in the fixed slots, and the remainder are
+ * stored in the dynamic array. If all properties fit in the fixed slots, the
+ * 'slots_' member is nullptr.
+ *
+ * Elements are indexed via the 'elements_' member. This member can point to
+ * either the shared emptyObjectElements and emptyObjectElementsShared singletons,
+ * into the inline value array (the address of the third value, to leave room
+ * for a ObjectElements header;in this case numFixedSlots() is zero) or to
+ * a dynamically allocated array.
+ *
+ * Slots and elements may both be non-empty. The slots may be either names or
+ * indexes; no indexed property will be in both the slots and elements.
+ */
+class NativeObject : public ShapedObject
+{
+ protected:
+ /* Slots for object properties. */
+ js::HeapSlot* slots_;
+
+ /* Slots for object dense elements. */
+ js::HeapSlot* elements_;
+
+ friend class ::JSObject;
+
+ private:
+ static void staticAsserts() {
+ static_assert(sizeof(NativeObject) == sizeof(JSObject_Slots0),
+ "native object size must match GC thing size");
+ static_assert(sizeof(NativeObject) == sizeof(shadow::Object),
+ "shadow interface must match actual implementation");
+ static_assert(sizeof(NativeObject) % sizeof(Value) == 0,
+ "fixed slots after an object must be aligned");
+
+ static_assert(offsetof(NativeObject, group_) == offsetof(shadow::Object, group),
+ "shadow type must match actual type");
+ static_assert(offsetof(NativeObject, slots_) == offsetof(shadow::Object, slots),
+ "shadow slots must match actual slots");
+ static_assert(offsetof(NativeObject, elements_) == offsetof(shadow::Object, _1),
+ "shadow placeholder must match actual elements");
+
+ static_assert(MAX_FIXED_SLOTS <= Shape::FIXED_SLOTS_MAX,
+ "verify numFixedSlots() bitfield is big enough");
+ static_assert(sizeof(NativeObject) + MAX_FIXED_SLOTS * sizeof(Value) == JSObject::MAX_BYTE_SIZE,
+ "inconsistent maximum object size");
+ }
+
+ public:
+ Shape* lastProperty() const {
+ MOZ_ASSERT(shape_);
+ return shape_;
+ }
+
+ uint32_t propertyCount() const {
+ return lastProperty()->entryCount();
+ }
+
+ bool hasShapeTable() const {
+ return lastProperty()->hasTable();
+ }
+
+ HeapSlotArray getDenseElements() {
+ return HeapSlotArray(elements_, !getElementsHeader()->isCopyOnWrite());
+ }
+ HeapSlotArray getDenseElementsAllowCopyOnWrite() {
+ // Backdoor allowing direct access to copy on write elements.
+ return HeapSlotArray(elements_, true);
+ }
+ const Value& getDenseElement(uint32_t idx) const {
+ MOZ_ASSERT(idx < getDenseInitializedLength());
+ return elements_[idx];
+ }
+ bool containsDenseElement(uint32_t idx) {
+ return idx < getDenseInitializedLength() && !elements_[idx].isMagic(JS_ELEMENTS_HOLE);
+ }
+ uint32_t getDenseInitializedLength() const {
+ return getElementsHeader()->initializedLength;
+ }
+ uint32_t getDenseCapacity() const {
+ return getElementsHeader()->capacity;
+ }
+
+ bool isSharedMemory() const {
+ return getElementsHeader()->isSharedMemory();
+ }
+
+ // Update the last property, keeping the number of allocated slots in sync
+ // with the object's new slot span.
+ bool setLastProperty(ExclusiveContext* cx, Shape* shape);
+
+ // As for setLastProperty(), but allows the number of fixed slots to
+ // change. This can only be used when fixed slots are being erased from the
+ // object, and only when the object will not require dynamic slots to cover
+ // the new properties.
+ void setLastPropertyShrinkFixedSlots(Shape* shape);
+
+ // As for setLastProperty(), but changes the class associated with the
+ // object to a non-native one. This leaves the object with a type and shape
+ // that are (temporarily) inconsistent.
+ void setLastPropertyMakeNonNative(Shape* shape);
+
+ // As for setLastProperty(), but changes the class associated with the
+ // object to a native one. The object's type has already been changed, and
+ // this brings the shape into sync with it.
+ void setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape);
+
+ // Newly-created TypedArrays that map a SharedArrayBuffer are
+ // marked as shared by giving them an ObjectElements that has the
+ // ObjectElements::SHARED_MEMORY flag set.
+ void setIsSharedMemory() {
+ MOZ_ASSERT(elements_ == emptyObjectElements);
+ elements_ = emptyObjectElementsShared;
+ }
+
+ bool isInWholeCellBuffer() const {
+ const gc::TenuredCell* cell = &asTenured();
+ gc::ArenaCellSet* cells = cell->arena()->bufferedCells;
+ return cells && cells->hasCell(cell);
+ }
+
+ protected:
+#ifdef DEBUG
+ void checkShapeConsistency();
+#else
+ void checkShapeConsistency() { }
+#endif
+
+ Shape*
+ replaceWithNewEquivalentShape(ExclusiveContext* cx,
+ Shape* existingShape, Shape* newShape = nullptr,
+ bool accessorShape = false);
+
+ /*
+ * Remove the last property of an object, provided that it is safe to do so
+ * (the shape and previous shape do not carry conflicting information about
+ * the object itself).
+ */
+ inline void removeLastProperty(ExclusiveContext* cx);
+ inline bool canRemoveLastProperty();
+
+ /*
+ * Update the slot span directly for a dictionary object, and allocate
+ * slots to cover the new span if necessary.
+ */
+ bool setSlotSpan(ExclusiveContext* cx, uint32_t span);
+
+ bool toDictionaryMode(ExclusiveContext* cx);
+
+ private:
+ friend class TenuringTracer;
+
+ /*
+ * Get internal pointers to the range of values starting at start and
+ * running for length.
+ */
+ void getSlotRangeUnchecked(uint32_t start, uint32_t length,
+ HeapSlot** fixedStart, HeapSlot** fixedEnd,
+ HeapSlot** slotsStart, HeapSlot** slotsEnd)
+ {
+ MOZ_ASSERT(start + length >= start);
+
+ uint32_t fixed = numFixedSlots();
+ if (start < fixed) {
+ if (start + length < fixed) {
+ *fixedStart = &fixedSlots()[start];
+ *fixedEnd = &fixedSlots()[start + length];
+ *slotsStart = *slotsEnd = nullptr;
+ } else {
+ uint32_t localCopy = fixed - start;
+ *fixedStart = &fixedSlots()[start];
+ *fixedEnd = &fixedSlots()[start + localCopy];
+ *slotsStart = &slots_[0];
+ *slotsEnd = &slots_[length - localCopy];
+ }
+ } else {
+ *fixedStart = *fixedEnd = nullptr;
+ *slotsStart = &slots_[start - fixed];
+ *slotsEnd = &slots_[start - fixed + length];
+ }
+ }
+
+ void getSlotRange(uint32_t start, uint32_t length,
+ HeapSlot** fixedStart, HeapSlot** fixedEnd,
+ HeapSlot** slotsStart, HeapSlot** slotsEnd)
+ {
+ MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
+ getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
+ }
+
+ protected:
+ friend class GCMarker;
+ friend class Shape;
+ friend class NewObjectCache;
+
+ void invalidateSlotRange(uint32_t start, uint32_t length) {
+#ifdef DEBUG
+ HeapSlot* fixedStart;
+ HeapSlot* fixedEnd;
+ HeapSlot* slotsStart;
+ HeapSlot* slotsEnd;
+ getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+ Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
+ Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
+#endif /* DEBUG */
+ }
+
+ void initializeSlotRange(uint32_t start, uint32_t count);
+
+ /*
+ * Initialize a flat array of slots to this object at a start slot. The
+ * caller must ensure that are enough slots.
+ */
+ void initSlotRange(uint32_t start, const Value* vector, uint32_t length);
+
+ /*
+ * Copy a flat array of slots to this object at a start slot. Caller must
+ * ensure there are enough slots in this object.
+ */
+ void copySlotRange(uint32_t start, const Value* vector, uint32_t length);
+
+#ifdef DEBUG
+ enum SentinelAllowed {
+ SENTINEL_NOT_ALLOWED,
+ SENTINEL_ALLOWED
+ };
+
+ /*
+ * Check that slot is in range for the object's allocated slots.
+ * If sentinelAllowed then slot may equal the slot capacity.
+ */
+ bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
+#endif
+
+ /*
+ * Minimum size for dynamically allocated slots in normal Objects.
+ * ArrayObjects don't use this limit and can have a lower slot capacity,
+ * since they normally don't have a lot of slots.
+ */
+ static const uint32_t SLOT_CAPACITY_MIN = 8;
+
+ HeapSlot* fixedSlots() const {
+ return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(NativeObject));
+ }
+
+ public:
+ bool generateOwnShape(ExclusiveContext* cx, Shape* newShape = nullptr) {
+ return replaceWithNewEquivalentShape(cx, lastProperty(), newShape);
+ }
+
+ bool shadowingShapeChange(ExclusiveContext* cx, const Shape& shape);
+ bool clearFlag(ExclusiveContext* cx, BaseShape::Flag flag);
+
+ // The maximum number of slots in an object.
+ // |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow
+ // int32_t (see slotsSizeMustNotOverflow).
+ static const uint32_t MAX_SLOTS_COUNT = (1 << 28) - 1;
+
+ static void slotsSizeMustNotOverflow() {
+ static_assert(NativeObject::MAX_SLOTS_COUNT <= INT32_MAX / sizeof(JS::Value),
+ "every caller of this method requires that a slot "
+ "number (or slot count) count multiplied by "
+ "sizeof(Value) can't overflow uint32_t (and sometimes "
+ "int32_t, too)");
+ }
+
+ uint32_t numFixedSlots() const {
+ return reinterpret_cast<const shadow::Object*>(this)->numFixedSlots();
+ }
+ uint32_t numUsedFixedSlots() const {
+ uint32_t nslots = lastProperty()->slotSpan(getClass());
+ return Min(nslots, numFixedSlots());
+ }
+ uint32_t numFixedSlotsForCompilation() const;
+
+ uint32_t slotSpan() const {
+ if (inDictionaryMode())
+ return lastProperty()->base()->slotSpan();
+ return lastProperty()->slotSpan();
+ }
+
+ /* Whether a slot is at a fixed offset from this object. */
+ bool isFixedSlot(size_t slot) {
+ return slot < numFixedSlots();
+ }
+
+ /* Index into the dynamic slots array to use for a dynamic slot. */
+ size_t dynamicSlotIndex(size_t slot) {
+ MOZ_ASSERT(slot >= numFixedSlots());
+ return slot - numFixedSlots();
+ }
+
+ /*
+ * Grow or shrink slots immediately before changing the slot span.
+ * The number of allocated slots is not stored explicitly, and changes to
+ * the slots must track changes in the slot span.
+ */
+ bool growSlots(ExclusiveContext* cx, uint32_t oldCount, uint32_t newCount);
+ void shrinkSlots(ExclusiveContext* cx, uint32_t oldCount, uint32_t newCount);
+
+ /*
+ * This method is static because it's called from JIT code. On OOM, returns
+ * false without leaving a pending exception on the context.
+ */
+ static bool growSlotsDontReportOOM(ExclusiveContext* cx, NativeObject* obj, uint32_t newCount);
+
+ bool hasDynamicSlots() const { return !!slots_; }
+
+ /* Compute dynamicSlotsCount() for this object. */
+ uint32_t numDynamicSlots() const {
+ return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
+ }
+
+ bool empty() const {
+ return lastProperty()->isEmptyShape();
+ }
+
+ Shape* lookup(ExclusiveContext* cx, jsid id);
+ Shape* lookup(ExclusiveContext* cx, PropertyName* name) {
+ return lookup(cx, NameToId(name));
+ }
+
+ bool contains(ExclusiveContext* cx, jsid id) {
+ return lookup(cx, id) != nullptr;
+ }
+ bool contains(ExclusiveContext* cx, PropertyName* name) {
+ return lookup(cx, name) != nullptr;
+ }
+ bool contains(ExclusiveContext* cx, Shape* shape) {
+ return lookup(cx, shape->propid()) == shape;
+ }
+
+ bool containsShapeOrElement(ExclusiveContext* cx, jsid id) {
+ if (JSID_IS_INT(id) && containsDenseElement(JSID_TO_INT(id)))
+ return true;
+ return contains(cx, id);
+ }
+
+ /* Contextless; can be called from other pure code. */
+ Shape* lookupPure(jsid id);
+ Shape* lookupPure(PropertyName* name) {
+ return lookupPure(NameToId(name));
+ }
+
+ bool containsPure(jsid id) {
+ return lookupPure(id) != nullptr;
+ }
+ bool containsPure(PropertyName* name) {
+ return containsPure(NameToId(name));
+ }
+ bool containsPure(Shape* shape) {
+ return lookupPure(shape->propid()) == shape;
+ }
+
+ /*
+ * Allocate and free an object slot.
+ *
+ * FIXME: bug 593129 -- slot allocation should be done by object methods
+ * after calling object-parameter-free shape methods, avoiding coupling
+ * logic across the object vs. shape module wall.
+ */
+ static bool allocSlot(ExclusiveContext* cx, HandleNativeObject obj, uint32_t* slotp);
+ void freeSlot(ExclusiveContext* cx, uint32_t slot);
+
+ private:
+ static Shape* getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObject obj,
+ HandleShape parent, MutableHandle<StackShape> child);
+ static Shape* getChildProperty(ExclusiveContext* cx, HandleNativeObject obj,
+ HandleShape parent, MutableHandle<StackShape> child);
+
+ public:
+ /* Add a property whose id is not yet in this scope. */
+ static Shape* addProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ JSGetterOp getter, JSSetterOp setter,
+ uint32_t slot, unsigned attrs, unsigned flags,
+ bool allowDictionary = true);
+
+ /* Add a data property whose id is not yet in this scope. */
+ Shape* addDataProperty(ExclusiveContext* cx,
+ jsid id_, uint32_t slot, unsigned attrs);
+ Shape* addDataProperty(ExclusiveContext* cx, HandlePropertyName name,
+ uint32_t slot, unsigned attrs);
+
+ /* Add or overwrite a property for id in this scope. */
+ static Shape*
+ putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ JSGetterOp getter, JSSetterOp setter,
+ uint32_t slot, unsigned attrs,
+ unsigned flags);
+ static inline Shape*
+ putProperty(ExclusiveContext* cx, HandleObject obj, PropertyName* name,
+ JSGetterOp getter, JSSetterOp setter,
+ uint32_t slot, unsigned attrs,
+ unsigned flags);
+
+ /* Change the given property into a sibling with the same id in this scope. */
+ static Shape*
+ changeProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleShape shape,
+ unsigned attrs, JSGetterOp getter, JSSetterOp setter);
+
+ /* Remove the property named by id from this object. */
+ bool removeProperty(ExclusiveContext* cx, jsid id);
+
+ /* Clear the scope, making it empty. */
+ static void clear(ExclusiveContext* cx, HandleNativeObject obj);
+
+ protected:
+ /*
+ * Internal helper that adds a shape not yet mapped by this object.
+ *
+ * Notes:
+ * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
+ * 2. Checks for non-extensibility must be done by callers.
+ */
+ static Shape*
+ addPropertyInternal(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ JSGetterOp getter, JSSetterOp setter, uint32_t slot, unsigned attrs,
+ unsigned flags, ShapeTable::Entry* entry, bool allowDictionary,
+ const AutoKeepShapeTables& keep);
+
+ bool fillInAfterSwap(JSContext* cx, const Vector<Value>& values, void* priv);
+
+ public:
+ // Return true if this object has been converted from shared-immutable
+ // prototype-rooted shape storage to dictionary-shapes in a doubly-linked
+ // list.
+ bool inDictionaryMode() const {
+ return lastProperty()->inDictionary();
+ }
+
+ const Value& getSlot(uint32_t slot) const {
+ MOZ_ASSERT(slotInRange(slot));
+ uint32_t fixed = numFixedSlots();
+ if (slot < fixed)
+ return fixedSlots()[slot];
+ return slots_[slot - fixed];
+ }
+
+ const HeapSlot* getSlotAddressUnchecked(uint32_t slot) const {
+ uint32_t fixed = numFixedSlots();
+ if (slot < fixed)
+ return fixedSlots() + slot;
+ return slots_ + (slot - fixed);
+ }
+
+ HeapSlot* getSlotAddressUnchecked(uint32_t slot) {
+ uint32_t fixed = numFixedSlots();
+ if (slot < fixed)
+ return fixedSlots() + slot;
+ return slots_ + (slot - fixed);
+ }
+
+ HeapSlot* getSlotAddress(uint32_t slot) {
+ /*
+ * This can be used to get the address of the end of the slots for the
+ * object, which may be necessary when fetching zero-length arrays of
+ * slots (e.g. for callObjVarArray).
+ */
+ MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
+ return getSlotAddressUnchecked(slot);
+ }
+
+ const HeapSlot* getSlotAddress(uint32_t slot) const {
+ /*
+ * This can be used to get the address of the end of the slots for the
+ * object, which may be necessary when fetching zero-length arrays of
+ * slots (e.g. for callObjVarArray).
+ */
+ MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
+ return getSlotAddressUnchecked(slot);
+ }
+
+ HeapSlot& getSlotRef(uint32_t slot) {
+ MOZ_ASSERT(slotInRange(slot));
+ return *getSlotAddress(slot);
+ }
+
+ const HeapSlot& getSlotRef(uint32_t slot) const {
+ MOZ_ASSERT(slotInRange(slot));
+ return *getSlotAddress(slot);
+ }
+
+ void setSlot(uint32_t slot, const Value& value) {
+ MOZ_ASSERT(slotInRange(slot));
+ MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
+ getSlotRef(slot).set(this, HeapSlot::Slot, slot, value);
+ }
+
+ void initSlot(uint32_t slot, const Value& value) {
+ MOZ_ASSERT(getSlot(slot).isUndefined());
+ MOZ_ASSERT(slotInRange(slot));
+ MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
+ initSlotUnchecked(slot, value);
+ }
+
+ void initSlotUnchecked(uint32_t slot, const Value& value) {
+ getSlotAddressUnchecked(slot)->init(this, HeapSlot::Slot, slot, value);
+ }
+
+ // MAX_FIXED_SLOTS is the biggest number of fixed slots our GC
+ // size classes will give an object.
+ static const uint32_t MAX_FIXED_SLOTS = 16;
+
+ protected:
+ inline bool updateSlotsForSpan(ExclusiveContext* cx, size_t oldSpan, size_t newSpan);
+
+ private:
+ void prepareElementRangeForOverwrite(size_t start, size_t end) {
+ MOZ_ASSERT(end <= getDenseInitializedLength());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ for (size_t i = start; i < end; i++)
+ elements_[i].HeapSlot::~HeapSlot();
+ }
+
+ /*
+ * Trigger the write barrier on a range of slots that will no longer be
+ * reachable.
+ */
+ void prepareSlotRangeForOverwrite(size_t start, size_t end) {
+ for (size_t i = start; i < end; i++)
+ getSlotAddressUnchecked(i)->HeapSlot::~HeapSlot();
+ }
+
+ public:
+ static bool rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj,
+ uint32_t slotSpan);
+
+ inline void setSlotWithType(ExclusiveContext* cx, Shape* shape,
+ const Value& value, bool overwriting = true);
+
+ inline const Value& getReservedSlot(uint32_t index) const {
+ MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
+ return getSlot(index);
+ }
+
+ const HeapSlot& getReservedSlotRef(uint32_t index) const {
+ MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
+ return getSlotRef(index);
+ }
+
+ HeapSlot& getReservedSlotRef(uint32_t index) {
+ MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
+ return getSlotRef(index);
+ }
+
+ void initReservedSlot(uint32_t index, const Value& v) {
+ MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
+ initSlot(index, v);
+ }
+
+ void setReservedSlot(uint32_t index, const Value& v) {
+ MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
+ setSlot(index, v);
+ }
+
+ /* For slots which are known to always be fixed, due to the way they are allocated. */
+
+ HeapSlot& getFixedSlotRef(uint32_t slot) {
+ MOZ_ASSERT(slot < numFixedSlots());
+ return fixedSlots()[slot];
+ }
+
+ const Value& getFixedSlot(uint32_t slot) const {
+ MOZ_ASSERT(slot < numFixedSlots());
+ return fixedSlots()[slot];
+ }
+
+ void setFixedSlot(uint32_t slot, const Value& value) {
+ MOZ_ASSERT(slot < numFixedSlots());
+ fixedSlots()[slot].set(this, HeapSlot::Slot, slot, value);
+ }
+
+ void initFixedSlot(uint32_t slot, const Value& value) {
+ MOZ_ASSERT(slot < numFixedSlots());
+ fixedSlots()[slot].init(this, HeapSlot::Slot, slot, value);
+ }
+
+ /*
+ * Get the number of dynamic slots to allocate to cover the properties in
+ * an object with the given number of fixed slots and slot span. The slot
+ * capacity is not stored explicitly, and the allocated size of the slot
+ * array is kept in sync with this count.
+ */
+ static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class* clasp);
+ static uint32_t dynamicSlotsCount(Shape* shape) {
+ return dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), shape->getObjectClass());
+ }
+
+ /* Elements accessors. */
+
+ // The maximum size, in sizeof(Value), of the allocation used for an
+ // object's dense elements. (This includes space used to store an
+ // ObjectElements instance.)
+ // |MAX_DENSE_ELEMENTS_ALLOCATION * sizeof(JS::Value)| shouldn't overflow
+ // int32_t (see elementsSizeMustNotOverflow).
+ static const uint32_t MAX_DENSE_ELEMENTS_ALLOCATION = (1 << 28) - 1;
+
+ // The maximum number of usable dense elements in an object.
+ static const uint32_t MAX_DENSE_ELEMENTS_COUNT =
+ MAX_DENSE_ELEMENTS_ALLOCATION - ObjectElements::VALUES_PER_HEADER;
+
+ static void elementsSizeMustNotOverflow() {
+ static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX / sizeof(JS::Value),
+ "every caller of this method require that an element "
+ "count multiplied by sizeof(Value) can't overflow "
+ "uint32_t (and sometimes int32_t ,too)");
+ }
+
+ ObjectElements * getElementsHeader() const {
+ return ObjectElements::fromElements(elements_);
+ }
+
+ /* Accessors for elements. */
+ bool ensureElements(ExclusiveContext* cx, uint32_t capacity) {
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ if (capacity > getDenseCapacity())
+ return growElements(cx, capacity);
+ return true;
+ }
+
+ static bool goodElementsAllocationAmount(ExclusiveContext* cx, uint32_t reqAllocated,
+ uint32_t length, uint32_t* goodAmount);
+ bool growElements(ExclusiveContext* cx, uint32_t newcap);
+ void shrinkElements(ExclusiveContext* cx, uint32_t cap);
+ void setDynamicElements(ObjectElements* header) {
+ MOZ_ASSERT(!hasDynamicElements());
+ elements_ = header->elements();
+ MOZ_ASSERT(hasDynamicElements());
+ }
+
+ static bool CopyElementsForWrite(ExclusiveContext* cx, NativeObject* obj);
+
+ bool maybeCopyElementsForWrite(ExclusiveContext* cx) {
+ if (denseElementsAreCopyOnWrite())
+ return CopyElementsForWrite(cx, this);
+ return true;
+ }
+
+ private:
+ inline void ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext* cx,
+ uint32_t index, uint32_t extra);
+
+ // Run a post write barrier that encompasses multiple contiguous elements in a
+ // single step.
+ inline void elementsRangeWriteBarrierPost(uint32_t start, uint32_t count) {
+ for (size_t i = 0; i < count; i++) {
+ const Value& v = elements_[start + i];
+ if (v.isObject() && IsInsideNursery(&v.toObject())) {
+ JS::shadow::Runtime* shadowRuntime = shadowRuntimeFromMainThread();
+ shadowRuntime->gcStoreBufferPtr()->putSlot(this, HeapSlot::Element,
+ start + i, count - i);
+ return;
+ }
+ }
+ }
+
+ // See the comment over setDenseElementUnchecked, this applies in the same way.
+ void setDenseInitializedLengthUnchecked(uint32_t length) {
+ MOZ_ASSERT(length <= getDenseCapacity());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
+ getElementsHeader()->initializedLength = length;
+ }
+
+ // Use this function with care. This is done to allow sparsifying frozen
+ // objects, but should only be called in a few places, and should be
+ // audited carefully!
+ void setDenseElementUnchecked(uint32_t index, const Value& val) {
+ MOZ_ASSERT(index < getDenseInitializedLength());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ elements_[index].set(this, HeapSlot::Element, index, val);
+ }
+
+ public:
+ void setDenseInitializedLength(uint32_t length) {
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ setDenseInitializedLengthUnchecked(length);
+ }
+
+ inline void ensureDenseInitializedLength(ExclusiveContext* cx,
+ uint32_t index, uint32_t extra);
+
+ void setDenseElement(uint32_t index, const Value& val) {
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ setDenseElementUnchecked(index, val);
+ }
+
+ void initDenseElement(uint32_t index, const Value& val) {
+ MOZ_ASSERT(index < getDenseInitializedLength());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ elements_[index].init(this, HeapSlot::Element, index, val);
+ }
+
+ void setDenseElementMaybeConvertDouble(uint32_t index, const Value& val) {
+ if (val.isInt32() && shouldConvertDoubleElements())
+ setDenseElement(index, DoubleValue(val.toInt32()));
+ else
+ setDenseElement(index, val);
+ }
+
+ inline void setDenseElementWithType(ExclusiveContext* cx, uint32_t index,
+ const Value& val);
+ inline void initDenseElementWithType(ExclusiveContext* cx, uint32_t index,
+ const Value& val);
+ inline void setDenseElementHole(ExclusiveContext* cx, uint32_t index);
+ static inline void removeDenseElementForSparseIndex(ExclusiveContext* cx,
+ HandleNativeObject obj, uint32_t index);
+
+ inline Value getDenseOrTypedArrayElement(uint32_t idx);
+
+ void copyDenseElements(uint32_t dstStart, const Value* src, uint32_t count) {
+ MOZ_ASSERT(dstStart + count <= getDenseCapacity());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
+ for (uint32_t i = 0; i < count; ++i)
+ elements_[dstStart + i].set(this, HeapSlot::Element, dstStart + i, src[i]);
+ } else {
+ memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
+ elementsRangeWriteBarrierPost(dstStart, count);
+ }
+ }
+
+ void initDenseElements(uint32_t dstStart, const Value* src, uint32_t count) {
+ MOZ_ASSERT(dstStart + count <= getDenseCapacity());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+ memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
+ elementsRangeWriteBarrierPost(dstStart, count);
+ }
+
+ void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
+ MOZ_ASSERT(dstStart + count <= getDenseCapacity());
+ MOZ_ASSERT(srcStart + count <= getDenseInitializedLength());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+
+ /*
+ * Using memmove here would skip write barriers. Also, we need to consider
+ * an array containing [A, B, C], in the following situation:
+ *
+ * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
+ * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
+ * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
+ *
+ * Since normal marking never happens on B, it is very important that the
+ * write barrier is invoked here on B, despite the fact that it exists in
+ * the array before and after the move.
+ */
+ if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
+ if (dstStart < srcStart) {
+ HeapSlot* dst = elements_ + dstStart;
+ HeapSlot* src = elements_ + srcStart;
+ for (uint32_t i = 0; i < count; i++, dst++, src++)
+ dst->set(this, HeapSlot::Element, dst - elements_, *src);
+ } else {
+ HeapSlot* dst = elements_ + dstStart + count - 1;
+ HeapSlot* src = elements_ + srcStart + count - 1;
+ for (uint32_t i = 0; i < count; i++, dst--, src--)
+ dst->set(this, HeapSlot::Element, dst - elements_, *src);
+ }
+ } else {
+ memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot));
+ elementsRangeWriteBarrierPost(dstStart, count);
+ }
+ }
+
+ void moveDenseElementsNoPreBarrier(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
+ MOZ_ASSERT(!shadowZone()->needsIncrementalBarrier());
+
+ MOZ_ASSERT(dstStart + count <= getDenseCapacity());
+ MOZ_ASSERT(srcStart + count <= getDenseCapacity());
+ MOZ_ASSERT(!denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(!denseElementsAreFrozen());
+
+ memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(Value));
+ elementsRangeWriteBarrierPost(dstStart, count);
+ }
+
+ bool shouldConvertDoubleElements() {
+ return getElementsHeader()->shouldConvertDoubleElements();
+ }
+
+ inline void setShouldConvertDoubleElements();
+ inline void clearShouldConvertDoubleElements();
+
+ bool denseElementsAreCopyOnWrite() {
+ return getElementsHeader()->isCopyOnWrite();
+ }
+
+ bool denseElementsAreFrozen() {
+ return getElementsHeader()->isFrozen();
+ }
+
+ /* Packed information for this object's elements. */
+ inline bool writeToIndexWouldMarkNotPacked(uint32_t index);
+ inline void markDenseElementsNotPacked(ExclusiveContext* cx);
+
+ // Ensures that the object can hold at least index + extra elements. This
+ // returns DenseElement_Success on success, DenseElement_Failed on failure
+ // to grow the array, or DenseElement_Incomplete when the object is too
+ // sparse to grow (this includes the case of index + extra overflow). In
+ // the last two cases the object is kept intact.
+ inline DenseElementResult ensureDenseElements(ExclusiveContext* cx,
+ uint32_t index, uint32_t extra);
+
+ inline DenseElementResult extendDenseElements(ExclusiveContext* cx,
+ uint32_t requiredCapacity, uint32_t extra);
+
+ /* Convert a single dense element to a sparse property. */
+ static bool sparsifyDenseElement(ExclusiveContext* cx,
+ HandleNativeObject obj, uint32_t index);
+
+ /* Convert all dense elements to sparse properties. */
+ static bool sparsifyDenseElements(ExclusiveContext* cx, HandleNativeObject obj);
+
+ /* Small objects are dense, no matter what. */
+ static const uint32_t MIN_SPARSE_INDEX = 1000;
+
+ /*
+ * Element storage for an object will be sparse if fewer than 1/8 indexes
+ * are filled in.
+ */
+ static const unsigned SPARSE_DENSITY_RATIO = 8;
+
+ /*
+ * Check if after growing the object's elements will be too sparse.
+ * newElementsHint is an estimated number of elements to be added.
+ */
+ bool willBeSparseElements(uint32_t requiredCapacity, uint32_t newElementsHint);
+
+ /*
+ * After adding a sparse index to obj, see if it should be converted to use
+ * dense elements.
+ */
+ static DenseElementResult maybeDensifySparseElements(ExclusiveContext* cx,
+ HandleNativeObject obj);
+
+ inline HeapSlot* fixedElements() const {
+ static_assert(2 * sizeof(Value) == sizeof(ObjectElements),
+ "when elements are stored inline, the first two "
+ "slots will hold the ObjectElements header");
+ return &fixedSlots()[2];
+ }
+
+#ifdef DEBUG
+ bool canHaveNonEmptyElements();
+#endif
+
+ void setFixedElements() {
+ MOZ_ASSERT(canHaveNonEmptyElements());
+ elements_ = fixedElements();
+ }
+
+ inline bool hasDynamicElements() const {
+ /*
+ * Note: for objects with zero fixed slots this could potentially give
+ * a spurious 'true' result, if the end of this object is exactly
+ * aligned with the end of its arena and dynamic slots are allocated
+ * immediately afterwards. Such cases cannot occur for dense arrays
+ * (which have at least two fixed slots) and can only result in a leak.
+ */
+ return !hasEmptyElements() && elements_ != fixedElements();
+ }
+
+ inline bool hasFixedElements() const {
+ return elements_ == fixedElements();
+ }
+
+ inline bool hasEmptyElements() const {
+ return elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared;
+ }
+
+ /*
+ * Get a pointer to the unused data in the object's allocation immediately
+ * following this object, for use with objects which allocate a larger size
+ * class than they need and store non-elements data inline.
+ */
+ inline uint8_t* fixedData(size_t nslots) const;
+
+ inline void privateWriteBarrierPre(void** oldval);
+
+ void privateWriteBarrierPost(void** pprivate) {
+ gc::Cell** cellp = reinterpret_cast<gc::Cell**>(pprivate);
+ MOZ_ASSERT(cellp);
+ MOZ_ASSERT(*cellp);
+ gc::StoreBuffer* storeBuffer = (*cellp)->storeBuffer();
+ if (storeBuffer)
+ storeBuffer->putCell(cellp);
+ }
+
+ /* Private data accessors. */
+
+ inline void*& privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
+ /*
+ * The private pointer of an object can hold any word sized value.
+ * Private pointers are stored immediately after the last fixed slot of
+ * the object.
+ */
+ MOZ_ASSERT(nfixed == numFixedSlots());
+ MOZ_ASSERT(hasPrivate());
+ HeapSlot* end = &fixedSlots()[nfixed];
+ return *reinterpret_cast<void**>(end);
+ }
+
+ bool hasPrivate() const {
+ return getClass()->hasPrivate();
+ }
+ void* getPrivate() const {
+ return privateRef(numFixedSlots());
+ }
+ void setPrivate(void* data) {
+ void** pprivate = &privateRef(numFixedSlots());
+ privateWriteBarrierPre(pprivate);
+ *pprivate = data;
+ }
+
+ void setPrivateGCThing(gc::Cell* cell) {
+ void** pprivate = &privateRef(numFixedSlots());
+ privateWriteBarrierPre(pprivate);
+ *pprivate = reinterpret_cast<void*>(cell);
+ privateWriteBarrierPost(pprivate);
+ }
+
+ void setPrivateUnbarriered(void* data) {
+ void** pprivate = &privateRef(numFixedSlots());
+ *pprivate = data;
+ }
+ void initPrivate(void* data) {
+ privateRef(numFixedSlots()) = data;
+ }
+
+ /* Access private data for an object with a known number of fixed slots. */
+ inline void* getPrivate(uint32_t nfixed) const {
+ return privateRef(nfixed);
+ }
+
+ static inline NativeObject*
+ copy(ExclusiveContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
+ HandleNativeObject templateObject);
+
+ void updateShapeAfterMovingGC();
+ void sweepDictionaryListPointer();
+
+ /* JIT Accessors */
+ static size_t offsetOfElements() { return offsetof(NativeObject, elements_); }
+ static size_t offsetOfFixedElements() {
+ return sizeof(NativeObject) + sizeof(ObjectElements);
+ }
+
+ static size_t getFixedSlotOffset(size_t slot) {
+ return sizeof(NativeObject) + slot * sizeof(Value);
+ }
+ static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
+ static size_t offsetOfSlots() { return offsetof(NativeObject, slots_); }
+};
+
+// Object class for plain native objects created using '{}' object literals,
+// 'new Object()', 'Object.create', etc.
+class PlainObject : public NativeObject
+{
+ public:
+ static const js::Class class_;
+};
+
+inline void
+NativeObject::privateWriteBarrierPre(void** oldval)
+{
+ JS::shadow::Zone* shadowZone = this->shadowZoneFromAnyThread();
+ if (shadowZone->needsIncrementalBarrier() && *oldval && getClass()->hasTrace())
+ getClass()->doTrace(shadowZone->barrierTracer(), this);
+}
+
+#ifdef DEBUG
+static inline bool
+IsObjectValueInCompartment(const Value& v, JSCompartment* comp)
+{
+ if (!v.isObject())
+ return true;
+ return v.toObject().compartment() == comp;
+}
+#endif
+
+
+/*** Standard internal methods *******************************************************************/
+
+/*
+ * These functions should follow the algorithms in ES6 draft rev 29 section 9.1
+ * ("Ordinary Object Internal Methods"). It's an ongoing project.
+ *
+ * Many native objects are not "ordinary" in ES6, so these functions also have
+ * to serve some of the special needs of Functions (9.2, 9.3, 9.4.1), Arrays
+ * (9.4.2), Strings (9.4.3), and so on.
+ */
+
+extern bool
+NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ Handle<JS::PropertyDescriptor> desc,
+ ObjectOpResult& result);
+
+extern bool
+NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+ JSGetterOp getter, JSSetterOp setter, unsigned attrs,
+ ObjectOpResult& result);
+
+extern bool
+NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
+ HandleValue value, GetterOp getter, SetterOp setter,
+ unsigned attrs, ObjectOpResult& result);
+
+extern bool
+NativeDefineElement(ExclusiveContext* cx, HandleNativeObject obj, uint32_t index, HandleValue value,
+ JSGetterOp getter, JSSetterOp setter, unsigned attrs,
+ ObjectOpResult& result);
+
+/* If the result out-param is omitted, throw on failure. */
+extern bool
+NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+ JSGetterOp getter, JSSetterOp setter, unsigned attrs);
+
+extern bool
+NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
+ HandleValue value, JSGetterOp getter, JSSetterOp setter,
+ unsigned attrs);
+
+extern bool
+NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp);
+
+extern bool
+NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, HandleId id,
+ MutableHandle<JS::PropertyDescriptor> desc);
+
+extern bool
+NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp);
+
+extern bool
+NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp);
+
+inline bool
+NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleValue vp)
+{
+ RootedValue receiver(cx, ObjectValue(*obj));
+ return NativeGetProperty(cx, obj, receiver, id, vp);
+}
+
+bool
+SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
+ ObjectOpResult& result);
+
+bool
+SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+
+/*
+ * Indicates whether an assignment operation is qualified (`x.y = 0`) or
+ * unqualified (`y = 0`). In strict mode, the latter is an error if no such
+ * variable already exists.
+ *
+ * Used as an argument to NativeSetProperty.
+ */
+enum QualifiedBool {
+ Unqualified = 0,
+ Qualified = 1
+};
+
+extern bool
+NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result);
+
+extern bool
+NativeSetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+
+extern bool
+NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, ObjectOpResult& result);
+
+
+/*** SpiderMonkey nonstandard internal methods ***************************************************/
+
+template <AllowGC allowGC>
+extern bool
+NativeLookupOwnProperty(ExclusiveContext* cx,
+ typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+ typename MaybeRooted<jsid, allowGC>::HandleType id,
+ typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
+
+/*
+ * Get a property from `receiver`, after having already done a lookup and found
+ * the property on a native object `obj`.
+ *
+ * `shape` must not be null and must not be an implicit dense property. It must
+ * be present in obj's shape chain.
+ */
+extern bool
+NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObject obj,
+ HandleShape shape, MutableHandleValue vp);
+
+/* * */
+
+/*
+ * If obj has an already-resolved data property for id, return true and
+ * store the property value in *vp.
+ */
+extern bool
+HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp);
+
+inline bool
+HasDataProperty(JSContext* cx, NativeObject* obj, PropertyName* name, Value* vp)
+{
+ return HasDataProperty(cx, obj, NameToId(name), vp);
+}
+
+extern bool
+GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
+
+} /* namespace js */
+
+template <>
+inline bool
+JSObject::is<js::NativeObject>() const { return isNative(); }
+
+namespace js {
+
+// Alternate to JSObject::as<NativeObject>() that tolerates null pointers.
+inline NativeObject*
+MaybeNativeObject(JSObject* obj)
+{
+ return obj ? &obj->as<NativeObject>() : nullptr;
+}
+
+// Defined in NativeObject-inl.h.
+bool IsPackedArray(JSObject* obj);
+
+} // namespace js
+
+
+/*** Inline functions declared in jsobj.h that use the native declarations above *****************/
+
+inline bool
+js::HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ if (HasPropertyOp op = obj->getOpsHasProperty())
+ return op(cx, obj, id, foundp);
+ return NativeHasProperty(cx, obj.as<NativeObject>(), id, foundp);
+}
+
+inline bool
+js::GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
+ MutableHandleValue vp)
+{
+ if (GetPropertyOp op = obj->getOpsGetProperty())
+ return op(cx, obj, receiver, id, vp);
+ return NativeGetProperty(cx, obj.as<NativeObject>(), receiver, id, vp);
+}
+
+inline bool
+js::GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp)
+{
+ if (obj->getOpsGetProperty())
+ return false;
+ return NativeGetPropertyNoGC(cx, &obj->as<NativeObject>(), receiver, id, vp);
+}
+
+inline bool
+js::SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ if (obj->getOpsSetProperty())
+ return JSObject::nonNativeSetProperty(cx, obj, id, v, receiver, result);
+ return NativeSetProperty(cx, obj.as<NativeObject>(), id, v, receiver, Qualified, result);
+}
+
+inline bool
+js::SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ if (obj->getOpsSetProperty())
+ return JSObject::nonNativeSetElement(cx, obj, index, v, receiver, result);
+ return NativeSetElement(cx, obj.as<NativeObject>(), index, v, receiver, result);
+}
+
+#endif /* vm_NativeObject_h */
diff --git a/js/src/vm/NumberObject-inl.h b/js/src/vm/NumberObject-inl.h
new file mode 100644
index 000000000..7e0237b1c
--- /dev/null
+++ b/js/src/vm/NumberObject-inl.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_NumberObject_inl_h
+#define vm_NumberObject_inl_h
+
+#include "vm/NumberObject.h"
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+inline NumberObject*
+NumberObject::create(JSContext* cx, double d, HandleObject proto /* = nullptr */)
+{
+ NumberObject* obj = NewObjectWithClassProto<NumberObject>(cx, proto);
+ if (!obj)
+ return nullptr;
+ obj->setPrimitiveValue(d);
+ return obj;
+}
+
+} // namespace js
+
+#endif /* vm_NumberObject_inl_h */
diff --git a/js/src/vm/NumberObject.h b/js/src/vm/NumberObject.h
new file mode 100644
index 000000000..dd808309c
--- /dev/null
+++ b/js/src/vm/NumberObject.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_NumberObject_h
+#define vm_NumberObject_h
+
+#include "jsnum.h"
+
+namespace js {
+
+class NumberObject : public NativeObject
+{
+ /* Stores this Number object's [[PrimitiveValue]]. */
+ static const unsigned PRIMITIVE_VALUE_SLOT = 0;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 1;
+
+ static const Class class_;
+
+ /*
+ * Creates a new Number object boxing the given number.
+ * If proto is nullptr, then Number.prototype will be used instead.
+ */
+ static inline NumberObject* create(JSContext* cx, double d,
+ HandleObject proto = nullptr);
+
+ double unbox() const {
+ return getFixedSlot(PRIMITIVE_VALUE_SLOT).toNumber();
+ }
+
+ private:
+ inline void setPrimitiveValue(double d) {
+ setFixedSlot(PRIMITIVE_VALUE_SLOT, NumberValue(d));
+ }
+
+ /* For access to init, as Number.prototype is special. */
+ friend JSObject*
+ js::InitNumberClass(JSContext* cx, HandleObject global);
+};
+
+} // namespace js
+
+#endif /* vm_NumberObject_h */
diff --git a/js/src/vm/ObjectGroup-inl.h b/js/src/vm/ObjectGroup-inl.h
new file mode 100644
index 000000000..9074f4d97
--- /dev/null
+++ b/js/src/vm/ObjectGroup-inl.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ObjectGroup_inl_h
+#define vm_ObjectGroup_inl_h
+
+#include "vm/ObjectGroup.h"
+
+namespace js {
+
+inline bool
+ObjectGroup::needsSweep()
+{
+ // Note: this can be called off thread during compacting GCs, in which case
+ // nothing will be running on the main thread.
+ return generation() != zoneFromAnyThread()->types.generation;
+}
+
+inline void
+ObjectGroup::maybeSweep(AutoClearTypeInferenceStateOnOOM* oom)
+{
+ if (needsSweep())
+ sweep(oom);
+}
+
+inline ObjectGroupFlags
+ObjectGroup::flags()
+{
+ maybeSweep(nullptr);
+ return flagsDontCheckGeneration();
+}
+
+inline void
+ObjectGroup::addFlags(ObjectGroupFlags flags)
+{
+ maybeSweep(nullptr);
+ flags_ |= flags;
+}
+
+inline void
+ObjectGroup::clearFlags(ObjectGroupFlags flags)
+{
+ maybeSweep(nullptr);
+ flags_ &= ~flags;
+}
+
+inline bool
+ObjectGroup::hasAnyFlags(ObjectGroupFlags flags)
+{
+ MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
+ return !!(this->flags() & flags);
+}
+
+inline bool
+ObjectGroup::hasAllFlags(ObjectGroupFlags flags)
+{
+ MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
+ return (this->flags() & flags) == flags;
+}
+
+inline bool
+ObjectGroup::unknownProperties()
+{
+ MOZ_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
+ hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
+ return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
+}
+
+inline bool
+ObjectGroup::shouldPreTenure()
+{
+ return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
+}
+
+inline bool
+ObjectGroup::canPreTenure()
+{
+ return !unknownProperties();
+}
+
+inline bool
+ObjectGroup::fromAllocationSite()
+{
+ return flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE;
+}
+
+inline void
+ObjectGroup::setShouldPreTenure(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(canPreTenure());
+ setFlags(cx, OBJECT_FLAG_PRE_TENURE);
+}
+
+inline TypeNewScript*
+ObjectGroup::newScript()
+{
+ maybeSweep(nullptr);
+ return newScriptDontCheckGeneration();
+}
+
+inline PreliminaryObjectArrayWithTemplate*
+ObjectGroup::maybePreliminaryObjects()
+{
+ maybeSweep(nullptr);
+ return maybePreliminaryObjectsDontCheckGeneration();
+}
+
+inline UnboxedLayout*
+ObjectGroup::maybeUnboxedLayout()
+{
+ maybeSweep(nullptr);
+ return maybeUnboxedLayoutDontCheckGeneration();
+}
+
+inline UnboxedLayout&
+ObjectGroup::unboxedLayout()
+{
+ maybeSweep(nullptr);
+ return unboxedLayoutDontCheckGeneration();
+}
+
+} // namespace js
+
+#endif /* vm_ObjectGroup_inl_h */
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
new file mode 100644
index 000000000..7be697fb6
--- /dev/null
+++ b/js/src/vm/ObjectGroup.cpp
@@ -0,0 +1,1862 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ObjectGroup.h"
+
+#include "jshashutil.h"
+#include "jsobj.h"
+
+#include "gc/Marking.h"
+#include "gc/Policy.h"
+#include "gc/StoreBuffer.h"
+#include "gc/Zone.h"
+#include "js/CharacterEncoding.h"
+#include "vm/ArrayObject.h"
+#include "vm/Shape.h"
+#include "vm/TaggedProto.h"
+#include "vm/UnboxedObject.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/UnboxedObject-inl.h"
+
+using namespace js;
+
+using mozilla::DebugOnly;
+using mozilla::PodZero;
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroup
+/////////////////////////////////////////////////////////////////////
+
+ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto, JSCompartment* comp,
+ ObjectGroupFlags initialFlags)
+{
+ PodZero(this);
+
+ /* Windows may not appear on prototype chains. */
+ MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
+ MOZ_ASSERT(JS::StringIsASCII(clasp->name));
+
+ this->clasp_ = clasp;
+ this->proto_ = proto;
+ this->compartment_ = comp;
+ this->flags_ = initialFlags;
+
+ setGeneration(zone()->types.generation);
+}
+
+void
+ObjectGroup::finalize(FreeOp* fop)
+{
+ if (newScriptDontCheckGeneration())
+ newScriptDontCheckGeneration()->clear();
+ fop->delete_(newScriptDontCheckGeneration());
+ fop->delete_(maybeUnboxedLayoutDontCheckGeneration());
+ if (maybePreliminaryObjectsDontCheckGeneration())
+ maybePreliminaryObjectsDontCheckGeneration()->clear();
+ fop->delete_(maybePreliminaryObjectsDontCheckGeneration());
+}
+
+void
+ObjectGroup::setProtoUnchecked(TaggedProto proto)
+{
+ proto_ = proto;
+ MOZ_ASSERT_IF(proto_.isObject() && proto_.toObject()->isNative(),
+ proto_.toObject()->isDelegate());
+}
+
+void
+ObjectGroup::setProto(TaggedProto proto)
+{
+ MOZ_ASSERT(singleton());
+ setProtoUnchecked(proto);
+}
+
+size_t
+ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ size_t n = 0;
+ if (TypeNewScript* newScript = newScriptDontCheckGeneration())
+ n += newScript->sizeOfIncludingThis(mallocSizeOf);
+ if (UnboxedLayout* layout = maybeUnboxedLayoutDontCheckGeneration())
+ n += layout->sizeOfIncludingThis(mallocSizeOf);
+ return n;
+}
+
+void
+ObjectGroup::setAddendum(AddendumKind kind, void* addendum, bool writeBarrier /* = true */)
+{
+ MOZ_ASSERT(!needsSweep());
+ MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT));
+
+ if (writeBarrier) {
+ // Manually trigger barriers if we are clearing new script or
+ // preliminary object information. Other addendums are immutable.
+ switch (addendumKind()) {
+ case Addendum_PreliminaryObjects:
+ PreliminaryObjectArrayWithTemplate::writeBarrierPre(maybePreliminaryObjects());
+ break;
+ case Addendum_NewScript:
+ TypeNewScript::writeBarrierPre(newScript());
+ break;
+ case Addendum_None:
+ break;
+ default:
+ MOZ_ASSERT(addendumKind() == kind);
+ }
+ }
+
+ flags_ &= ~OBJECT_FLAG_ADDENDUM_MASK;
+ flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT;
+ addendum_ = addendum;
+}
+
+/* static */ bool
+ObjectGroup::useSingletonForClone(JSFunction* fun)
+{
+ if (!fun->isInterpreted())
+ return false;
+
+ if (fun->isArrow())
+ return false;
+
+ if (fun->isSingleton())
+ return false;
+
+ /*
+ * When a function is being used as a wrapper for another function, it
+ * improves precision greatly to distinguish between different instances of
+ * the wrapper; otherwise we will conflate much of the information about
+ * the wrapped functions.
+ *
+ * An important example is the Class.create function at the core of the
+ * Prototype.js library, which looks like:
+ *
+ * var Class = {
+ * create: function() {
+ * return function() {
+ * this.initialize.apply(this, arguments);
+ * }
+ * }
+ * };
+ *
+ * Each instance of the innermost function will have a different wrapped
+ * initialize method. We capture this, along with similar cases, by looking
+ * for short scripts which use both .apply and arguments. For such scripts,
+ * whenever creating a new instance of the function we both give that
+ * instance a singleton type and clone the underlying script.
+ */
+
+ uint32_t begin, end;
+ if (fun->hasScript()) {
+ if (!fun->nonLazyScript()->isLikelyConstructorWrapper())
+ return false;
+ begin = fun->nonLazyScript()->sourceStart();
+ end = fun->nonLazyScript()->sourceEnd();
+ } else {
+ if (!fun->lazyScript()->isLikelyConstructorWrapper())
+ return false;
+ begin = fun->lazyScript()->begin();
+ end = fun->lazyScript()->end();
+ }
+
+ return end - begin <= 100;
+}
+
+/* static */ bool
+ObjectGroup::useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecode* pc)
+{
+ /*
+ * Make a heuristic guess at a use of JSOP_NEW that the constructed object
+ * should have a fresh group. We do this when the NEW is immediately
+ * followed by a simple assignment to an object's .prototype field.
+ * This is designed to catch common patterns for subclassing in JS:
+ *
+ * function Super() { ... }
+ * function Sub1() { ... }
+ * function Sub2() { ... }
+ *
+ * Sub1.prototype = new Super();
+ * Sub2.prototype = new Super();
+ *
+ * Using distinct groups for the particular prototypes of Sub1 and
+ * Sub2 lets us continue to distinguish the two subclasses and any extra
+ * properties added to those prototype objects.
+ */
+ if (script->isGenerator())
+ return false;
+ if (JSOp(*pc) != JSOP_NEW)
+ return false;
+ pc += JSOP_NEW_LENGTH;
+ if (JSOp(*pc) == JSOP_SETPROP) {
+ if (script->getName(pc) == cx->names().prototype)
+ return true;
+ }
+ return false;
+}
+
+/* static */ bool
+ObjectGroup::useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, JSProtoKey key)
+{
+ // The return value of this method can either be tested like a boolean or
+ // passed to a NewObject method.
+ JS_STATIC_ASSERT(GenericObject == 0);
+
+ /*
+ * Objects created outside loops in global and eval scripts should have
+ * singleton types. For now this is only done for plain objects, but not
+ * typed arrays or normal arrays.
+ */
+
+ if (script->functionNonDelazifying() && !script->treatAsRunOnce())
+ return GenericObject;
+
+ if (key != JSProto_Object)
+ return GenericObject;
+
+ // All loops in the script will have a try note indicating their boundary.
+
+ if (!script->hasTrynotes())
+ return SingletonObject;
+
+ unsigned offset = script->pcToOffset(pc);
+
+ JSTryNote* tn = script->trynotes()->vector;
+ JSTryNote* tnlimit = tn + script->trynotes()->length;
+ for (; tn < tnlimit; tn++) {
+ if (tn->kind != JSTRY_FOR_IN && tn->kind != JSTRY_FOR_OF && tn->kind != JSTRY_LOOP)
+ continue;
+
+ unsigned startOffset = script->mainOffset() + tn->start;
+ unsigned endOffset = startOffset + tn->length;
+
+ if (offset >= startOffset && offset < endOffset)
+ return GenericObject;
+ }
+
+ return SingletonObject;
+}
+
+/* static */ bool
+ObjectGroup::useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, const Class* clasp)
+{
+ return useSingletonForAllocationSite(script, pc, JSCLASS_CACHED_PROTO_KEY(clasp));
+}
+
+/////////////////////////////////////////////////////////////////////
+// JSObject
+/////////////////////////////////////////////////////////////////////
+
+bool
+JSObject::shouldSplicePrototype(JSContext* cx)
+{
+ /*
+ * During bootstrapping, if inference is enabled we need to make sure not
+ * to splice a new prototype in for Function.prototype or the global
+ * object if their __proto__ had previously been set to null, as this
+ * will change the prototype for all other objects with the same type.
+ */
+ if (staticPrototype() != nullptr)
+ return false;
+ return isSingleton();
+}
+
+bool
+JSObject::splicePrototype(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto)
+{
+ MOZ_ASSERT(cx->compartment() == compartment());
+
+ RootedObject self(cx, this);
+
+ /*
+ * For singleton groups representing only a single JSObject, the proto
+ * can be rearranged as needed without destroying type information for
+ * the old or new types.
+ */
+ MOZ_ASSERT(self->isSingleton());
+
+ // Windows may not appear on prototype chains.
+ MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
+
+ if (proto.isObject() && !proto.toObject()->setDelegate(cx))
+ return false;
+
+ // Force type instantiation when splicing lazy group.
+ RootedObjectGroup group(cx, self->getGroup(cx));
+ if (!group)
+ return false;
+ RootedObjectGroup protoGroup(cx, nullptr);
+ if (proto.isObject()) {
+ protoGroup = proto.toObject()->getGroup(cx);
+ if (!protoGroup)
+ return false;
+ }
+
+ group->setClasp(clasp);
+ group->setProto(proto);
+ return true;
+}
+
+/* static */ ObjectGroup*
+JSObject::makeLazyGroup(JSContext* cx, HandleObject obj)
+{
+ MOZ_ASSERT(obj->hasLazyGroup());
+ MOZ_ASSERT(cx->compartment() == obj->compartment());
+
+ /* De-lazification of functions can GC, so we need to do it up here. */
+ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
+ RootedFunction fun(cx, &obj->as<JSFunction>());
+ if (!fun->getOrCreateScript(cx))
+ return nullptr;
+ }
+
+ // Find flags which need to be specified immediately on the object.
+ // Don't track whether singletons are packed.
+ ObjectGroupFlags initialFlags = OBJECT_FLAG_SINGLETON | OBJECT_FLAG_NON_PACKED;
+
+ if (obj->isIteratedSingleton())
+ initialFlags |= OBJECT_FLAG_ITERATED;
+
+ if (obj->isIndexed())
+ initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
+
+ if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
+ initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
+
+ Rooted<TaggedProto> proto(cx, obj->taggedProto());
+ ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto,
+ initialFlags);
+ if (!group)
+ return nullptr;
+
+ AutoEnterAnalysis enter(cx);
+
+ /* Fill in the type according to the state of this object. */
+
+ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
+ group->setInterpretedFunction(&obj->as<JSFunction>());
+
+ obj->group_ = group;
+
+ return group;
+}
+
+/* static */ bool
+JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj)
+{
+ ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj);
+ return obj->setFlags(cx, BaseShape::NEW_GROUP_UNKNOWN);
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroupCompartment NewTable
+/////////////////////////////////////////////////////////////////////
+
+/*
+ * Entries for the per-compartment set of groups which are the default
+ * types to use for some prototype. An optional associated object is used which
+ * allows multiple groups to be created with the same prototype. The
+ * associated object may be a function (for types constructed with 'new') or a
+ * type descriptor (for typed objects). These entries are also used for the set
+ * of lazy groups in the compartment, which use a null associated object
+ * (though there are only a few of these per compartment).
+ */
+struct ObjectGroupCompartment::NewEntry
+{
+ ReadBarrieredObjectGroup group;
+
+ // Note: This pointer is only used for equality and does not need a read barrier.
+ JSObject* associated;
+
+ NewEntry(ObjectGroup* group, JSObject* associated)
+ : group(group), associated(associated)
+ {}
+
+ struct Lookup {
+ const Class* clasp;
+ TaggedProto proto;
+ JSObject* associated;
+
+ Lookup(const Class* clasp, TaggedProto proto, JSObject* associated)
+ : clasp(clasp), proto(proto), associated(associated)
+ {}
+
+ bool hasAssocId() const {
+ return !associated || associated->zone()->hasUniqueId(associated);
+ }
+
+ bool ensureAssocId() const {
+ uint64_t unusedId;
+ return !associated ||
+ associated->zoneFromAnyThread()->getUniqueId(associated, &unusedId);
+ }
+
+ uint64_t getAssocId() const {
+ return associated ? associated->zone()->getUniqueIdInfallible(associated) : 0;
+ }
+ };
+
+ static bool hasHash(const Lookup& l) {
+ return l.proto.hasUniqueId() && l.hasAssocId();
+ }
+
+ static bool ensureHash(const Lookup& l) {
+ return l.proto.ensureUniqueId() && l.ensureAssocId();
+ }
+
+ static inline HashNumber hash(const Lookup& lookup) {
+ MOZ_ASSERT(lookup.proto.hasUniqueId());
+ MOZ_ASSERT(lookup.hasAssocId());
+ HashNumber hash = uintptr_t(lookup.clasp);
+ hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.proto.uniqueId());
+ hash = mozilla::RotateLeft(hash, 4) ^ Zone::UniqueIdToHash(lookup.getAssocId());
+ return hash;
+ }
+
+ static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) {
+ TaggedProto proto = key.group.unbarrieredGet()->proto().unbarrieredGet();
+ JSObject* assoc = key.associated;
+ MOZ_ASSERT(proto.hasUniqueId());
+ MOZ_ASSERT_IF(assoc, assoc->zone()->hasUniqueId(assoc));
+ MOZ_ASSERT(lookup.proto.hasUniqueId());
+ MOZ_ASSERT(lookup.hasAssocId());
+
+ if (lookup.clasp && key.group.unbarrieredGet()->clasp() != lookup.clasp)
+ return false;
+ if (proto.uniqueId() != lookup.proto.uniqueId())
+ return false;
+ return !assoc || assoc->zone()->getUniqueIdInfallible(assoc) == lookup.getAssocId();
+ }
+
+ static void rekey(NewEntry& k, const NewEntry& newKey) { k = newKey; }
+
+ bool needsSweep() {
+ return (IsAboutToBeFinalized(&group) ||
+ (associated && IsAboutToBeFinalizedUnbarriered(&associated)));
+ }
+};
+
+namespace js {
+template <>
+struct FallibleHashMethods<ObjectGroupCompartment::NewEntry>
+{
+ template <typename Lookup> static bool hasHash(Lookup&& l) {
+ return ObjectGroupCompartment::NewEntry::hasHash(mozilla::Forward<Lookup>(l));
+ }
+ template <typename Lookup> static bool ensureHash(Lookup&& l) {
+ return ObjectGroupCompartment::NewEntry::ensureHash(mozilla::Forward<Lookup>(l));
+ }
+};
+} // namespace js
+
+class ObjectGroupCompartment::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry,
+ SystemAllocPolicy>>
+{
+ using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>;
+ using Base = JS::WeakCache<Table>;
+
+ public:
+ explicit NewTable(Zone* zone) : Base(zone, Table()) {}
+};
+
+/* static */ ObjectGroup*
+ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
+ TaggedProto proto, JSObject* associated)
+{
+ MOZ_ASSERT_IF(associated, proto.isObject());
+ MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
+
+ // A null lookup clasp is used for 'new' groups with an associated
+ // function. The group starts out as a plain object but might mutate into an
+ // unboxed plain object.
+ MOZ_ASSERT_IF(!clasp, !!associated);
+
+ AutoEnterAnalysis enter(cx);
+
+ ObjectGroupCompartment::NewTable*& table = cx->compartment()->objectGroups.defaultNewTable;
+
+ if (!table) {
+ table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
+ if (!table || !table->init()) {
+ js_delete(table);
+ table = nullptr;
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ }
+
+ if (associated && !associated->is<TypeDescr>()) {
+ MOZ_ASSERT(!clasp);
+ if (associated->is<JSFunction>()) {
+
+ // Canonicalize new functions to use the original one associated with its script.
+ JSFunction* fun = &associated->as<JSFunction>();
+ if (fun->hasScript())
+ associated = fun->nonLazyScript()->functionNonDelazifying();
+ else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin())
+ associated = fun->lazyScript()->functionNonDelazifying();
+ else
+ associated = nullptr;
+
+ // If we have previously cleared the 'new' script information for this
+ // function, don't try to construct another one.
+ if (associated && associated->wasNewScriptCleared())
+ associated = nullptr;
+
+ } else {
+ associated = nullptr;
+ }
+
+ if (!associated)
+ clasp = &PlainObject::class_;
+ }
+
+ if (proto.isObject() && !proto.toObject()->isDelegate()) {
+ RootedObject protoObj(cx, proto.toObject());
+ if (!protoObj->setDelegate(cx))
+ return nullptr;
+
+ // Objects which are prototypes of one another should be singletons, so
+ // that their type information can be tracked more precisely. Limit
+ // this group change to plain objects, to avoid issues with other types
+ // of singletons like typed arrays.
+ if (protoObj->is<PlainObject>() && !protoObj->isSingleton()) {
+ if (!JSObject::changeToSingleton(cx->asJSContext(), protoObj))
+ return nullptr;
+ }
+ }
+
+ ObjectGroupCompartment::NewTable::AddPtr p =
+ table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, associated));
+ if (p) {
+ ObjectGroup* group = p->group;
+ MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
+ MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ ||
+ group->clasp() == &UnboxedPlainObject::class_);
+ MOZ_ASSERT(group->proto() == proto);
+ return group;
+ }
+
+ ObjectGroupFlags initialFlags = 0;
+ if (proto.isDynamic() || (proto.isObject() && proto.toObject()->isNewGroupUnknown()))
+ initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
+
+ Rooted<TaggedProto> protoRoot(cx, proto);
+ ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, clasp ? clasp : &PlainObject::class_,
+ protoRoot, initialFlags);
+ if (!group)
+ return nullptr;
+
+ if (!table->add(p, ObjectGroupCompartment::NewEntry(group, associated))) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ if (associated) {
+ if (associated->is<JSFunction>()) {
+ if (!TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>()))
+ return nullptr;
+ } else {
+ group->setTypeDescr(&associated->as<TypeDescr>());
+ }
+ }
+
+ /*
+ * Some builtin objects have slotful native properties baked in at
+ * creation via the Shape::{insert,get}initialShape mechanism. Since
+ * these properties are never explicitly defined on new objects, update
+ * the type information for them here.
+ */
+
+ const JSAtomState& names = cx->names();
+
+ if (clasp == &RegExpObject::class_) {
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.lastIndex), TypeSet::Int32Type());
+ } else if (clasp == &StringObject::class_) {
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type());
+ } else if (ErrorObject::isErrorClass((clasp))) {
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType());
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type());
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type());
+ AddTypePropertyId(cx, group, nullptr, NameToId(names.stack), TypeSet::StringType());
+ }
+
+ return group;
+}
+
+/* static */ ObjectGroup*
+ObjectGroup::lazySingletonGroup(ExclusiveContext* cx, const Class* clasp, TaggedProto proto)
+{
+ MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
+
+ ObjectGroupCompartment::NewTable*& table = cx->compartment()->objectGroups.lazyTable;
+
+ if (!table) {
+ table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
+ if (!table || !table->init()) {
+ ReportOutOfMemory(cx);
+ js_delete(table);
+ table = nullptr;
+ return nullptr;
+ }
+ }
+
+ ObjectGroupCompartment::NewTable::AddPtr p =
+ table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, nullptr));
+ if (p) {
+ ObjectGroup* group = p->group;
+ MOZ_ASSERT(group->lazy());
+
+ return group;
+ }
+
+ AutoEnterAnalysis enter(cx);
+
+ Rooted<TaggedProto> protoRoot(cx, proto);
+ ObjectGroup* group =
+ ObjectGroupCompartment::makeGroup(cx, clasp, protoRoot,
+ OBJECT_FLAG_SINGLETON | OBJECT_FLAG_LAZY_SINGLETON);
+ if (!group)
+ return nullptr;
+
+ if (!table->add(p, ObjectGroupCompartment::NewEntry(group, nullptr))) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ return group;
+}
+
+/* static */ void
+ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, const Class* clasp, HandleObject obj)
+{
+ // If the object already has a new group, mark that group as unknown.
+ ObjectGroupCompartment::NewTable* table = cx->compartment()->objectGroups.defaultNewTable;
+ if (table) {
+ Rooted<TaggedProto> taggedProto(cx, TaggedProto(obj));
+ auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, taggedProto, nullptr);
+ auto p = table->lookup(lookup);
+ if (p)
+ MarkObjectGroupUnknownProperties(cx, p->group);
+ }
+}
+
+#ifdef DEBUG
+/* static */ bool
+ObjectGroup::hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group)
+{
+ ObjectGroupCompartment::NewTable* table = proto->compartment()->objectGroups.defaultNewTable;
+
+ if (table) {
+ auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr);
+ auto p = table->lookup(lookup);
+ return p && p->group == group;
+ }
+ return false;
+}
+#endif /* DEBUG */
+
+inline const Class*
+GetClassForProtoKey(JSProtoKey key)
+{
+ switch (key) {
+ case JSProto_Null:
+ case JSProto_Object:
+ return &PlainObject::class_;
+ case JSProto_Array:
+ return &ArrayObject::class_;
+
+ case JSProto_Number:
+ return &NumberObject::class_;
+ case JSProto_Boolean:
+ return &BooleanObject::class_;
+ case JSProto_String:
+ return &StringObject::class_;
+ case JSProto_Symbol:
+ return &SymbolObject::class_;
+ case JSProto_RegExp:
+ return &RegExpObject::class_;
+
+ case JSProto_Int8Array:
+ case JSProto_Uint8Array:
+ case JSProto_Int16Array:
+ case JSProto_Uint16Array:
+ case JSProto_Int32Array:
+ case JSProto_Uint32Array:
+ case JSProto_Float32Array:
+ case JSProto_Float64Array:
+ case JSProto_Uint8ClampedArray:
+ return &TypedArrayObject::classes[key - JSProto_Int8Array];
+
+ case JSProto_ArrayBuffer:
+ return &ArrayBufferObject::class_;
+
+ case JSProto_SharedArrayBuffer:
+ return &SharedArrayBufferObject::class_;
+
+ case JSProto_DataView:
+ return &DataViewObject::class_;
+
+ default:
+ MOZ_CRASH("Bad proto key");
+ }
+}
+
+/* static */ ObjectGroup*
+ObjectGroup::defaultNewGroup(JSContext* cx, JSProtoKey key)
+{
+ RootedObject proto(cx);
+ if (key != JSProto_Null && !GetBuiltinPrototype(cx, key, &proto))
+ return nullptr;
+ return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto.get()));
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroupCompartment ArrayObjectTable
+/////////////////////////////////////////////////////////////////////
+
+struct ObjectGroupCompartment::ArrayObjectKey : public DefaultHasher<ArrayObjectKey>
+{
+ TypeSet::Type type;
+
+ ArrayObjectKey()
+ : type(TypeSet::UndefinedType())
+ {}
+
+ explicit ArrayObjectKey(TypeSet::Type type)
+ : type(type)
+ {}
+
+ static inline uint32_t hash(const ArrayObjectKey& v) {
+ return v.type.raw();
+ }
+
+ static inline bool match(const ArrayObjectKey& v1, const ArrayObjectKey& v2) {
+ return v1.type == v2.type;
+ }
+
+ bool operator==(const ArrayObjectKey& other) {
+ return type == other.type;
+ }
+
+ bool operator!=(const ArrayObjectKey& other) {
+ return !(*this == other);
+ }
+
+ bool needsSweep() {
+ MOZ_ASSERT(type.isUnknown() || !type.isSingleton());
+ if (!type.isUnknown() && type.isGroup()) {
+ ObjectGroup* group = type.groupNoBarrier();
+ if (IsAboutToBeFinalizedUnbarriered(&group))
+ return true;
+ if (group != type.groupNoBarrier())
+ type = TypeSet::ObjectType(group);
+ }
+ return false;
+ }
+};
+
+static inline bool
+NumberTypes(TypeSet::Type a, TypeSet::Type b)
+{
+ return (a.isPrimitive(JSVAL_TYPE_INT32) || a.isPrimitive(JSVAL_TYPE_DOUBLE))
+ && (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE));
+}
+
+/*
+ * As for GetValueType, but requires object types to be non-singletons with
+ * their default prototype. These are the only values that should appear in
+ * arrays and objects whose type can be fixed.
+ */
+static inline TypeSet::Type
+GetValueTypeForTable(const Value& v)
+{
+ TypeSet::Type type = TypeSet::GetValueType(v);
+ MOZ_ASSERT(!type.isSingleton());
+ return type;
+}
+
+/* static */ JSObject*
+ObjectGroup::newArrayObject(ExclusiveContext* cx,
+ const Value* vp, size_t length,
+ NewObjectKind newKind, NewArrayKind arrayKind)
+{
+ MOZ_ASSERT(newKind != SingletonObject);
+
+ // If we are making a copy on write array, don't try to adjust the group as
+ // getOrFixupCopyOnWriteObject will do this before any objects are copied
+ // from this one.
+ if (arrayKind == NewArrayKind::CopyOnWrite) {
+ ArrayObject* obj = NewDenseCopiedArray(cx, length, vp, nullptr, newKind);
+ if (!obj || !ObjectElements::MakeElementsCopyOnWrite(cx, obj))
+ return nullptr;
+ return obj;
+ }
+
+ // Get a type which captures all the elements in the array to be created.
+ Rooted<TypeSet::Type> elementType(cx, TypeSet::UnknownType());
+ if (arrayKind != NewArrayKind::UnknownIndex && length != 0) {
+ elementType = GetValueTypeForTable(vp[0]);
+ for (unsigned i = 1; i < length; i++) {
+ TypeSet::Type ntype = GetValueTypeForTable(vp[i]);
+ if (ntype != elementType) {
+ if (NumberTypes(elementType, ntype)) {
+ elementType = TypeSet::DoubleType();
+ } else {
+ elementType = TypeSet::UnknownType();
+ break;
+ }
+ }
+ }
+ }
+
+ ObjectGroupCompartment::ArrayObjectTable*& table =
+ cx->compartment()->objectGroups.arrayObjectTable;
+
+ if (!table) {
+ table = cx->new_<ObjectGroupCompartment::ArrayObjectTable>();
+ if (!table || !table->init()) {
+ ReportOutOfMemory(cx);
+ js_delete(table);
+ table = nullptr;
+ return nullptr;
+ }
+ }
+
+ ObjectGroupCompartment::ArrayObjectKey key(elementType);
+ DependentAddPtr<ObjectGroupCompartment::ArrayObjectTable> p(cx, *table, key);
+
+ RootedObjectGroup group(cx);
+ if (p) {
+ group = p->value();
+ } else {
+ RootedObject proto(cx);
+ if (!GetBuiltinPrototype(cx, JSProto_Array, &proto))
+ return nullptr;
+ Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
+ group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto);
+ if (!group)
+ return nullptr;
+
+ AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
+
+ if (elementType != TypeSet::UnknownType()) {
+ // Keep track of the initial objects we create with this type.
+ // If the initial ones have a consistent shape and property types, we
+ // will try to use an unboxed layout for the group.
+ PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+ cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
+ if (!preliminaryObjects)
+ return nullptr;
+ group->setPreliminaryObjects(preliminaryObjects);
+ }
+
+ if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
+ return nullptr;
+ }
+
+ // The type of the elements being added will already be reflected in type
+ // information, but make sure when creating an unboxed array that the
+ // common element type is suitable for the unboxed representation.
+ ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate;
+ if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length))
+ return nullptr;
+ if (group->maybePreliminaryObjects())
+ group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
+ if (group->maybeUnboxedLayout()) {
+ switch (group->unboxedLayout().elementType()) {
+ case JSVAL_TYPE_BOOLEAN:
+ if (elementType != TypeSet::BooleanType())
+ updateTypes = ShouldUpdateTypes::Update;
+ break;
+ case JSVAL_TYPE_INT32:
+ if (elementType != TypeSet::Int32Type())
+ updateTypes = ShouldUpdateTypes::Update;
+ break;
+ case JSVAL_TYPE_DOUBLE:
+ if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType())
+ updateTypes = ShouldUpdateTypes::Update;
+ break;
+ case JSVAL_TYPE_STRING:
+ if (elementType != TypeSet::StringType())
+ updateTypes = ShouldUpdateTypes::Update;
+ break;
+ case JSVAL_TYPE_OBJECT:
+ if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked())
+ updateTypes = ShouldUpdateTypes::Update;
+ break;
+ default:
+ MOZ_CRASH();
+ }
+ }
+
+ return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes);
+}
+
+// Try to change the group of |source| to match that of |target|.
+static bool
+GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
+{
+ MOZ_ASSERT(source->group() != target->group());
+
+ if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>())
+ return true;
+
+ if (target->group()->maybePreliminaryObjects()) {
+ bool force = IsInsideNursery(source);
+ target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force);
+ }
+
+ if (target->is<ArrayObject>()) {
+ ObjectGroup* sourceGroup = source->group();
+
+ if (source->is<UnboxedArrayObject>()) {
+ Shape* shape = target->as<ArrayObject>().lastProperty();
+ if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape))
+ return false;
+ } else if (source->is<ArrayObject>()) {
+ source->setGroup(target->group());
+ } else {
+ return true;
+ }
+
+ if (sourceGroup->maybePreliminaryObjects())
+ sourceGroup->maybePreliminaryObjects()->unregisterObject(source);
+ if (target->group()->maybePreliminaryObjects())
+ target->group()->maybePreliminaryObjects()->registerNewObject(source);
+
+ for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) {
+ Value v = source->as<ArrayObject>().getDenseElement(i);
+ AddTypePropertyId(cx, source->group(), source, JSID_VOID, v);
+ }
+
+ return true;
+ }
+
+ if (target->is<UnboxedArrayObject>()) {
+ if (!source->is<UnboxedArrayObject>())
+ return true;
+ if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32)
+ return true;
+ if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE)
+ return true;
+
+ return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group());
+ }
+
+ return true;
+}
+
+static bool
+SameGroup(JSObject* first, JSObject* second)
+{
+ return first->group() == second->group();
+}
+
+// When generating a multidimensional array of literals, such as
+// [[1,2],[3,4],[5.5,6.5]], try to ensure that each element of the array has
+// the same group. This is mainly important when the elements might have
+// different native vs. unboxed layouts, or different unboxed layouts, and
+// accessing the heterogenous layouts from JIT code will be much slower than
+// if they were homogenous.
+//
+// To do this, with each new array element we compare it with one of the
+// previous ones, and try to mutate the group of the new element to fit that
+// of the old element. If this isn't possible, the groups for all old elements
+// are mutated to fit that of the new element.
+bool
+js::CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj,
+ const Value* compare, size_t ncompare)
+{
+ if (!ncompare || !compare[0].isObject())
+ return true;
+
+ JSObject* oldObj = &compare[0].toObject();
+ if (SameGroup(oldObj, newObj))
+ return true;
+
+ if (!GiveObjectGroup(cx, newObj, oldObj))
+ return false;
+
+ if (SameGroup(oldObj, newObj))
+ return true;
+
+ if (!GiveObjectGroup(cx, oldObj, newObj))
+ return false;
+
+ if (SameGroup(oldObj, newObj)) {
+ for (size_t i = 1; i < ncompare; i++) {
+ if (compare[i].isObject() && !SameGroup(&compare[i].toObject(), newObj)) {
+ if (!GiveObjectGroup(cx, &compare[i].toObject(), newObj))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Similarly to CombineArrayElementTypes, if we are generating an array of
+// plain objects with a consistent property layout, such as
+// [{p:[1,2]},{p:[3,4]},{p:[5.5,6.5]}], where those plain objects in
+// turn have arrays as their own properties, try to ensure that a consistent
+// group is given to each array held by the same property of the plain objects.
+bool
+js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj,
+ const Value* compare, size_t ncompare)
+{
+ if (!ncompare || !compare[0].isObject())
+ return true;
+
+ JSObject* oldObj = &compare[0].toObject();
+ if (!SameGroup(oldObj, newObj))
+ return true;
+
+ if (newObj->is<PlainObject>()) {
+ if (newObj->as<PlainObject>().lastProperty() != oldObj->as<PlainObject>().lastProperty())
+ return true;
+
+ for (size_t slot = 0; slot < newObj->as<PlainObject>().slotSpan(); slot++) {
+ Value newValue = newObj->as<PlainObject>().getSlot(slot);
+ Value oldValue = oldObj->as<PlainObject>().getSlot(slot);
+
+ if (!newValue.isObject() || !oldValue.isObject())
+ continue;
+
+ JSObject* newInnerObj = &newValue.toObject();
+ JSObject* oldInnerObj = &oldValue.toObject();
+
+ if (SameGroup(oldInnerObj, newInnerObj))
+ continue;
+
+ if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj))
+ return false;
+
+ if (SameGroup(oldInnerObj, newInnerObj))
+ continue;
+
+ if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj))
+ return false;
+
+ if (SameGroup(oldInnerObj, newInnerObj)) {
+ for (size_t i = 1; i < ncompare; i++) {
+ if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) {
+ Value otherValue = compare[i].toObject().as<PlainObject>().getSlot(slot);
+ if (otherValue.isObject() && !SameGroup(&otherValue.toObject(), newInnerObj)) {
+ if (!GiveObjectGroup(cx, &otherValue.toObject(), newInnerObj))
+ return false;
+ }
+ }
+ }
+ }
+ }
+ } else if (newObj->is<UnboxedPlainObject>()) {
+ const UnboxedLayout& layout = newObj->as<UnboxedPlainObject>().layout();
+ const int32_t* traceList = layout.traceList();
+ if (!traceList)
+ return true;
+
+ uint8_t* newData = newObj->as<UnboxedPlainObject>().data();
+ uint8_t* oldData = oldObj->as<UnboxedPlainObject>().data();
+
+ for (; *traceList != -1; traceList++) {}
+ traceList++;
+ for (; *traceList != -1; traceList++) {
+ JSObject* newInnerObj = *reinterpret_cast<JSObject**>(newData + *traceList);
+ JSObject* oldInnerObj = *reinterpret_cast<JSObject**>(oldData + *traceList);
+
+ if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj))
+ continue;
+
+ if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj))
+ return false;
+
+ if (SameGroup(oldInnerObj, newInnerObj))
+ continue;
+
+ if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj))
+ return false;
+
+ if (SameGroup(oldInnerObj, newInnerObj)) {
+ for (size_t i = 1; i < ncompare; i++) {
+ if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) {
+ uint8_t* otherData = compare[i].toObject().as<UnboxedPlainObject>().data();
+ JSObject* otherInnerObj = *reinterpret_cast<JSObject**>(otherData + *traceList);
+ if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) {
+ if (!GiveObjectGroup(cx, otherInnerObj, newInnerObj))
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroupCompartment PlainObjectTable
+/////////////////////////////////////////////////////////////////////
+
+struct ObjectGroupCompartment::PlainObjectKey
+{
+ jsid* properties;
+ uint32_t nproperties;
+
+ struct Lookup {
+ IdValuePair* properties;
+ uint32_t nproperties;
+
+ Lookup(IdValuePair* properties, uint32_t nproperties)
+ : properties(properties), nproperties(nproperties)
+ {}
+ };
+
+ static inline HashNumber hash(const Lookup& lookup) {
+ return (HashNumber) (HashId(lookup.properties[lookup.nproperties - 1].id) ^
+ lookup.nproperties);
+ }
+
+ static inline bool match(const PlainObjectKey& v, const Lookup& lookup) {
+ if (lookup.nproperties != v.nproperties)
+ return false;
+ for (size_t i = 0; i < lookup.nproperties; i++) {
+ if (lookup.properties[i].id != v.properties[i])
+ return false;
+ }
+ return true;
+ }
+
+ bool needsSweep() {
+ for (unsigned i = 0; i < nproperties; i++) {
+ if (gc::IsAboutToBeFinalizedUnbarriered(&properties[i]))
+ return true;
+ }
+ return false;
+ }
+};
+
+struct ObjectGroupCompartment::PlainObjectEntry
+{
+ ReadBarrieredObjectGroup group;
+ ReadBarrieredShape shape;
+ TypeSet::Type* types;
+
+ bool needsSweep(unsigned nproperties) {
+ if (IsAboutToBeFinalized(&group))
+ return true;
+ if (IsAboutToBeFinalized(&shape))
+ return true;
+ for (unsigned i = 0; i < nproperties; i++) {
+ MOZ_ASSERT(!types[i].isSingleton());
+ if (types[i].isGroup()) {
+ ObjectGroup* group = types[i].groupNoBarrier();
+ if (IsAboutToBeFinalizedUnbarriered(&group))
+ return true;
+ if (group != types[i].groupNoBarrier())
+ types[i] = TypeSet::ObjectType(group);
+ }
+ }
+ return false;
+ }
+};
+
+static bool
+CanShareObjectGroup(IdValuePair* properties, size_t nproperties)
+{
+ // Don't reuse groups for objects containing indexed properties, which
+ // might end up as dense elements.
+ for (size_t i = 0; i < nproperties; i++) {
+ uint32_t index;
+ if (IdIsIndex(properties[i].id, &index))
+ return false;
+ }
+ return true;
+}
+
+static bool
+AddPlainObjectProperties(ExclusiveContext* cx, HandlePlainObject obj,
+ IdValuePair* properties, size_t nproperties)
+{
+ RootedId propid(cx);
+ RootedValue value(cx);
+
+ for (size_t i = 0; i < nproperties; i++) {
+ propid = properties[i].id;
+ value = properties[i].value;
+ if (!NativeDefineProperty(cx, obj, propid, value, nullptr, nullptr, JSPROP_ENUMERATE))
+ return false;
+ }
+
+ return true;
+}
+
+PlainObject*
+js::NewPlainObjectWithProperties(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties,
+ NewObjectKind newKind)
+{
+ gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties);
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, allocKind, newKind));
+ if (!obj || !AddPlainObjectProperties(cx, obj, properties, nproperties))
+ return nullptr;
+ return obj;
+}
+
+/* static */ JSObject*
+ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties,
+ NewObjectKind newKind)
+{
+ // Watch for simple cases where we don't try to reuse plain object groups.
+ if (newKind == SingletonObject || nproperties == 0 || nproperties >= PropertyTree::MAX_HEIGHT)
+ return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
+
+ ObjectGroupCompartment::PlainObjectTable*& table =
+ cx->compartment()->objectGroups.plainObjectTable;
+
+ if (!table) {
+ table = cx->new_<ObjectGroupCompartment::PlainObjectTable>();
+ if (!table || !table->init()) {
+ ReportOutOfMemory(cx);
+ js_delete(table);
+ table = nullptr;
+ return nullptr;
+ }
+ }
+
+ ObjectGroupCompartment::PlainObjectKey::Lookup lookup(properties, nproperties);
+ ObjectGroupCompartment::PlainObjectTable::Ptr p = table->lookup(lookup);
+
+ if (!p) {
+ if (!CanShareObjectGroup(properties, nproperties))
+ return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
+
+ RootedObject proto(cx);
+ if (!GetBuiltinPrototype(cx, JSProto_Object, &proto))
+ return nullptr;
+
+ Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
+ RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_,
+ tagged));
+ if (!group)
+ return nullptr;
+
+ gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties);
+ RootedPlainObject obj(cx, NewObjectWithGroup<PlainObject>(cx, group,
+ allocKind, TenuredObject));
+ if (!obj || !AddPlainObjectProperties(cx, obj, properties, nproperties))
+ return nullptr;
+
+ // Don't make entries with duplicate property names, which will show up
+ // here as objects with fewer properties than we thought we were
+ // adding to the object. In this case, reset the object's group to the
+ // default (which will have unknown properties) so that the group we
+ // just created will be collected by the GC.
+ if (obj->slotSpan() != nproperties) {
+ ObjectGroup* group = defaultNewGroup(cx, obj->getClass(), obj->taggedProto());
+ if (!group)
+ return nullptr;
+ obj->setGroup(group);
+ return obj;
+ }
+
+ // Keep track of the initial objects we create with this type.
+ // If the initial ones have a consistent shape and property types, we
+ // will try to use an unboxed layout for the group.
+ PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+ cx->new_<PreliminaryObjectArrayWithTemplate>(obj->lastProperty());
+ if (!preliminaryObjects)
+ return nullptr;
+ group->setPreliminaryObjects(preliminaryObjects);
+ preliminaryObjects->registerNewObject(obj);
+
+ ScopedJSFreePtr<jsid> ids(group->zone()->pod_calloc<jsid>(nproperties));
+ if (!ids) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ ScopedJSFreePtr<TypeSet::Type> types(
+ group->zone()->pod_calloc<TypeSet::Type>(nproperties));
+ if (!types) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < nproperties; i++) {
+ ids[i] = properties[i].id;
+ types[i] = GetValueTypeForTable(obj->getSlot(i));
+ AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]);
+ }
+
+ ObjectGroupCompartment::PlainObjectKey key;
+ key.properties = ids;
+ key.nproperties = nproperties;
+ MOZ_ASSERT(ObjectGroupCompartment::PlainObjectKey::match(key, lookup));
+
+ ObjectGroupCompartment::PlainObjectEntry entry;
+ entry.group.set(group);
+ entry.shape.set(obj->lastProperty());
+ entry.types = types;
+
+ ObjectGroupCompartment::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
+ if (!table->add(np, key, entry)) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ ids.forget();
+ types.forget();
+
+ return obj;
+ }
+
+ RootedObjectGroup group(cx, p->value().group);
+
+ // Watch for existing groups which now use an unboxed layout.
+ if (group->maybeUnboxedLayout()) {
+ MOZ_ASSERT(group->unboxedLayout().properties().length() == nproperties);
+ return UnboxedPlainObject::createWithProperties(cx, group, newKind, properties);
+ }
+
+ // Update property types according to the properties we are about to add.
+ // Do this before we do anything which can GC, which might move or remove
+ // this table entry.
+ if (!group->unknownProperties()) {
+ for (size_t i = 0; i < nproperties; i++) {
+ TypeSet::Type type = p->value().types[i];
+ TypeSet::Type ntype = GetValueTypeForTable(properties[i].value);
+ if (ntype == type)
+ continue;
+ if (ntype.isPrimitive(JSVAL_TYPE_INT32) &&
+ type.isPrimitive(JSVAL_TYPE_DOUBLE))
+ {
+ // The property types already reflect 'int32'.
+ } else {
+ if (ntype.isPrimitive(JSVAL_TYPE_DOUBLE) &&
+ type.isPrimitive(JSVAL_TYPE_INT32))
+ {
+ // Include 'double' in the property types to avoid the update below later.
+ p->value().types[i] = TypeSet::DoubleType();
+ }
+ AddTypePropertyId(cx, group, nullptr, IdToTypeId(properties[i].id), ntype);
+ }
+ }
+ }
+
+ RootedShape shape(cx, p->value().shape);
+
+ if (group->maybePreliminaryObjects())
+ newKind = TenuredObject;
+
+ gc::AllocKind allocKind = gc::GetGCObjectKind(nproperties);
+ RootedPlainObject obj(cx, NewObjectWithGroup<PlainObject>(cx, group, allocKind,
+ newKind));
+
+ if (!obj || !obj->setLastProperty(cx, shape))
+ return nullptr;
+
+ for (size_t i = 0; i < nproperties; i++)
+ obj->setSlot(i, properties[i].value);
+
+ if (group->maybePreliminaryObjects()) {
+ group->maybePreliminaryObjects()->registerNewObject(obj);
+ group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
+ }
+
+ return obj;
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroupCompartment AllocationSiteTable
+/////////////////////////////////////////////////////////////////////
+
+struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
+ ReadBarrieredScript script;
+
+ uint32_t offset : 24;
+ JSProtoKey kind : 8;
+
+ ReadBarrieredObject proto;
+
+ static const uint32_t OFFSET_LIMIT = (1 << 23);
+
+ AllocationSiteKey(JSScript* script_, uint32_t offset_, JSProtoKey kind_, JSObject* proto_)
+ : script(script_), offset(offset_), kind(kind_), proto(proto_)
+ {
+ MOZ_ASSERT(offset_ < OFFSET_LIMIT);
+ }
+
+ AllocationSiteKey(const AllocationSiteKey& key)
+ : script(key.script),
+ offset(key.offset),
+ kind(key.kind),
+ proto(key.proto)
+ { }
+
+ AllocationSiteKey(AllocationSiteKey&& key)
+ : script(mozilla::Move(key.script)),
+ offset(key.offset),
+ kind(key.kind),
+ proto(mozilla::Move(key.proto))
+ { }
+
+ void operator=(AllocationSiteKey&& key) {
+ script = mozilla::Move(key.script);
+ offset = key.offset;
+ kind = key.kind;
+ proto = mozilla::Move(key.proto);
+ }
+
+ static inline uint32_t hash(AllocationSiteKey key) {
+ return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind ^
+ MovableCellHasher<JSObject*>::hash(key.proto));
+ }
+
+ static inline bool match(const AllocationSiteKey& a, const AllocationSiteKey& b) {
+ return DefaultHasher<JSScript*>::match(a.script, b.script) &&
+ a.offset == b.offset &&
+ a.kind == b.kind &&
+ MovableCellHasher<JSObject*>::match(a.proto, b.proto);
+ }
+
+ void trace(JSTracer* trc) {
+ TraceRoot(trc, &script, "AllocationSiteKey script");
+ TraceNullableRoot(trc, &proto, "AllocationSiteKey proto");
+ }
+
+ bool needsSweep() {
+ return IsAboutToBeFinalizedUnbarriered(script.unsafeGet()) ||
+ (proto && IsAboutToBeFinalizedUnbarriered(proto.unsafeGet()));
+ }
+};
+
+class ObjectGroupCompartment::AllocationSiteTable
+ : public JS::WeakCache<js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
+ AllocationSiteKey, SystemAllocPolicy>>
+{
+ using Table = js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
+ AllocationSiteKey, SystemAllocPolicy>;
+ using Base = JS::WeakCache<Table>;
+
+ public:
+ explicit AllocationSiteTable(Zone* zone) : Base(zone, Table()) {}
+};
+
+/* static */ ObjectGroup*
+ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* pc,
+ JSProtoKey kind, HandleObject protoArg /* = nullptr */)
+{
+ MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
+ MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
+
+ uint32_t offset = scriptArg->pcToOffset(pc);
+
+ if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) {
+ if (protoArg)
+ return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg));
+ return defaultNewGroup(cx, kind);
+ }
+
+ ObjectGroupCompartment::AllocationSiteTable*& table =
+ cx->compartment()->objectGroups.allocationSiteTable;
+
+ if (!table) {
+ table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>(cx->zone());
+ if (!table || !table->init()) {
+ ReportOutOfMemory(cx);
+ js_delete(table);
+ table = nullptr;
+ return nullptr;
+ }
+ }
+
+ RootedScript script(cx, scriptArg);
+ RootedObject proto(cx, protoArg);
+ if (!proto && kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto))
+ return nullptr;
+
+ Rooted<ObjectGroupCompartment::AllocationSiteKey> key(cx,
+ ObjectGroupCompartment::AllocationSiteKey(script, offset, kind, proto));
+
+ ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
+ if (p)
+ return p->value();
+
+ AutoEnterAnalysis enter(cx);
+
+ Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
+ ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged,
+ OBJECT_FLAG_FROM_ALLOCATION_SITE);
+ if (!res)
+ return nullptr;
+
+ if (JSOp(*pc) == JSOP_NEWOBJECT) {
+ // Keep track of the preliminary objects with this group, so we can try
+ // to use an unboxed layout for the object once some are allocated.
+ Shape* shape = script->getObject(pc)->as<PlainObject>().lastProperty();
+ if (!shape->isEmptyShape()) {
+ PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+ cx->new_<PreliminaryObjectArrayWithTemplate>(shape);
+ if (preliminaryObjects)
+ res->setPreliminaryObjects(preliminaryObjects);
+ else
+ cx->recoverFromOutOfMemory();
+ }
+ }
+
+ if (kind == JSProto_Array &&
+ (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) &&
+ cx->options().unboxedArrays())
+ {
+ PreliminaryObjectArrayWithTemplate* preliminaryObjects =
+ cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
+ if (preliminaryObjects)
+ res->setPreliminaryObjects(preliminaryObjects);
+ else
+ cx->recoverFromOutOfMemory();
+ }
+
+ if (!table->add(p, key, res)) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ return res;
+}
+
+void
+ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
+ JSProtoKey kind, ObjectGroup* group)
+{
+ AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
+
+ AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
+ MOZ_RELEASE_ASSERT(p);
+ allocationSiteTable->get().remove(p);
+ {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!allocationSiteTable->putNew(key, group))
+ oomUnsafe.crash("Inconsistent object table");
+ }
+}
+
+/* static */ ObjectGroup*
+ObjectGroup::callingAllocationSiteGroup(JSContext* cx, JSProtoKey key, HandleObject proto)
+{
+ MOZ_ASSERT_IF(proto, key == JSProto_Array);
+
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ if (script)
+ return allocationSiteGroup(cx, script, pc, key, proto);
+ if (proto)
+ return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto));
+ return defaultNewGroup(cx, key);
+}
+
+/* static */ bool
+ObjectGroup::setAllocationSiteObjectGroup(JSContext* cx,
+ HandleScript script, jsbytecode* pc,
+ HandleObject obj, bool singleton)
+{
+ JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+ MOZ_ASSERT(key != JSProto_Null);
+ MOZ_ASSERT(singleton == useSingletonForAllocationSite(script, pc, key));
+
+ if (singleton) {
+ MOZ_ASSERT(obj->isSingleton());
+
+ /*
+ * Inference does not account for types of run-once initializer
+ * objects, as these may not be created until after the script
+ * has been analyzed.
+ */
+ TypeScript::Monitor(cx, script, pc, ObjectValue(*obj));
+ } else {
+ ObjectGroup* group = allocationSiteGroup(cx, script, pc, key);
+ if (!group)
+ return false;
+ obj->setGroup(group);
+ }
+
+ return true;
+}
+
+/* static */ ArrayObject*
+ObjectGroup::getOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script, jsbytecode* pc)
+{
+ // Make sure that the template object for script/pc has a type indicating
+ // that the object and its copies have copy on write elements.
+ RootedArrayObject obj(cx, &script->getObject(GET_UINT32_INDEX(pc))->as<ArrayObject>());
+ MOZ_ASSERT(obj->denseElementsAreCopyOnWrite());
+
+ if (obj->group()->fromAllocationSite()) {
+ MOZ_ASSERT(obj->group()->hasAnyFlags(OBJECT_FLAG_COPY_ON_WRITE));
+ return obj;
+ }
+
+ RootedObjectGroup group(cx, allocationSiteGroup(cx, script, pc, JSProto_Array));
+ if (!group)
+ return nullptr;
+
+ group->addFlags(OBJECT_FLAG_COPY_ON_WRITE);
+
+ // Update type information in the initializer object group.
+ MOZ_ASSERT(obj->slotSpan() == 0);
+ for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
+ const Value& v = obj->getDenseElement(i);
+ AddTypePropertyId(cx, group, nullptr, JSID_VOID, v);
+ }
+
+ obj->setGroup(group);
+ return obj;
+}
+
+/* static */ ArrayObject*
+ObjectGroup::getCopyOnWriteObject(JSScript* script, jsbytecode* pc)
+{
+ // getOrFixupCopyOnWriteObject should already have been called for
+ // script/pc, ensuring that the template object has a group with the
+ // COPY_ON_WRITE flag. We don't assert this here, due to a corner case
+ // where this property doesn't hold. See jsop_newarray_copyonwrite in
+ // IonBuilder.
+ ArrayObject* obj = &script->getObject(GET_UINT32_INDEX(pc))->as<ArrayObject>();
+ MOZ_ASSERT(obj->denseElementsAreCopyOnWrite());
+
+ return obj;
+}
+
+/* static */ bool
+ObjectGroup::findAllocationSite(JSContext* cx, ObjectGroup* group,
+ JSScript** script, uint32_t* offset)
+{
+ *script = nullptr;
+ *offset = 0;
+
+ const ObjectGroupCompartment::AllocationSiteTable* table =
+ cx->compartment()->objectGroups.allocationSiteTable;
+
+ if (!table)
+ return false;
+
+ for (ObjectGroupCompartment::AllocationSiteTable::Range r = table->all();
+ !r.empty();
+ r.popFront())
+ {
+ if (group == r.front().value()) {
+ *script = r.front().key().script;
+ *offset = r.front().key().offset;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroupCompartment
+/////////////////////////////////////////////////////////////////////
+
+ObjectGroupCompartment::ObjectGroupCompartment()
+{
+ PodZero(this);
+}
+
+ObjectGroupCompartment::~ObjectGroupCompartment()
+{
+ js_delete(defaultNewTable);
+ js_delete(lazyTable);
+ js_delete(arrayObjectTable);
+ js_delete(plainObjectTable);
+ js_delete(allocationSiteTable);
+}
+
+void
+ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto proto,
+ JSObject* associated)
+{
+ auto p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated));
+ MOZ_RELEASE_ASSERT(p);
+
+ defaultNewTable->get().remove(p);
+}
+
+void
+ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto,
+ JSObject* associated, ObjectGroup* group)
+{
+ NewEntry::Lookup lookup(clasp, proto, associated);
+
+ auto p = defaultNewTable->lookup(lookup);
+ MOZ_RELEASE_ASSERT(p);
+ defaultNewTable->get().remove(p);
+ {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!defaultNewTable->putNew(lookup, NewEntry(group, associated)))
+ oomUnsafe.crash("Inconsistent object table");
+ }
+}
+
+/* static */
+ObjectGroup*
+ObjectGroupCompartment::makeGroup(ExclusiveContext* cx, const Class* clasp,
+ Handle<TaggedProto> proto,
+ ObjectGroupFlags initialFlags /* = 0 */)
+{
+ MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
+
+ ObjectGroup* group = Allocate<ObjectGroup>(cx);
+ if (!group)
+ return nullptr;
+ new(group) ObjectGroup(clasp, proto, cx->compartment(), initialFlags);
+
+ return group;
+}
+
+void
+ObjectGroupCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ size_t* allocationSiteTables,
+ size_t* arrayObjectGroupTables,
+ size_t* plainObjectGroupTables,
+ size_t* compartmentTables)
+{
+ if (allocationSiteTable)
+ *allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
+
+ if (arrayObjectTable)
+ *arrayObjectGroupTables += arrayObjectTable->sizeOfIncludingThis(mallocSizeOf);
+
+ if (plainObjectTable) {
+ *plainObjectGroupTables += plainObjectTable->sizeOfIncludingThis(mallocSizeOf);
+
+ for (PlainObjectTable::Enum e(*plainObjectTable);
+ !e.empty();
+ e.popFront())
+ {
+ const PlainObjectKey& key = e.front().key();
+ const PlainObjectEntry& value = e.front().value();
+
+ /* key.ids and values.types have the same length. */
+ *plainObjectGroupTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types);
+ }
+ }
+
+ if (defaultNewTable)
+ *compartmentTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf);
+
+ if (lazyTable)
+ *compartmentTables += lazyTable->sizeOfIncludingThis(mallocSizeOf);
+}
+
+void
+ObjectGroupCompartment::clearTables()
+{
+ if (allocationSiteTable && allocationSiteTable->initialized())
+ allocationSiteTable->clear();
+ if (arrayObjectTable && arrayObjectTable->initialized())
+ arrayObjectTable->clear();
+ if (plainObjectTable && plainObjectTable->initialized()) {
+ for (PlainObjectTable::Enum e(*plainObjectTable); !e.empty(); e.popFront()) {
+ const PlainObjectKey& key = e.front().key();
+ PlainObjectEntry& entry = e.front().value();
+ js_free(key.properties);
+ js_free(entry.types);
+ }
+ plainObjectTable->clear();
+ }
+ if (defaultNewTable && defaultNewTable->initialized())
+ defaultNewTable->clear();
+ if (lazyTable && lazyTable->initialized())
+ lazyTable->clear();
+}
+
+/* static */ bool
+ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key,
+ PlainObjectEntry* entry)
+{
+ if (!(JS::GCPolicy<PlainObjectKey>::needsSweep(key) || entry->needsSweep(key->nproperties)))
+ return false;
+ js_free(key->properties);
+ js_free(entry->types);
+ return true;
+}
+
+void
+ObjectGroupCompartment::sweep(FreeOp* fop)
+{
+ /*
+ * Iterate through the array/object group tables and remove all entries
+ * referencing collected data. These tables only hold weak references.
+ */
+
+ if (arrayObjectTable)
+ arrayObjectTable->sweep();
+ if (plainObjectTable)
+ plainObjectTable->sweep();
+}
+
+void
+ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable* table)
+{
+ /*
+ * Each entry's hash depends on the object's prototype and we can't tell
+ * whether that has been moved or not in sweepNewObjectGroupTable().
+ */
+ if (table && table->initialized()) {
+ for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
+ NewEntry& entry = e.mutableFront();
+
+ ObjectGroup* group = entry.group.unbarrieredGet();
+ if (IsForwarded(group)) {
+ group = Forwarded(group);
+ entry.group.set(group);
+ }
+ TaggedProto proto = group->proto();
+ if (proto.isObject() && IsForwarded(proto.toObject())) {
+ proto = TaggedProto(Forwarded(proto.toObject()));
+ // Update the group's proto here so that we are able to lookup
+ // entries in this table before all object pointers are updated.
+ group->proto() = proto;
+ }
+ if (entry.associated && IsForwarded(entry.associated))
+ entry.associated = Forwarded(entry.associated);
+ }
+ }
+}
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+
+void
+ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table)
+{
+ /*
+ * Assert that nothing points into the nursery or needs to be relocated, and
+ * that the hash table entries are discoverable.
+ */
+ if (!table || !table->initialized())
+ return;
+
+ for (NewTable::Enum e(*table); !e.empty(); e.popFront()) {
+ NewEntry entry = e.front();
+ CheckGCThingAfterMovingGC(entry.group.unbarrieredGet());
+ TaggedProto proto = entry.group.unbarrieredGet()->proto();
+ if (proto.isObject())
+ CheckGCThingAfterMovingGC(proto.toObject());
+ CheckGCThingAfterMovingGC(entry.associated);
+
+ const Class* clasp = entry.group.unbarrieredGet()->clasp();
+ if (entry.associated && entry.associated->is<JSFunction>())
+ clasp = nullptr;
+
+ NewEntry::Lookup lookup(clasp, proto, entry.associated);
+ auto ptr = table->lookup(lookup);
+ MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
+ }
+}
+
+#endif // JSGC_HASH_TABLE_CHECKS
diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
new file mode 100644
index 000000000..4e24de9f1
--- /dev/null
+++ b/js/src/vm/ObjectGroup.h
@@ -0,0 +1,655 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ObjectGroup_h
+#define vm_ObjectGroup_h
+
+#include "jsbytecode.h"
+#include "jsfriendapi.h"
+
+#include "ds/IdValuePair.h"
+#include "gc/Barrier.h"
+#include "js/CharacterEncoding.h"
+#include "js/GCHashTable.h"
+#include "vm/TaggedProto.h"
+#include "vm/TypeInference.h"
+
+namespace js {
+
+class TypeDescr;
+class UnboxedLayout;
+
+class PreliminaryObjectArrayWithTemplate;
+class TypeNewScript;
+class HeapTypeSet;
+class AutoClearTypeInferenceStateOnOOM;
+class CompilerConstraintList;
+
+namespace gc {
+void MergeCompartments(JSCompartment* source, JSCompartment* target);
+} // namespace gc
+
+/*
+ * The NewObjectKind allows an allocation site to specify the type properties
+ * and lifetime requirements that must be fixed at allocation time.
+ */
+enum NewObjectKind {
+ /* This is the default. Most objects are generic. */
+ GenericObject,
+
+ /*
+ * Singleton objects are treated specially by the type system. This flag
+ * ensures that the new object is automatically set up correctly as a
+ * singleton and is allocated in the tenured heap.
+ */
+ SingletonObject,
+
+ /*
+ * CrossCompartmentWrappers use the common Proxy class, but are allowed
+ * to have nursery lifetime.
+ */
+ NurseryAllocatedProxy,
+
+ /*
+ * Objects which will not benefit from being allocated in the nursery
+ * (e.g. because they are known to have a long lifetime) may be allocated
+ * with this kind to place them immediately into the tenured generation.
+ */
+ TenuredObject
+};
+
+/*
+ * Lazy object groups overview.
+ *
+ * Object groups which represent at most one JS object are constructed lazily.
+ * These include groups for native functions, standard classes, scripted
+ * functions defined at the top level of global/eval scripts, objects which
+ * dynamically become the prototype of some other object, and in some other
+ * cases. Typical web workloads often create many windows (and many copies of
+ * standard natives) and many scripts, with comparatively few non-singleton
+ * groups.
+ *
+ * We can recover the type information for the object from examining it,
+ * so don't normally track the possible types of its properties as it is
+ * updated. Property type sets for the object are only constructed when an
+ * analyzed script attaches constraints to it: the script is querying that
+ * property off the object or another which delegates to it, and the analysis
+ * information is sensitive to changes in the property's type. Future changes
+ * to the property (whether those uncovered by analysis or those occurring
+ * in the VM) will treat these properties like those of any other object group.
+ */
+
+/* Type information about an object accessed by a script. */
+class ObjectGroup : public gc::TenuredCell
+{
+ friend void gc::MergeCompartments(JSCompartment* source, JSCompartment* target);
+
+ /* Class shared by objects in this group. */
+ const Class* clasp_;
+
+ /* Prototype shared by objects in this group. */
+ GCPtr<TaggedProto> proto_;
+
+ /* Compartment shared by objects in this group. */
+ JSCompartment* compartment_;
+
+ public:
+
+ const Class* clasp() const {
+ return clasp_;
+ }
+
+ void setClasp(const Class* clasp) {
+ MOZ_ASSERT(JS::StringIsASCII(clasp->name));
+ clasp_ = clasp;
+ }
+
+ bool hasDynamicPrototype() const {
+ return proto_.isDynamic();
+ }
+
+ const GCPtr<TaggedProto>& proto() const {
+ return proto_;
+ }
+
+ GCPtr<TaggedProto>& proto() {
+ return proto_;
+ }
+
+ void setProto(TaggedProto proto);
+ void setProtoUnchecked(TaggedProto proto);
+
+ bool singleton() const {
+ return flagsDontCheckGeneration() & OBJECT_FLAG_SINGLETON;
+ }
+
+ bool lazy() const {
+ bool res = flagsDontCheckGeneration() & OBJECT_FLAG_LAZY_SINGLETON;
+ MOZ_ASSERT_IF(res, singleton());
+ return res;
+ }
+
+ JSCompartment* compartment() const { return compartment_; }
+ JSCompartment* maybeCompartment() const { return compartment(); }
+
+ private:
+ /* Flags for this group. */
+ ObjectGroupFlags flags_;
+
+ // Kinds of addendums which can be attached to ObjectGroups.
+ enum AddendumKind {
+ Addendum_None,
+
+ // When used by interpreted function, the addendum stores the
+ // canonical JSFunction object.
+ Addendum_InterpretedFunction,
+
+ // When used by the 'new' group when constructing an interpreted
+ // function, the addendum stores a TypeNewScript.
+ Addendum_NewScript,
+
+ // For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate.
+ Addendum_PreliminaryObjects,
+
+ // When objects in this group have an unboxed representation, the
+ // addendum stores an UnboxedLayout (which might have a TypeNewScript
+ // as well, if the group is also constructed using 'new').
+ Addendum_UnboxedLayout,
+
+ // If this group is used by objects that have been converted from an
+ // unboxed representation and/or have the same allocation kind as such
+ // objects, the addendum points to that unboxed group.
+ Addendum_OriginalUnboxedGroup,
+
+ // When used by typed objects, the addendum stores a TypeDescr.
+ Addendum_TypeDescr
+ };
+
+ // If non-null, holds additional information about this object, whose
+ // format is indicated by the object's addendum kind.
+ void* addendum_;
+
+ void setAddendum(AddendumKind kind, void* addendum, bool writeBarrier = true);
+
+ AddendumKind addendumKind() const {
+ return (AddendumKind)
+ ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
+ }
+
+ TypeNewScript* newScriptDontCheckGeneration() const {
+ if (addendumKind() == Addendum_NewScript)
+ return reinterpret_cast<TypeNewScript*>(addendum_);
+ return nullptr;
+ }
+
+ TypeNewScript* anyNewScript();
+ void detachNewScript(bool writeBarrier, ObjectGroup* replacement);
+
+ ObjectGroupFlags flagsDontCheckGeneration() const {
+ return flags_;
+ }
+
+ public:
+
+ inline ObjectGroupFlags flags();
+ inline void addFlags(ObjectGroupFlags flags);
+ inline void clearFlags(ObjectGroupFlags flags);
+ inline TypeNewScript* newScript();
+
+ void setNewScript(TypeNewScript* newScript) {
+ setAddendum(Addendum_NewScript, newScript);
+ }
+
+ inline PreliminaryObjectArrayWithTemplate* maybePreliminaryObjects();
+
+ PreliminaryObjectArrayWithTemplate* maybePreliminaryObjectsDontCheckGeneration() {
+ if (addendumKind() == Addendum_PreliminaryObjects)
+ return reinterpret_cast<PreliminaryObjectArrayWithTemplate*>(addendum_);
+ return nullptr;
+ }
+
+ void setPreliminaryObjects(PreliminaryObjectArrayWithTemplate* preliminaryObjects) {
+ setAddendum(Addendum_PreliminaryObjects, preliminaryObjects);
+ }
+
+ void detachPreliminaryObjects() {
+ MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration());
+ setAddendum(Addendum_None, nullptr);
+ }
+
+ bool hasUnanalyzedPreliminaryObjects() {
+ return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
+ maybePreliminaryObjectsDontCheckGeneration();
+ }
+
+ inline UnboxedLayout* maybeUnboxedLayout();
+ inline UnboxedLayout& unboxedLayout();
+
+ UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
+ if (addendumKind() == Addendum_UnboxedLayout)
+ return reinterpret_cast<UnboxedLayout*>(addendum_);
+ return nullptr;
+ }
+
+ UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
+ MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
+ return *maybeUnboxedLayoutDontCheckGeneration();
+ }
+
+ void setUnboxedLayout(UnboxedLayout* layout) {
+ setAddendum(Addendum_UnboxedLayout, layout);
+ }
+
+ ObjectGroup* maybeOriginalUnboxedGroup() const {
+ if (addendumKind() == Addendum_OriginalUnboxedGroup)
+ return reinterpret_cast<ObjectGroup*>(addendum_);
+ return nullptr;
+ }
+
+ void setOriginalUnboxedGroup(ObjectGroup* group) {
+ setAddendum(Addendum_OriginalUnboxedGroup, group);
+ }
+
+ TypeDescr* maybeTypeDescr() {
+ // Note: there is no need to sweep when accessing the type descriptor
+ // of an object, as it is strongly held and immutable.
+ if (addendumKind() == Addendum_TypeDescr)
+ return reinterpret_cast<TypeDescr*>(addendum_);
+ return nullptr;
+ }
+
+ TypeDescr& typeDescr() {
+ MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
+ return *maybeTypeDescr();
+ }
+
+ void setTypeDescr(TypeDescr* descr) {
+ setAddendum(Addendum_TypeDescr, descr);
+ }
+
+ JSFunction* maybeInterpretedFunction() {
+ // Note: as with type descriptors, there is no need to sweep when
+ // accessing the interpreted function associated with an object.
+ if (addendumKind() == Addendum_InterpretedFunction)
+ return reinterpret_cast<JSFunction*>(addendum_);
+ return nullptr;
+ }
+
+ void setInterpretedFunction(JSFunction* fun) {
+ setAddendum(Addendum_InterpretedFunction, fun);
+ }
+
+ class Property
+ {
+ public:
+ // Identifier for this property, JSID_VOID for the aggregate integer
+ // index property, or JSID_EMPTY for properties holding constraints
+ // listening to changes in the group's state.
+ GCPtrId id;
+
+ // Possible own types for this property.
+ HeapTypeSet types;
+
+ explicit Property(jsid id)
+ : id(id)
+ {}
+
+ Property(const Property& o)
+ : id(o.id.get()), types(o.types)
+ {}
+
+ static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
+ static jsid getKey(Property* p) { return p->id; }
+ };
+
+ private:
+ /*
+ * Properties of this object.
+ *
+ * The type sets in the properties of a group describe the possible values
+ * that can be read out of that property in actual JS objects. In native
+ * objects, property types account for plain data properties (those with a
+ * slot and no getter or setter hook) and dense elements. In typed objects
+ * and unboxed objects, property types account for object and value
+ * properties and elements in the object, and expando properties in unboxed
+ * objects.
+ *
+ * For accesses on these properties, the correspondence is as follows:
+ *
+ * 1. If the group has unknownProperties(), the possible properties and
+ * value types for associated JSObjects are unknown.
+ *
+ * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property
+ * in |obj|, before obj->getProperty(id) the property in |group| for
+ * |id| must reflect the result of the getProperty.
+ *
+ * There are several exceptions to this:
+ *
+ * 1. For properties of global JS objects which are undefined at the point
+ * where the property was (lazily) generated, the property type set will
+ * remain empty, and the 'undefined' type will only be added after a
+ * subsequent assignment or deletion. After these properties have been
+ * assigned a defined value, the only way they can become undefined
+ * again is after such an assign or deletion.
+ *
+ * 2. Array lengths are special cased by the compiler and VM and are not
+ * reflected in property types.
+ *
+ * 3. In typed objects (but not unboxed objects), the initial values of
+ * properties (null pointers and undefined values) are not reflected in
+ * the property types. These values are always possible when reading the
+ * property.
+ *
+ * We establish these by using write barriers on calls to setProperty and
+ * defineProperty which are on native properties, and on any jitcode which
+ * might update the property with a new type.
+ */
+ Property** propertySet;
+ public:
+
+ inline ObjectGroup(const Class* clasp, TaggedProto proto, JSCompartment* comp,
+ ObjectGroupFlags initialFlags);
+
+ inline bool hasAnyFlags(ObjectGroupFlags flags);
+ inline bool hasAllFlags(ObjectGroupFlags flags);
+
+ bool hasAllFlagsDontCheckGeneration(ObjectGroupFlags flags) {
+ MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
+ return (this->flagsDontCheckGeneration() & flags) == flags;
+ }
+
+ inline bool unknownProperties();
+
+ bool unknownPropertiesDontCheckGeneration() {
+ MOZ_ASSERT_IF(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
+ hasAllFlagsDontCheckGeneration(OBJECT_FLAG_DYNAMIC_MASK));
+ return !!(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
+ }
+
+ inline bool shouldPreTenure();
+
+ gc::InitialHeap initialHeap(CompilerConstraintList* constraints);
+
+ inline bool canPreTenure();
+ inline bool fromAllocationSite();
+ inline void setShouldPreTenure(ExclusiveContext* cx);
+
+ /*
+ * Get or create a property of this object. Only call this for properties which
+ * a script accesses explicitly.
+ */
+ inline HeapTypeSet* getProperty(ExclusiveContext* cx, JSObject* obj, jsid id);
+
+ /* Get a property only if it already exists. */
+ inline HeapTypeSet* maybeGetProperty(jsid id);
+
+ /*
+ * Iterate through the group's properties. getPropertyCount overapproximates
+ * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
+ * getProperty may return nullptr.
+ */
+ inline unsigned getPropertyCount();
+ inline Property* getProperty(unsigned i);
+
+ /* Helpers */
+
+ void updateNewPropertyTypes(ExclusiveContext* cx, JSObject* obj, jsid id, HeapTypeSet* types);
+ void addDefiniteProperties(ExclusiveContext* cx, Shape* shape);
+ bool matchDefiniteProperties(HandleObject obj);
+ void markPropertyNonData(ExclusiveContext* cx, JSObject* obj, jsid id);
+ void markPropertyNonWritable(ExclusiveContext* cx, JSObject* obj, jsid id);
+ void markStateChange(ExclusiveContext* cx);
+ void setFlags(ExclusiveContext* cx, ObjectGroupFlags flags);
+ void markUnknown(ExclusiveContext* cx);
+ void maybeClearNewScriptOnOOM();
+ void clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement = nullptr);
+
+ void print();
+
+ inline void clearProperties();
+ void traceChildren(JSTracer* trc);
+
+ inline bool needsSweep();
+ inline void maybeSweep(AutoClearTypeInferenceStateOnOOM* oom);
+
+ private:
+ void sweep(AutoClearTypeInferenceStateOnOOM* oom);
+
+ uint32_t generation() {
+ return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT;
+ }
+
+ public:
+ void setGeneration(uint32_t generation) {
+ MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT));
+ flags_ &= ~OBJECT_FLAG_GENERATION_MASK;
+ flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT;
+ }
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+ void finalize(FreeOp* fop);
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::ObjectGroup;
+
+ static inline uint32_t offsetOfClasp() {
+ return offsetof(ObjectGroup, clasp_);
+ }
+
+ static inline uint32_t offsetOfProto() {
+ return offsetof(ObjectGroup, proto_);
+ }
+
+ static inline uint32_t offsetOfAddendum() {
+ return offsetof(ObjectGroup, addendum_);
+ }
+
+ static inline uint32_t offsetOfFlags() {
+ return offsetof(ObjectGroup, flags_);
+ }
+
+ const ObjectGroupFlags* addressOfFlags() const {
+ return &flags_;
+ }
+
+ // Get the bit pattern stored in an object's addendum when it has an
+ // original unboxed group.
+ static inline int32_t addendumOriginalUnboxedGroupValue() {
+ return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT;
+ }
+
+ inline uint32_t basePropertyCount();
+
+ private:
+ inline void setBasePropertyCount(uint32_t count);
+
+ static void staticAsserts() {
+ JS_STATIC_ASSERT(offsetof(ObjectGroup, proto_) == offsetof(js::shadow::ObjectGroup, proto));
+ }
+
+ public:
+ // Whether to make a deep cloned singleton when cloning fun.
+ static bool useSingletonForClone(JSFunction* fun);
+
+ // Whether to make a singleton when calling 'new' at script/pc.
+ static bool useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecode* pc);
+
+ // Whether to make a singleton object at an allocation site.
+ static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
+ JSProtoKey key);
+ static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
+ const Class* clasp);
+
+ // Static accessors for ObjectGroupCompartment NewTable.
+
+ static ObjectGroup* defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
+ TaggedProto proto,
+ JSObject* associated = nullptr);
+ static ObjectGroup* lazySingletonGroup(ExclusiveContext* cx, const Class* clasp,
+ TaggedProto proto);
+
+ static void setDefaultNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
+
+#ifdef DEBUG
+ static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
+#endif
+
+ // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable.
+
+ enum class NewArrayKind {
+ Normal, // Specialize array group based on its element type.
+ CopyOnWrite, // Make an array with copy-on-write elements.
+ UnknownIndex // Make an array with an unknown element type.
+ };
+
+ // Create an ArrayObject or UnboxedArrayObject with the specified elements
+ // and a group specialized for the elements.
+ static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
+ NewObjectKind newKind,
+ NewArrayKind arrayKind = NewArrayKind::Normal);
+
+ // Create a PlainObject or UnboxedPlainObject with the specified properties
+ // and a group specialized for those properties.
+ static JSObject* newPlainObject(ExclusiveContext* cx,
+ IdValuePair* properties, size_t nproperties,
+ NewObjectKind newKind);
+
+ // Static accessors for ObjectGroupCompartment AllocationSiteTable.
+
+ // Get a non-singleton group to use for objects created at the specified
+ // allocation site.
+ static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
+ JSProtoKey key, HandleObject proto = nullptr);
+
+ // Get a non-singleton group to use for objects created in a JSNative call.
+ static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key,
+ HandleObject proto = nullptr);
+
+ // Set the group or singleton-ness of an object created for an allocation site.
+ static bool
+ setAllocationSiteObjectGroup(JSContext* cx, HandleScript script, jsbytecode* pc,
+ HandleObject obj, bool singleton);
+
+ static ArrayObject* getOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script,
+ jsbytecode* pc);
+ static ArrayObject* getCopyOnWriteObject(JSScript* script, jsbytecode* pc);
+
+ // Returns false if not found.
+ static bool findAllocationSite(JSContext* cx, ObjectGroup* group,
+ JSScript** script, uint32_t* offset);
+
+ private:
+ static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
+};
+
+// Structure used to manage the groups in a compartment.
+class ObjectGroupCompartment
+{
+ friend class ObjectGroup;
+
+ class NewTable;
+
+ // Set of default 'new' or lazy groups in the compartment.
+ NewTable* defaultNewTable;
+ NewTable* lazyTable;
+
+ struct ArrayObjectKey;
+ using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
+ ReadBarrieredObjectGroup,
+ ArrayObjectKey,
+ SystemAllocPolicy>;
+
+ struct PlainObjectKey;
+ struct PlainObjectEntry;
+ struct PlainObjectTableSweepPolicy {
+ static bool needsSweep(PlainObjectKey* key, PlainObjectEntry* entry);
+ };
+ using PlainObjectTable = JS::GCHashMap<PlainObjectKey,
+ PlainObjectEntry,
+ PlainObjectKey,
+ SystemAllocPolicy,
+ PlainObjectTableSweepPolicy>;
+
+ // Tables for managing groups common to the contents of large script
+ // singleton objects and JSON objects. These are vanilla ArrayObjects and
+ // PlainObjects, so we distinguish the groups of different ones by looking
+ // at the types of their properties.
+ //
+ // All singleton/JSON arrays which have the same prototype, are homogenous
+ // and of the same element type will share a group. All singleton/JSON
+ // objects which have the same shape and property types will also share a
+ // group. We don't try to collate arrays or objects with type mismatches.
+ ArrayObjectTable* arrayObjectTable;
+ PlainObjectTable* plainObjectTable;
+
+ struct AllocationSiteKey;
+ class AllocationSiteTable;
+
+ // Table for referencing types of objects keyed to an allocation site.
+ AllocationSiteTable* allocationSiteTable;
+
+ public:
+ struct NewEntry;
+
+ ObjectGroupCompartment();
+ ~ObjectGroupCompartment();
+
+ void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
+ JSProtoKey kind, ObjectGroup* group);
+
+ void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated);
+ void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated,
+ ObjectGroup* group);
+
+ static ObjectGroup* makeGroup(ExclusiveContext* cx, const Class* clasp,
+ Handle<TaggedProto> proto,
+ ObjectGroupFlags initialFlags = 0);
+
+ void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ size_t* allocationSiteTables,
+ size_t* arrayGroupTables,
+ size_t* plainObjectGroupTables,
+ size_t* compartmentTables);
+
+ void clearTables();
+
+ void sweep(FreeOp* fop);
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+ void checkTablesAfterMovingGC() {
+ checkNewTableAfterMovingGC(defaultNewTable);
+ checkNewTableAfterMovingGC(lazyTable);
+ }
+#endif
+
+ void fixupTablesAfterMovingGC() {
+ fixupNewTableAfterMovingGC(defaultNewTable);
+ fixupNewTableAfterMovingGC(lazyTable);
+ }
+
+ private:
+#ifdef JSGC_HASH_TABLE_CHECKS
+ void checkNewTableAfterMovingGC(NewTable* table);
+#endif
+
+ void fixupNewTableAfterMovingGC(NewTable* table);
+};
+
+PlainObject*
+NewPlainObjectWithProperties(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties,
+ NewObjectKind newKind);
+
+bool
+CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj,
+ const Value* compare, size_t ncompare);
+
+bool
+CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj,
+ const Value* compare, size_t ncompare);
+
+} // namespace js
+
+#endif /* vm_ObjectGroup_h */
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
new file mode 100644
index 000000000..18ae6f073
--- /dev/null
+++ b/js/src/vm/Opcodes.h
@@ -0,0 +1,2314 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=0 ft=c:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Opcodes_h
+#define vm_Opcodes_h
+
+#include "mozilla/Attributes.h"
+
+#include <stddef.h>
+
+/*
+ * JavaScript operation bytecodes. Add a new bytecode by claiming one of the
+ * JSOP_UNUSED* here or by extracting the first unused opcode from
+ * FOR_EACH_TRAILING_UNUSED_OPCODE and updating js::detail::LastDefinedOpcode
+ * below.
+ *
+ * Includers must define a macro with the following form:
+ *
+ * #define MACRO(op,val,name,image,length,nuses,ndefs,format) ...
+ *
+ * Then simply use FOR_EACH_OPCODE(MACRO) to invoke MACRO for every opcode.
+ * Selected arguments can be expanded in initializers.
+ *
+ * Field Description
+ * op Bytecode name, which is the JSOp enumerator name
+ * value Bytecode value, which is the JSOp enumerator value
+ * name C string containing name for disassembler
+ * image C string containing "image" for pretty-printer, null if ugly
+ * length Number of bytes including any immediate operands
+ * nuses Number of stack slots consumed by bytecode, -1 if variadic
+ * ndefs Number of stack slots produced by bytecode, -1 if variadic
+ * format Bytecode plus immediate operand encoding format
+ *
+ * This file is best viewed with 128 columns:
+12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
+ */
+
+/*
+ * SpiderMonkey bytecode categorization (as used in generated documentation):
+ *
+ * [Index]
+ * [Statements]
+ * Jumps
+ * Switch Statement
+ * For-In Statement
+ * With Statement
+ * Exception Handling
+ * Function
+ * Generator
+ * Debugger
+ * [Variables and Scopes]
+ * Variables
+ * Free Variables
+ * Local Variables
+ * Aliased Variables
+ * Intrinsics
+ * Block-local Scope
+ * This
+ * Super
+ * Arguments
+ * Var Scope
+ * [Operators]
+ * Comparison Operators
+ * Arithmetic Operators
+ * Bitwise Logical Operators
+ * Bitwise Shift Operators
+ * Logical Operators
+ * Special Operators
+ * Stack Operations
+ * Debugger
+ * [Literals]
+ * Constants
+ * Object
+ * Array
+ * RegExp
+ * Class
+ * [Other]
+ */
+
+#define FOR_EACH_OPCODE(macro) \
+ /* legend: op val name image len use def format */ \
+ /*
+ * No operation is performed.
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /* Long-standing JavaScript bytecodes. */ \
+ /*
+ * Pushes 'undefined' onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => undefined
+ */ \
+ macro(JSOP_UNDEFINED, 1, js_undefined_str, "", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes stack frame's 'rval' onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: => rval
+ */ \
+ macro(JSOP_GETRVAL, 2, "getrval", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pops the top of stack value, converts it to an object, and adds a
+ * 'WithEnvironmentObject' wrapping that object to the scope chain.
+ *
+ * There is a matching JSOP_LEAVEWITH instruction later. All name
+ * lookups between the two that may need to consult the With object
+ * are deoptimized.
+ * Category: Statements
+ * Type: With Statement
+ * Operands: uint32_t staticWithIndex
+ * Stack: val =>
+ */ \
+ macro(JSOP_ENTERWITH, 3, "enterwith", NULL, 5, 1, 0, JOF_SCOPE) \
+ /*
+ * Pops the scope chain object pushed by JSOP_ENTERWITH.
+ * Category: Statements
+ * Type: With Statement
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_LEAVEWITH, 4, "leavewith", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the top of stack value as 'rval', stops interpretation of current
+ * script and returns 'rval'.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: rval =>
+ */ \
+ macro(JSOP_RETURN, 5, "return", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Jumps to a 32-bit offset from the current bytecode.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: =>
+ */ \
+ macro(JSOP_GOTO, 6, "goto", NULL, 5, 0, 0, JOF_JUMP) \
+ /*
+ * Pops the top of stack value, converts it into a boolean, if the result is
+ * 'false', jumps to a 32-bit offset from the current bytecode.
+ *
+ * The idea is that a sequence like
+ * JSOP_ZERO; JSOP_ZERO; JSOP_EQ; JSOP_IFEQ; JSOP_RETURN;
+ * reads like a nice linear sequence that will execute the return.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond =>
+ */ \
+ macro(JSOP_IFEQ, 7, "ifeq", NULL, 5, 1, 0, JOF_JUMP|JOF_DETECTING) \
+ /*
+ * Pops the top of stack value, converts it into a boolean, if the result is
+ * 'true', jumps to a 32-bit offset from the current bytecode.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond =>
+ */ \
+ macro(JSOP_IFNE, 8, "ifne", NULL, 5, 1, 0, JOF_JUMP) \
+ \
+ /*
+ * Pushes the 'arguments' object for the current function activation.
+ *
+ * If 'JSScript' is not marked 'needsArgsObj', then a
+ * JS_OPTIMIZED_ARGUMENTS magic value is pushed. Otherwise, a proper
+ * arguments object is constructed and pushed.
+ *
+ * This opcode requires that the function does not have rest parameter.
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands:
+ * Stack: => arguments
+ */ \
+ macro(JSOP_ARGUMENTS, 9, "arguments", NULL, 1, 0, 1, JOF_BYTE) \
+ \
+ /*
+ * Swaps the top two values on the stack. This is useful for things like
+ * post-increment/decrement.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v1, v2 => v2, v1
+ */ \
+ macro(JSOP_SWAP, 10, "swap", NULL, 1, 2, 2, JOF_BYTE) \
+ /*
+ * Pops the top 'n' values from the stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands: uint16_t n
+ * Stack: v[n-1], ..., v[1], v[0] =>
+ * nuses: n
+ */ \
+ macro(JSOP_POPN, 11, "popn", NULL, 3, -1, 0, JOF_UINT16) \
+ \
+ /* More long-standing bytecodes. */ \
+ /*
+ * Pushes a copy of the top value on the stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v => v, v
+ */ \
+ macro(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Duplicates the top two values on the stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v1, v2 => v1, v2, v1, v2
+ */ \
+ macro(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, JOF_BYTE) \
+ \
+ /*
+ * Checks that the top value on the stack is an object, and throws a
+ * TypeError if not. The operand 'kind' is used only to generate an
+ * appropriate error message.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint8_t kind
+ * Stack: result => result
+ */ \
+ macro(JSOP_CHECKISOBJ,14, "checkisobj", NULL, 2, 1, 1, JOF_UINT8) \
+ \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * the result of the operation applied to the two operands, converting
+ * both to 32-bit signed integers if necessary.
+ * Category: Operators
+ * Type: Bitwise Logical Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ macro(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the top two values from the stack and pushes the result of
+ * comparing them.
+ * Category: Operators
+ * Type: Comparison Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ macro(JSOP_EQ, 18, "eq", "==", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
+ macro(JSOP_NE, 19, "ne", "!=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
+ macro(JSOP_LT, 20, "lt", "<", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_LE, 21, "le", "<=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_GT, 22, "gt", ">", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_GE, 23, "ge", ">=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * the result of the operation applied to the operands.
+ * Category: Operators
+ * Type: Bitwise Shift Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ macro(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * 'lval >>> rval'.
+ * Category: Operators
+ * Type: Bitwise Shift Operators
+ * Operands:
+ * Stack: lval, rval => (lval >>> rval)
+ */ \
+ macro(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * the result of 'lval + rval'.
+ * Category: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: lval, rval => (lval + rval)
+ */ \
+ macro(JSOP_ADD, 27, "add", "+", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * the result of applying the arithmetic operation to them.
+ * Category: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ macro(JSOP_SUB, 28, "sub", "-", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_MUL, 29, "mul", "*", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_DIV, 30, "div", "/", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_MOD, 31, "mod", "%", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+ /*
+ * Pops the value 'val' from the stack, then pushes '!val'.
+ * Category: Operators
+ * Type: Logical Operators
+ * Operands:
+ * Stack: val => (!val)
+ */ \
+ macro(JSOP_NOT, 32, "not", "!", 1, 1, 1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
+ /*
+ * Pops the value 'val' from the stack, then pushes '~val'.
+ * Category: Operators
+ * Type: Bitwise Logical Operators
+ * Operands:
+ * Stack: val => (~val)
+ */ \
+ macro(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, JOF_BYTE|JOF_ARITH) \
+ /*
+ * Pops the value 'val' from the stack, then pushes '-val'.
+ * Category: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: val => (-val)
+ */ \
+ macro(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, JOF_BYTE|JOF_ARITH) \
+ /*
+ * Pops the value 'val' from the stack, then pushes '+val'.
+ * ('+val' is the value converted to a number.)
+ * Category: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: val => (+val)
+ */ \
+ macro(JSOP_POS, 35, "pos", "+ ", 1, 1, 1, JOF_BYTE|JOF_ARITH) \
+ /*
+ * Looks up name on the scope chain and deletes it, pushes 'true' onto the
+ * stack if succeeded (if the property was present and deleted or if the
+ * property wasn't present in the first place), 'false' if not.
+ *
+ * Strict mode code should never contain this opcode.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => succeeded
+ */ \
+ macro(JSOP_DELNAME, 36, "delname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_CHECKSLOPPY) \
+ /*
+ * Pops the top of stack value, deletes property from it, pushes 'true' onto
+ * the stack if succeeded, 'false' if not.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands: uint32_t nameIndex
+ * Stack: obj => succeeded
+ */ \
+ macro(JSOP_DELPROP, 37, "delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSLOPPY) \
+ /*
+ * Pops the top two values on the stack as 'propval' and 'obj',
+ * deletes 'propval' property from 'obj', pushes 'true' onto the stack if
+ * succeeded, 'false' if not.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: obj, propval => succeeded
+ */ \
+ macro(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_CHECKSLOPPY) \
+ /*
+ * Pops the value 'val' from the stack, then pushes 'typeof val'.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: val => (typeof val)
+ */ \
+ macro(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING) \
+ /*
+ * Pops the top value on the stack and pushes 'undefined'.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: val => undefined
+ */ \
+ macro(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, JOF_BYTE) \
+ \
+ /*
+ * spreadcall variant of JSOP_CALL.
+ *
+ * Invokes 'callee' with 'this' and 'args', pushes the return value onto
+ * the stack.
+ *
+ * 'args' is an Array object which contains actual arguments.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ macro(JSOP_SPREADCALL,41, "spreadcall", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * spreadcall variant of JSOP_NEW
+ *
+ * Invokes 'callee' as a constructor with 'this' and 'args', pushes the
+ * return value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args, newTarget => rval
+ */ \
+ macro(JSOP_SPREADNEW, 42, "spreadnew", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * spreadcall variant of JSOP_EVAL
+ *
+ * Invokes 'eval' with 'args' and pushes the return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function
+ * with 'this' and 'args', and pushes return value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ macro(JSOP_SPREADEVAL,43, "spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY) \
+ \
+ /*
+ * Duplicates the Nth value from the top onto the stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands: uint24_t n
+ * Stack: v[n], v[n-1], ..., v[1], v[0] =>
+ * v[n], v[n-1], ..., v[1], v[0], v[n]
+ */ \
+ macro(JSOP_DUPAT, 44, "dupat", NULL, 4, 0, 1, JOF_UINT24) \
+ \
+ /*
+ * Push a well-known symbol onto the operand stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint8_t n, the JS::SymbolCode of the symbol to use
+ * Stack: => symbol
+ */ \
+ macro(JSOP_SYMBOL, 45, "symbol", NULL, 2, 0, 1, JOF_UINT8) \
+ \
+ /*
+ * Pops the top of stack value and attempts to delete the given property
+ * from it. Pushes 'true' onto success, else throws a TypeError per strict
+ * mode property-deletion requirements.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands: uint32_t nameIndex
+ * Stack: obj => succeeded
+ */ \
+ macro(JSOP_STRICTDELPROP, 46, "strict-delprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_CHECKSTRICT) \
+ /*
+ * Pops the top two values on the stack as 'propval' and 'obj',
+ * and attempts to delete 'propval' property from 'obj'. Pushes 'true' onto
+ * the stack on success, else throws a TypeError per strict mode property
+ * deletion requirements.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval => succeeded
+ */ \
+ macro(JSOP_STRICTDELELEM, 47, "strict-delelem", NULL, 1, 2, 1, JOF_BYTE|JOF_ELEM|JOF_CHECKSTRICT) \
+ /*
+ * Pops the top two values on the stack as 'val' and 'obj', and performs
+ * 'obj.prop = val', pushing 'val' back onto the stack. Throws a TypeError
+ * if the set-operation failed (per strict mode semantics).
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ macro(JSOP_STRICTSETPROP, 48, "strict-setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING|JOF_CHECKSTRICT) \
+ /*
+ * Pops a scope and value from the stack, assigns value to the given name,
+ * and pushes the value back on the stack. If the set failed, then throw
+ * a TypeError, per usual strict mode semantics.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: scope, val => val
+ */ \
+ macro(JSOP_STRICTSETNAME, 49, "strict-setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_CHECKSTRICT) \
+ /*
+ * spreadcall variant of JSOP_EVAL
+ *
+ * Invokes 'eval' with 'args' and pushes the return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function
+ * with 'this' and 'args', and pushes return value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args => rval
+ */ \
+ macro(JSOP_STRICTSPREADEVAL, 50, "strict-spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT) \
+ /*
+ * Writes the [[Prototype]] objects for both a class and its .prototype to
+ * the stack, given the result of a heritage expression.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: heritage => funcProto, objProto
+ */ \
+ macro(JSOP_CLASSHERITAGE, 51, "classheritage", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Pushes a clone of a function with a given [[Prototype]] onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint32_t funcIndex
+ * Stack: proto => obj
+ */ \
+ macro(JSOP_FUNWITHPROTO, 52, "funwithproto", NULL, 5, 1, 1, JOF_OBJECT) \
+ \
+ /*
+ * Pops the top of stack value, pushes property of it onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ macro(JSOP_GETPROP, 53, "getprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET) \
+ /*
+ * Pops the top two values on the stack as 'val' and 'obj' and performs
+ * 'obj.prop = val', pushing 'val' back onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => val
+ */ \
+ macro(JSOP_SETPROP, 54, "setprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ /*
+ * Pops the top two values on the stack as 'propval' and 'obj', pushes
+ * 'propval' property of 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval => obj[propval]
+ */ \
+ macro(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+ /*
+ * Pops the top three values on the stack as 'val', 'propval' and 'obj',
+ * sets 'propval' property of 'obj' as 'val', pushes 'obj' onto the
+ * stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval, val => val
+ */ \
+ macro(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ /*
+ * Pops the top three values on the stack as 'val', 'propval' and 'obj',
+ * sets 'propval' property of 'obj' as 'val', pushes 'obj' onto the
+ * stack. Throws a TypeError if the set fails, per strict mode
+ * semantics.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval, val => val
+ */ \
+ macro(JSOP_STRICTSETELEM, 57, "strict-setelem", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING|JOF_CHECKSTRICT) \
+ /*
+ * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+ * stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ macro(JSOP_CALL, 58, "call", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * Looks up name on the scope chain and pushes its value onto the stack.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ macro(JSOP_GETNAME, 59, "getname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \
+ /*
+ * Pushes numeric constant onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint32_t constIndex
+ * Stack: => val
+ */ \
+ macro(JSOP_DOUBLE, 60, "double", NULL, 5, 0, 1, JOF_DOUBLE) \
+ /*
+ * Pushes string constant onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint32_t atomIndex
+ * Stack: => string
+ */ \
+ macro(JSOP_STRING, 61, "string", NULL, 5, 0, 1, JOF_ATOM) \
+ /*
+ * Pushes '0' onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => 0
+ */ \
+ macro(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes '1' onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => 1
+ */ \
+ macro(JSOP_ONE, 63, "one", "1", 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes 'null' onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => null
+ */ \
+ macro(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes 'JS_IS_CONSTRUCTING'
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => JS_IS_CONSTRUCTING
+ */ \
+ macro(JSOP_IS_CONSTRUCTING, 65, "is-constructing", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes boolean value onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => true/false
+ */ \
+ macro(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, JOF_BYTE) \
+ macro(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Converts the top of stack value into a boolean, if the result is 'true',
+ * jumps to a 32-bit offset from the current bytecode.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond => cond
+ */ \
+ macro(JSOP_OR, 68, "or", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
+ /*
+ * Converts the top of stack value into a boolean, if the result is 'false',
+ * jumps to a 32-bit offset from the current bytecode.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: cond => cond
+ */ \
+ macro(JSOP_AND, 69, "and", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
+ \
+ /*
+ * Pops the top of stack value as 'i', if 'low <= i <= high',
+ * jumps to a 32-bit offset: 'offset[i - low]' from the current bytecode,
+ * jumps to a 32-bit offset: 'len' from the current bytecode if not.
+ *
+ * This opcode has variable length.
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t len, int32_t low, int32_t high,
+ * int32_t offset[0], ..., int32_t offset[high-low]
+ * Stack: i =>
+ * len: len
+ */ \
+ macro(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, JOF_TABLESWITCH|JOF_DETECTING) \
+ \
+ /*
+ * Prologue emitted in scripts expected to run once, which deoptimizes code
+ * if it executes multiple times.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_RUNONCE, 71, "runonce", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /* New, infallible/transitive identity ops. */ \
+ /*
+ * Pops the top two values from the stack, then pushes the result of
+ * applying the operator to the two values.
+ * Category: Operators
+ * Type: Comparison Operators
+ * Operands:
+ * Stack: lval, rval => (lval OP rval)
+ */ \
+ macro(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
+ macro(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
+ \
+ /*
+ * Sometimes we know when emitting that an operation will always throw.
+ *
+ * Throws the indicated JSMSG.
+ *
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands: uint16_t msgNumber
+ * Stack: =>
+ */ \
+ macro(JSOP_THROWMSG, 74, "throwmsg", NULL, 3, 0, 0, JOF_UINT16) \
+ \
+ /*
+ * Sets up a for-in or for-each-in loop using the JSITER_* flag bits in
+ * this op's uint8_t immediate operand. It pops the top of stack value as
+ * 'val' and pushes 'iter' which is an iterator for 'val'.
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands: uint8_t flags
+ * Stack: val => iter
+ */ \
+ macro(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, JOF_UINT8) \
+ /*
+ * Pushes the next iterated value onto the stack. If no value is available,
+ * MagicValue(JS_NO_ITER_VALUE) is pushed.
+ *
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: iter => iter, val
+ */ \
+ macro(JSOP_MOREITER, 76, "moreiter", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Pushes a boolean indicating whether the value on top of the stack is
+ * MagicValue(JS_NO_ITER_VALUE).
+ *
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: val => val, res
+ */ \
+ macro(JSOP_ISNOITER, 77, "isnoiter", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Exits a for-in loop by popping the iterator object from the stack and
+ * closing it.
+ * Category: Statements
+ * Type: For-In Statement
+ * Operands:
+ * Stack: iter =>
+ */ \
+ macro(JSOP_ENDITER, 78, "enditer", NULL, 1, 1, 0, JOF_BYTE) \
+ \
+ /*
+ * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+ * stack.
+ *
+ * This is for 'f.apply'.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ macro(JSOP_FUNAPPLY, 79, "funapply", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ \
+ /*
+ * Pushes deep-cloned object literal or singleton onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ macro(JSOP_OBJECT, 80, "object", NULL, 5, 0, 1, JOF_OBJECT) \
+ \
+ /*
+ * Pops the top value off the stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands:
+ * Stack: v =>
+ */ \
+ macro(JSOP_POP, 81, "pop", NULL, 1, 1, 0, JOF_BYTE) \
+ \
+ /*
+ * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
+ * value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
+ * nuses: (argc+3)
+ */ \
+ macro(JSOP_NEW, 82, "new", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * Pushes newly created object onto the stack with provided [[Prototype]].
+ *
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: proto => obj
+ */ \
+ macro(JSOP_OBJWITHPROTO, 83, "objwithproto", NULL, 1, 1, 1, JOF_BYTE) \
+ \
+ /*
+ * Fast get op for function arguments and local variables.
+ *
+ * Pushes 'arguments[argno]' onto the stack.
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands: uint16_t argno
+ * Stack: => arguments[argno]
+ */ \
+ macro(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, JOF_QARG |JOF_NAME) \
+ /*
+ * Fast set op for function arguments and local variables.
+ *
+ * Sets 'arguments[argno]' as the top of stack value.
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands: uint16_t argno
+ * Stack: v => v
+ */ \
+ macro(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, JOF_QARG |JOF_NAME|JOF_SET) \
+ /*
+ * Pushes the value of local variable onto the stack.
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint32_t localno
+ * Stack: => val
+ */ \
+ macro(JSOP_GETLOCAL, 86,"getlocal", NULL, 4, 0, 1, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Stores the top stack value to the given local.
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint32_t localno
+ * Stack: v => v
+ */ \
+ macro(JSOP_SETLOCAL, 87,"setlocal", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ \
+ /*
+ * Pushes unsigned 16-bit int immediate integer operand onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint16_t val
+ * Stack: => val
+ */ \
+ macro(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, JOF_UINT16) \
+ \
+ /* Object and array literal support. */ \
+ /*
+ * Pushes newly created object onto the stack.
+ *
+ * This opcode takes the kind of initializer (JSProto_Array or
+ * JSProto_Object).
+ *
+ * This opcode has three extra bytes so it can be exchanged with
+ * JSOP_NEWOBJECT during emit.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint8_t kind (, uint24_t extra)
+ * Stack: => obj
+ */ \
+ macro(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, JOF_UINT8) \
+ /*
+ * Pushes newly created array onto the stack.
+ *
+ * This opcode takes the final length, which is preallocated.
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t length
+ * Stack: => obj
+ */ \
+ macro(JSOP_NEWARRAY, 90, "newarray", NULL, 5, 0, 1, JOF_UINT32) \
+ /*
+ * Pushes newly created object onto the stack.
+ *
+ * This opcode takes an object with the final shape, which can be set at
+ * the start and slots then filled in directly.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t baseobjIndex
+ * Stack: => obj
+ */ \
+ macro(JSOP_NEWOBJECT, 91, "newobject", NULL, 5, 0, 1, JOF_OBJECT) \
+ \
+ /*
+ * Initialize the home object for functions with super bindings.
+ *
+ * This opcode takes the function and the object to be the home object, does
+ * the set, and leaves both on the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint8_t n
+ * Stack: homeObject, [...n], fun => homeObject, [...n], fun
+ */\
+ macro(JSOP_INITHOMEOBJECT, 92, "inithomeobject", NULL, 2, 2, 2, JOF_UINT8) \
+ \
+ /*
+ * Initialize a named property in an object literal, like '{a: x}'.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines
+ * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITPROP, 93, "initprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ \
+ /*
+ * Initialize a numeric property in an object literal, like '{1: x}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITELEM, 94, "initelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ \
+ /*
+ * Pops the top three values on the stack as 'val', 'index' and 'obj', sets
+ * 'index' property of 'obj' as 'val', pushes 'obj' and 'index + 1' onto
+ * the stack.
+ *
+ * This opcode is used in Array literals with spread and spreadcall
+ * arguments.
+ * Category: Literals
+ * Type: Array
+ * Operands:
+ * Stack: obj, index, val => obj, (index + 1)
+ */ \
+ macro(JSOP_INITELEM_INC,95, "initelem_inc", NULL, 1, 3, 2, JOF_BYTE|JOF_ELEM|JOF_SET) \
+ \
+ /*
+ * Initialize an array element.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', sets 'index'
+ * property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t index
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITELEM_ARRAY,96, "initelem_array", NULL, 5, 2, 1, JOF_UINT32|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ \
+ /*
+ * Initialize a getter in an object literal.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines getter
+ * of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITPROP_GETTER, 97, "initprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a setter in an object literal.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines setter
+ * of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITPROP_SETTER, 98, "initprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a numeric getter in an object literal like
+ * '{get 2() {}}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITELEM_GETTER, 99, "initelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a numeric setter in an object literal like
+ * '{set 2(v) {}}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITELEM_SETTER, 100, "initelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ /*
+ * Pushes the call site object specified by objectIndex onto the stack. Defines the raw
+ * property specified by objectIndex + 1 on the call site object and freezes both the call site
+ * object as well as its raw property.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ macro(JSOP_CALLSITEOBJ, 101, "callsiteobj", NULL, 5, 0, 1, JOF_OBJECT) \
+ \
+ /*
+ * Pushes a newly created array onto the stack, whose elements are the same
+ * as that of a template object's copy on write elements.
+ *
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t objectIndex
+ * Stack: => obj
+ */ \
+ macro(JSOP_NEWARRAY_COPYONWRITE, 102, "newarray_copyonwrite", NULL, 5, 0, 1, JOF_OBJECT) \
+ \
+ /*
+ * Pushes the prototype of the home object for current callee onto the
+ * stack.
+ * Category: Variables and Scopes
+ * Type: Super
+ * Operands:
+ * Stack: => homeObjectProto
+ */\
+ macro(JSOP_SUPERBASE, 103, "superbase", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pops the top two values, and pushes the property of one, using the other
+ * as the receiver.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: receiver obj => obj[name]
+ */ \
+ macro(JSOP_GETPROP_SUPER, 104, "getprop-super", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP) \
+ /*
+ * Pops the top three values on the stack as 'val' and 'obj', and 'receiver',
+ * and performs 'obj.prop = val', pushing 'val' back onto the stack.
+ * Throws a TypeError if the set-operation failed (per strict mode semantics).
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj, val => val
+ */ \
+ macro(JSOP_STRICTSETPROP_SUPER, 105, "strictsetprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING|JOF_CHECKSTRICT) \
+ \
+ /*
+ * This opcode precedes every labeled statement. It's a no-op.
+ *
+ * 'offset' is the offset to the next instruction after this statement,
+ * the one 'break LABEL;' would jump to. IonMonkey uses this.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: int32_t offset
+ * Stack: =>
+ */ \
+ macro(JSOP_LABEL, 106,"label", NULL, 5, 0, 0, JOF_JUMP) \
+ \
+ /*
+ * Pops the top three values on the stack as 'val', 'obj' and 'receiver',
+ * and performs 'obj.prop = val', pushing 'val' back onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: receiver, obj, val => val
+ */ \
+ macro(JSOP_SETPROP_SUPER, 107, "setprop-super", NULL, 5, 3, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ \
+ /*
+ * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+ * stack.
+ *
+ * If 'callee' is determined to be the canonical 'Function.prototype.call'
+ * function, then this operation is optimized to directly call 'callee'
+ * with 'args[0]' as 'this', and the remaining arguments as formal args
+ * to 'callee'.
+ *
+ * Like JSOP_FUNAPPLY but for 'f.call' instead of 'f.apply'.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ macro(JSOP_FUNCALL, 108,"funcall", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ \
+ /*
+ * Another no-op.
+ *
+ * This opcode is the target of the backwards jump for some loop.
+ * Category: Statements
+ * Type: Jumps
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_LOOPHEAD, 109,"loophead", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /* ECMA-compliant assignment ops. */ \
+ /*
+ * Looks up name on the scope chain and pushes the scope which contains
+ * the name onto the stack. If not found, pushes global scope onto the
+ * stack.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => scope
+ */ \
+ macro(JSOP_BINDNAME, 110,"bindname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_SET) \
+ /*
+ * Pops a scope and value from the stack, assigns value to the given name,
+ * and pushes the value back on the stack
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: scope, val => val
+ */ \
+ macro(JSOP_SETNAME, 111,"setname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ \
+ /* Exception handling ops. */ \
+ /*
+ * Pops the top of stack value as 'v', sets pending exception as 'v', then
+ * raises error.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: v =>
+ */ \
+ macro(JSOP_THROW, 112,js_throw_str, NULL, 1, 1, 0, JOF_BYTE) \
+ \
+ /*
+ * Pops the top two values 'id' and 'obj' from the stack, then pushes
+ * 'id in obj'. This will throw a 'TypeError' if 'obj' is not an object.
+ *
+ * Note that 'obj' is the top value.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: id, obj => (id in obj)
+ */ \
+ macro(JSOP_IN, 113,js_in_str, js_in_str, 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC) \
+ /*
+ * Pops the top two values 'obj' and 'ctor' from the stack, then pushes
+ * 'obj instanceof ctor'. This will throw a 'TypeError' if 'obj' is not an
+ * object.
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: obj, ctor => (obj instanceof ctor)
+ */ \
+ macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE|JOF_LEFTASSOC) \
+ \
+ /*
+ * Invokes debugger.
+ * Category: Statements
+ * Type: Debugger
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_DEBUGGER, 115,"debugger", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Pushes 'false' and next bytecode's PC onto the stack, and jumps to
+ * a 32-bit offset from the current bytecode.
+ *
+ * This opcode is used for entering 'finally' block.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands: int32_t offset
+ * Stack: => false, (next bytecode's PC)
+ */ \
+ macro(JSOP_GOSUB, 116,"gosub", NULL, 5, 0, 0, JOF_JUMP) \
+ /*
+ * Pops the top two values on the stack as 'rval' and 'lval', converts
+ * 'lval' into a boolean, raises error if the result is 'true',
+ * jumps to a 32-bit absolute PC: 'rval' if 'false'.
+ *
+ * This opcode is used for returning from 'finally' block.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: lval, rval =>
+ */ \
+ macro(JSOP_RETSUB, 117,"retsub", NULL, 1, 2, 0, JOF_BYTE) \
+ \
+ /* More exception handling ops. */ \
+ /*
+ * Pushes the current pending exception onto the stack and clears the
+ * pending exception. This is only emitted at the beginning of code for a
+ * catch-block, so it is known that an exception is pending. It is used to
+ * implement catch-blocks and 'yield*'.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: => exception
+ */ \
+ macro(JSOP_EXCEPTION, 118,"exception", NULL, 1, 0, 1, JOF_BYTE) \
+ \
+ /*
+ * Embedded lineno to speedup 'pc->line' mapping.
+ * Category: Other
+ * Operands: uint32_t lineno
+ * Stack: =>
+ */ \
+ macro(JSOP_LINENO, 119,"lineno", NULL, 5, 0, 0, JOF_UINT32) \
+ \
+ /*
+ * This no-op appears after the bytecode for EXPR in 'switch (EXPR) {...}'
+ * if the switch cannot be optimized using JSOP_TABLESWITCH.
+ * For a non-optimized switch statement like this:
+ *
+ * switch (EXPR) {
+ * case V0:
+ * C0;
+ * ...
+ * default:
+ * D;
+ * }
+ *
+ * the bytecode looks like this:
+ *
+ * (EXPR)
+ * condswitch
+ * (V0)
+ * case ->C0
+ * ...
+ * default ->D
+ * (C0)
+ * ...
+ * (D)
+ *
+ * Note that code for all case-labels is emitted first, then code for
+ * the body of each case clause.
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_CONDSWITCH,120,"condswitch", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the top two values on the stack as 'rval' and 'lval', compare them
+ * with '===', if the result is 'true', jumps to a 32-bit offset from the
+ * current bytecode, re-pushes 'lval' onto the stack if 'false'.
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t offset
+ * Stack: lval, rval => lval(if lval !== rval)
+ */ \
+ macro(JSOP_CASE, 121,"case", NULL, 5, 2, 1, JOF_JUMP) \
+ /*
+ * This appears after all cases in a JSOP_CONDSWITCH, whether there is a
+ * 'default:' label in the switch statement or not. Pop the switch operand
+ * from the stack and jump to a 32-bit offset from the current bytecode.
+ * offset from the current bytecode.
+ * Category: Statements
+ * Type: Switch Statement
+ * Operands: int32_t offset
+ * Stack: lval =>
+ */ \
+ macro(JSOP_DEFAULT, 122,"default", NULL, 5, 1, 0, JOF_JUMP) \
+ \
+ /* ECMA-compliant call to eval op. */ \
+ /*
+ * Invokes 'eval' with 'args' and pushes return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function
+ * with 'this' and 'args', and pushes return value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ macro(JSOP_EVAL, 123,"eval", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSLOPPY) \
+ \
+ /* ECMA-compliant call to eval op. */ \
+ /*
+ * Invokes 'eval' with 'args' and pushes return value onto the stack.
+ *
+ * If 'eval' in global scope is not original one, invokes the function
+ * with 'this' and 'args', and pushes return value onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1] => rval
+ * nuses: (argc+2)
+ */ \
+ macro(JSOP_STRICTEVAL, 124, "strict-eval", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT) \
+ /*
+ * LIKE JSOP_GETELEM but takes receiver on stack, and the propval is
+ * evaluated before the obj.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: receiver, obj, propval => obj[propval]
+ */ \
+ macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \
+ /*
+ * Pushes newly created array for a spread call onto the stack. This has
+ * the same semantics as JSOP_NEWARRAY, but is distinguished to avoid
+ * using unboxed arrays in spread calls, which would make compiling spread
+ * calls in baseline more complex.
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t length
+ * Stack: => obj
+ */ \
+ macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 5, 0, 1, JOF_UINT32) \
+ \
+ /*
+ * Defines the given function on the current scope.
+ *
+ * This is used for global scripts and also in some cases for function
+ * scripts where use of dynamic scoping inhibits optimization.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands:
+ * Stack: fun =>
+ */ \
+ macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \
+ /* Defines the new constant binding on global lexical scope.
+ *
+ * Throws if a binding with the same name already exists on the scope, or
+ * if a var binding with the same name exists on the global.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: =>
+ */ \
+ macro(JSOP_DEFCONST, 128,"defconst", NULL, 5, 0, 0, JOF_ATOM) \
+ /*
+ * Defines the new binding on the frame's current variables-object (the
+ * scope object on the scope chain designated to receive new variables).
+ *
+ * Throws if the current variables-object is the global object and a
+ * binding with the same name exists on the global lexical scope.
+ *
+ * This is used for global scripts and also in some cases for function
+ * scripts where use of dynamic scoping inhibits optimization.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: =>
+ */ \
+ macro(JSOP_DEFVAR, 129,"defvar", NULL, 5, 0, 0, JOF_ATOM) \
+ \
+ /*
+ * Pushes a closure for a named or anonymous function expression onto the
+ * stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint32_t funcIndex
+ * Stack: => obj
+ */ \
+ macro(JSOP_LAMBDA, 130, "lambda", NULL, 5, 0, 1, JOF_OBJECT) \
+ /*
+ * Pops the top of stack value as 'new.target', pushes an arrow function with
+ * lexical 'new.target' onto the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint32_t funcIndex
+ * Stack: new.target => obj
+ */ \
+ macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL, 5, 1, 1, JOF_OBJECT) \
+ \
+ /*
+ * Pushes current callee onto the stack.
+ *
+ * Used for named function expression self-naming, if lightweight.
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands:
+ * Stack: => callee
+ */ \
+ macro(JSOP_CALLEE, 132, "callee", NULL, 1, 0, 1, JOF_BYTE) \
+ \
+ /*
+ * Picks the nth element from the stack and moves it to the top of the
+ * stack.
+ * Category: Operators
+ * Type: Stack Operations
+ * Operands: uint8_t n
+ * Stack: v[n], v[n-1], ..., v[1], v[0] => v[n-1], ..., v[1], v[0], v[n]
+ */ \
+ macro(JSOP_PICK, 133, "pick", NULL, 2, 0, 0, JOF_UINT8) \
+ \
+ /*
+ * This no-op appears at the top of the bytecode for a 'TryStatement'.
+ *
+ * Location information for catch/finally blocks is stored in a
+ * side table, 'script->trynotes()'.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_TRY, 134,"try", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * This opcode has a def count of 2, but these values are already on the
+ * stack (they're pushed by JSOP_GOSUB).
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: => false, (next bytecode's PC)
+ */ \
+ macro(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, JOF_BYTE) \
+ \
+ /*
+ * Pushes aliased variable onto the stack.
+ *
+ * An "aliased variable" is a var, let, or formal arg that is aliased.
+ * Sources of aliasing include: nested functions accessing the vars of an
+ * enclosing function, function statements that are conditionally executed,
+ * 'eval', 'with', and 'arguments'. All of these cases require creating a
+ * CallObject to own the aliased variable.
+ *
+ * An ALIASEDVAR opcode contains the following immediates:
+ * uint8 hops: the number of scope objects to skip to find the ScopeObject
+ * containing the variable being accessed
+ * uint24 slot: the slot containing the variable in the ScopeObject (this
+ * 'slot' does not include RESERVED_SLOTS).
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: => aliasedVar
+ */ \
+ macro(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME|JOF_TYPESET) \
+ /*
+ * Sets aliased variable as the top of stack value.
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ macro(JSOP_SETALIASEDVAR, 137,"setaliasedvar",NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ \
+ /*
+ * Checks if the value of the local variable is the
+ * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so.
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint32_t localno
+ * Stack: =>
+ */ \
+ macro(JSOP_CHECKLEXICAL, 138, "checklexical", NULL, 4, 0, 0, JOF_LOCAL|JOF_NAME) \
+ /*
+ * Initializes an uninitialized local lexical binding with the top of stack
+ * value.
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint32_t localno
+ * Stack: v => v
+ */ \
+ macro(JSOP_INITLEXICAL, 139, "initlexical", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ /*
+ * Checks if the value of the aliased variable is the
+ * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so.
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: =>
+ */ \
+ macro(JSOP_CHECKALIASEDLEXICAL, 140, "checkaliasedlexical", NULL, 5, 0, 0, JOF_ENVCOORD|JOF_NAME) \
+ /*
+ * Initializes an uninitialized aliased lexical binding with the top of
+ * stack value.
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: v => v
+ */ \
+ macro(JSOP_INITALIASEDLEXICAL, 141, "initaliasedlexical", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ /*
+ * Pushes a JS_UNINITIALIZED_LEXICAL value onto the stack, representing an
+ * uninitialized lexical binding.
+ *
+ * This opcode is used with the JSOP_INITLET opcode.
+ * Category: Literals
+ * Type: Constants
+ * Operands:
+ * Stack: => uninitialized
+ */ \
+ macro(JSOP_UNINITIALIZED, 142, "uninitialized", NULL, 1, 0, 1, JOF_BYTE) \
+ /* Pushes the value of the intrinsic onto the stack.
+ *
+ * Intrinsic names are emitted instead of JSOP_*NAME ops when the
+ * 'CompileOptions' flag 'selfHostingMode' is set.
+ *
+ * They are used in self-hosted code to access other self-hosted values and
+ * intrinsic functions the runtime doesn't give client JS code access to.
+ * Category: Variables and Scopes
+ * Type: Intrinsics
+ * Operands: uint32_t nameIndex
+ * Stack: => intrinsic[name]
+ */ \
+ macro(JSOP_GETINTRINSIC, 143, "getintrinsic", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \
+ /*
+ * Stores the top stack value in the specified intrinsic.
+ * Category: Variables and Scopes
+ * Type: Intrinsics
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
+ */ \
+ macro(JSOP_SETINTRINSIC, 144, "setintrinsic", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ /*
+ * Like JSOP_CALL, but used as part of for-of and destructuring bytecode
+ * to provide better error messages.
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc (must be 0)
+ * Stack: callee, this => rval
+ * nuses: 2
+ */ \
+ macro(JSOP_CALLITER, 145, "calliter", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * Initialize a non-configurable, non-writable, non-enumerable data-property on an object.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines
+ * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITLOCKEDPROP, 146, "initlockedprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable data-property on an object.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines
+ * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITHIDDENPROP, 147,"inithiddenprop", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Push "new.target"
+ *
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands:
+ * Stack: => new.target
+ */ \
+ macro(JSOP_NEWTARGET, 148, "newtarget", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pops the top of stack value as 'unwrapped', converts it to async
+ * function 'wrapped', and pushes 'wrapped' back on the stack.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: unwrapped => wrapped
+ */ \
+ macro(JSOP_TOASYNC, 149, "toasync", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Pops the top two values 'lval' and 'rval' from the stack, then pushes
+ * the result of 'Math.pow(lval, rval)'.
+ * Category: Operators
+ * Type: Arithmetic Operators
+ * Operands:
+ * Stack: lval, rval => (lval ** rval)
+ */ \
+ macro(JSOP_POW, 150, "pow", "**", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
+ \
+ /*
+ * Pops the top of stack value as 'v', sets pending exception as 'v',
+ * to trigger rethrow.
+ *
+ * This opcode is used in conditional catch clauses.
+ * Category: Statements
+ * Type: Exception Handling
+ * Operands:
+ * Stack: v =>
+ */ \
+ macro(JSOP_THROWING, 151,"throwing", NULL, 1, 1, 0, JOF_BYTE) \
+ \
+ /*
+ * Pops the top of stack value as 'rval', sets the return value in stack
+ * frame as 'rval'.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: rval =>
+ */ \
+ macro(JSOP_SETRVAL, 152,"setrval", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Stops interpretation and returns value set by JSOP_SETRVAL. When not set,
+ * returns 'undefined'.
+ *
+ * Also emitted at end of script so interpreter don't need to check if
+ * opcode is still in script range.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Looks up name on global scope and pushes its value onto the stack,
+ * unless the script has a non-syntactic global scope, in which case it
+ * acts just like JSOP_NAME.
+ *
+ * Free variable references that must either be found on the global or a
+ * ReferenceError.
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ macro(JSOP_GETGNAME, 154,"getgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) \
+ /*
+ * Pops the top two values on the stack as 'val' and 'scope', sets property
+ * of 'scope' as 'val' and pushes 'val' back on the stack.
+ *
+ * 'scope' should be the global scope unless the script has a non-syntactic
+ * global scope, in which case acts like JSOP_SETNAME.
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: scope, val => val
+ */ \
+ macro(JSOP_SETGNAME, 155,"setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSLOPPY) \
+ \
+ /*
+ * Pops the top two values on the stack as 'val' and 'scope', sets property
+ * of 'scope' as 'val' and pushes 'val' back on the stack. Throws a
+ * TypeError if the set fails, per strict mode semantics.
+ *
+ * 'scope' should be the global scope unless the script has a non-syntactic
+ * global scope, in which case acts like JSOP_STRICTSETNAME.
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: scope, val => val
+ */ \
+ macro(JSOP_STRICTSETGNAME, 156, "strict-setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSTRICT) \
+ /*
+ * Pushes the implicit 'this' value for calls to the associated name onto
+ * the stack; only used when we know this implicit this will be our first
+ * non-syntactic scope.
+ *
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands: uint32_t nameIndex
+ * Stack: => this
+ */ \
+ macro(JSOP_GIMPLICITTHIS, 157, "gimplicitthis", "", 5, 0, 1, JOF_ATOM) \
+ /*
+ * LIKE JSOP_SETELEM, but takes receiver on the stack, and the propval is
+ * evaluated before the base.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: propval, receiver, obj, val => val
+ */ \
+ macro(JSOP_SETELEM_SUPER, 158, "setelem-super", NULL, 1, 4, 1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING|JOF_CHECKSLOPPY) \
+ /*
+ * LIKE JSOP_STRICTSETELEM, but takes receiver on the stack, and the
+ * propval is evaluated before the base.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: propval, receiver, obj, val => val
+ */ \
+ macro(JSOP_STRICTSETELEM_SUPER, 159, "strict-setelem-super", NULL, 1, 4, 1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING|JOF_CHECKSTRICT) \
+ \
+ /*
+ * Pushes a regular expression literal onto the stack.
+ * It requires special "clone on exec" handling.
+ * Category: Literals
+ * Type: RegExp
+ * Operands: uint32_t regexpIndex
+ * Stack: => regexp
+ */ \
+ macro(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, JOF_REGEXP) \
+ \
+ /*
+ * Initializes an uninitialized global lexical binding with the top of
+ * stack value.
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: val => val
+ */ \
+ macro(JSOP_INITGLEXICAL, 161,"initglexical", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) \
+ \
+ /* Defines the new mutable binding on global lexical scope.
+ *
+ * Throws if a binding with the same name already exists on the scope, or
+ * if a var binding with the same name exists on the global.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: =>
+ */ \
+ macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \
+ /*
+ * 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.
+ *
+ * Category: Variables and Scopes
+ * Type: Super
+ * Operands:
+ * Stack: => superFun
+ */ \
+ macro(JSOP_SUPERFUN, 164,"superfun", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Behaves exactly like JSOP_NEW, but allows JITs to distinguish the two cases.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands: uint16_t argc
+ * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
+ * nuses: (argc+3)
+ */ \
+ macro(JSOP_SUPERCALL, 165,"supercall", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * spreadcall variant of JSOP_SUPERCALL.
+ *
+ * Behaves exactly like JSOP_SPREADNEW.
+ *
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: callee, this, args, newTarget => rval
+ */ \
+ macro(JSOP_SPREADSUPERCALL, 166, "spreadsupercall", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
+ /*
+ * Push a default constructor for a base class literal.
+ *
+ * Category: Literals
+ * Type: Class
+ * Operands: atom className
+ * Stack: => constructor
+ */ \
+ macro(JSOP_CLASSCONSTRUCTOR, 167,"classconstructor", NULL, 5, 0, 1, JOF_ATOM) \
+ /*
+ * Push a default constructor for a derived class literal.
+ *
+ * Category: Literals
+ * Type: Class
+ * Operands: atom className
+ * Stack: => constructor
+ */ \
+ macro(JSOP_DERIVEDCONSTRUCTOR, 168,"derivedconstructor", NULL, 5, 1, 1, JOF_ATOM) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to 'const'. The
+ * localno is used for better error messages.
+ *
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands: uint32_t localno
+ * Stack: =>
+ */ \
+ macro(JSOP_THROWSETCONST, 169, "throwsetconst", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to 'const'. The
+ * scope coordinate is used for better error messages.
+ *
+ * Category: Variables and Scopes
+ * Type: Aliased Variables
+ * Operands: uint8_t hops, uint24_t slot
+ * Stack: =>
+ */ \
+ macro(JSOP_THROWSETALIASEDCONST, 170, "throwsetaliasedconst", NULL, 5, 1, 1, JOF_ENVCOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable getter in an object literal.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines
+ * getter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITHIDDENPROP_GETTER, 171, "inithiddenprop_getter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable setter in an object literal.
+ *
+ * Pops the top two values on the stack as 'val' and 'obj', defines
+ * setter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj, val => obj
+ */ \
+ macro(JSOP_INITHIDDENPROP_SETTER, 172, "inithiddenprop_setter", NULL, 5, 2, 1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable numeric getter in an object literal like
+ * '{get 2() {}}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITHIDDENELEM_GETTER, 173, "inithiddenelem_getter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable numeric setter in an object literal like
+ * '{set 2(v) {}}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITHIDDENELEM_SETTER, 174, "inithiddenelem_setter", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ /*
+ * Initialize a non-enumerable numeric property in an object literal, like '{1: x}'.
+ *
+ * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+ * 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, id, val => obj
+ */ \
+ macro(JSOP_INITHIDDENELEM, 175, "inithiddenelem", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+ /*
+ * Gets the value of a module import by name and pushes it onto the stack.
+ * Category: Variables and Scopes
+ * Type: Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => val
+ */ \
+ macro(JSOP_GETIMPORT, 176,"getimport", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \
+ /*
+ * Examines the top stack value, asserting that it's either a self-hosted
+ * function or a self-hosted intrinsic. This opcode does nothing in a
+ * non-debug build.
+ * Category: Other
+ * Operands:
+ * Stack: checkVal => checkVal
+ */ \
+ macro(JSOP_DEBUGCHECKSELFHOSTED, 177,"debug-checkselfhosted", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Pops the top stack value, pushes the value and a boolean value that
+ * indicates whether the spread operation for the value can be optimized
+ * in spread call.
+ * Category: Statements
+ * Type: Function
+ * Operands:
+ * Stack: arr => arr optimized
+ */ \
+ macro(JSOP_OPTIMIZE_SPREADCALL,178,"optimize-spreadcall", NULL, 1, 1, 2, JOF_BYTE) \
+ /*
+ * Throws a runtime TypeError for invalid assignment to the callee in a
+ * named lambda, which is always a 'const' binding. This is a different
+ * bytecode than JSOP_SETCONST because the named lambda callee, if not
+ * closed over, does not have a frame slot to look up the name with for
+ * the error message.
+ *
+ * Category: Variables and Scopes
+ * Type: Local Variables
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_THROWSETCALLEE, 179, "throwsetcallee", NULL, 1, 1, 1, JOF_SET|JOF_BYTE) \
+ /*
+ * Pushes a var environment onto the env chain.
+ * Category: Variables and Scopes
+ * Type: Var Scope
+ * Operands: uint32_t scopeIndex
+ * Stack: =>
+ */ \
+ macro(JSOP_PUSHVARENV, 180, "pushvarenv", NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Pops a var environment from the env chain.
+ * Category: Variables and Scopes
+ * Type: Var Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_POPVARENV, 181, "popvarenv", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED182, 182,"unused182", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED183, 183,"unused183", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Pops the top of stack value, pushes property of it onto the stack.
+ *
+ * Like JSOP_GETPROP but for call context.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ macro(JSOP_CALLPROP, 184,"callprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET) \
+ /*
+ * Determines the 'this' value for current function frame and pushes it onto
+ * the stack. Emitted in the prologue of functions with a this-binding.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: => this
+ */ \
+ macro(JSOP_FUNCTIONTHIS, 185,"functionthis",NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes 'this' value for current stack frame onto the stack. Emitted when
+ * 'this' refers to the global 'this'.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: => this
+ */ \
+ macro(JSOP_GLOBALTHIS, 186,"globalthis", NULL, 1, 0, 1, JOF_BYTE) \
+ macro(JSOP_UNUSED187, 187,"unused187", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Pushes unsigned 24-bit int immediate integer operand onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: uint24_t val
+ * Stack: => val
+ */ \
+ macro(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, JOF_UINT24) \
+ /*
+ * Throw if the value on top of the stack is the TDZ MagicValue. Used in
+ * derived class constructors.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: this => this
+ */ \
+ macro(JSOP_CHECKTHIS, 189,"checkthis", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * Check if a derived class constructor has a valid return value and 'this'
+ * value before it returns. If the return value is not an object, stores
+ * the 'this' value to the return value slot.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: this =>
+ */ \
+ macro(JSOP_CHECKRETURN, 190,"checkreturn", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Throw an exception if the value on top of the stack is not the TDZ
+ * MagicValue. Used in derived class constructors.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands:
+ * Stack: this => this
+ */ \
+ macro(JSOP_CHECKTHISREINIT,191,"checkthisreinit",NULL,1, 1, 1, JOF_BYTE) \
+ macro(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Pops the top two values on the stack as 'propval' and 'obj', pushes
+ * 'propval' property of 'obj' onto the stack.
+ *
+ * Like JSOP_GETELEM but for call context.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, propval => obj[propval]
+ */ \
+ macro(JSOP_CALLELEM, 193, "callelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+ \
+ /*
+ * '__proto__: v' inside an object initializer.
+ *
+ * Pops the top two values on the stack as 'newProto' and 'obj', sets
+ * prototype of 'obj' as 'newProto', pushes 'true' onto the stack if
+ * succeeded, 'false' if not.
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: obj, newProto => succeeded
+ */ \
+ macro(JSOP_MUTATEPROTO, 194, "mutateproto",NULL, 1, 2, 1, JOF_BYTE) \
+ \
+ /*
+ * Pops the top of stack value, gets an extant property value of it,
+ * throwing ReferenceError if the identified property does not exist.
+ * Category: Literals
+ * Type: Object
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj[name]
+ */ \
+ macro(JSOP_GETXPROP, 195,"getxprop", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET) \
+ \
+ /*
+ * Pops the top stack value as 'val' and pushes 'typeof val'. Note that
+ * this opcode isn't used when, in the original source code, 'val' is a
+ * name -- see 'JSOP_TYPEOF' for that.
+ * (This is because 'typeof undefinedName === "undefined"'.)
+ * Category: Operators
+ * Type: Special Operators
+ * Operands:
+ * Stack: val => (typeof val)
+ */ \
+ macro(JSOP_TYPEOFEXPR, 196,"typeofexpr", NULL, 1, 1, 1, JOF_BYTE|JOF_DETECTING) \
+ \
+ /* Lexical environment support. */ \
+ /*
+ * Replaces the current block on the env chain with a fresh block
+ * that copies all the bindings in the bock. This operation implements the
+ * behavior of inducing a fresh lexical environment for every iteration of a
+ * for(let ...; ...; ...) loop, if any declarations induced by such a loop
+ * are captured within the loop.
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_FRESHENLEXICALENV,197,"freshenlexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Recreates the current block on the env chain with a fresh block
+ * with uninitialized bindings. This operation implements the behavior of
+ * inducing a fresh lexical environment for every iteration of a for-in/of loop
+ * whose loop-head has a (captured) lexical declaration.
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_RECREATELEXICALENV,198,"recreatelexicalenv",NULL,1,0,0,JOF_BYTE) \
+ /*
+ * Pushes lexical environment onto the env chain.
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands: uint32_t scopeIndex
+ * Stack: =>
+ */ \
+ macro(JSOP_PUSHLEXICALENV,199,"pushlexicalenv", NULL, 5, 0, 0, JOF_SCOPE) \
+ /*
+ * Pops lexical environment from the env chain.
+ * Category: Variables and Scopes
+ * Type: Block-local Scope
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_POPLEXICALENV, 200,"poplexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * The opcode to assist the debugger.
+ * Category: Statements
+ * Type: Debugger
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_DEBUGLEAVELEXICALENV, 201,"debugleavelexicalenv", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Pops the generator from the top of the stack, suspends it and stops
+ * interpretation.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t yieldIndex
+ * Stack: generator =>
+ */ \
+ macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
+ /*
+ * Pops the generator and the return value 'rval1', stops interpretation and
+ * returns 'rval1'. Pushes sent value from 'send()' onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t yieldIndex
+ * Stack: rval1, gen => rval2
+ */ \
+ macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
+ /*
+ * Pops the generator and suspends and closes it. Yields the value in the
+ * frame's return value slot.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: gen =>
+ */ \
+ macro(JSOP_FINALYIELDRVAL,204,"finalyieldrval",NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and argument from the stack, pushes a new generator
+ * frame and resumes execution of it. Pushes the return value after the
+ * generator yields.
+ * Category: Statements
+ * Type: Generator
+ * Operands: resume kind (GeneratorObject::ResumeKind)
+ * Stack: gen, val => rval
+ */ \
+ macro(JSOP_RESUME, 205,"resume", NULL, 3, 2, 1, JOF_UINT8|JOF_INVOKE) \
+ /*
+ * Pops the top two values on the stack as 'obj' and 'v', pushes 'v' to
+ * 'obj'.
+ *
+ * This opcode is used for Array Comprehension.
+ * Category: Literals
+ * Type: Array
+ * Operands:
+ * Stack: v, obj =>
+ */ \
+ macro(JSOP_ARRAYPUSH, 206,"arraypush", NULL, 1, 2, 0, JOF_BYTE) \
+ \
+ /*
+ * No-op bytecode only emitted in some self-hosted functions. Not handled by
+ * the JITs so the script always runs in the interpreter.
+ *
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_FORCEINTERPRETER, 207, "forceinterpreter", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Bytecode emitted after 'yield' expressions to help the Debugger
+ * fix up the frame in the JITs. No-op in the interpreter.
+ *
+ * Category: Operators
+ * Type: Debugger
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Initializes generator frame, creates a generator and pushes it on the
+ * stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: => generator
+ */ \
+ macro(JSOP_GENERATOR, 212,"generator", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes the nearest 'var' environment.
+ *
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands:
+ * Stack: => scope
+ */ \
+ macro(JSOP_BINDVAR, 213, "bindvar", NULL, 1, 0, 1, JOF_BYTE) \
+ /*
+ * Pushes the global scope onto the stack if the script doesn't have a
+ * non-syntactic global scope. Otherwise will act like JSOP_BINDNAME.
+ *
+ * 'nameIndex' is only used when acting like JSOP_BINDNAME.
+ * Category: Variables and Scopes
+ * Type: Free Variables
+ * Operands: uint32_t nameIndex
+ * Stack: => global
+ */ \
+ macro(JSOP_BINDGNAME, 214, "bindgname", NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) \
+ \
+ /*
+ * Pushes 8-bit int immediate integer operand onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: int8_t val
+ * Stack: => val
+ */ \
+ macro(JSOP_INT8, 215, "int8", NULL, 2, 0, 1, JOF_INT8) \
+ /*
+ * Pushes 32-bit int immediate integer operand onto the stack.
+ * Category: Literals
+ * Type: Constants
+ * Operands: int32_t val
+ * Stack: => val
+ */ \
+ macro(JSOP_INT32, 216, "int32", NULL, 5, 0, 1, JOF_INT32) \
+ \
+ /*
+ * Pops the top of stack value, pushes the 'length' property of it onto the
+ * stack.
+ * Category: Literals
+ * Type: Array
+ * Operands: uint32_t nameIndex
+ * Stack: obj => obj['length']
+ */ \
+ macro(JSOP_LENGTH, 217, "length", NULL, 5, 1, 1, JOF_ATOM|JOF_PROP|JOF_TYPESET) \
+ \
+ /*
+ * Pushes a JS_ELEMENTS_HOLE value onto the stack, representing an omitted
+ * property in an array literal (e.g. property 0 in the array '[, 1]').
+ *
+ * This opcode is used with the JSOP_NEWARRAY opcode.
+ * Category: Literals
+ * Type: Array
+ * Operands:
+ * Stack: => hole
+ */ \
+ macro(JSOP_HOLE, 218, "hole", NULL, 1, 0, 1, JOF_BYTE) \
+ \
+ macro(JSOP_UNUSED219, 219,"unused219", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED220, 220,"unused220", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED221, 221,"unused221", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED222, 222,"unused222", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_UNUSED223, 223,"unused223", NULL, 1, 0, 0, JOF_BYTE) \
+ \
+ /*
+ * Creates rest parameter array for current function call, and pushes it
+ * onto the stack.
+ * Category: Variables and Scopes
+ * Type: Arguments
+ * Operands:
+ * Stack: => rest
+ */ \
+ macro(JSOP_REST, 224, "rest", NULL, 1, 0, 1, JOF_BYTE|JOF_TYPESET) \
+ \
+ /*
+ * Replace the top-of-stack value propertyNameValue with
+ * ToPropertyKey(propertyNameValue).
+ * Category: Literals
+ * Type: Object
+ * Operands:
+ * Stack: propertyNameValue => propertyKey
+ */ \
+ macro(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, JOF_BYTE) \
+ \
+ /*
+ * Pushes the implicit 'this' value for calls to the associated name onto
+ * the stack.
+ * Category: Variables and Scopes
+ * Type: This
+ * Operands: uint32_t nameIndex
+ * Stack: => this
+ */ \
+ macro(JSOP_IMPLICITTHIS, 226, "implicitthis", "", 5, 0, 1, JOF_ATOM) \
+ \
+ /*
+ * This opcode is the target of the entry jump for some loop. The uint8
+ * argument is a bitfield. The lower 7 bits of the argument indicate the
+ * loop depth. This value starts at 1 and is just a hint: deeply nested
+ * loops all have the same value. The upper bit is set if Ion should be
+ * able to OSR at this point, which is true unless there is non-loop state
+ * on the stack.
+ * Category: Statements
+ * Type: Jumps
+ * Operands: uint8_t BITFIELD
+ * Stack: =>
+ */ \
+ macro(JSOP_LOOPENTRY, 227, "loopentry", NULL, 2, 0, 0, JOF_UINT8) \
+ /*
+ * Converts the value on the top of the stack to a String
+ * Category: Other
+ * Operands:
+ * Stack: val => ToString(val)
+ */ \
+ macro(JSOP_TOSTRING, 228, "tostring", NULL, 1, 1, 1, JOF_BYTE) \
+ /*
+ * No-op used by the decompiler to produce nicer error messages about
+ * destructuring code.
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * This opcode is a no-op and it indicates the location of a jump
+ * instruction target. Some other opcodes act as jump targets, such as
+ * LOOPENTRY, as well as all which are matched by BytecodeIsJumpTarget
+ * function.
+ * Category: Other
+ * Operands:
+ * Stack: =>
+ */ \
+ macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)
+
+/*
+ * In certain circumstances it may be useful to "pad out" the opcode space to
+ * a power of two. Use this macro to do so.
+ */
+#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
+ macro(231) \
+ macro(232) \
+ macro(233) \
+ macro(234) \
+ macro(235) \
+ macro(236) \
+ macro(237) \
+ macro(238) \
+ macro(239) \
+ macro(240) \
+ macro(241) \
+ macro(242) \
+ macro(243) \
+ macro(244) \
+ macro(245) \
+ macro(246) \
+ macro(247) \
+ macro(248) \
+ macro(249) \
+ macro(250) \
+ macro(251) \
+ macro(252) \
+ macro(253) \
+ macro(254) \
+ macro(255)
+
+namespace js {
+
+// Sanity check that opcode values and trailing unused opcodes completely cover
+// the [0, 256) range. Avert your eyes! You don't want to know how the
+// sausage gets made.
+
+#define VALUE_AND_VALUE_PLUS_ONE(op, val, ...) \
+ val) && (val + 1 ==
+#define TRAILING_VALUE_AND_VALUE_PLUS_ONE(val) \
+ val) && (val + 1 ==
+static_assert((0 ==
+ FOR_EACH_OPCODE(VALUE_AND_VALUE_PLUS_ONE)
+ FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_VALUE_AND_VALUE_PLUS_ONE)
+ 256),
+ "opcode values and trailing unused opcode values monotonically "
+ "increase from zero to 255");
+#undef TRAILING_VALUE_AND_VALUE_PLUS_ONE
+#undef VALUE_AND_VALUE_PLUS_ONE
+
+// Define JSOP_*_LENGTH constants for all ops.
+#define DEFINE_LENGTH_CONSTANT(op, val, name, image, len, ...) \
+ constexpr size_t op##_LENGTH = len;
+FOR_EACH_OPCODE(DEFINE_LENGTH_CONSTANT)
+#undef DEFINE_LENGTH_CONSTANT
+
+} // namespace js
+
+#endif // vm_Opcodes_h
diff --git a/js/src/vm/PIC.cpp b/js/src/vm/PIC.cpp
new file mode 100644
index 000000000..46843b759
--- /dev/null
+++ b/js/src/vm/PIC.cpp
@@ -0,0 +1,330 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/PIC.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsobj.h"
+#include "gc/Marking.h"
+
+#include "vm/GlobalObject.h"
+#include "vm/SelfHosting.h"
+
+#include "jsobjinlines.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+bool
+js::ForOfPIC::Chain::initialize(JSContext* cx)
+{
+ MOZ_ASSERT(!initialized_);
+
+ // Get the canonical Array.prototype
+ RootedNativeObject arrayProto(cx, GlobalObject::getOrCreateArrayPrototype(cx, cx->global()));
+ if (!arrayProto)
+ return false;
+
+ // Get the canonical ArrayIterator.prototype
+ RootedNativeObject arrayIteratorProto(cx,
+ GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
+ if (!arrayIteratorProto)
+ return false;
+
+ // From this point on, we can't fail. Set initialized and fill the fields
+ // for the canonical Array.prototype and ArrayIterator.prototype objects.
+ initialized_ = true;
+ arrayProto_ = arrayProto;
+ arrayIteratorProto_ = arrayIteratorProto;
+
+ // Shortcut returns below means Array for-of will never be optimizable,
+ // do set disabled_ now, and clear it later when we succeed.
+ disabled_ = true;
+
+ // Look up Array.prototype[@@iterator], ensure it's a slotful shape.
+ Shape* iterShape = arrayProto->lookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+ if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
+ return true;
+
+ // Get the referred value, and ensure it holds the canonical ArrayValues function.
+ Value iterator = arrayProto->getSlot(iterShape->slot());
+ JSFunction* iterFun;
+ if (!IsFunctionObject(iterator, &iterFun))
+ return true;
+ if (!IsSelfHostedFunctionWithName(iterFun, cx->names().ArrayValues))
+ return true;
+
+ // Look up the 'next' value on ArrayIterator.prototype
+ Shape* nextShape = arrayIteratorProto->lookup(cx, cx->names().next);
+ if (!nextShape || !nextShape->hasSlot())
+ return true;
+
+ // Get the referred value, ensure it holds the canonical ArrayIteratorNext function.
+ Value next = arrayIteratorProto->getSlot(nextShape->slot());
+ JSFunction* nextFun;
+ if (!IsFunctionObject(next, &nextFun))
+ return true;
+ if (!IsSelfHostedFunctionWithName(nextFun, cx->names().ArrayIteratorNext))
+ return true;
+
+ disabled_ = false;
+ arrayProtoShape_ = arrayProto->lastProperty();
+ arrayProtoIteratorSlot_ = iterShape->slot();
+ canonicalIteratorFunc_ = iterator;
+ arrayIteratorProtoShape_ = arrayIteratorProto->lastProperty();
+ arrayIteratorProtoNextSlot_ = nextShape->slot();
+ canonicalNextFunc_ = next;
+ return true;
+}
+
+js::ForOfPIC::Stub*
+js::ForOfPIC::Chain::isArrayOptimized(ArrayObject* obj)
+{
+ Stub* stub = getMatchingStub(obj);
+ if (!stub)
+ return nullptr;
+
+ // Ensure that this is an otherwise optimizable array.
+ if (!isOptimizableArray(obj))
+ return nullptr;
+
+ // Not yet enough! Ensure that the world as we know it remains sane.
+ if (!isArrayStateStillSane())
+ return nullptr;
+
+ return stub;
+}
+
+bool
+js::ForOfPIC::Chain::tryOptimizeArray(JSContext* cx, HandleArrayObject array, bool* optimized)
+{
+ MOZ_ASSERT(optimized);
+
+ *optimized = false;
+
+ if (!initialized_) {
+ // If PIC is not initialized, initialize it.
+ if (!initialize(cx))
+ return false;
+
+ } else if (!disabled_ && !isArrayStateStillSane()) {
+ // Otherwise, if array state is no longer sane, reinitialize.
+ reset(cx);
+
+ if (!initialize(cx))
+ return false;
+ }
+ MOZ_ASSERT(initialized_);
+
+ // If PIC is disabled, don't bother trying to optimize.
+ if (disabled_)
+ return true;
+
+ // By the time we get here, we should have a sane array state to work with.
+ MOZ_ASSERT(isArrayStateStillSane());
+
+ // Check if stub already exists.
+ ForOfPIC::Stub* stub = isArrayOptimized(&array->as<ArrayObject>());
+ if (stub) {
+ *optimized = true;
+ return true;
+ }
+
+ // If the number of stubs is about to exceed the limit, throw away entire
+ // existing cache before adding new stubs. We shouldn't really have heavy
+ // churn on these.
+ if (numStubs() >= MAX_STUBS)
+ eraseChain();
+
+ // Ensure array's prototype is the actual Array.prototype
+ if (!isOptimizableArray(array))
+ return true;
+
+ // Ensure array doesn't define @@iterator directly.
+ if (array->lookup(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator)))
+ return true;
+
+ // Good to optimize now, create stub to add.
+ RootedShape shape(cx, array->lastProperty());
+ stub = cx->new_<Stub>(shape);
+ if (!stub)
+ return false;
+
+ // Add the stub.
+ addStub(stub);
+
+ *optimized = true;
+ return true;
+}
+
+js::ForOfPIC::Stub*
+js::ForOfPIC::Chain::getMatchingStub(JSObject* obj)
+{
+ // Ensure PIC is initialized and not disabled.
+ if (!initialized_ || disabled_)
+ return nullptr;
+
+ // Check if there is a matching stub.
+ for (Stub* stub = stubs(); stub != nullptr; stub = stub->next()) {
+ if (stub->shape() == obj->maybeShape())
+ return stub;
+ }
+
+ return nullptr;
+}
+
+bool
+js::ForOfPIC::Chain::isOptimizableArray(JSObject* obj)
+{
+ MOZ_ASSERT(obj->is<ArrayObject>());
+ return obj->staticPrototype() == arrayProto_;
+}
+
+bool
+js::ForOfPIC::Chain::isArrayStateStillSane()
+{
+ // Ensure that canonical Array.prototype has matching shape.
+ if (arrayProto_->lastProperty() != arrayProtoShape_)
+ return false;
+
+ // Ensure that Array.prototype[@@iterator] contains the
+ // canonical iterator function.
+ if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
+ return false;
+
+ // Chain to isArrayNextStillSane.
+ return isArrayNextStillSane();
+}
+
+void
+js::ForOfPIC::Chain::reset(JSContext* cx)
+{
+ // Should never reset a disabled_ stub.
+ MOZ_ASSERT(!disabled_);
+
+ // Erase the chain.
+ eraseChain();
+
+ arrayProto_ = nullptr;
+ arrayIteratorProto_ = nullptr;
+
+ arrayProtoShape_ = nullptr;
+ arrayProtoIteratorSlot_ = -1;
+ canonicalIteratorFunc_ = UndefinedValue();
+
+ arrayIteratorProtoShape_ = nullptr;
+ arrayIteratorProtoNextSlot_ = -1;
+ canonicalNextFunc_ = UndefinedValue();
+
+ initialized_ = false;
+}
+
+void
+js::ForOfPIC::Chain::eraseChain()
+{
+ // Should never need to clear the chain of a disabled stub.
+ MOZ_ASSERT(!disabled_);
+
+ // Free all stubs.
+ Stub* stub = stubs_;
+ while (stub) {
+ Stub* next = stub->next();
+ js_delete(stub);
+ stub = next;
+ }
+ stubs_ = nullptr;
+}
+
+
+// Trace the pointers stored directly on the stub.
+void
+js::ForOfPIC::Chain::mark(JSTracer* trc)
+{
+ if (!initialized_ || disabled_)
+ return;
+
+ TraceEdge(trc, &arrayProto_, "ForOfPIC Array.prototype.");
+ TraceEdge(trc, &arrayIteratorProto_, "ForOfPIC ArrayIterator.prototype.");
+
+ TraceEdge(trc, &arrayProtoShape_, "ForOfPIC Array.prototype shape.");
+ TraceEdge(trc, &arrayIteratorProtoShape_, "ForOfPIC ArrayIterator.prototype shape.");
+
+ TraceEdge(trc, &canonicalIteratorFunc_, "ForOfPIC ArrayValues builtin.");
+ TraceEdge(trc, &canonicalNextFunc_, "ForOfPIC ArrayIterator.prototype.next builtin.");
+
+ // Free all the stubs in the chain.
+ while (stubs_)
+ removeStub(stubs_, nullptr);
+}
+
+void
+js::ForOfPIC::Chain::sweep(FreeOp* fop)
+{
+ // Free all the stubs in the chain.
+ while (stubs_) {
+ Stub* next = stubs_->next();
+ fop->delete_(stubs_);
+ stubs_ = next;
+ }
+ fop->delete_(this);
+}
+
+static void
+ForOfPIC_finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->maybeOffMainThread());
+ if (ForOfPIC::Chain* chain = ForOfPIC::fromJSObject(&obj->as<NativeObject>()))
+ chain->sweep(fop);
+}
+
+static void
+ForOfPIC_traceObject(JSTracer* trc, JSObject* obj)
+{
+ if (ForOfPIC::Chain* chain = ForOfPIC::fromJSObject(&obj->as<NativeObject>()))
+ chain->mark(trc);
+}
+
+static const ClassOps ForOfPICClassOps = {
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, ForOfPIC_finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ForOfPIC_traceObject
+};
+
+const Class ForOfPIC::class_ = {
+ "ForOfPIC",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &ForOfPICClassOps
+};
+
+/* static */ NativeObject*
+js::ForOfPIC::createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global)
+{
+ assertSameCompartment(cx, global);
+ NativeObject* obj = NewNativeObjectWithGivenProto(cx, &ForOfPIC::class_, nullptr);
+ if (!obj)
+ return nullptr;
+ ForOfPIC::Chain* chain = cx->new_<ForOfPIC::Chain>();
+ if (!chain)
+ return nullptr;
+ obj->setPrivate(chain);
+ return obj;
+}
+
+/* static */ js::ForOfPIC::Chain*
+js::ForOfPIC::create(JSContext* cx)
+{
+ MOZ_ASSERT(!cx->global()->getForOfPICObject());
+ Rooted<GlobalObject*> global(cx, cx->global());
+ NativeObject* obj = GlobalObject::getOrCreateForOfPICObject(cx, global);
+ if (!obj)
+ return nullptr;
+ return fromJSObject(obj);
+}
diff --git a/js/src/vm/PIC.h b/js/src/vm/PIC.h
new file mode 100644
index 000000000..a24321514
--- /dev/null
+++ b/js/src/vm/PIC.h
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_PIC_h
+#define vm_PIC_h
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsfriendapi.h"
+#include "jsobj.h"
+
+#include "gc/Barrier.h"
+#include "gc/Heap.h"
+#include "gc/Marking.h"
+
+#include "js/Value.h"
+#include "vm/GlobalObject.h"
+
+namespace js {
+
+class Shape;
+
+template <typename Category> class PICChain;
+
+/*
+ * The basic PICStub just has a pointer to the next stub.
+ */
+template <typename Category>
+class PICStub
+{
+ friend class PICChain<Category>;
+ private:
+ typedef typename Category::Stub CatStub;
+ typedef typename Category::Chain CatChain;
+
+ protected:
+ CatStub* next_;
+
+ PICStub() : next_(nullptr) {}
+ explicit PICStub(const CatStub* next) : next_(next) {
+ MOZ_ASSERT(next_);
+ }
+ explicit PICStub(const CatStub& other) : next_(other.next_) {}
+
+ public:
+ CatStub* next() const {
+ return next_;
+ }
+
+ protected:
+ void append(CatStub* stub) {
+ MOZ_ASSERT(!next_);
+ MOZ_ASSERT(!stub->next_);
+ next_ = stub;
+ }
+};
+
+/*
+ * The basic PIC just has a pointer to the list of stubs.
+ */
+template <typename Category>
+class PICChain
+{
+ private:
+ typedef typename Category::Stub CatStub;
+ typedef typename Category::Chain CatChain;
+
+ protected:
+ CatStub* stubs_;
+
+ PICChain() : stubs_(nullptr) {}
+ // PICs should never be copy constructed.
+ PICChain(const PICChain<Category>& other) = delete;
+
+ public:
+ CatStub* stubs() const {
+ return stubs_;
+ }
+
+ void addStub(CatStub* stub) {
+ MOZ_ASSERT(stub);
+ MOZ_ASSERT(!stub->next());
+ if (!stubs_) {
+ stubs_ = stub;
+ return;
+ }
+
+ CatStub* cur = stubs_;
+ while (cur->next())
+ cur = cur->next();
+ cur->append(stub);
+ }
+
+ unsigned numStubs() const {
+ unsigned count = 0;
+ for (CatStub* stub = stubs_; stub; stub = stub->next())
+ count++;
+ return count;
+ }
+
+ void removeStub(CatStub* stub, CatStub* previous) {
+ if (previous) {
+ MOZ_ASSERT(previous->next() == stub);
+ previous->next_ = stub->next();
+ } else {
+ MOZ_ASSERT(stub == stubs_);
+ stubs_ = stub->next();
+ }
+ js_delete(stub);
+ }
+};
+
+/*
+ * ForOfPIC defines a PIC category for optimizing for-of operations.
+ */
+struct ForOfPIC
+{
+ /* Forward declarations so template-substitution works. */
+ class Stub;
+ class Chain;
+
+ ForOfPIC() = delete;
+ ForOfPIC(const ForOfPIC& other) = delete;
+
+ typedef PICStub<ForOfPIC> BaseStub;
+ typedef PICChain<ForOfPIC> BaseChain;
+
+ /*
+ * A ForOfPIC has only one kind of stub for now: one that holds the shape
+ * of an array object that does not override its @@iterator property.
+ */
+ class Stub : public BaseStub
+ {
+ private:
+ // Shape of matching array object.
+ Shape* shape_;
+
+ public:
+ explicit Stub(Shape* shape)
+ : BaseStub(),
+ shape_(shape)
+ {
+ MOZ_ASSERT(shape_);
+ }
+
+ Shape* shape() {
+ return shape_;
+ }
+ };
+
+ /*
+ * A ForOfPIC chain holds the following:
+ *
+ * Array.prototype (arrayProto_)
+ * To ensure that the incoming array has the standard proto.
+ *
+ * Array.prototype's shape (arrayProtoShape_)
+ * To ensure that Array.prototype has not been modified.
+ *
+ * ArrayIterator.prototype (arrayIteratorProto_)
+ * ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
+ * To ensure that an ArrayIterator.prototype has not been modified.
+ *
+ * Array.prototype's slot number for @@iterator (arrayProtoIteratorSlot_)
+ * Array.prototype's canonical value for @@iterator (canonicalIteratorFunc_)
+ * To quickly retrieve and ensure that the iterator constructor
+ * stored in the slot has not changed.
+ *
+ * ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_)
+ * ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_)
+ * To quickly retrieve and ensure that the 'next' method for ArrayIterator
+ * objects has not changed.
+ */
+ class Chain : public BaseChain
+ {
+ private:
+ // Pointer to canonical Array.prototype and ArrayIterator.prototype
+ GCPtrNativeObject arrayProto_;
+ GCPtrNativeObject arrayIteratorProto_;
+
+ // Shape of matching Array.prototype object, and slot containing
+ // the @@iterator for it, and the canonical value.
+ GCPtrShape arrayProtoShape_;
+ uint32_t arrayProtoIteratorSlot_;
+ GCPtrValue canonicalIteratorFunc_;
+
+ // Shape of matching ArrayIteratorProto, and slot containing
+ // the 'next' property, and the canonical value.
+ GCPtrShape arrayIteratorProtoShape_;
+ uint32_t arrayIteratorProtoNextSlot_;
+ GCPtrValue canonicalNextFunc_;
+
+ // Initialization flag marking lazy initialization of above fields.
+ bool initialized_;
+
+ // Disabled flag is set when we don't want to try optimizing anymore
+ // because core objects were changed.
+ bool disabled_;
+
+ static const unsigned MAX_STUBS = 10;
+
+ public:
+ Chain()
+ : BaseChain(),
+ arrayProto_(nullptr),
+ arrayIteratorProto_(nullptr),
+ arrayProtoShape_(nullptr),
+ arrayProtoIteratorSlot_(-1),
+ canonicalIteratorFunc_(UndefinedValue()),
+ arrayIteratorProtoShape_(nullptr),
+ arrayIteratorProtoNextSlot_(-1),
+ initialized_(false),
+ disabled_(false)
+ {}
+
+ // Initialize the canonical iterator function.
+ bool initialize(JSContext* cx);
+
+ // Check if a given array object is optimized by this PIC.
+ Stub* isArrayOptimized(ArrayObject* obj);
+
+ // Try to optimize this chain for an object.
+ bool tryOptimizeArray(JSContext* cx, HandleArrayObject array, bool* optimized);
+
+ // Check if the global array-related objects have not been messed with
+ // in a way that would disable this PIC.
+ bool isArrayStateStillSane();
+
+ // Check if ArrayIterator.next is still optimizable.
+ inline bool isArrayNextStillSane() {
+ return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
+ (arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
+ }
+
+ void mark(JSTracer* trc);
+ void sweep(FreeOp* fop);
+
+ private:
+ // Get a matching optimized stub for the given object.
+ Stub* getMatchingStub(JSObject* obj);
+
+ // Check if the given object is for-of optimizable with this PIC.
+ bool isOptimizableArray(JSObject* obj);
+
+ // Reset the PIC and all info associated with it.
+ void reset(JSContext* cx);
+
+ // Erase the stub chain.
+ void eraseChain();
+ };
+
+ // Class for object that holds ForOfPIC chain.
+ static const Class class_;
+
+ static NativeObject* createForOfPICObject(JSContext* cx, Handle<GlobalObject*> global);
+
+ static inline Chain* fromJSObject(NativeObject* obj) {
+ MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::class_);
+ return (ForOfPIC::Chain*) obj->getPrivate();
+ }
+ static inline Chain* getOrCreate(JSContext* cx) {
+ NativeObject* obj = cx->global()->getForOfPICObject();
+ if (obj)
+ return fromJSObject(obj);
+ return create(cx);
+ }
+ static Chain* create(JSContext* cx);
+};
+
+
+} // namespace js
+
+#endif /* vm_PIC_h */
diff --git a/js/src/vm/PosixNSPR.cpp b/js/src/vm/PosixNSPR.cpp
new file mode 100644
index 000000000..5acfbcd1a
--- /dev/null
+++ b/js/src/vm/PosixNSPR.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/PosixNSPR.h"
+
+#include "js/Utility.h"
+
+#ifdef JS_POSIX_NSPR
+
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+
+int32_t
+PR_FileDesc2NativeHandle(PRFileDesc* fd)
+{
+ MOZ_CRASH("PR_FileDesc2NativeHandle");
+}
+
+PRStatus
+PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info)
+{
+ MOZ_CRASH("PR_GetOpenFileInfo");
+}
+
+int32_t
+PR_Seek(PRFileDesc *fd, int32_t offset, PRSeekWhence whence)
+{
+ MOZ_CRASH("PR_Seek");
+}
+
+PRFileMap*
+PR_CreateFileMap(PRFileDesc *fd, int64_t size, PRFileMapProtect prot)
+{
+ MOZ_CRASH("PR_CreateFileMap");
+}
+
+void*
+PR_MemMap(PRFileMap *fmap, int64_t offset, uint32_t len)
+{
+ MOZ_CRASH("PR_MemMap");
+}
+
+PRStatus
+PR_MemUnmap(void *addr, uint32_t len)
+{
+ MOZ_CRASH("PR_MemUnmap");
+}
+
+PRStatus
+PR_CloseFileMap(PRFileMap *fmap)
+{
+ MOZ_CRASH("PR_CloseFileMap");
+}
+
+#endif /* JS_POSIX_NSPR */
diff --git a/js/src/vm/PosixNSPR.h b/js/src/vm/PosixNSPR.h
new file mode 100644
index 000000000..fbca5896b
--- /dev/null
+++ b/js/src/vm/PosixNSPR.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_PosixNSPR_h
+#define vm_PosixNSPR_h
+
+#ifdef JS_POSIX_NSPR
+
+#include "jspubtd.h"
+
+int32_t
+PR_FileDesc2NativeHandle(PRFileDesc* fd);
+
+enum PRFileType
+{
+ PR_FILE_FILE = 1,
+ PR_FILE_DIRECTORY = 2,
+ PR_FILE_OTHER = 3
+};
+
+struct PRFileInfo
+{
+ PRFileType type;
+ int32_t size;
+ int64_t creationTime;
+ int64_t modifyTime;
+};
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+PRStatus
+PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info);
+
+enum PRSeekWhence
+{
+ PR_SEEK_SET = 0,
+ PR_SEEK_CUR = 1,
+ PR_SEEK_END = 2
+};
+
+int32_t
+PR_Seek(PRFileDesc *fd, int32_t offset, PRSeekWhence whence);
+
+enum PRFileMapProtect
+{
+ PR_PROT_READONLY,
+ PR_PROT_READWRITE,
+ PR_PROT_WRITECOPY
+};
+
+struct PRFileMap;
+
+PRFileMap*
+PR_CreateFileMap(PRFileDesc *fd, int64_t size, PRFileMapProtect prot);
+
+void*
+PR_MemMap(PRFileMap *fmap, int64_t offset, uint32_t len);
+
+PRStatus
+PR_MemUnmap(void *addr, uint32_t len);
+
+PRStatus
+PR_CloseFileMap(PRFileMap *fmap);
+
+#endif /* JS_POSIX_NSPR */
+
+#endif /* vm_PosixNSPR_h */
diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp
new file mode 100644
index 000000000..88350a4bd
--- /dev/null
+++ b/js/src/vm/Printer.cpp
@@ -0,0 +1,618 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Printer.h"
+
+#include "mozilla/PodOperations.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "jscntxt.h"
+#include "jsprf.h"
+#include "jsutil.h"
+
+#include "ds/LifoAlloc.h"
+
+using mozilla::PodCopy;
+
+namespace js {
+
+GenericPrinter::GenericPrinter()
+ : hadOOM_(false)
+{
+}
+
+void
+GenericPrinter::reportOutOfMemory()
+{
+ if (hadOOM_)
+ return;
+ hadOOM_ = true;
+}
+
+bool
+GenericPrinter::hadOutOfMemory() const
+{
+ return hadOOM_;
+}
+
+int
+GenericPrinter::printf(const char* fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ int i = vprintf(fmt, va);
+ va_end(va);
+ return i;
+}
+
+int
+GenericPrinter::vprintf(const char* fmt, va_list ap)
+{
+ // Simple shortcut to avoid allocating strings.
+ if (strchr(fmt, '%') == nullptr)
+ return put(fmt);
+
+ char* bp;
+ bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */
+ if (!bp) {
+ reportOutOfMemory();
+ return -1;
+ }
+ int i = put(bp);
+ js_free(bp);
+ return i;
+}
+
+const size_t Sprinter::DefaultSize = 64;
+
+bool
+Sprinter::realloc_(size_t newSize)
+{
+ MOZ_ASSERT(newSize > (size_t) offset);
+ char* newBuf = (char*) js_realloc(base, newSize);
+ if (!newBuf) {
+ reportOutOfMemory();
+ return false;
+ }
+ base = newBuf;
+ size = newSize;
+ base[size - 1] = 0;
+ return true;
+}
+
+Sprinter::Sprinter(ExclusiveContext* cx, bool shouldReportOOM)
+ : context(cx),
+#ifdef DEBUG
+ initialized(false),
+#endif
+ shouldReportOOM(shouldReportOOM),
+ base(nullptr), size(0), offset(0)
+{ }
+
+Sprinter::~Sprinter()
+{
+#ifdef DEBUG
+ if (initialized)
+ checkInvariants();
+#endif
+ js_free(base);
+}
+
+bool
+Sprinter::init()
+{
+ MOZ_ASSERT(!initialized);
+ base = (char*) js_malloc(DefaultSize);
+ if (!base) {
+ reportOutOfMemory();
+ return false;
+ }
+#ifdef DEBUG
+ initialized = true;
+#endif
+ *base = 0;
+ size = DefaultSize;
+ base[size - 1] = 0;
+ return true;
+}
+
+void
+Sprinter::checkInvariants() const
+{
+ MOZ_ASSERT(initialized);
+ MOZ_ASSERT((size_t) offset < size);
+ MOZ_ASSERT(base[size - 1] == 0);
+}
+
+const char*
+Sprinter::string() const
+{
+ return base;
+}
+
+const char*
+Sprinter::stringEnd() const
+{
+ return base + offset;
+}
+
+char*
+Sprinter::stringAt(ptrdiff_t off) const
+{
+ MOZ_ASSERT(off >= 0 && (size_t) off < size);
+ return base + off;
+}
+
+char&
+Sprinter::operator[](size_t off)
+{
+ MOZ_ASSERT(off < size);
+ return *(base + off);
+}
+
+char*
+Sprinter::reserve(size_t len)
+{
+ InvariantChecker ic(this);
+
+ while (len + 1 > size - offset) { /* Include trailing \0 */
+ if (!realloc_(size * 2))
+ return nullptr;
+ }
+
+ char* sb = base + offset;
+ offset += len;
+ return sb;
+}
+
+int
+Sprinter::put(const char* s, size_t len)
+{
+ InvariantChecker ic(this);
+
+ const char* oldBase = base;
+ const char* oldEnd = base + size;
+
+ ptrdiff_t oldOffset = offset;
+ char* bp = reserve(len);
+ if (!bp)
+ return -1;
+
+ /* s is within the buffer already */
+ if (s >= oldBase && s < oldEnd) {
+ /* buffer was realloc'ed */
+ if (base != oldBase)
+ s = stringAt(s - oldBase); /* this is where it lives now */
+ memmove(bp, s, len);
+ } else {
+ js_memcpy(bp, s, len);
+ }
+
+ bp[len] = 0;
+ return oldOffset;
+}
+
+int
+Sprinter::vprintf(const char* fmt, va_list ap)
+{
+ InvariantChecker ic(this);
+
+ do {
+ va_list aq;
+ va_copy(aq, ap);
+ int i = vsnprintf(base + offset, size - offset, fmt, aq);
+ va_end(aq);
+ if (i > -1 && (size_t) i < size - offset) {
+ offset += i;
+ return i;
+ }
+ } while (realloc_(size * 2));
+
+ return -1;
+}
+
+int
+Sprinter::putString(JSString* s)
+{
+ InvariantChecker ic(this);
+
+ size_t length = s->length();
+ size_t size = length;
+
+ ptrdiff_t oldOffset = offset;
+ char* buffer = reserve(size);
+ if (!buffer)
+ return -1;
+
+ JSLinearString* linear = s->ensureLinear(context);
+ if (!linear)
+ return -1;
+
+ JS::AutoCheckCannotGC nogc;
+ if (linear->hasLatin1Chars())
+ PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc), length);
+ else
+ DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size);
+
+ buffer[size] = 0;
+ return oldOffset;
+}
+
+ptrdiff_t
+Sprinter::getOffset() const
+{
+ return offset;
+}
+
+void
+Sprinter::reportOutOfMemory()
+{
+ if (hadOOM_)
+ return;
+ if (context && shouldReportOOM)
+ ReportOutOfMemory(context);
+ hadOOM_ = true;
+}
+
+bool
+Sprinter::jsprintf(const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ UniquePtr<char, JS::FreePolicy> chars(JS_vsmprintf(format, ap)); /* XXX vsaprintf */
+ va_end(ap);
+ if (!chars) {
+ reportOutOfMemory();
+ return false;
+ }
+
+ return put(chars.get()) >= 0;
+}
+
+const char js_EscapeMap[] = {
+ '\b', 'b',
+ '\f', 'f',
+ '\n', 'n',
+ '\r', 'r',
+ '\t', 't',
+ '\v', 'v',
+ '"', '"',
+ '\'', '\'',
+ '\\', '\\',
+ '\0'
+};
+
+template <typename CharT>
+static char*
+QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote)
+{
+ /* Sample off first for later return value pointer computation. */
+ ptrdiff_t offset = sp->getOffset();
+
+ if (quote) {
+ if (!sp->jsprintf("%c", char(quote)))
+ return nullptr;
+ }
+
+ const CharT* end = s + length;
+
+ /* Loop control variables: end points at end of string sentinel. */
+ for (const CharT* t = s; t < end; s = ++t) {
+ /* Move t forward from s past un-quote-worthy characters. */
+ char16_t c = *t;
+ while (c < 127 && isprint(c) && c != quote && c != '\\' && c != '\t') {
+ c = *++t;
+ if (t == end)
+ break;
+ }
+
+ {
+ ptrdiff_t len = t - s;
+ ptrdiff_t base = sp->getOffset();
+ if (!sp->reserve(len))
+ return nullptr;
+
+ for (ptrdiff_t i = 0; i < len; ++i)
+ (*sp)[base + i] = char(*s++);
+ (*sp)[base + len] = 0;
+ }
+
+ if (t == end)
+ break;
+
+ /* Use js_EscapeMap, \u, or \x only if necessary. */
+ const char* escape;
+ if (!(c >> 8) && c != 0 && (escape = strchr(js_EscapeMap, int(c))) != nullptr) {
+ if (!sp->jsprintf("\\%c", escape[1]))
+ return nullptr;
+ } else {
+ /*
+ * Use \x only if the high byte is 0 and we're in a quoted string,
+ * because ECMA-262 allows only \u, not \x, in Unicode identifiers
+ * (see bug 621814).
+ */
+ if (!sp->jsprintf((quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c))
+ return nullptr;
+ }
+ }
+
+ /* Sprint the closing quote and return the quoted string. */
+ if (quote) {
+ if (!sp->jsprintf("%c", char(quote)))
+ return nullptr;
+ }
+
+ /*
+ * If we haven't Sprint'd anything yet, Sprint an empty string so that
+ * the return below gives a valid result.
+ */
+ if (offset == sp->getOffset()) {
+ if (sp->put("") < 0)
+ return nullptr;
+ }
+
+ return sp->stringAt(offset);
+}
+
+char*
+QuoteString(Sprinter* sp, JSString* str, char16_t quote)
+{
+ JSLinearString* linear = str->ensureLinear(sp->context);
+ if (!linear)
+ return nullptr;
+
+ JS::AutoCheckCannotGC nogc;
+ return linear->hasLatin1Chars()
+ ? QuoteString(sp, linear->latin1Chars(nogc), linear->length(), quote)
+ : QuoteString(sp, linear->twoByteChars(nogc), linear->length(), quote);
+}
+
+JSString*
+QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote)
+{
+ Sprinter sprinter(cx);
+ if (!sprinter.init())
+ return nullptr;
+ char* bytes = QuoteString(&sprinter, str, quote);
+ if (!bytes)
+ return nullptr;
+ return NewStringCopyZ<CanGC>(cx, bytes);
+}
+
+Fprinter::Fprinter(FILE* fp)
+ : file_(nullptr),
+ init_(false)
+{
+ init(fp);
+}
+
+Fprinter::Fprinter()
+ : file_(nullptr),
+ init_(false)
+{ }
+
+Fprinter::~Fprinter()
+{
+ MOZ_ASSERT_IF(init_, !file_);
+}
+
+bool
+Fprinter::init(const char* path)
+{
+ MOZ_ASSERT(!file_);
+ file_ = fopen(path, "w");
+ if (!file_)
+ return false;
+ init_ = true;
+ return true;
+}
+
+void
+Fprinter::init(FILE *fp)
+{
+ MOZ_ASSERT(!file_);
+ file_ = fp;
+ init_ = false;
+}
+
+void
+Fprinter::flush()
+{
+ MOZ_ASSERT(file_);
+ fflush(file_);
+}
+
+void
+Fprinter::finish()
+{
+ MOZ_ASSERT(file_);
+ if (init_)
+ fclose(file_);
+ file_ = nullptr;
+}
+
+int
+Fprinter::put(const char* s, size_t len)
+{
+ MOZ_ASSERT(file_);
+ int i = fwrite(s, len, 1, file_);
+ if (size_t(i) != len) {
+ reportOutOfMemory();
+ return -1;
+ }
+ return i;
+}
+
+int
+Fprinter::printf(const char* fmt, ...)
+{
+ MOZ_ASSERT(file_);
+ va_list ap;
+ va_start(ap, fmt);
+ int i = vfprintf(file_, fmt, ap);
+ if (i == -1)
+ reportOutOfMemory();
+ va_end(ap);
+ return i;
+}
+
+int
+Fprinter::vprintf(const char* fmt, va_list ap)
+{
+ MOZ_ASSERT(file_);
+ int i = vfprintf(file_, fmt, ap);
+ if (i == -1)
+ reportOutOfMemory();
+ return i;
+}
+
+LSprinter::LSprinter(LifoAlloc* lifoAlloc)
+ : alloc_(lifoAlloc),
+ head_(nullptr),
+ tail_(nullptr),
+ unused_(0)
+{ }
+
+LSprinter::~LSprinter()
+{
+ // This LSprinter might be allocated as part of the same LifoAlloc, so we
+ // should not expect the destructor to be called.
+}
+
+void
+LSprinter::exportInto(GenericPrinter& out) const
+{
+ if (!head_)
+ return;
+
+ for (Chunk* it = head_; it != tail_; it = it->next)
+ out.put(it->chars(), it->length);
+ out.put(tail_->chars(), tail_->length - unused_);
+}
+
+void
+LSprinter::clear()
+{
+ head_ = nullptr;
+ tail_ = nullptr;
+ unused_ = 0;
+ hadOOM_ = false;
+}
+
+int
+LSprinter::put(const char* s, size_t len)
+{
+ // Compute how much data will fit in the current chunk.
+ size_t existingSpaceWrite = 0;
+ size_t overflow = len;
+ if (unused_ > 0 && tail_) {
+ existingSpaceWrite = std::min(unused_, len);
+ overflow = len - existingSpaceWrite;
+ }
+
+ // If necessary, allocate a new chunk for overflow data.
+ size_t allocLength = 0;
+ Chunk* last = nullptr;
+ if (overflow > 0) {
+ allocLength = AlignBytes(sizeof(Chunk) + overflow, js::detail::LIFO_ALLOC_ALIGN);
+
+ LifoAlloc::AutoFallibleScope fallibleAllocator(alloc_);
+ last = reinterpret_cast<Chunk*>(alloc_->alloc(allocLength));
+ if (!last) {
+ reportOutOfMemory();
+ return -1;
+ }
+ }
+
+ // All fallible operations complete: now fill up existing space, then
+ // overflow space in any new chunk.
+ MOZ_ASSERT(existingSpaceWrite + overflow == len);
+
+ if (existingSpaceWrite > 0) {
+ PodCopy(tail_->end() - unused_, s, existingSpaceWrite);
+ unused_ -= existingSpaceWrite;
+ s += existingSpaceWrite;
+ }
+
+ if (overflow > 0) {
+ if (tail_ && reinterpret_cast<char*>(last) == tail_->end()) {
+ // tail_ and last are consecutive in memory. LifoAlloc has no
+ // metadata and is just a bump allocator, so we can cheat by
+ // appending the newly-allocated space to tail_.
+ unused_ = allocLength;
+ tail_->length += allocLength;
+ } else {
+ // Remove the size of the header from the allocated length.
+ size_t availableSpace = allocLength - sizeof(Chunk);
+ last->next = nullptr;
+ last->length = availableSpace;
+
+ unused_ = availableSpace;
+ if (!head_)
+ head_ = last;
+ else
+ tail_->next = last;
+
+ tail_ = last;
+ }
+
+ PodCopy(tail_->end() - unused_, s, overflow);
+
+ MOZ_ASSERT(unused_ >= overflow);
+ unused_ -= overflow;
+ }
+
+ MOZ_ASSERT(len <= INT_MAX);
+ return int(len);
+}
+
+int
+LSprinter::printf(const char* fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ int i = vprintf(fmt, va);
+ va_end(va);
+ return i;
+}
+
+int
+LSprinter::vprintf(const char* fmt, va_list ap)
+{
+ // Simple shortcut to avoid allocating strings.
+ if (strchr(fmt, '%') == nullptr)
+ return put(fmt);
+
+ char* bp;
+ bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */
+ if (!bp) {
+ reportOutOfMemory();
+ return -1;
+ }
+ int i = put(bp);
+ js_free(bp);
+ return i;
+}
+
+void
+LSprinter::reportOutOfMemory()
+{
+ if (hadOOM_)
+ return;
+ hadOOM_ = true;
+}
+
+bool
+LSprinter::hadOutOfMemory() const
+{
+ return hadOOM_;
+}
+
+} // namespace js
diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h
new file mode 100644
index 000000000..3ee76da44
--- /dev/null
+++ b/js/src/vm/Printer.h
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Printer_h
+#define vm_Printer_h
+
+#include "mozilla/Attributes.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+class JSString;
+
+namespace js {
+
+class ExclusiveContext;
+class LifoAlloc;
+
+// Generic printf interface, similar to an ostream in the standard library.
+//
+// This class is useful to make generic printers which can work either with a
+// file backend, with a buffer allocated with an ExclusiveContext or a link-list
+// of chunks allocated with a LifoAlloc.
+class GenericPrinter
+{
+ protected:
+ bool hadOOM_; // whether reportOutOfMemory() has been called.
+
+ GenericPrinter();
+
+ public:
+ // Puts |len| characters from |s| at the current position and return an offset to
+ // the beginning of this new data.
+ virtual int put(const char* s, size_t len) = 0;
+
+ inline int put(const char* s) {
+ return put(s, strlen(s));
+ }
+
+ // Prints a formatted string into the buffer.
+ virtual int printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
+ virtual int vprintf(const char* fmt, va_list ap);
+
+ // Report that a string operation failed to get the memory it requested. The
+ // first call to this function calls JS_ReportOutOfMemory, and sets this
+ // Sprinter's outOfMemory flag; subsequent calls do nothing.
+ virtual void reportOutOfMemory();
+
+ // Return true if this Sprinter ran out of memory.
+ virtual bool hadOutOfMemory() const;
+};
+
+// Sprintf, but with unlimited and automatically allocated buffering.
+class Sprinter final : public GenericPrinter
+{
+ public:
+ struct InvariantChecker
+ {
+ const Sprinter* parent;
+
+ explicit InvariantChecker(const Sprinter* p) : parent(p) {
+ parent->checkInvariants();
+ }
+
+ ~InvariantChecker() {
+ parent->checkInvariants();
+ }
+ };
+
+ ExclusiveContext* context; // context executing the decompiler
+
+ private:
+ static const size_t DefaultSize;
+#ifdef DEBUG
+ bool initialized; // true if this is initialized, use for debug builds
+#endif
+ bool shouldReportOOM; // whether to report OOM to the context
+ char* base; // malloc'd buffer address
+ size_t size; // size of buffer allocated at base
+ ptrdiff_t offset; // offset of next free char in buffer
+
+ MOZ_MUST_USE bool realloc_(size_t newSize);
+
+ public:
+ explicit Sprinter(ExclusiveContext* cx, bool shouldReportOOM = true);
+ ~Sprinter();
+
+ // Initialize this sprinter, returns false on error.
+ MOZ_MUST_USE bool init();
+
+ void checkInvariants() const;
+
+ const char* string() const;
+ const char* stringEnd() const;
+ // Returns the string at offset |off|.
+ char* stringAt(ptrdiff_t off) const;
+ // Returns the char at offset |off|.
+ char& operator[](size_t off);
+
+ // Attempt to reserve len + 1 space (for a trailing nullptr byte). If the
+ // attempt succeeds, return a pointer to the start of that space and adjust the
+ // internal content. The caller *must* completely fill this space on success.
+ char* reserve(size_t len);
+
+ // Puts |len| characters from |s| at the current position and return an offset to
+ // the beginning of this new data.
+ virtual int put(const char* s, size_t len) override;
+ using GenericPrinter::put; // pick up |inline int put(const char* s);|
+
+ // Format the given format/arguments as if by JS_vsmprintf, then put it.
+ // Return true on success, else return false and report an error (typically
+ // OOM).
+ MOZ_MUST_USE bool jsprintf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
+
+ // Prints a formatted string into the buffer.
+ virtual int vprintf(const char* fmt, va_list ap) override;
+
+ int putString(JSString* str);
+
+ ptrdiff_t getOffset() const;
+
+ // Report that a string operation failed to get the memory it requested. The
+ // first call to this function calls JS_ReportOutOfMemory, and sets this
+ // Sprinter's outOfMemory flag; subsequent calls do nothing.
+ virtual void reportOutOfMemory() override;
+};
+
+// Fprinter, print a string directly into a file.
+class Fprinter final : public GenericPrinter
+{
+ private:
+ FILE* file_;
+ bool init_;
+
+ public:
+ explicit Fprinter(FILE* fp);
+ Fprinter();
+ ~Fprinter();
+
+ // Initialize this printer, returns false on error.
+ MOZ_MUST_USE bool init(const char* path);
+ void init(FILE* fp);
+ bool isInitialized() const {
+ return file_ != nullptr;
+ }
+ void flush();
+ void finish();
+
+ // Puts |len| characters from |s| at the current position and return an
+ // offset to the beginning of this new data.
+ virtual int put(const char* s, size_t len) override;
+ using GenericPrinter::put; // pick up |inline int put(const char* s);|
+
+ // Prints a formatted string into the buffer.
+ virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
+ virtual int vprintf(const char* fmt, va_list ap) override;
+};
+
+// LSprinter, is similar to Sprinter except that instead of using an
+// ExclusiveContext to allocate strings, it use a LifoAlloc as a backend for the
+// allocation of the chunk of the string.
+class LSprinter final : public GenericPrinter
+{
+ private:
+ struct Chunk
+ {
+ Chunk* next;
+ size_t length;
+
+ char* chars() {
+ return reinterpret_cast<char*>(this + 1);
+ }
+ char* end() {
+ return chars() + length;
+ }
+ };
+
+ private:
+ LifoAlloc* alloc_; // LifoAlloc used as a backend of chunk allocations.
+ Chunk* head_;
+ Chunk* tail_;
+ size_t unused_;
+
+ public:
+ explicit LSprinter(LifoAlloc* lifoAlloc);
+ ~LSprinter();
+
+ // Copy the content of the chunks into another printer, such that we can
+ // flush the content of this printer to a file.
+ void exportInto(GenericPrinter& out) const;
+
+ // Drop the current string, and let them be free with the LifoAlloc.
+ void clear();
+
+ // Puts |len| characters from |s| at the current position and return an
+ // offset to the beginning of this new data.
+ virtual int put(const char* s, size_t len) override;
+ using GenericPrinter::put; // pick up |inline int put(const char* s);|
+
+ // Prints a formatted string into the buffer.
+ virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
+ virtual int vprintf(const char* fmt, va_list ap) override;
+
+ // Report that a string operation failed to get the memory it requested. The
+ // first call to this function calls JS_ReportOutOfMemory, and sets this
+ // Sprinter's outOfMemory flag; subsequent calls do nothing.
+ virtual void reportOutOfMemory() override;
+
+ // Return true if this Sprinter ran out of memory.
+ virtual bool hadOutOfMemory() const override;
+};
+
+// Map escaped code to the letter/symbol escaped with a backslash.
+extern const char js_EscapeMap[];
+
+// Return a GC'ed string containing the chars in str, with any non-printing
+// chars or quotes (' or " as specified by the quote argument) escaped, and
+// with the quote character at the beginning and end of the result string.
+extern JSString*
+QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote);
+
+extern char*
+QuoteString(Sprinter* sp, JSString* str, char16_t quote);
+
+
+} // namespace js
+
+#endif // vm_Printer_h
diff --git a/js/src/vm/Probes-inl.h b/js/src/vm/Probes-inl.h
new file mode 100644
index 000000000..347f842b8
--- /dev/null
+++ b/js/src/vm/Probes-inl.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Probes_inl_h
+#define vm_Probes_inl_h
+
+#include "vm/Probes.h"
+
+#include "jscntxt.h"
+
+namespace js {
+
+/*
+ * Many probe handlers are implemented inline for minimal performance impact,
+ * especially important when no backends are enabled.
+ */
+
+inline bool
+probes::CallTrackingActive(JSContext* cx)
+{
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
+ return true;
+#endif
+ return false;
+}
+
+inline bool
+probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
+ InterpreterFrame* fp)
+{
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
+ DTraceEnterJSFun(cx, maybeFun, script);
+#endif
+
+ JSRuntime* rt = cx->runtime();
+ if (rt->spsProfiler.enabled()) {
+ if (!rt->spsProfiler.enter(cx, script, maybeFun))
+ return false;
+ MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
+ fp->setPushedSPSFrame();
+ }
+
+ return true;
+}
+
+inline void
+probes::ExitScript(JSContext* cx, JSScript* script, JSFunction* maybeFun, bool popSPSFrame)
+{
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
+ DTraceExitJSFun(cx, maybeFun, script);
+#endif
+
+ if (popSPSFrame)
+ cx->runtime()->spsProfiler.exit(script, maybeFun);
+}
+
+inline bool
+probes::StartExecution(JSScript* script)
+{
+ bool ok = true;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_EXECUTE_START_ENABLED())
+ JAVASCRIPT_EXECUTE_START((script->filename() ? (char*)script->filename() : nullName),
+ script->lineno());
+#endif
+
+ return ok;
+}
+
+inline bool
+probes::StopExecution(JSScript* script)
+{
+ bool ok = true;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
+ JAVASCRIPT_EXECUTE_DONE((script->filename() ? (char*)script->filename() : nullName),
+ script->lineno());
+#endif
+
+ return ok;
+}
+
+} /* namespace js */
+
+#endif /* vm_Probes_inl_h */
diff --git a/js/src/vm/Probes.cpp b/js/src/vm/Probes.cpp
new file mode 100644
index 000000000..ff3b74974
--- /dev/null
+++ b/js/src/vm/Probes.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Probes-inl.h"
+
+#include "jscntxt.h"
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+#include "jsscriptinlines.h"
+#endif
+
+#define TYPEOF(cx,v) (v.isNull() ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
+
+using namespace js;
+
+const char probes::nullName[] = "(null)";
+const char probes::anonymousName[] = "(anonymous)";
+
+bool probes::ProfilingActive = true;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+static const char*
+ScriptFilename(const JSScript* script)
+{
+ if (!script)
+ return probes::nullName;
+ if (!script->filename())
+ return probes::anonymousName;
+ return script->filename();
+}
+
+static const char*
+FunctionName(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
+{
+ if (!fun)
+ return probes::nullName;
+ if (!fun->displayAtom())
+ return probes::anonymousName;
+ return bytes->encodeLatin1(cx, fun->displayAtom()) ? bytes->ptr() : probes::nullName;
+}
+
+/*
+ * These functions call the DTrace macros for the JavaScript USDT probes.
+ * Originally this code was inlined in the JavaScript code; however since
+ * a number of operations are called, these have been placed into functions
+ * to reduce any negative compiler optimization effect that the addition of
+ * a number of usually unused lines of code would cause.
+ */
+void
+probes::DTraceEnterJSFun(JSContext* cx, JSFunction* fun, JSScript* script)
+{
+ JSAutoByteString funNameBytes;
+ JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), probes::nullName,
+ FunctionName(cx, fun, &funNameBytes));
+}
+
+void
+probes::DTraceExitJSFun(JSContext* cx, JSFunction* fun, JSScript* script)
+{
+ JSAutoByteString funNameBytes;
+ JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), probes::nullName,
+ FunctionName(cx, fun, &funNameBytes));
+}
+#endif
diff --git a/js/src/vm/Probes.h b/js/src/vm/Probes.h
new file mode 100644
index 000000000..edcc9d33e
--- /dev/null
+++ b/js/src/vm/Probes.h
@@ -0,0 +1,143 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Probes_h
+#define vm_Probes_h
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+#include "javascript-trace.h"
+#endif
+
+#include "vm/Stack.h"
+
+namespace js {
+
+namespace probes {
+
+/*
+ * Static probes
+ *
+ * The probe points defined in this file are scattered around the SpiderMonkey
+ * source tree. The presence of probes::SomeEvent() means that someEvent is
+ * about to happen or has happened. To the extent possible, probes should be
+ * inserted in all paths associated with a given event, regardless of the
+ * active runmode (interpreter/traceJIT/methodJIT/ionJIT).
+ *
+ * When a probe fires, it is handled by any probe handling backends that have
+ * been compiled in. By default, most probes do nothing or at least do nothing
+ * expensive, so the presence of the probe should have negligible effect on
+ * running time. (Probes in slow paths may do something by default, as long as
+ * there is no noticeable slowdown.)
+ *
+ * For some probes, the mere existence of the probe is too expensive even if it
+ * does nothing when called. For example, just having consistent information
+ * available for a function call entry/exit probe causes the JITs to
+ * de-optimize function calls. In those cases, the JITs may query at compile
+ * time whether a probe is desired, and omit the probe invocation if not. If a
+ * probe is runtime-disabled at compilation time, it is not guaranteed to fire
+ * within a compiled function if it is later enabled.
+ *
+ * Not all backends handle all of the probes listed here.
+ */
+
+/*
+ * Internal use only: remember whether "profiling", whatever that means, is
+ * currently active. Used for state management.
+ */
+extern bool ProfilingActive;
+
+extern const char nullName[];
+extern const char anonymousName[];
+
+/*
+ * Test whether we are tracking JS function call enter/exit. The JITs use this
+ * to decide whether they can optimize in a way that would prevent probes from
+ * firing.
+ */
+bool CallTrackingActive(JSContext*);
+
+/* Entering a JS function */
+bool EnterScript(JSContext*, JSScript*, JSFunction*, InterpreterFrame*);
+
+/* About to leave a JS function */
+void ExitScript(JSContext*, JSScript*, JSFunction*, bool popSPSFrame);
+
+/* Executing a script */
+bool StartExecution(JSScript* script);
+
+/* Script has completed execution */
+bool StopExecution(JSScript* script);
+
+/*
+ * Object has been created. |obj| must exist (its class and size are read)
+ */
+bool CreateObject(ExclusiveContext* cx, JSObject* obj);
+
+/*
+ * Object is about to be finalized. |obj| must still exist (its class is
+ * read)
+ */
+bool FinalizeObject(JSObject* obj);
+
+/*
+ * Internal: DTrace-specific functions to be called during probes::EnterScript
+ * and probes::ExitScript. These will not be inlined, but the argument
+ * marshalling required for these probe points is expensive enough that it
+ * shouldn't really matter.
+ */
+void DTraceEnterJSFun(JSContext* cx, JSFunction* fun, JSScript* script);
+void DTraceExitJSFun(JSContext* cx, JSFunction* fun, JSScript* script);
+
+} // namespace probes
+
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+static const char* ObjectClassname(JSObject* obj) {
+ if (!obj)
+ return "(null object)";
+ const Class* clasp = obj->getClass();
+ if (!clasp)
+ return "(null)";
+ const char* class_name = clasp->name;
+ if (!class_name)
+ return "(null class name)";
+ return class_name;
+}
+#endif
+
+inline bool
+probes::CreateObject(ExclusiveContext* cx, JSObject* obj)
+{
+ bool ok = true;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
+ JAVASCRIPT_OBJECT_CREATE(ObjectClassname(obj), (uintptr_t)obj);
+#endif
+
+ return ok;
+}
+
+inline bool
+probes::FinalizeObject(JSObject* obj)
+{
+ bool ok = true;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+ if (JAVASCRIPT_OBJECT_FINALIZE_ENABLED()) {
+ const Class* clasp = obj->getClass();
+
+ /* the first arg is nullptr - reserved for future use (filename?) */
+ JAVASCRIPT_OBJECT_FINALIZE(nullptr, (char*)clasp->name, (uintptr_t)obj);
+ }
+#endif
+
+ return ok;
+}
+
+} /* namespace js */
+
+#endif /* vm_Probes_h */
diff --git a/js/src/vm/PropDesc.h b/js/src/vm/PropDesc.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/js/src/vm/PropDesc.h
diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp
new file mode 100644
index 000000000..49ed5a624
--- /dev/null
+++ b/js/src/vm/ProxyObject.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ProxyObject.h"
+
+#include "jscompartment.h"
+
+#include "proxy/DeadObjectProxy.h"
+#include "proxy/ScriptedProxyHandler.h"
+
+#include "jsobjinlines.h"
+
+using namespace js;
+
+/* static */ ProxyObject*
+ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, TaggedProto proto_,
+ const ProxyOptions& options)
+{
+ Rooted<TaggedProto> proto(cx, proto_);
+
+ const Class* clasp = options.clasp();
+
+ MOZ_ASSERT(isValidProxyClass(clasp));
+ MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
+ MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
+ MOZ_ASSERT(clasp->hasFinalize());
+
+ /*
+ * Eagerly mark properties unknown for proxies, so we don't try to track
+ * their properties and so that we don't need to walk the compartment if
+ * their prototype changes later. But don't do this for DOM proxies,
+ * because we want to be able to keep track of them in typesets in useful
+ * ways.
+ */
+ if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) {
+ RootedObject protoObj(cx, proto.toObject());
+ if (!JSObject::setNewGroupUnknown(cx, clasp, protoObj))
+ return nullptr;
+ }
+
+ // Ensure that the wrapper has the same lifetime assumptions as the
+ // wrappee. Prefer to allocate in the nursery, when possible.
+ NewObjectKind newKind = NurseryAllocatedProxy;
+ if (options.singleton()) {
+ MOZ_ASSERT(priv.isGCThing() && priv.toGCThing()->isTenured());
+ newKind = SingletonObject;
+ } else if ((priv.isGCThing() && priv.toGCThing()->isTenured()) ||
+ !handler->canNurseryAllocate() ||
+ !handler->finalizeInBackground(priv))
+ {
+ newKind = TenuredObject;
+ }
+
+ gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
+ if (handler->finalizeInBackground(priv))
+ allocKind = GetBackgroundAllocKind(allocKind);
+
+ AutoSetNewObjectMetadata metadata(cx);
+ // Note: this will initialize the object's |data| to strange values, but we
+ // will immediately overwrite those below.
+ RootedObject obj(cx, NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind,
+ newKind));
+ if (!obj)
+ return nullptr;
+
+ Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
+ new (proxy->data.values) detail::ProxyValueArray;
+ proxy->data.handler = handler;
+ proxy->setCrossCompartmentPrivate(priv);
+
+ /* Don't track types of properties of non-DOM and non-singleton proxies. */
+ if (newKind != SingletonObject && !clasp->isDOMClass())
+ MarkObjectGroupUnknownProperties(cx, proxy->group());
+
+ return proxy;
+}
+
+gc::AllocKind
+ProxyObject::allocKindForTenure() const
+{
+ gc::AllocKind allocKind = gc::GetGCObjectKind(group()->clasp());
+ if (data.handler->finalizeInBackground(const_cast<ProxyObject*>(this)->private_()))
+ allocKind = GetBackgroundAllocKind(allocKind);
+ return allocKind;
+}
+
+/* static */ size_t
+ProxyObject::objectMovedDuringMinorGC(TenuringTracer* trc, JSObject* dst, JSObject* src)
+{
+ ProxyObject& psrc = src->as<ProxyObject>();
+ ProxyObject& pdst = dst->as<ProxyObject>();
+
+ // We're about to sweep the nursery heap, so migrate the inline
+ // ProxyValueArray to the malloc heap if they were nursery allocated.
+ if (trc->runtime()->gc.nursery.isInside(psrc.data.values))
+ pdst.data.values = js_new<detail::ProxyValueArray>(*psrc.data.values);
+ else
+ trc->runtime()->gc.nursery.removeMallocedBuffer(psrc.data.values);
+ return sizeof(detail::ProxyValueArray);
+}
+
+void
+ProxyObject::setCrossCompartmentPrivate(const Value& priv)
+{
+ *slotOfPrivate() = priv;
+}
+
+void
+ProxyObject::setSameCompartmentPrivate(const Value& priv)
+{
+ MOZ_ASSERT(IsObjectValueInCompartment(priv, compartment()));
+ *slotOfPrivate() = priv;
+}
+
+void
+ProxyObject::nuke()
+{
+ // When nuking scripted proxies, isCallable and isConstructor values for
+ // the proxy needs to be preserved. Do this before clearing the target.
+ uint32_t callable = handler()->isCallable(this)
+ ? ScriptedProxyHandler::IS_CALLABLE : 0;
+ uint32_t constructor = handler()->isConstructor(this)
+ ? ScriptedProxyHandler::IS_CONSTRUCTOR : 0;
+ setExtra(ScriptedProxyHandler::IS_CALLCONSTRUCT_EXTRA,
+ PrivateUint32Value(callable | constructor));
+
+ // Clear the target reference.
+ setSameCompartmentPrivate(NullValue());
+
+ // Update the handler to make this a DeadObjectProxy.
+ setHandler(&DeadObjectProxy::singleton);
+
+ // The proxy's extra slots are not cleared and will continue to be
+ // traced. This avoids the possibility of triggering write barriers while
+ // nuking proxies in dead compartments which could otherwise cause those
+ // compartments to be kept alive. Note that these are slots cannot hold
+ // cross compartment pointers, so this cannot cause the target compartment
+ // to leak.
+}
+
+JS_FRIEND_API(void)
+js::SetValueInProxy(Value* slot, const Value& value)
+{
+ // Slots in proxies are not GCPtrValues, so do a cast whenever assigning
+ // values to them which might trigger a barrier.
+ *reinterpret_cast<GCPtrValue*>(slot) = value;
+}
diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h
new file mode 100644
index 000000000..a0a929b20
--- /dev/null
+++ b/js/src/vm/ProxyObject.h
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ProxyObject_h
+#define vm_ProxyObject_h
+
+#include "js/Proxy.h"
+#include "vm/ShapedObject.h"
+
+namespace js {
+
+/**
+ * This is the base class for the various kinds of proxy objects. It's never
+ * instantiated.
+ *
+ * Proxy objects use ShapedObject::shape_ primarily to record flags. Property
+ * information, &c. is all dynamically computed.
+ */
+class ProxyObject : public ShapedObject
+{
+ // GetProxyDataLayout computes the address of this field.
+ detail::ProxyDataLayout data;
+
+ void static_asserts() {
+ static_assert(sizeof(ProxyObject) == sizeof(JSObject_Slots0),
+ "proxy object size must match GC thing size");
+ static_assert(offsetof(ProxyObject, data) == detail::ProxyDataOffset,
+ "proxy object layout must match shadow interface");
+ }
+
+ public:
+ static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv,
+ TaggedProto proto_, const ProxyOptions& options);
+
+ const Value& private_() {
+ return GetProxyPrivate(this);
+ }
+
+ void setCrossCompartmentPrivate(const Value& priv);
+ void setSameCompartmentPrivate(const Value& priv);
+
+ GCPtrValue* slotOfPrivate() {
+ return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values->privateSlot);
+ }
+
+ JSObject* target() const {
+ return const_cast<ProxyObject*>(this)->private_().toObjectOrNull();
+ }
+
+ const BaseProxyHandler* handler() const {
+ return GetProxyHandler(const_cast<ProxyObject*>(this));
+ }
+
+ void setHandler(const BaseProxyHandler* handler) {
+ SetProxyHandler(this, handler);
+ }
+
+ static size_t offsetOfValues() {
+ return offsetof(ProxyObject, data.values);
+ }
+ static size_t offsetOfHandler() {
+ return offsetof(ProxyObject, data.handler);
+ }
+ static size_t offsetOfExtraSlotInValues(size_t slot) {
+ MOZ_ASSERT(slot < detail::PROXY_EXTRA_SLOTS);
+ return offsetof(detail::ProxyValueArray, extraSlots) + slot * sizeof(Value);
+ }
+
+ const Value& extra(size_t n) const {
+ return GetProxyExtra(const_cast<ProxyObject*>(this), n);
+ }
+
+ void setExtra(size_t n, const Value& extra) {
+ SetProxyExtra(this, n, extra);
+ }
+
+ gc::AllocKind allocKindForTenure() const;
+ static size_t objectMovedDuringMinorGC(TenuringTracer* trc, JSObject* dst, JSObject* src);
+
+ private:
+ GCPtrValue* slotOfExtra(size_t n) {
+ MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS);
+ return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values->extraSlots[n]);
+ }
+
+ static bool isValidProxyClass(const Class* clasp) {
+ // Since we can take classes from the outside, make sure that they
+ // are "sane". They have to quack enough like proxies for us to belive
+ // they should be treated as such.
+
+ // proxy_Trace is just a trivial wrapper around ProxyObject::trace for
+ // friend api exposure.
+
+ // Proxy classes are not allowed to have call or construct hooks directly. Their
+ // callability is instead decided by handler()->isCallable().
+ return clasp->isProxy() &&
+ clasp->isTrace(proxy_Trace) &&
+ !clasp->getCall() && !clasp->getConstruct();
+ }
+
+ public:
+ static unsigned grayLinkExtraSlot(JSObject* obj);
+
+ void renew(JSContext* cx, const BaseProxyHandler* handler, const Value& priv);
+
+ static void trace(JSTracer* trc, JSObject* obj);
+
+ void nuke();
+
+ // There is no class_ member to force specialization of JSObject::is<T>().
+ // The implementation in JSObject is incorrect for proxies since it doesn't
+ // take account of the handler type.
+ static const Class proxyClass;
+};
+
+inline bool
+IsProxyClass(const Class* clasp)
+{
+ return clasp->isProxy();
+}
+
+bool IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler);
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::ProxyObject>() const
+{
+ // Note: this method is implemented in terms of the IsProxy() friend API
+ // functions to ensure the implementations are tied together.
+ // Note 2: this specialization isn't used for subclasses of ProxyObject
+ // which must supply their own implementation.
+ return js::IsProxy(const_cast<JSObject*>(this));
+}
+
+inline bool
+js::IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler) {
+ return obj->is<js::ProxyObject>() && obj->as<js::ProxyObject>().handler() == handler;
+}
+
+#endif /* vm_ProxyObject_h */
diff --git a/js/src/vm/Realm.cpp b/js/src/vm/Realm.cpp
new file mode 100644
index 000000000..da4a1cf93
--- /dev/null
+++ b/js/src/vm/Realm.cpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/Realm.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h" // For ExclusiveContext::global
+
+#include "vm/GlobalObject.h"
+
+using namespace js;
+
+JS_PUBLIC_API(JSObject*)
+JS::GetRealmObjectPrototype(JSContext* cx)
+{
+ CHECK_REQUEST(cx);
+ return GlobalObject::getOrCreateObjectPrototype(cx, cx->global());
+}
+
+JS_PUBLIC_API(JSObject*)
+JS::GetRealmFunctionPrototype(JSContext* cx)
+{
+ CHECK_REQUEST(cx);
+ return GlobalObject::getOrCreateFunctionPrototype(cx, cx->global());
+}
+
+JS_PUBLIC_API(JSObject*)
+JS::GetRealmArrayPrototype(JSContext* cx)
+{
+ CHECK_REQUEST(cx);
+ return GlobalObject::getOrCreateArrayPrototype(cx, cx->global());
+}
+
+JS_PUBLIC_API(JSObject*)
+JS::GetRealmErrorPrototype(JSContext* cx)
+{
+ CHECK_REQUEST(cx);
+ return GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), JSEXN_ERR);
+}
+
+JS_PUBLIC_API(JSObject*)
+JS::GetRealmIteratorPrototype(JSContext* cx)
+{
+ CHECK_REQUEST(cx);
+ return GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
+}
diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp
new file mode 100644
index 000000000..97df908c3
--- /dev/null
+++ b/js/src/vm/ReceiverGuard.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/ReceiverGuard.h"
+
+#include "builtin/TypedObject.h"
+#include "vm/UnboxedObject.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+
+ReceiverGuard::ReceiverGuard(JSObject* obj)
+ : group(nullptr), shape(nullptr)
+{
+ if (obj) {
+ if (obj->is<UnboxedPlainObject>()) {
+ group = obj->group();
+ if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
+ shape = expando->lastProperty();
+ } else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
+ group = obj->group();
+ } else {
+ shape = obj->maybeShape();
+ }
+ }
+}
+
+ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
+ : group(group), shape(shape)
+{
+ if (group) {
+ const Class* clasp = group->clasp();
+ if (clasp == &UnboxedPlainObject::class_) {
+ // Keep both group and shape.
+ } else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) {
+ this->shape = nullptr;
+ } else {
+ this->group = nullptr;
+ }
+ }
+}
+
+/* static */ int32_t
+HeapReceiverGuard::keyBits(JSObject* obj)
+{
+ if (obj->is<UnboxedPlainObject>()) {
+ // Both the group and shape need to be guarded for unboxed plain objects.
+ return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
+ }
+ if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
+ // Only the group needs to be guarded for unboxed arrays and typed objects.
+ return 2;
+ }
+ // Other objects only need the shape to be guarded.
+ return 3;
+}
+
+void
+HeapReceiverGuard::trace(JSTracer* trc)
+{
+ TraceNullableEdge(trc, &shape_, "receiver_guard_shape");
+ TraceNullableEdge(trc, &group_, "receiver_guard_group");
+}
diff --git a/js/src/vm/ReceiverGuard.h b/js/src/vm/ReceiverGuard.h
new file mode 100644
index 000000000..459cc0012
--- /dev/null
+++ b/js/src/vm/ReceiverGuard.h
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ReceiverGuard_h
+#define vm_ReceiverGuard_h
+
+#include "vm/Shape.h"
+
+namespace js {
+
+// A ReceiverGuard encapsulates the information about an object that needs to
+// be tested to determine if it has the same 'structure' as another object.
+// The guard includes the shape and/or group of the object, and which of these
+// is tested, as well as the meaning here of 'structure', depends on the kind
+// of object being tested:
+//
+// NativeObject: The structure of a native object is determined by its shape.
+// Two objects with the same shape have the same class, prototype, flags,
+// and all properties except those stored in dense elements.
+//
+// ProxyObject: The structure of a proxy object is determined by its shape.
+// Proxies with the same shape have the same class and prototype, but no
+// other commonality is guaranteed.
+//
+// TypedObject: The structure of a typed object is determined by its group.
+// All typed objects with the same group have the same class, prototype, and
+// own properties.
+//
+// UnboxedPlainObject: The structure of an unboxed plain object is determined
+// by its group and its expando object's shape, if there is one. All unboxed
+// plain objects with the same group and expando shape have the same
+// properties except those stored in the expando's dense elements.
+
+class HeapReceiverGuard;
+class RootedReceiverGuard;
+
+class ReceiverGuard
+{
+ public:
+ ObjectGroup* group;
+ Shape* shape;
+
+ ReceiverGuard()
+ : group(nullptr), shape(nullptr)
+ {}
+
+ inline MOZ_IMPLICIT ReceiverGuard(const HeapReceiverGuard& guard);
+ inline MOZ_IMPLICIT ReceiverGuard(const RootedReceiverGuard& guard);
+
+ explicit ReceiverGuard(JSObject* obj);
+ ReceiverGuard(ObjectGroup* group, Shape* shape);
+
+ bool operator ==(const ReceiverGuard& other) const {
+ return group == other.group && shape == other.shape;
+ }
+
+ bool operator !=(const ReceiverGuard& other) const {
+ return !(*this == other);
+ }
+
+ uintptr_t hash() const {
+ return (uintptr_t(group) >> 3) ^ (uintptr_t(shape) >> 3);
+ }
+};
+
+class HeapReceiverGuard
+{
+ GCPtrObjectGroup group_;
+ GCPtrShape shape_;
+
+ public:
+ explicit HeapReceiverGuard(const ReceiverGuard& guard)
+ : group_(guard.group), shape_(guard.shape)
+ {}
+
+ bool matches(const ReceiverGuard& guard) {
+ return group_ == guard.group && shape_ == guard.shape;
+ }
+
+ void update(const ReceiverGuard& other) {
+ group_ = other.group;
+ shape_ = other.shape;
+ }
+
+ void init(const ReceiverGuard& other) {
+ group_.init(other.group);
+ shape_.init(other.shape);
+ }
+
+ void trace(JSTracer* trc);
+
+ Shape* shape() const {
+ return shape_;
+ }
+ ObjectGroup* group() const {
+ return group_;
+ }
+
+ static size_t offsetOfShape() {
+ return offsetof(HeapReceiverGuard, shape_);
+ }
+ static size_t offsetOfGroup() {
+ return offsetof(HeapReceiverGuard, group_);
+ }
+
+ // Bits to munge into Baseline IC compiler keys when that IC has a
+ // HeapReceiverGuard. This uses at most two bits for data.
+ static int32_t keyBits(JSObject* obj);
+};
+
+class RootedReceiverGuard
+{
+ public:
+ RootedObjectGroup group;
+ RootedShape shape;
+
+ RootedReceiverGuard(JSContext* cx, const ReceiverGuard& guard)
+ : group(cx, guard.group), shape(cx, guard.shape)
+ {}
+};
+
+inline
+ReceiverGuard::ReceiverGuard(const HeapReceiverGuard& guard)
+ : group(guard.group()), shape(guard.shape())
+{}
+
+inline
+ReceiverGuard::ReceiverGuard(const RootedReceiverGuard& guard)
+ : group(guard.group), shape(guard.shape)
+{}
+
+} // namespace js
+
+#endif /* vm_ReceiverGuard_h */
diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
new file mode 100644
index 000000000..97f1163aa
--- /dev/null
+++ b/js/src/vm/RegExpObject.cpp
@@ -0,0 +1,1555 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/RegExpObject.h"
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/PodOperations.h"
+
+#include "jsstr.h"
+#ifdef DEBUG
+#include "jsutil.h"
+#endif
+
+#include "builtin/RegExp.h"
+#include "frontend/TokenStream.h"
+#ifdef DEBUG
+#include "irregexp/RegExpBytecode.h"
+#endif
+#include "irregexp/RegExpParser.h"
+#include "vm/MatchPairs.h"
+#include "vm/RegExpStatics.h"
+#include "vm/StringBuffer.h"
+#include "vm/TraceLogging.h"
+#ifdef DEBUG
+#include "vm/Unicode.h"
+#endif
+#include "vm/Xdr.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Shape-inl.h"
+
+using namespace js;
+
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::Maybe;
+using mozilla::PodCopy;
+using js::frontend::TokenStream;
+
+using JS::AutoCheckCannotGC;
+
+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 */)
+{
+ // Note: RegExp objects are always allocated in the tenured heap. This is
+ // not strictly required, but simplifies embedding them in jitcode.
+ Rooted<RegExpObject*> regexp(cx);
+
+ regexp = NewObjectWithClassProto<RegExpObject>(cx, proto, TenuredObject);
+ if (!regexp)
+ return nullptr;
+
+ regexp->initPrivate(nullptr);
+
+ if (!EmptyShape::ensureInitialCustomShape<RegExpObject>(cx, regexp))
+ return nullptr;
+
+ MOZ_ASSERT(regexp->lookupPure(cx->names().lastIndex)->slot() ==
+ RegExpObject::lastIndexSlot());
+
+ return regexp;
+}
+
+/* MatchPairs */
+
+bool
+MatchPairs::initArrayFrom(MatchPairs& copyFrom)
+{
+ MOZ_ASSERT(copyFrom.pairCount() > 0);
+
+ if (!allocOrExpandArray(copyFrom.pairCount()))
+ return false;
+
+ PodCopy(pairs_, copyFrom.pairs_, pairCount_);
+
+ return true;
+}
+
+bool
+ScopedMatchPairs::allocOrExpandArray(size_t pairCount)
+{
+ /* Array expansion is forbidden, but array reuse is acceptable. */
+ if (pairCount_) {
+ MOZ_ASSERT(pairs_);
+ MOZ_ASSERT(pairCount_ == pairCount);
+ return true;
+ }
+
+ MOZ_ASSERT(!pairs_);
+ pairs_ = (MatchPair*)lifoScope_.alloc().alloc(sizeof(MatchPair) * pairCount);
+ if (!pairs_)
+ return false;
+
+ pairCount_ = pairCount;
+ return true;
+}
+
+bool
+VectorMatchPairs::allocOrExpandArray(size_t pairCount)
+{
+ if (!vec_.resizeUninitialized(sizeof(MatchPair) * pairCount))
+ return false;
+
+ pairs_ = &vec_[0];
+ pairCount_ = pairCount;
+ return true;
+}
+
+/* RegExpObject */
+
+static inline void
+RegExpSharedReadBarrier(JSContext* cx, RegExpShared* shared)
+{
+ Zone* zone = cx->zone();
+ if (zone->needsIncrementalBarrier())
+ shared->trace(zone->barrierTracer());
+ if (shared->isMarkedGray())
+ shared->unmarkGray();
+}
+
+bool
+RegExpObject::getShared(JSContext* cx, RegExpGuard* g)
+{
+ if (RegExpShared* shared = maybeShared()) {
+ // Fetching a RegExpShared from an object requires a read
+ // barrier, as the shared pointer might be weak.
+ RegExpSharedReadBarrier(cx, shared);
+
+ g->init(*shared);
+ return true;
+ }
+
+ return createShared(cx, g);
+}
+
+/* static */ bool
+RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
+{
+ if (native == regexp_global) {
+ *mask = GlobalFlag;
+ return true;
+ }
+ if (native == regexp_ignoreCase) {
+ *mask = IgnoreCaseFlag;
+ return true;
+ }
+ if (native == regexp_multiline) {
+ *mask = MultilineFlag;
+ return true;
+ }
+ if (native == regexp_sticky) {
+ *mask = StickyFlag;
+ return true;
+ }
+ if (native == regexp_unicode) {
+ *mask = UnicodeFlag;
+ return true;
+ }
+
+ return false;
+}
+
+/* static */ void
+RegExpObject::trace(JSTracer* trc, JSObject* obj)
+{
+ RegExpShared* shared = obj->as<RegExpObject>().maybeShared();
+ if (!shared)
+ return;
+
+ // When tracing through the object normally, we have the option of
+ // unlinking the object from its RegExpShared so that the RegExpShared may
+ // be collected. To detect this we need to test all the following
+ // conditions, since:
+ // 1. During TraceRuntime, isHeapBusy() is true, but the tracer might not
+ // be a marking tracer.
+ // 2. When a write barrier executes, IsMarkingTracer is true, but
+ // isHeapBusy() will be false.
+ if (trc->runtime()->isHeapCollecting() &&
+ trc->isMarkingTracer() &&
+ !obj->asTenured().zone()->isPreservingCode())
+ {
+ obj->as<RegExpObject>().NativeObject::setPrivate(nullptr);
+ } else {
+ shared->trace(trc);
+ }
+}
+
+static const ClassOps RegExpObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ RegExpObject::trace,
+};
+
+static const ClassSpec RegExpObjectClassSpec = {
+ GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
+ CreateRegExpPrototype,
+ nullptr,
+ js::regexp_static_props,
+ js::regexp_methods,
+ js::regexp_properties
+};
+
+const Class RegExpObject::class_ = {
+ js_RegExp_str,
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
+ &RegExpObjectClassOps,
+ &RegExpObjectClassSpec
+};
+
+RegExpObject*
+RegExpObject::create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
+ TokenStream* tokenStream, LifoAlloc& alloc)
+{
+ RootedAtom source(cx, AtomizeChars(cx, chars, length));
+ if (!source)
+ return nullptr;
+
+ return create(cx, source, flags, tokenStream, alloc);
+}
+
+RegExpObject*
+RegExpObject::create(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags,
+ TokenStream* tokenStream, LifoAlloc& alloc)
+{
+ Maybe<CompileOptions> dummyOptions;
+ Maybe<TokenStream> dummyTokenStream;
+ if (!tokenStream) {
+ dummyOptions.emplace(cx->asJSContext());
+ dummyTokenStream.emplace(cx, *dummyOptions,
+ (const char16_t*) nullptr, 0,
+ (frontend::StrictModeGetter*) nullptr);
+ tokenStream = dummyTokenStream.ptr();
+ }
+
+ if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag))
+ return nullptr;
+
+ Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
+ if (!regexp)
+ return nullptr;
+
+ regexp->initAndZeroLastIndex(source, flags, cx);
+
+ return regexp;
+}
+
+bool
+RegExpObject::createShared(JSContext* cx, RegExpGuard* g)
+{
+ Rooted<RegExpObject*> self(cx, this);
+
+ MOZ_ASSERT(!maybeShared());
+ if (!cx->compartment()->regExps.get(cx, getSource(), getFlags(), g))
+ return false;
+
+ self->setShared(**g);
+ return true;
+}
+
+Shape*
+RegExpObject::assignInitialShape(ExclusiveContext* cx, Handle<RegExpObject*> self)
+{
+ MOZ_ASSERT(self->empty());
+
+ JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
+
+ /* The lastIndex property alone is writable but non-configurable. */
+ return self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT);
+}
+
+void
+RegExpObject::initIgnoringLastIndex(HandleAtom source, RegExpFlag flags)
+{
+ // If this is a re-initialization with an existing RegExpShared, 'flags'
+ // may not match getShared()->flags, so forget the RegExpShared.
+ NativeObject::setPrivate(nullptr);
+
+ setSource(source);
+ setFlags(flags);
+}
+
+void
+RegExpObject::initAndZeroLastIndex(HandleAtom source, RegExpFlag flags, ExclusiveContext* cx)
+{
+ initIgnoringLastIndex(source, flags);
+ zeroLastIndex(cx);
+}
+
+static MOZ_ALWAYS_INLINE bool
+IsLineTerminator(const JS::Latin1Char c)
+{
+ return c == '\n' || c == '\r';
+}
+
+static MOZ_ALWAYS_INLINE bool
+IsLineTerminator(const char16_t c)
+{
+ return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
+}
+
+static MOZ_ALWAYS_INLINE bool
+AppendEscapedLineTerminator(StringBuffer& sb, const JS::Latin1Char c)
+{
+ switch (c) {
+ case '\n':
+ if (!sb.append('n'))
+ return false;
+ break;
+ case '\r':
+ if (!sb.append('r'))
+ return false;
+ break;
+ default:
+ MOZ_CRASH("Bad LineTerminator");
+ }
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE bool
+AppendEscapedLineTerminator(StringBuffer& sb, const char16_t c)
+{
+ switch (c) {
+ case '\n':
+ if (!sb.append('n'))
+ return false;
+ break;
+ case '\r':
+ if (!sb.append('r'))
+ return false;
+ break;
+ case 0x2028:
+ if (!sb.append("u2028"))
+ return false;
+ break;
+ case 0x2029:
+ if (!sb.append("u2029"))
+ return false;
+ break;
+ default:
+ MOZ_CRASH("Bad LineTerminator");
+ }
+ return true;
+}
+
+template <typename CharT>
+static MOZ_ALWAYS_INLINE bool
+SetupBuffer(StringBuffer& sb, const CharT* oldChars, size_t oldLen, const CharT* it)
+{
+ if (mozilla::IsSame<CharT, char16_t>::value && !sb.ensureTwoByteChars())
+ return false;
+
+ if (!sb.reserve(oldLen + 1))
+ return false;
+
+ sb.infallibleAppend(oldChars, size_t(it - oldChars));
+ return true;
+}
+
+// Note: leaves the string buffer empty if no escaping need be performed.
+template <typename CharT>
+static bool
+EscapeRegExpPattern(StringBuffer& sb, const CharT* oldChars, size_t oldLen)
+{
+ bool inBrackets = false;
+ bool previousCharacterWasBackslash = false;
+
+ for (const CharT* it = oldChars; it < oldChars + oldLen; ++it) {
+ CharT ch = *it;
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else if (ch == '/') {
+ // There's a forward slash that needs escaping.
+ if (sb.empty()) {
+ // This is the first char we've seen that needs escaping,
+ // copy everything up to this point.
+ if (!SetupBuffer(sb, oldChars, oldLen, it))
+ return false;
+ }
+ if (!sb.append('\\'))
+ return false;
+ } else if (ch == '[') {
+ inBrackets = true;
+ }
+ }
+
+ if (IsLineTerminator(ch)) {
+ // There's LineTerminator that needs escaping.
+ if (sb.empty()) {
+ // This is the first char we've seen that needs escaping,
+ // copy everything up to this point.
+ if (!SetupBuffer(sb, oldChars, oldLen, it))
+ return false;
+ }
+ if (!previousCharacterWasBackslash) {
+ if (!sb.append('\\'))
+ return false;
+ }
+ if (!AppendEscapedLineTerminator(sb, ch))
+ return false;
+ } else if (!sb.empty()) {
+ if (!sb.append(ch))
+ return false;
+ }
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else if (ch == '\\')
+ previousCharacterWasBackslash = true;
+ }
+
+ return true;
+}
+
+// ES6 draft rev32 21.2.3.2.4.
+JSAtom*
+js::EscapeRegExpPattern(JSContext* cx, HandleAtom src)
+{
+ // Step 2.
+ if (src->length() == 0)
+ return cx->names().emptyRegExp;
+
+ // We may never need to use |sb|. Start using it lazily.
+ StringBuffer sb(cx);
+
+ if (src->hasLatin1Chars()) {
+ JS::AutoCheckCannotGC nogc;
+ if (!::EscapeRegExpPattern(sb, src->latin1Chars(nogc), src->length()))
+ return nullptr;
+ } else {
+ JS::AutoCheckCannotGC nogc;
+ if (!::EscapeRegExpPattern(sb, src->twoByteChars(nogc), src->length()))
+ return nullptr;
+ }
+
+ // Step 3.
+ return sb.empty() ? src : sb.finishAtom();
+}
+
+// ES6 draft rev32 21.2.5.14. Optimized for RegExpObject.
+JSFlatString*
+RegExpObject::toString(JSContext* cx) const
+{
+ // Steps 3-4.
+ RootedAtom src(cx, getSource());
+ if (!src)
+ return nullptr;
+ RootedAtom escapedSrc(cx, EscapeRegExpPattern(cx, src));
+
+ // Step 7.
+ StringBuffer sb(cx);
+ size_t len = escapedSrc->length();
+ if (!sb.reserve(len + 2))
+ return nullptr;
+ sb.infallibleAppend('/');
+ if (!sb.append(escapedSrc))
+ return nullptr;
+ sb.infallibleAppend('/');
+
+ // Steps 5-7.
+ if (global() && !sb.append('g'))
+ return nullptr;
+ if (ignoreCase() && !sb.append('i'))
+ return nullptr;
+ if (multiline() && !sb.append('m'))
+ return nullptr;
+ if (unicode() && !sb.append('u'))
+ return nullptr;
+ if (sticky() && !sb.append('y'))
+ return nullptr;
+
+ return sb.finishString();
+}
+
+#ifdef DEBUG
+bool
+RegExpShared::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input)
+{
+ CompilationMode mode = match_only ? MatchOnly : Normal;
+ if (!compileIfNecessary(cx, input, mode, ForceByteCode))
+ return false;
+
+ const uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
+ const uint8_t* pc = byteCode;
+
+ auto Load32Aligned = [](const uint8_t* pc) -> int32_t {
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(pc) & 3) == 0);
+ return *reinterpret_cast<const int32_t*>(pc);
+ };
+
+ auto Load16Aligned = [](const uint8_t* pc) -> int32_t {
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(pc) & 1) == 0);
+ return *reinterpret_cast<const uint16_t*>(pc);
+ };
+
+ int32_t numRegisters = Load32Aligned(pc);
+ fprintf(stderr, "numRegisters: %d\n", numRegisters);
+ pc += 4;
+
+ fprintf(stderr, "loc op\n");
+ fprintf(stderr, "----- --\n");
+
+ auto DumpLower = [](const char* text) {
+ while (*text) {
+ fprintf(stderr, "%c", unicode::ToLowerCase(*text));
+ text++;
+ }
+ };
+
+#define BYTECODE(NAME) \
+ case irregexp::BC_##NAME: \
+ DumpLower(#NAME);
+#define ADVANCE(NAME) \
+ fprintf(stderr, "\n"); \
+ pc += irregexp::BC_##NAME##_LENGTH; \
+ maxPc = js::Max(maxPc, pc); \
+ break;
+#define STOP(NAME) \
+ fprintf(stderr, "\n"); \
+ pc += irregexp::BC_##NAME##_LENGTH; \
+ break;
+#define JUMP(NAME, OFFSET) \
+ fprintf(stderr, "\n"); \
+ maxPc = js::Max(maxPc, byteCode + OFFSET); \
+ pc += irregexp::BC_##NAME##_LENGTH; \
+ break;
+#define BRANCH(NAME, OFFSET) \
+ fprintf(stderr, "\n"); \
+ pc += irregexp::BC_##NAME##_LENGTH; \
+ maxPc = js::Max(maxPc, js::Max(pc, byteCode + OFFSET)); \
+ break;
+
+ // Bytecode has no end marker, we need to calculate the bytecode length by
+ // tracing jumps and branches.
+ const uint8_t* maxPc = pc;
+ while (pc <= maxPc) {
+ fprintf(stderr, "%05d: ", int32_t(pc - byteCode));
+ int32_t insn = Load32Aligned(pc);
+ switch (insn & irregexp::BYTECODE_MASK) {
+ BYTECODE(BREAK) {
+ STOP(BREAK);
+ }
+ BYTECODE(PUSH_CP) {
+ ADVANCE(PUSH_CP);
+ }
+ BYTECODE(PUSH_BT) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d",
+ offset);
+ // Pushed value is used by POP_BT for jumping.
+ // Resolve maxPc here.
+ BRANCH(PUSH_BT, offset);
+ }
+ BYTECODE(PUSH_REGISTER) {
+ fprintf(stderr, " reg[%d]",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(PUSH_REGISTER);
+ }
+ BYTECODE(SET_REGISTER) {
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4));
+ ADVANCE(SET_REGISTER);
+ }
+ BYTECODE(ADVANCE_REGISTER) {
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4));
+ ADVANCE(ADVANCE_REGISTER);
+ }
+ BYTECODE(SET_REGISTER_TO_CP) {
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4));
+ ADVANCE(SET_REGISTER_TO_CP);
+ }
+ BYTECODE(SET_CP_TO_REGISTER) {
+ fprintf(stderr, " reg[%d]",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(SET_CP_TO_REGISTER);
+ }
+ BYTECODE(SET_REGISTER_TO_SP) {
+ fprintf(stderr, " reg[%d]",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(SET_REGISTER_TO_SP);
+ }
+ BYTECODE(SET_SP_TO_REGISTER) {
+ fprintf(stderr, " reg[%d]",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(SET_SP_TO_REGISTER);
+ }
+ BYTECODE(POP_CP) {
+ ADVANCE(POP_CP);
+ }
+ BYTECODE(POP_BT) {
+ // Jump is already resolved in PUSH_BT.
+ STOP(POP_BT);
+ }
+ BYTECODE(POP_REGISTER) {
+ fprintf(stderr, " reg[%d]",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(POP_REGISTER);
+ }
+ BYTECODE(FAIL) {
+ ADVANCE(FAIL);
+ }
+ BYTECODE(SUCCEED) {
+ ADVANCE(SUCCEED);
+ }
+ BYTECODE(ADVANCE_CP) {
+ fprintf(stderr, " %d",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(ADVANCE_CP);
+ }
+ BYTECODE(GOTO) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d",
+ offset);
+ JUMP(GOTO, offset);
+ }
+ BYTECODE(ADVANCE_CP_AND_GOTO) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ JUMP(ADVANCE_CP_AND_GOTO, offset);
+ }
+ BYTECODE(CHECK_GREEDY) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d",
+ offset);
+ BRANCH(CHECK_GREEDY, offset);
+ }
+ BYTECODE(LOAD_CURRENT_CHAR) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(LOAD_CURRENT_CHAR, offset);
+ }
+ BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
+ fprintf(stderr, " %d",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(LOAD_CURRENT_CHAR_UNCHECKED);
+ }
+ BYTECODE(LOAD_2_CURRENT_CHARS) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(LOAD_2_CURRENT_CHARS, offset);
+ }
+ BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
+ fprintf(stderr, " %d",
+ insn >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(LOAD_2_CURRENT_CHARS_UNCHECKED);
+ }
+ BYTECODE(LOAD_4_CURRENT_CHARS) {
+ ADVANCE(LOAD_4_CURRENT_CHARS);
+ }
+ BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
+ ADVANCE(LOAD_4_CURRENT_CHARS_UNCHECKED);
+ }
+ BYTECODE(CHECK_4_CHARS) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d",
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(CHECK_4_CHARS, offset);
+ }
+ BYTECODE(CHECK_CHAR) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_CHAR, offset);
+ }
+ BYTECODE(CHECK_NOT_4_CHARS) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d",
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(CHECK_NOT_4_CHARS, offset);
+ }
+ BYTECODE(CHECK_NOT_CHAR) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_NOT_CHAR, offset);
+ }
+ BYTECODE(AND_CHECK_4_CHARS) {
+ int32_t offset = Load32Aligned(pc + 12);
+ fprintf(stderr, " %d, %d, %d",
+ Load32Aligned(pc + 4),
+ Load32Aligned(pc + 8),
+ offset);
+ BRANCH(AND_CHECK_4_CHARS, offset);
+ }
+ BYTECODE(AND_CHECK_CHAR) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(AND_CHECK_CHAR, offset);
+ }
+ BYTECODE(AND_CHECK_NOT_4_CHARS) {
+ int32_t offset = Load32Aligned(pc + 12);
+ fprintf(stderr, " %d, %d, %d",
+ Load32Aligned(pc + 4),
+ Load32Aligned(pc + 8),
+ offset);
+ BRANCH(AND_CHECK_NOT_4_CHARS, offset);
+ }
+ BYTECODE(AND_CHECK_NOT_CHAR) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(AND_CHECK_NOT_CHAR, offset);
+ }
+ BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d, %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load16Aligned(pc + 4),
+ Load16Aligned(pc + 6),
+ offset);
+ BRANCH(MINUS_AND_CHECK_NOT_CHAR, offset);
+ }
+ BYTECODE(CHECK_CHAR_IN_RANGE) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d, %d",
+ Load16Aligned(pc + 4),
+ Load16Aligned(pc + 6),
+ offset);
+ BRANCH(CHECK_CHAR_IN_RANGE, offset);
+ }
+ BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " %d, %d, %d",
+ Load16Aligned(pc + 4),
+ Load16Aligned(pc + 6),
+ offset);
+ BRANCH(CHECK_CHAR_NOT_IN_RANGE, offset);
+ }
+ BYTECODE(CHECK_BIT_IN_TABLE) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x",
+ offset,
+ pc[8], pc[9], pc[10], pc[11],
+ pc[12], pc[13], pc[14], pc[15],
+ pc[16], pc[17], pc[18], pc[19],
+ pc[20], pc[21], pc[22], pc[23]);
+ BRANCH(CHECK_BIT_IN_TABLE, offset);
+ }
+ BYTECODE(CHECK_LT) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_LT, offset);
+ }
+ BYTECODE(CHECK_GT) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_GT, offset);
+ }
+ BYTECODE(CHECK_REGISTER_LT) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " reg[%d], %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(CHECK_REGISTER_LT, offset);
+ }
+ BYTECODE(CHECK_REGISTER_GE) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " reg[%d], %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(CHECK_REGISTER_GE, offset);
+ }
+ BYTECODE(CHECK_REGISTER_EQ_POS) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_REGISTER_EQ_POS, offset);
+ }
+ BYTECODE(CHECK_NOT_REGS_EQUAL) {
+ int32_t offset = Load32Aligned(pc + 8);
+ fprintf(stderr, " reg[%d], %d, %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ Load32Aligned(pc + 4),
+ offset);
+ BRANCH(CHECK_NOT_REGS_EQUAL, offset);
+ }
+ BYTECODE(CHECK_NOT_BACK_REF) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_NOT_BACK_REF, offset);
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_NOT_BACK_REF_NO_CASE, offset);
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " reg[%d], %d",
+ insn >> irregexp::BYTECODE_SHIFT,
+ offset);
+ BRANCH(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, offset);
+ }
+ BYTECODE(CHECK_AT_START) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d",
+ offset);
+ BRANCH(CHECK_AT_START, offset);
+ }
+ BYTECODE(CHECK_NOT_AT_START) {
+ int32_t offset = Load32Aligned(pc + 4);
+ fprintf(stderr, " %d",
+ offset);
+ BRANCH(CHECK_NOT_AT_START, offset);
+ }
+ BYTECODE(SET_CURRENT_POSITION_FROM_END) {
+ fprintf(stderr, " %u",
+ static_cast<uint32_t>(insn) >> irregexp::BYTECODE_SHIFT);
+ ADVANCE(SET_CURRENT_POSITION_FROM_END);
+ }
+ default:
+ MOZ_CRASH("Bad bytecode");
+ }
+ }
+
+#undef BYTECODE
+#undef ADVANCE
+#undef STOP
+#undef JUMP
+#undef BRANCH
+
+ return true;
+}
+
+bool
+RegExpObject::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input)
+{
+ RegExpGuard g(cx);
+ if (!getShared(cx, &g))
+ return false;
+
+ return g.re()->dumpBytecode(cx, match_only, input);
+}
+#endif
+
+template <typename CharT>
+static MOZ_ALWAYS_INLINE bool
+IsRegExpMetaChar(CharT ch)
+{
+ switch (ch) {
+ /* ES 2016 draft Mar 25, 2016 21.2.1 SyntaxCharacter. */
+ case '^': case '$': case '\\': case '.': case '*': case '+':
+ case '?': case '(': case ')': case '[': case ']': case '{':
+ case '}': case '|':
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename CharT>
+bool
+js::HasRegExpMetaChars(const CharT* chars, size_t length)
+{
+ for (size_t i = 0; i < length; ++i) {
+ if (IsRegExpMetaChar<CharT>(chars[i]))
+ return true;
+ }
+ return false;
+}
+
+template bool
+js::HasRegExpMetaChars<Latin1Char>(const Latin1Char* chars, size_t length);
+
+template bool
+js::HasRegExpMetaChars<char16_t>(const char16_t* chars, size_t length);
+
+bool
+js::StringHasRegExpMetaChars(JSLinearString* str)
+{
+ AutoCheckCannotGC nogc;
+ if (str->hasLatin1Chars())
+ return HasRegExpMetaChars(str->latin1Chars(nogc), str->length());
+
+ return HasRegExpMetaChars(str->twoByteChars(nogc), str->length());
+}
+
+/* RegExpShared */
+
+RegExpShared::RegExpShared(JSAtom* source, RegExpFlag flags)
+ : source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false)
+{}
+
+RegExpShared::~RegExpShared()
+{
+ for (size_t i = 0; i < tables.length(); i++)
+ js_delete(tables[i]);
+}
+
+void
+RegExpShared::trace(JSTracer* trc)
+{
+ if (trc->isMarkingTracer())
+ marked_ = true;
+
+ TraceNullableEdge(trc, &source, "RegExpShared source");
+ for (auto& comp : compilationArray)
+ TraceNullableEdge(trc, &comp.jitCode, "RegExpShared code");
+}
+
+bool
+RegExpShared::isMarkedGray() const
+{
+ if (source && source->isMarked(gc::GRAY))
+ return true;
+ for (const auto& comp : compilationArray) {
+ if (comp.jitCode && comp.jitCode->isMarked(gc::GRAY))
+ return true;
+ }
+ return false;
+}
+
+void
+RegExpShared::unmarkGray()
+{
+ if (source)
+ JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(source));
+ for (const auto& comp : compilationArray) {
+ if (comp.jitCode)
+ JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(comp.jitCode.get()));
+ }
+}
+
+bool
+RegExpShared::compile(JSContext* cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force)
+{
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+ AutoTraceLog logCompile(logger, TraceLogger_IrregexpCompile);
+
+ RootedAtom pattern(cx, source);
+ return compile(cx, pattern, input, mode, force);
+}
+
+bool
+RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force)
+{
+ if (!ignoreCase() && !StringHasRegExpMetaChars(pattern))
+ canStringMatch = true;
+
+ CompileOptions options(cx);
+ TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
+
+ LifoAllocScope scope(&cx->tempLifoAlloc());
+
+ /* Parse the pattern. */
+ irregexp::RegExpCompileData data;
+ if (!irregexp::ParsePattern(dummyTokenStream, cx->tempLifoAlloc(), pattern,
+ multiline(), mode == MatchOnly, unicode(), ignoreCase(),
+ global(), sticky(), &data))
+ {
+ return false;
+ }
+
+ this->parenCount = data.capture_count;
+
+ irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input,
+ false /* global() */,
+ ignoreCase(),
+ input->hasLatin1Chars(),
+ mode == MatchOnly,
+ force == ForceByteCode,
+ sticky(), unicode());
+ if (code.empty())
+ return false;
+
+ MOZ_ASSERT(!code.jitCode || !code.byteCode);
+ MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
+
+ RegExpCompilation& compilation = this->compilation(mode, input->hasLatin1Chars());
+ if (code.jitCode)
+ compilation.jitCode = code.jitCode;
+ else if (code.byteCode)
+ compilation.byteCode = code.byteCode;
+
+ return true;
+}
+
+bool
+RegExpShared::compileIfNecessary(JSContext* cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force)
+{
+ if (isCompiled(mode, input->hasLatin1Chars(), force))
+ return true;
+ return compile(cx, input, mode, force);
+}
+
+RegExpRunStatus
+RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start,
+ MatchPairs* matches, size_t* endIndex)
+{
+ MOZ_ASSERT_IF(matches, !endIndex);
+ MOZ_ASSERT_IF(!matches, endIndex);
+ TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
+
+ CompilationMode mode = matches ? Normal : MatchOnly;
+
+ /* Compile the code at point-of-use. */
+ if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
+ return RegExpRunStatus_Error;
+
+ /*
+ * Ensure sufficient memory for output vector.
+ * No need to initialize it. The RegExp engine fills them in on a match.
+ */
+ if (matches && !matches->allocOrExpandArray(pairCount())) {
+ ReportOutOfMemory(cx);
+ return RegExpRunStatus_Error;
+ }
+
+ size_t length = input->length();
+
+ // Reset the Irregexp backtrack stack if it grows during execution.
+ irregexp::RegExpStackScope stackScope(cx->runtime());
+
+ if (canStringMatch) {
+ MOZ_ASSERT(pairCount() == 1);
+ size_t sourceLength = source->length();
+ if (sticky()) {
+ // First part checks size_t overflow.
+ if (sourceLength + start < sourceLength || sourceLength + start > length)
+ return RegExpRunStatus_Success_NotFound;
+ if (!HasSubstringAt(input, source, start))
+ return RegExpRunStatus_Success_NotFound;
+
+ if (matches) {
+ (*matches)[0].start = start;
+ (*matches)[0].limit = start + sourceLength;
+
+ matches->checkAgainst(length);
+ } else if (endIndex) {
+ *endIndex = start + sourceLength;
+ }
+ return RegExpRunStatus_Success;
+ }
+
+ int res = StringFindPattern(input, source, start);
+ if (res == -1)
+ return RegExpRunStatus_Success_NotFound;
+
+ if (matches) {
+ (*matches)[0].start = res;
+ (*matches)[0].limit = res + sourceLength;
+
+ matches->checkAgainst(length);
+ } else if (endIndex) {
+ *endIndex = res + sourceLength;
+ }
+ return RegExpRunStatus_Success;
+ }
+
+ do {
+ jit::JitCode* code = compilation(mode, input->hasLatin1Chars()).jitCode;
+ if (!code)
+ break;
+
+ RegExpRunStatus result;
+ {
+ AutoTraceLog logJIT(logger, TraceLogger_IrregexpExecute);
+ AutoCheckCannotGC nogc;
+ if (input->hasLatin1Chars()) {
+ const Latin1Char* chars = input->latin1Chars(nogc);
+ result = irregexp::ExecuteCode(cx, code, chars, start, length, matches, endIndex);
+ } else {
+ const char16_t* chars = input->twoByteChars(nogc);
+ result = irregexp::ExecuteCode(cx, code, chars, start, length, matches, endIndex);
+ }
+ }
+
+ if (result == RegExpRunStatus_Error) {
+ // An 'Error' result is returned if a stack overflow guard or
+ // interrupt guard failed. If CheckOverRecursed doesn't throw, break
+ // out and retry the regexp in the bytecode interpreter, which can
+ // execute while tolerating future interrupts. Otherwise, if we keep
+ // getting interrupted we will never finish executing the regexp.
+ if (!jit::CheckOverRecursed(cx))
+ return RegExpRunStatus_Error;
+ break;
+ }
+
+ if (result == RegExpRunStatus_Success_NotFound)
+ return RegExpRunStatus_Success_NotFound;
+
+ MOZ_ASSERT(result == RegExpRunStatus_Success);
+
+ if (matches)
+ matches->checkAgainst(length);
+ return RegExpRunStatus_Success;
+ } while (false);
+
+ // Compile bytecode for the RegExp if necessary.
+ if (!compileIfNecessary(cx, input, mode, ForceByteCode))
+ return RegExpRunStatus_Error;
+
+ uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
+ AutoTraceLog logInterpreter(logger, TraceLogger_IrregexpExecute);
+
+ AutoStableStringChars inputChars(cx);
+ if (!inputChars.init(cx, input))
+ return RegExpRunStatus_Error;
+
+ RegExpRunStatus result;
+ if (inputChars.isLatin1()) {
+ const Latin1Char* chars = inputChars.latin1Range().begin().get();
+ result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches, endIndex);
+ } else {
+ const char16_t* chars = inputChars.twoByteRange().begin().get();
+ result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches, endIndex);
+ }
+
+ if (result == RegExpRunStatus_Success && matches)
+ matches->checkAgainst(length);
+ return result;
+}
+
+size_t
+RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ size_t n = mallocSizeOf(this);
+
+ for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
+ const RegExpCompilation& compilation = compilationArray[i];
+ if (compilation.byteCode)
+ n += mallocSizeOf(compilation.byteCode);
+ }
+
+ n += tables.sizeOfExcludingThis(mallocSizeOf);
+ for (size_t i = 0; i < tables.length(); i++)
+ n += mallocSizeOf(tables[i]);
+
+ return n;
+}
+
+/* RegExpCompartment */
+
+RegExpCompartment::RegExpCompartment(JSRuntime* rt)
+ : set_(rt),
+ matchResultTemplateObject_(nullptr),
+ optimizableRegExpPrototypeShape_(nullptr),
+ optimizableRegExpInstanceShape_(nullptr)
+{}
+
+RegExpCompartment::~RegExpCompartment()
+{
+ // Because of stray mark bits being set (see RegExpCompartment::sweep)
+ // there might still be RegExpShared instances which haven't been deleted.
+ if (set_.initialized()) {
+ for (Set::Enum e(set_); !e.empty(); e.popFront()) {
+ RegExpShared* shared = e.front();
+ js_delete(shared);
+ }
+ }
+}
+
+ArrayObject*
+RegExpCompartment::createMatchResultTemplateObject(JSContext* cx)
+{
+ MOZ_ASSERT(!matchResultTemplateObject_);
+
+ /* Create template array object */
+ RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, RegExpObject::MaxPairCount,
+ nullptr, TenuredObject));
+ if (!templateObject)
+ return matchResultTemplateObject_; // = nullptr
+
+ // Create a new group for the template.
+ Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
+ ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto);
+ if (!group)
+ return matchResultTemplateObject_; // = nullptr
+ templateObject->setGroup(group);
+
+ /* Set dummy index property */
+ RootedValue index(cx, Int32Value(0));
+ if (!NativeDefineProperty(cx, templateObject, cx->names().index, index, nullptr, nullptr,
+ JSPROP_ENUMERATE))
+ {
+ return matchResultTemplateObject_; // = nullptr
+ }
+
+ /* Set dummy input property */
+ RootedValue inputVal(cx, StringValue(cx->runtime()->emptyString));
+ if (!NativeDefineProperty(cx, templateObject, cx->names().input, inputVal, nullptr, nullptr,
+ JSPROP_ENUMERATE))
+ {
+ return matchResultTemplateObject_; // = nullptr
+ }
+
+ // Make sure that the properties are in the right slots.
+ DebugOnly<Shape*> shape = templateObject->lastProperty();
+ MOZ_ASSERT(shape->previous()->slot() == 0 &&
+ shape->previous()->propidRef() == NameToId(cx->names().index));
+ MOZ_ASSERT(shape->slot() == 1 &&
+ shape->propidRef() == NameToId(cx->names().input));
+
+ // Make sure type information reflects the indexed properties which might
+ // be added.
+ AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::StringType());
+ AddTypePropertyId(cx, templateObject, JSID_VOID, TypeSet::UndefinedType());
+
+ matchResultTemplateObject_.set(templateObject);
+
+ return matchResultTemplateObject_;
+}
+
+bool
+RegExpCompartment::init(JSContext* cx)
+{
+ if (!set_.init(0)) {
+ if (cx)
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+RegExpShared::needsSweep(JSRuntime* rt)
+{
+ // Sometimes RegExpShared instances are marked without the compartment
+ // being subsequently cleared. This can happen if a GC is restarted while
+ // in progress (i.e. performing a full GC in the middle of an incremental
+ // GC) or if a RegExpShared referenced via the stack is traced but is not
+ // in a zone being collected.
+ //
+ // Because of this we only treat the marked_ bit as a hint, and destroy the
+ // RegExpShared if it was accidentally marked earlier but wasn't marked by
+ // the current trace.
+ bool keep = marked() && IsMarked(rt, &source);
+ for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
+ RegExpShared::RegExpCompilation& compilation = compilationArray[i];
+ if (compilation.jitCode && gc::IsAboutToBeFinalized(&compilation.jitCode))
+ keep = false;
+ }
+
+ MOZ_ASSERT(rt->isHeapMajorCollecting());
+ if (keep || rt->gc.isHeapCompacting()) {
+ clearMarked();
+ return false;
+ }
+
+ return true;
+}
+
+void
+RegExpShared::discardJitCode()
+{
+ for (size_t i = 0; i < ArrayLength(compilationArray); i++)
+ compilationArray[i].jitCode = nullptr;
+}
+
+void
+RegExpCompartment::sweep(JSRuntime* rt)
+{
+ if (!set_.initialized())
+ return;
+
+ for (Set::Enum e(set_); !e.empty(); e.popFront()) {
+ RegExpShared* shared = e.front();
+ if (shared->needsSweep(rt)) {
+ js_delete(shared);
+ e.removeFront();
+ } else {
+ // Discard code to avoid holding onto ExecutablePools.
+ if (rt->gc.isHeapCompacting())
+ shared->discardJitCode();
+ }
+ }
+
+ if (matchResultTemplateObject_ &&
+ IsAboutToBeFinalized(&matchResultTemplateObject_))
+ {
+ matchResultTemplateObject_.set(nullptr);
+ }
+
+ if (optimizableRegExpPrototypeShape_ &&
+ IsAboutToBeFinalized(&optimizableRegExpPrototypeShape_))
+ {
+ optimizableRegExpPrototypeShape_.set(nullptr);
+ }
+
+ if (optimizableRegExpInstanceShape_ &&
+ IsAboutToBeFinalized(&optimizableRegExpInstanceShape_))
+ {
+ optimizableRegExpInstanceShape_.set(nullptr);
+ }
+}
+
+bool
+RegExpCompartment::get(JSContext* cx, JSAtom* source, RegExpFlag flags, RegExpGuard* g)
+{
+ Key key(source, flags);
+ Set::AddPtr p = set_.lookupForAdd(key);
+ if (p) {
+ // Trigger a read barrier on existing RegExpShared instances fetched
+ // from the table (which only holds weak references).
+ RegExpSharedReadBarrier(cx, *p);
+
+ g->init(**p);
+ return true;
+ }
+
+ ScopedJSDeletePtr<RegExpShared> shared(cx->new_<RegExpShared>(source, flags));
+ if (!shared)
+ return false;
+
+ if (!set_.add(p, shared)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ // Trace RegExpShared instances created during an incremental GC.
+ RegExpSharedReadBarrier(cx, shared);
+
+ g->init(*shared.forget());
+ return true;
+}
+
+bool
+RegExpCompartment::get(JSContext* cx, HandleAtom atom, JSString* opt, RegExpGuard* g)
+{
+ RegExpFlag flags = RegExpFlag(0);
+ if (opt && !ParseRegExpFlags(cx, opt, &flags))
+ return false;
+
+ return get(cx, atom, flags, g);
+}
+
+size_t
+RegExpCompartment::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ size_t n = 0;
+ n += set_.sizeOfExcludingThis(mallocSizeOf);
+ for (Set::Enum e(set_); !e.empty(); e.popFront()) {
+ RegExpShared* shared = e.front();
+ n += shared->sizeOfIncludingThis(mallocSizeOf);
+ }
+ return n;
+}
+
+/* Functions */
+
+JSObject*
+js::CloneRegExpObject(JSContext* cx, JSObject* obj_)
+{
+ Rooted<RegExpObject*> regex(cx, &obj_->as<RegExpObject>());
+
+ // Unlike RegExpAlloc, all clones must use |regex|'s group. Allocate
+ // in the tenured heap to simplify embedding them in JIT code.
+ RootedObjectGroup group(cx, regex->group());
+ Rooted<RegExpObject*> clone(cx, NewObjectWithGroup<RegExpObject>(cx, group, TenuredObject));
+ if (!clone)
+ return nullptr;
+ clone->initPrivate(nullptr);
+
+ if (!EmptyShape::ensureInitialCustomShape<RegExpObject>(cx, clone))
+ return nullptr;
+
+ Rooted<JSAtom*> source(cx, regex->getSource());
+
+ RegExpGuard g(cx);
+ if (!regex->getShared(cx, &g))
+ return nullptr;
+
+ clone->initAndZeroLastIndex(source, g->getFlags(), cx);
+ clone->setShared(*g.re());
+
+ return clone;
+}
+
+static bool
+HandleRegExpFlag(RegExpFlag flag, RegExpFlag* flags)
+{
+ if (*flags & flag)
+ return false;
+ *flags = RegExpFlag(*flags | flag);
+ return true;
+}
+
+template <typename CharT>
+static size_t
+ParseRegExpFlags(const CharT* chars, size_t length, RegExpFlag* flagsOut, char16_t* lastParsedOut)
+{
+ *flagsOut = RegExpFlag(0);
+
+ for (size_t i = 0; i < length; i++) {
+ *lastParsedOut = chars[i];
+ switch (chars[i]) {
+ case 'i':
+ if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
+ return false;
+ break;
+ case 'g':
+ if (!HandleRegExpFlag(GlobalFlag, flagsOut))
+ return false;
+ break;
+ case 'm':
+ if (!HandleRegExpFlag(MultilineFlag, flagsOut))
+ return false;
+ break;
+ case 'y':
+ if (!HandleRegExpFlag(StickyFlag, flagsOut))
+ return false;
+ break;
+ case 'u':
+ if (!HandleRegExpFlag(UnicodeFlag, flagsOut))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+js::ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut)
+{
+ JSLinearString* linear = flagStr->ensureLinear(cx);
+ if (!linear)
+ return false;
+
+ size_t len = linear->length();
+
+ bool ok;
+ char16_t lastParsed;
+ if (linear->hasLatin1Chars()) {
+ AutoCheckCannotGC nogc;
+ ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &lastParsed);
+ } else {
+ AutoCheckCannotGC nogc;
+ ok = ::ParseRegExpFlags(linear->twoByteChars(nogc), len, flagsOut, &lastParsed);
+ }
+
+ if (!ok) {
+ TwoByteChars range(&lastParsed, 1);
+ UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, range).c_str());
+ if (!utf8)
+ return false;
+ JS_ReportErrorFlagsAndNumberUTF8(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
+ JSMSG_BAD_REGEXP_FLAG, utf8.get());
+ return false;
+ }
+
+ return true;
+}
+
+template<XDRMode mode>
+bool
+js::XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp)
+{
+ /* NB: Keep this in sync with CloneScriptRegExpObject. */
+
+ RootedAtom source(xdr->cx());
+ uint32_t flagsword = 0;
+
+ if (mode == XDR_ENCODE) {
+ MOZ_ASSERT(objp);
+ RegExpObject& reobj = *objp;
+ source = reobj.getSource();
+ flagsword = reobj.getFlags();
+ }
+ if (!XDRAtom(xdr, &source) || !xdr->codeUint32(&flagsword))
+ return false;
+ if (mode == XDR_DECODE) {
+ RegExpFlag flags = RegExpFlag(flagsword);
+ RegExpObject* reobj = RegExpObject::create(xdr->cx(), source, flags, nullptr,
+ xdr->cx()->tempLifoAlloc());
+ if (!reobj)
+ return false;
+
+ objp.set(reobj);
+ }
+ return true;
+}
+
+template bool
+js::XDRScriptRegExpObject(XDRState<XDR_ENCODE>* xdr, MutableHandle<RegExpObject*> objp);
+
+template bool
+js::XDRScriptRegExpObject(XDRState<XDR_DECODE>* xdr, MutableHandle<RegExpObject*> objp);
+
+JSObject*
+js::CloneScriptRegExpObject(JSContext* cx, RegExpObject& reobj)
+{
+ /* NB: Keep this in sync with XDRScriptRegExpObject. */
+
+ RootedAtom source(cx, reobj.getSource());
+ return RegExpObject::create(cx, source, reobj.getFlags(), nullptr, cx->tempLifoAlloc());
+}
+
+JS_FRIEND_API(bool)
+js::RegExpToSharedNonInline(JSContext* cx, HandleObject obj, js::RegExpGuard* g)
+{
+ return RegExpToShared(cx, obj, g);
+}
diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h
new file mode 100644
index 000000000..d6dde1668
--- /dev/null
+++ b/js/src/vm/RegExpObject.h
@@ -0,0 +1,561 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_RegExpObject_h
+#define vm_RegExpObject_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/MemoryReporting.h"
+
+#include "jscntxt.h"
+
+#include "builtin/SelfHostingDefines.h"
+#include "gc/Marking.h"
+#include "gc/Zone.h"
+#include "proxy/Proxy.h"
+#include "vm/ArrayObject.h"
+#include "vm/Shape.h"
+
+/*
+ * JavaScript Regular Expressions
+ *
+ * There are several engine concepts associated with a single logical regexp:
+ *
+ * RegExpObject - The JS-visible object whose .[[Class]] equals "RegExp"
+ *
+ * RegExpShared - The compiled representation of the regexp.
+ *
+ * RegExpCompartment - Owns all RegExpShared instances in a compartment.
+ *
+ * To save memory, a RegExpShared is not created for a RegExpObject until it is
+ * needed for execution. When a RegExpShared needs to be created, it is looked
+ * up in a per-compartment table to allow reuse between objects. Lastly, on
+ * GC, every RegExpShared (that is not active on the callstack) is discarded.
+ * Because of the last point, any code using a RegExpShared (viz., by executing
+ * a regexp) must indicate the RegExpShared is active via RegExpGuard.
+ */
+namespace js {
+
+struct MatchPair;
+class MatchPairs;
+class RegExpShared;
+class RegExpStatics;
+
+namespace frontend { class TokenStream; }
+
+enum RegExpFlag
+{
+ IgnoreCaseFlag = 0x01,
+ GlobalFlag = 0x02,
+ MultilineFlag = 0x04,
+ StickyFlag = 0x08,
+ UnicodeFlag = 0x10,
+
+ NoFlags = 0x00,
+ AllFlags = 0x1f
+};
+
+static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
+ GlobalFlag == REGEXP_GLOBAL_FLAG &&
+ MultilineFlag == REGEXP_MULTILINE_FLAG &&
+ StickyFlag == REGEXP_STICKY_FLAG &&
+ UnicodeFlag == REGEXP_UNICODE_FLAG,
+ "Flag values should be in sync with self-hosted JS");
+
+enum RegExpRunStatus
+{
+ RegExpRunStatus_Error,
+ RegExpRunStatus_Success,
+ RegExpRunStatus_Success_NotFound
+};
+
+extern RegExpObject*
+RegExpAlloc(ExclusiveContext* cx, HandleObject proto = nullptr);
+
+// |regexp| is under-typed because this function's used in the JIT.
+extern JSObject*
+CloneRegExpObject(JSContext* cx, JSObject* regexp);
+
+extern JSObject*
+CreateRegExpPrototype(JSContext* cx, JSProtoKey key);
+
+/*
+ * A RegExpShared is the compiled representation of a regexp. A RegExpShared is
+ * potentially pointed to by multiple RegExpObjects. Additionally, C++ code may
+ * have pointers to RegExpShareds on the stack. The RegExpShareds are kept in a
+ * table so that they can be reused when compiling the same regex string.
+ *
+ * During a GC, RegExpShared instances are marked and swept like GC things.
+ * Usually, RegExpObjects clear their pointers to their RegExpShareds rather
+ * than explicitly tracing them, so that the RegExpShared and any jitcode can
+ * be reclaimed quicker. However, the RegExpShareds are traced through by
+ * objects when we are preserving jitcode in their zone, to avoid the same
+ * recompilation inefficiencies as normal Ion and baseline compilation.
+ */
+class RegExpShared
+{
+ public:
+ enum CompilationMode {
+ Normal,
+ MatchOnly
+ };
+
+ enum ForceByteCodeEnum {
+ DontForceByteCode,
+ ForceByteCode
+ };
+
+ private:
+ friend class RegExpCompartment;
+ friend class RegExpStatics;
+
+ typedef frontend::TokenStream TokenStream;
+
+ struct RegExpCompilation
+ {
+ HeapPtr<jit::JitCode*> jitCode;
+ uint8_t* byteCode;
+
+ RegExpCompilation() : byteCode(nullptr) {}
+ ~RegExpCompilation() { js_free(byteCode); }
+
+ bool compiled(ForceByteCodeEnum force = DontForceByteCode) const {
+ return byteCode || (force == DontForceByteCode && jitCode);
+ }
+ };
+
+ /* Source to the RegExp, for lazy compilation. */
+ HeapPtr<JSAtom*> source;
+
+ RegExpFlag flags;
+ size_t parenCount;
+ bool canStringMatch;
+ bool marked_;
+
+ RegExpCompilation compilationArray[4];
+
+ static int CompilationIndex(CompilationMode mode, bool latin1) {
+ switch (mode) {
+ case Normal: return latin1 ? 0 : 1;
+ case MatchOnly: return latin1 ? 2 : 3;
+ }
+ MOZ_CRASH();
+ }
+
+ // Tables referenced by JIT code.
+ Vector<uint8_t*, 0, SystemAllocPolicy> tables;
+
+ /* Internal functions. */
+ bool compile(JSContext* cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
+ bool compile(JSContext* cx, HandleAtom pattern, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
+
+ bool compileIfNecessary(JSContext* cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
+
+ const RegExpCompilation& compilation(CompilationMode mode, bool latin1) const {
+ return compilationArray[CompilationIndex(mode, latin1)];
+ }
+
+ RegExpCompilation& compilation(CompilationMode mode, bool latin1) {
+ return compilationArray[CompilationIndex(mode, latin1)];
+ }
+
+ public:
+ RegExpShared(JSAtom* source, RegExpFlag flags);
+ ~RegExpShared();
+
+ // Execute this RegExp on input starting from searchIndex, filling in
+ // matches if specified and otherwise only determining if there is a match.
+ RegExpRunStatus execute(JSContext* cx, HandleLinearString input, size_t searchIndex,
+ MatchPairs* matches, size_t* endIndex);
+
+ // Register a table with this RegExpShared, and take ownership.
+ bool addTable(uint8_t* table) {
+ return tables.append(table);
+ }
+
+ /* Accessors */
+
+ size_t getParenCount() const {
+ MOZ_ASSERT(isCompiled());
+ return parenCount;
+ }
+
+ /* Accounts for the "0" (whole match) pair. */
+ size_t pairCount() const { return getParenCount() + 1; }
+
+ JSAtom* getSource() const { return source; }
+ RegExpFlag getFlags() const { return flags; }
+ bool ignoreCase() const { return flags & IgnoreCaseFlag; }
+ 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 {
+ return compilation(mode, latin1).compiled(force);
+ }
+ bool isCompiled() const {
+ return isCompiled(Normal, true) || isCompiled(Normal, false)
+ || isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
+ }
+
+ void trace(JSTracer* trc);
+ bool needsSweep(JSRuntime* rt);
+ void discardJitCode();
+
+ bool marked() const { return marked_; }
+ void clearMarked() { marked_ = false; }
+
+ bool isMarkedGray() const;
+ void unmarkGray();
+
+ static size_t offsetOfSource() {
+ return offsetof(RegExpShared, source);
+ }
+
+ static size_t offsetOfFlags() {
+ return offsetof(RegExpShared, flags);
+ }
+
+ static size_t offsetOfParenCount() {
+ return offsetof(RegExpShared, parenCount);
+ }
+
+ static size_t offsetOfLatin1JitCode(CompilationMode mode) {
+ return offsetof(RegExpShared, compilationArray)
+ + (CompilationIndex(mode, true) * sizeof(RegExpCompilation))
+ + offsetof(RegExpCompilation, jitCode);
+ }
+ static size_t offsetOfTwoByteJitCode(CompilationMode mode) {
+ return offsetof(RegExpShared, compilationArray)
+ + (CompilationIndex(mode, false) * sizeof(RegExpCompilation))
+ + offsetof(RegExpCompilation, jitCode);
+ }
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+#ifdef DEBUG
+ bool dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input);
+#endif
+};
+
+/*
+ * Extend the lifetime of a given RegExpShared to at least the lifetime of
+ * the guard object. See Regular Expression comment at the top.
+ */
+class RegExpGuard : public JS::CustomAutoRooter
+{
+ RegExpShared* re_;
+
+ RegExpGuard(const RegExpGuard&) = delete;
+ void operator=(const RegExpGuard&) = delete;
+
+ public:
+ explicit RegExpGuard(ExclusiveContext* cx)
+ : CustomAutoRooter(cx), re_(nullptr)
+ {}
+
+ RegExpGuard(ExclusiveContext* cx, RegExpShared& re)
+ : CustomAutoRooter(cx), re_(nullptr)
+ {
+ init(re);
+ }
+
+ ~RegExpGuard() {
+ release();
+ }
+
+ public:
+ void init(RegExpShared& re) {
+ MOZ_ASSERT(!initialized());
+ re_ = &re;
+ }
+
+ void release() {
+ re_ = nullptr;
+ }
+
+ virtual void trace(JSTracer* trc) {
+ if (re_)
+ re_->trace(trc);
+ }
+
+ bool initialized() const { return !!re_; }
+ RegExpShared* re() const { MOZ_ASSERT(initialized()); return re_; }
+ RegExpShared* operator->() { return re(); }
+ RegExpShared& operator*() { return *re(); }
+};
+
+class RegExpCompartment
+{
+ struct Key {
+ JSAtom* atom;
+ uint16_t flag;
+
+ Key() {}
+ Key(JSAtom* atom, RegExpFlag flag)
+ : atom(atom), flag(flag)
+ { }
+ MOZ_IMPLICIT Key(RegExpShared* shared)
+ : atom(shared->getSource()), flag(shared->getFlags())
+ { }
+
+ typedef Key Lookup;
+ static HashNumber hash(const Lookup& l) {
+ return DefaultHasher<JSAtom*>::hash(l.atom) ^ (l.flag << 1);
+ }
+ static bool match(Key l, Key r) {
+ return l.atom == r.atom && l.flag == r.flag;
+ }
+ };
+
+ /*
+ * The set of all RegExpShareds in the compartment. On every GC, every
+ * RegExpShared that was not marked is deleted and removed from the set.
+ */
+ typedef HashSet<RegExpShared*, Key, RuntimeAllocPolicy> Set;
+ Set set_;
+
+ /*
+ * This is the template object where the result of re.exec() is based on,
+ * if there is a result. This is used in CreateRegExpMatchResult to set
+ * the input/index properties faster.
+ */
+ ReadBarriered<ArrayObject*> matchResultTemplateObject_;
+
+ /*
+ * The shape of RegExp.prototype object that satisfies following:
+ * * RegExp.prototype.flags getter is not modified
+ * * RegExp.prototype.global getter is not modified
+ * * RegExp.prototype.ignoreCase getter is not modified
+ * * RegExp.prototype.multiline getter is not modified
+ * * RegExp.prototype.sticky getter is not modified
+ * * RegExp.prototype.unicode getter is not modified
+ * * RegExp.prototype.exec is an own data property
+ * * RegExp.prototype[@@match] is an own data property
+ * * RegExp.prototype[@@search] is an own data property
+ */
+ ReadBarriered<Shape*> optimizableRegExpPrototypeShape_;
+
+ /*
+ * The shape of RegExp instance that satisfies following:
+ * * lastProperty is lastIndex
+ * * prototype is RegExp.prototype
+ */
+ ReadBarriered<Shape*> optimizableRegExpInstanceShape_;
+
+ ArrayObject* createMatchResultTemplateObject(JSContext* cx);
+
+ public:
+ explicit RegExpCompartment(JSRuntime* rt);
+ ~RegExpCompartment();
+
+ bool init(JSContext* cx);
+ void sweep(JSRuntime* rt);
+
+ bool empty() { return set_.empty(); }
+
+ bool get(JSContext* cx, JSAtom* source, RegExpFlag flags, RegExpGuard* g);
+
+ /* Like 'get', but compile 'maybeOpt' (if non-null). */
+ bool get(JSContext* cx, HandleAtom source, JSString* maybeOpt, RegExpGuard* g);
+
+ /* Get or create template object used to base the result of .exec() on. */
+ ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx) {
+ if (matchResultTemplateObject_)
+ return matchResultTemplateObject_;
+ return createMatchResultTemplateObject(cx);
+ }
+
+ Shape* getOptimizableRegExpPrototypeShape() {
+ return optimizableRegExpPrototypeShape_;
+ }
+ void setOptimizableRegExpPrototypeShape(Shape* shape) {
+ optimizableRegExpPrototypeShape_ = shape;
+ }
+ Shape* getOptimizableRegExpInstanceShape() {
+ return optimizableRegExpInstanceShape_;
+ }
+ void setOptimizableRegExpInstanceShape(Shape* shape) {
+ optimizableRegExpInstanceShape_ = shape;
+ }
+
+ static size_t offsetOfOptimizableRegExpPrototypeShape() {
+ return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_);
+ }
+ static size_t offsetOfOptimizableRegExpInstanceShape() {
+ return offsetof(RegExpCompartment, optimizableRegExpInstanceShape_);
+ }
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+};
+
+class RegExpObject : public NativeObject
+{
+ static const unsigned LAST_INDEX_SLOT = 0;
+ static const unsigned SOURCE_SLOT = 1;
+ static const unsigned FLAGS_SLOT = 2;
+
+ static_assert(RegExpObject::FLAGS_SLOT == REGEXP_FLAGS_SLOT,
+ "FLAGS_SLOT values should be in sync with self-hosted JS");
+
+ public:
+ static const unsigned RESERVED_SLOTS = 3;
+ static const unsigned PRIVATE_SLOT = 3;
+
+ static const Class class_;
+
+ // The maximum number of pairs a MatchResult can have, without having to
+ // allocate a bigger MatchResult.
+ static const size_t MaxPairCount = 14;
+
+ static RegExpObject*
+ create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
+ frontend::TokenStream* ts, LifoAlloc& alloc);
+
+ static RegExpObject*
+ create(ExclusiveContext* cx, HandleAtom atom, RegExpFlag flags,
+ frontend::TokenStream* ts, LifoAlloc& alloc);
+
+ /*
+ * Compute the initial shape to associate with fresh RegExp objects,
+ * encoding their initial properties. Return the shape after
+ * changing |obj|'s last property to it.
+ */
+ static Shape*
+ assignInitialShape(ExclusiveContext* cx, Handle<RegExpObject*> obj);
+
+ /* Accessors. */
+
+ static unsigned lastIndexSlot() { return LAST_INDEX_SLOT; }
+
+ static bool isInitialShape(RegExpObject* rx) {
+ Shape* shape = rx->lastProperty();
+ if (!shape->hasSlot())
+ return false;
+ if (shape->maybeSlot() != LAST_INDEX_SLOT)
+ return false;
+ return true;
+ }
+
+ const Value& getLastIndex() const { return getSlot(LAST_INDEX_SLOT); }
+
+ void setLastIndex(double d) {
+ setSlot(LAST_INDEX_SLOT, NumberValue(d));
+ }
+
+ void zeroLastIndex(ExclusiveContext* cx) {
+ MOZ_ASSERT(lookupPure(cx->names().lastIndex)->writable(),
+ "can't infallibly zero a non-writable lastIndex on a "
+ "RegExp that's been exposed to script");
+ setSlot(LAST_INDEX_SLOT, Int32Value(0));
+ }
+
+ JSFlatString* toString(JSContext* cx) const;
+
+ JSAtom* getSource() const { return &getSlot(SOURCE_SLOT).toString()->asAtom(); }
+
+ void setSource(JSAtom* source) {
+ setSlot(SOURCE_SLOT, StringValue(source));
+ }
+
+ /* Flags. */
+
+ static unsigned flagsSlot() { return FLAGS_SLOT; }
+
+ RegExpFlag getFlags() const {
+ return RegExpFlag(getFixedSlot(FLAGS_SLOT).toInt32());
+ }
+ void setFlags(RegExpFlag flags) {
+ setSlot(FLAGS_SLOT, Int32Value(flags));
+ }
+
+ bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
+ bool global() const { return getFlags() & GlobalFlag; }
+ bool multiline() const { return getFlags() & MultilineFlag; }
+ bool sticky() const { return getFlags() & StickyFlag; }
+ bool unicode() const { return getFlags() & UnicodeFlag; }
+
+ static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
+
+ bool getShared(JSContext* cx, RegExpGuard* g);
+
+ void setShared(RegExpShared& shared) {
+ MOZ_ASSERT(!maybeShared());
+ NativeObject::setPrivate(&shared);
+ }
+
+ static void trace(JSTracer* trc, JSObject* obj);
+
+ void initIgnoringLastIndex(HandleAtom source, RegExpFlag flags);
+
+ // NOTE: This method is *only* safe to call on RegExps that haven't been
+ // exposed to script, because it requires that the "lastIndex"
+ // property be writable.
+ void initAndZeroLastIndex(HandleAtom source, RegExpFlag flags, ExclusiveContext* cx);
+
+#ifdef DEBUG
+ bool dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input);
+#endif
+
+ private:
+ /*
+ * Precondition: the syntax for |source| has already been validated.
+ * Side effect: sets the private field.
+ */
+ bool createShared(JSContext* cx, RegExpGuard* g);
+ RegExpShared* maybeShared() const {
+ return static_cast<RegExpShared*>(NativeObject::getPrivate(PRIVATE_SLOT));
+ }
+
+ /* Call setShared in preference to setPrivate. */
+ void setPrivate(void* priv) = delete;
+};
+
+/*
+ * Parse regexp flags. Report an error and return false if an invalid
+ * sequence of flags is encountered (repeat/invalid flag).
+ *
+ * N.B. flagStr must be rooted.
+ */
+bool
+ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut);
+
+/* Assuming GetBuiltinClass(obj) is ESClass::RegExp, return a RegExpShared for obj. */
+inline bool
+RegExpToShared(JSContext* cx, HandleObject obj, RegExpGuard* g)
+{
+ if (obj->is<RegExpObject>())
+ return obj->as<RegExpObject>().getShared(cx, g);
+
+ return Proxy::regexp_toShared(cx, obj, g);
+}
+
+template<XDRMode mode>
+bool
+XDRScriptRegExpObject(XDRState<mode>* xdr, MutableHandle<RegExpObject*> objp);
+
+extern JSObject*
+CloneScriptRegExpObject(JSContext* cx, RegExpObject& re);
+
+/* Escape all slashes and newlines in the given string. */
+extern JSAtom*
+EscapeRegExpPattern(JSContext* cx, HandleAtom src);
+
+template <typename CharT>
+extern bool
+HasRegExpMetaChars(const CharT* chars, size_t length);
+
+extern bool
+StringHasRegExpMetaChars(JSLinearString* str);
+
+} /* namespace js */
+
+#endif /* vm_RegExpObject_h */
diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp
new file mode 100644
index 000000000..5375c0039
--- /dev/null
+++ b/js/src/vm/RegExpStatics.cpp
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/RegExpStatics.h"
+
+#include "vm/RegExpStaticsObject.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+/*
+ * RegExpStatics allocates memory -- in order to keep the statics stored
+ * per-global and not leak, we create a js::Class to wrap the C++ instance and
+ * provide an appropriate finalizer. We lazily create and store an instance of
+ * that js::Class in a global reserved slot.
+ */
+
+static void
+resc_finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->onMainThread());
+ RegExpStatics* res = static_cast<RegExpStatics*>(obj->as<RegExpStaticsObject>().getPrivate());
+ fop->delete_(res);
+}
+
+static void
+resc_trace(JSTracer* trc, JSObject* obj)
+{
+ void* pdata = obj->as<RegExpStaticsObject>().getPrivate();
+ if (pdata)
+ static_cast<RegExpStatics*>(pdata)->mark(trc);
+}
+
+static const ClassOps RegExpStaticsObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ resc_finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ resc_trace
+};
+
+const Class RegExpStaticsObject::class_ = {
+ "RegExpStatics",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_FOREGROUND_FINALIZE,
+ &RegExpStaticsObjectClassOps
+};
+
+RegExpStaticsObject*
+RegExpStatics::create(ExclusiveContext* cx, Handle<GlobalObject*> parent)
+{
+ RegExpStaticsObject* obj = NewObjectWithGivenProto<RegExpStaticsObject>(cx, nullptr);
+ if (!obj)
+ return nullptr;
+ RegExpStatics* res = cx->new_<RegExpStatics>();
+ if (!res)
+ return nullptr;
+ obj->setPrivate(static_cast<void*>(res));
+ return obj;
+}
+
+bool
+RegExpStatics::executeLazy(JSContext* cx)
+{
+ if (!pendingLazyEvaluation)
+ return true;
+
+ MOZ_ASSERT(lazySource);
+ MOZ_ASSERT(matchesInput);
+ MOZ_ASSERT(lazyIndex != size_t(-1));
+
+ /* Retrieve or create the RegExpShared in this compartment. */
+ RegExpGuard g(cx);
+ if (!cx->compartment()->regExps.get(cx, lazySource, lazyFlags, &g))
+ return false;
+
+ /*
+ * It is not necessary to call aboutToWrite(): evaluation of
+ * implicit copies is safe.
+ */
+
+ /* Execute the full regular expression. */
+ RootedLinearString input(cx, matchesInput);
+ RegExpRunStatus status = g->execute(cx, input, lazyIndex, &this->matches, nullptr);
+ if (status == RegExpRunStatus_Error)
+ return false;
+
+ /*
+ * RegExpStatics are only updated on successful (matching) execution.
+ * Re-running the same expression must therefore produce a matching result.
+ */
+ MOZ_ASSERT(status == RegExpRunStatus_Success);
+
+ /* Unset lazy state and remove rooted values that now have no use. */
+ pendingLazyEvaluation = false;
+ lazySource = nullptr;
+ lazyIndex = size_t(-1);
+
+ return true;
+}
diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h
new file mode 100644
index 000000000..1274e0894
--- /dev/null
+++ b/js/src/vm/RegExpStatics.h
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_RegExpStatics_h
+#define vm_RegExpStatics_h
+
+#include "gc/Marking.h"
+#include "vm/MatchPairs.h"
+#include "vm/RegExpObject.h"
+#include "vm/Runtime.h"
+
+namespace js {
+
+class GlobalObject;
+class RegExpStaticsObject;
+
+class RegExpStatics
+{
+ /* The latest RegExp output, set after execution. */
+ VectorMatchPairs matches;
+ HeapPtr<JSLinearString*> matchesInput;
+
+ /*
+ * The previous RegExp input, used to resolve lazy state.
+ * A raw RegExpShared cannot be stored because it may be in
+ * a different compartment via evalcx().
+ */
+ HeapPtr<JSAtom*> lazySource;
+ RegExpFlag lazyFlags;
+ size_t lazyIndex;
+
+ /* The latest RegExp input, set before execution. */
+ HeapPtr<JSString*> pendingInput;
+
+ /*
+ * If non-zero, |matchesInput| and the |lazy*| fields may be used
+ * to replay the last executed RegExp, and |matches| is invalid.
+ */
+ int32_t pendingLazyEvaluation;
+
+ public:
+ RegExpStatics() { clear(); }
+ static RegExpStaticsObject* create(ExclusiveContext* cx, Handle<GlobalObject*> parent);
+
+ private:
+ bool executeLazy(JSContext* cx);
+
+ inline void checkInvariants();
+
+ /*
+ * Check whether a match for pair |pairNum| occurred. If so, allocate and
+ * store the match string in |*out|; otherwise place |undefined| in |*out|.
+ */
+ bool makeMatch(JSContext* cx, size_t pairNum, MutableHandleValue out);
+ bool createDependent(JSContext* cx, size_t start, size_t end, MutableHandleValue out);
+
+ struct InitBuffer {};
+ explicit RegExpStatics(InitBuffer) {}
+
+ public:
+ /* Mutators. */
+ inline void updateLazily(JSContext* cx, JSLinearString* input,
+ RegExpShared* shared, size_t lastIndex);
+ inline bool updateFromMatchPairs(JSContext* cx, JSLinearString* input, MatchPairs& newPairs);
+
+ inline void clear();
+
+ /* Corresponds to JSAPI functionality to set the pending RegExp input. */
+ void reset(JSContext* cx, JSString* newInput) {
+ clear();
+ pendingInput = newInput;
+ checkInvariants();
+ }
+
+ inline void setPendingInput(JSString* newInput);
+
+ public:
+ /* Default match accessor. */
+ const MatchPairs& getMatches() const {
+ /* Safe: only used by String methods, which do not set lazy mode. */
+ MOZ_ASSERT(!pendingLazyEvaluation);
+ return matches;
+ }
+
+ JSString* getPendingInput() const { return pendingInput; }
+
+ void mark(JSTracer* trc) {
+ /*
+ * Changes to this function must also be reflected in
+ * RegExpStatics::AutoRooter::trace().
+ */
+ TraceNullableEdge(trc, &matchesInput, "res->matchesInput");
+ TraceNullableEdge(trc, &lazySource, "res->lazySource");
+ TraceNullableEdge(trc, &pendingInput, "res->pendingInput");
+ }
+
+ /* Value creators. */
+
+ bool createPendingInput(JSContext* cx, MutableHandleValue out);
+ bool createLastMatch(JSContext* cx, MutableHandleValue out);
+ bool createLastParen(JSContext* cx, MutableHandleValue out);
+ bool createParen(JSContext* cx, size_t pairNum, MutableHandleValue out);
+ bool createLeftContext(JSContext* cx, MutableHandleValue out);
+ bool createRightContext(JSContext* cx, MutableHandleValue out);
+
+ /* Infallible substring creators. */
+
+ void getParen(size_t pairNum, JSSubString* out) const;
+ void getLastMatch(JSSubString* out) const;
+ void getLastParen(JSSubString* out) const;
+ void getLeftContext(JSSubString* out) const;
+ void getRightContext(JSSubString* out) const;
+
+ static size_t offsetOfPendingInput() {
+ return offsetof(RegExpStatics, pendingInput);
+ }
+
+ static size_t offsetOfMatchesInput() {
+ return offsetof(RegExpStatics, matchesInput);
+ }
+
+ static size_t offsetOfLazySource() {
+ return offsetof(RegExpStatics, lazySource);
+ }
+
+ static size_t offsetOfLazyFlags() {
+ return offsetof(RegExpStatics, lazyFlags);
+ }
+
+ static size_t offsetOfLazyIndex() {
+ return offsetof(RegExpStatics, lazyIndex);
+ }
+
+ static size_t offsetOfPendingLazyEvaluation() {
+ return offsetof(RegExpStatics, pendingLazyEvaluation);
+ }
+};
+
+inline bool
+RegExpStatics::createDependent(JSContext* cx, size_t start, size_t end, MutableHandleValue out)
+{
+ /* Private function: caller must perform lazy evaluation. */
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ MOZ_ASSERT(start <= end);
+ MOZ_ASSERT(end <= matchesInput->length());
+ JSString* str = NewDependentString(cx, matchesInput, start, end - start);
+ if (!str)
+ return false;
+ out.setString(str);
+ return true;
+}
+
+inline bool
+RegExpStatics::createPendingInput(JSContext* cx, MutableHandleValue out)
+{
+ /* Lazy evaluation need not be resolved to return the input. */
+ out.setString(pendingInput ? pendingInput.get() : cx->runtime()->emptyString);
+ return true;
+}
+
+inline bool
+RegExpStatics::makeMatch(JSContext* cx, size_t pairNum, MutableHandleValue out)
+{
+ /* Private function: caller must perform lazy evaluation. */
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ if (matches.empty() || pairNum >= matches.pairCount() || matches[pairNum].isUndefined()) {
+ out.setUndefined();
+ return true;
+ }
+
+ const MatchPair& pair = matches[pairNum];
+ return createDependent(cx, pair.start, pair.limit, out);
+}
+
+inline bool
+RegExpStatics::createLastMatch(JSContext* cx, MutableHandleValue out)
+{
+ if (!executeLazy(cx))
+ return false;
+ return makeMatch(cx, 0, out);
+}
+
+inline bool
+RegExpStatics::createLastParen(JSContext* cx, MutableHandleValue out)
+{
+ if (!executeLazy(cx))
+ return false;
+
+ if (matches.empty() || matches.pairCount() == 1) {
+ out.setString(cx->runtime()->emptyString);
+ return true;
+ }
+ const MatchPair& pair = matches[matches.pairCount() - 1];
+ if (pair.start == -1) {
+ out.setString(cx->runtime()->emptyString);
+ return true;
+ }
+ MOZ_ASSERT(pair.start >= 0 && pair.limit >= 0);
+ MOZ_ASSERT(pair.limit >= pair.start);
+ return createDependent(cx, pair.start, pair.limit, out);
+}
+
+inline bool
+RegExpStatics::createParen(JSContext* cx, size_t pairNum, MutableHandleValue out)
+{
+ MOZ_ASSERT(pairNum >= 1);
+ if (!executeLazy(cx))
+ return false;
+
+ if (matches.empty() || pairNum >= matches.pairCount()) {
+ out.setString(cx->runtime()->emptyString);
+ return true;
+ }
+ return makeMatch(cx, pairNum, out);
+}
+
+inline bool
+RegExpStatics::createLeftContext(JSContext* cx, MutableHandleValue out)
+{
+ if (!executeLazy(cx))
+ return false;
+
+ if (matches.empty()) {
+ out.setString(cx->runtime()->emptyString);
+ return true;
+ }
+ if (matches[0].start < 0) {
+ out.setUndefined();
+ return true;
+ }
+ return createDependent(cx, 0, matches[0].start, out);
+}
+
+inline bool
+RegExpStatics::createRightContext(JSContext* cx, MutableHandleValue out)
+{
+ if (!executeLazy(cx))
+ return false;
+
+ if (matches.empty()) {
+ out.setString(cx->runtime()->emptyString);
+ return true;
+ }
+ if (matches[0].limit < 0) {
+ out.setUndefined();
+ return true;
+ }
+ return createDependent(cx, matches[0].limit, matchesInput->length(), out);
+}
+
+inline void
+RegExpStatics::getParen(size_t pairNum, JSSubString* out) const
+{
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ MOZ_ASSERT(pairNum >= 1 && pairNum < matches.pairCount());
+ const MatchPair& pair = matches[pairNum];
+ if (pair.isUndefined()) {
+ out->initEmpty(matchesInput);
+ return;
+ }
+ out->init(matchesInput, pair.start, pair.length());
+}
+
+inline void
+RegExpStatics::getLastMatch(JSSubString* out) const
+{
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ if (matches.empty()) {
+ out->initEmpty(matchesInput);
+ return;
+ }
+ MOZ_ASSERT(matchesInput);
+ MOZ_ASSERT(matches[0].limit >= matches[0].start);
+ out->init(matchesInput, matches[0].start, matches[0].length());
+}
+
+inline void
+RegExpStatics::getLastParen(JSSubString* out) const
+{
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ /* Note: the first pair is the whole match. */
+ if (matches.empty() || matches.pairCount() == 1) {
+ out->initEmpty(matchesInput);
+ return;
+ }
+ getParen(matches.parenCount(), out);
+}
+
+inline void
+RegExpStatics::getLeftContext(JSSubString* out) const
+{
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ if (matches.empty()) {
+ out->initEmpty(matchesInput);
+ return;
+ }
+ out->init(matchesInput, 0, matches[0].start);
+}
+
+inline void
+RegExpStatics::getRightContext(JSSubString* out) const
+{
+ MOZ_ASSERT(!pendingLazyEvaluation);
+
+ if (matches.empty()) {
+ out->initEmpty(matchesInput);
+ return;
+ }
+ MOZ_ASSERT(matches[0].limit <= int(matchesInput->length()));
+ size_t length = matchesInput->length() - matches[0].limit;
+ out->init(matchesInput, matches[0].limit, length);
+}
+
+inline void
+RegExpStatics::updateLazily(JSContext* cx, JSLinearString* input,
+ RegExpShared* shared, size_t lastIndex)
+{
+ MOZ_ASSERT(input && shared);
+
+ BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
+ pendingInput, input,
+ matchesInput, input);
+
+ lazySource = shared->source;
+ lazyFlags = shared->flags;
+ lazyIndex = lastIndex;
+ pendingLazyEvaluation = 1;
+}
+
+inline bool
+RegExpStatics::updateFromMatchPairs(JSContext* cx, JSLinearString* input, MatchPairs& newPairs)
+{
+ MOZ_ASSERT(input);
+
+ /* Unset all lazy state. */
+ pendingLazyEvaluation = false;
+ this->lazySource = nullptr;
+ this->lazyIndex = size_t(-1);
+
+ BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
+ pendingInput, input,
+ matchesInput, input);
+
+ if (!matches.initArrayFrom(newPairs)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ return true;
+}
+
+inline void
+RegExpStatics::clear()
+{
+ matches.forgetArray();
+ matchesInput = nullptr;
+ lazySource = nullptr;
+ lazyFlags = RegExpFlag(0);
+ lazyIndex = size_t(-1);
+ pendingInput = nullptr;
+ pendingLazyEvaluation = false;
+}
+
+inline void
+RegExpStatics::setPendingInput(JSString* newInput)
+{
+ pendingInput = newInput;
+}
+
+inline void
+RegExpStatics::checkInvariants()
+{
+#ifdef DEBUG
+ if (pendingLazyEvaluation) {
+ MOZ_ASSERT(lazySource);
+ MOZ_ASSERT(matchesInput);
+ MOZ_ASSERT(lazyIndex != size_t(-1));
+ return;
+ }
+
+ if (matches.empty()) {
+ MOZ_ASSERT(!matchesInput);
+ return;
+ }
+
+ /* Pair count is non-zero, so there must be match pairs input. */
+ MOZ_ASSERT(matchesInput);
+ size_t mpiLen = matchesInput->length();
+
+ /* Both members of the first pair must be non-negative. */
+ MOZ_ASSERT(!matches[0].isUndefined());
+ MOZ_ASSERT(matches[0].limit >= 0);
+
+ /* Present pairs must be valid. */
+ for (size_t i = 0; i < matches.pairCount(); i++) {
+ if (matches[i].isUndefined())
+ continue;
+ const MatchPair& pair = matches[i];
+ MOZ_ASSERT(mpiLen >= size_t(pair.limit) && pair.limit >= pair.start && pair.start >= 0);
+ }
+#endif /* DEBUG */
+}
+
+} /* namespace js */
+
+#endif /* vm_RegExpStatics_h */
diff --git a/js/src/vm/RegExpStaticsObject.h b/js/src/vm/RegExpStaticsObject.h
new file mode 100644
index 000000000..5b877e951
--- /dev/null
+++ b/js/src/vm/RegExpStaticsObject.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_RegExpStaticsObject_h
+#define vm_RegExpStaticsObject_h
+
+#include "jsobj.h"
+
+namespace js {
+
+class RegExpStaticsObject : public NativeObject
+{
+ public:
+ static const Class class_;
+
+ size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) {
+ // XXX: should really call RegExpStatics::sizeOfIncludingThis() here
+ // instead, but the extra memory it would measure is insignificant.
+ return mallocSizeOf(getPrivate());
+ }
+};
+
+} // namespace js
+
+#endif /* vm_RegExpStaticsObject_h */
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
new file mode 100644
index 000000000..646d48299
--- /dev/null
+++ b/js/src/vm/Runtime.cpp
@@ -0,0 +1,968 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/ThreadLocal.h"
+#include "mozilla/Unused.h"
+
+#if defined(XP_DARWIN)
+#include <mach/mach.h>
+#elif defined(XP_UNIX)
+#include <sys/resource.h>
+#elif defined(XP_WIN)
+#include <processthreadsapi.h>
+#include <windows.h>
+#endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
+
+#include <locale.h>
+#include <string.h>
+
+#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
+# include <sys/mman.h>
+#endif
+
+#include "jsatom.h"
+#include "jsdtoa.h"
+#include "jsgc.h"
+#include "jsmath.h"
+#include "jsnativestack.h"
+#include "jsobj.h"
+#include "jsscript.h"
+#include "jswatchpoint.h"
+#include "jswin.h"
+#include "jswrapper.h"
+
+#include "builtin/Promise.h"
+#include "gc/GCInternals.h"
+#include "jit/arm/Simulator-arm.h"
+#include "jit/arm64/vixl/Simulator-vixl.h"
+#include "jit/IonBuilder.h"
+#include "jit/JitCompartment.h"
+#include "jit/mips32/Simulator-mips32.h"
+#include "jit/mips64/Simulator-mips64.h"
+#include "jit/PcScriptCache.h"
+#include "js/Date.h"
+#include "js/MemoryMetrics.h"
+#include "js/SliceBudget.h"
+#include "vm/Debugger.h"
+#include "wasm/WasmSignalHandlers.h"
+
+#include "jscntxtinlines.h"
+#include "jsgcinlines.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::Atomic;
+using mozilla::DebugOnly;
+using mozilla::NegativeInfinity;
+using mozilla::PodZero;
+using mozilla::PodArrayZero;
+using mozilla::PositiveInfinity;
+using JS::GenericNaN;
+using JS::DoubleNaNValue;
+
+/* static */ MOZ_THREAD_LOCAL(PerThreadData*) js::TlsPerThreadData;
+/* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
+
+namespace js {
+ bool gCanUseExtraThreads = true;
+} // namespace js
+
+void
+js::DisableExtraThreads()
+{
+ gCanUseExtraThreads = false;
+}
+
+const JSSecurityCallbacks js::NullSecurityCallbacks = { };
+
+PerThreadData::PerThreadData(JSRuntime* runtime)
+ : runtime_(runtime)
+#ifdef JS_TRACE_LOGGING
+ , traceLogger(nullptr)
+#endif
+ , autoFlushICache_(nullptr)
+ , dtoaState(nullptr)
+ , suppressGC(0)
+#ifdef DEBUG
+ , ionCompiling(false)
+ , ionCompilingSafeForMinorGC(false)
+ , performingGC(false)
+ , gcSweeping(false)
+#endif
+{}
+
+PerThreadData::~PerThreadData()
+{
+ if (dtoaState)
+ DestroyDtoaState(dtoaState);
+}
+
+bool
+PerThreadData::init()
+{
+ dtoaState = NewDtoaState();
+ if (!dtoaState)
+ return false;
+
+ return true;
+}
+
+static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
+ TransparentObjectWrapper,
+ nullptr
+};
+
+static size_t
+ReturnZeroSize(const void* p)
+{
+ return 0;
+}
+
+JSRuntime::JSRuntime(JSRuntime* parentRuntime)
+ : mainThread(this),
+ jitTop(nullptr),
+ jitActivation(nullptr),
+ jitStackLimit_(0xbad),
+ jitStackLimitNoInterrupt_(0xbad),
+#ifdef DEBUG
+ ionBailAfter_(0),
+#endif
+ activation_(nullptr),
+ profilingActivation_(nullptr),
+ profilerSampleBufferGen_(0),
+ profilerSampleBufferLapCount_(1),
+ wasmActivationStack_(nullptr),
+ entryMonitor(nullptr),
+ noExecuteDebuggerTop(nullptr),
+ parentRuntime(parentRuntime),
+#ifdef DEBUG
+ updateChildRuntimeCount(parentRuntime),
+#endif
+ interrupt_(false),
+ telemetryCallback(nullptr),
+ handlingSegFault(false),
+ handlingJitInterrupt_(false),
+ interruptCallbackDisabled(false),
+ getIncumbentGlobalCallback(nullptr),
+ enqueuePromiseJobCallback(nullptr),
+ enqueuePromiseJobCallbackData(nullptr),
+ promiseRejectionTrackerCallback(nullptr),
+ promiseRejectionTrackerCallbackData(nullptr),
+ startAsyncTaskCallback(nullptr),
+ finishAsyncTaskCallback(nullptr),
+ promiseTasksToDestroy(mutexid::PromiseTaskPtrVector),
+ exclusiveAccessLock(mutexid::RuntimeExclusiveAccess),
+#ifdef DEBUG
+ mainThreadHasExclusiveAccess(false),
+#endif
+ numExclusiveThreads(0),
+ numCompartments(0),
+ localeCallbacks(nullptr),
+ defaultLocale(nullptr),
+ defaultVersion_(JSVERSION_DEFAULT),
+ ownerThread_(js::ThisThread::GetId()),
+ ownerThreadNative_(0),
+ tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+ jitRuntime_(nullptr),
+ selfHostingGlobal_(nullptr),
+ nativeStackBase(GetNativeStackBase()),
+ destroyCompartmentCallback(nullptr),
+ sizeOfIncludingThisCompartmentCallback(nullptr),
+ destroyZoneCallback(nullptr),
+ sweepZoneCallback(nullptr),
+ compartmentNameCallback(nullptr),
+ activityCallback(nullptr),
+ activityCallbackArg(nullptr),
+ requestDepth(0),
+#ifdef DEBUG
+ checkRequestDepth(0),
+#endif
+ gc(thisFromCtor()),
+ gcInitialized(false),
+#ifdef JS_SIMULATOR
+ simulator_(nullptr),
+#endif
+ scriptAndCountsVector(nullptr),
+ lcovOutput(),
+ NaNValue(DoubleNaNValue()),
+ negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
+ positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
+ emptyString(nullptr),
+ spsProfiler(thisFromCtor()),
+ profilingScripts(false),
+ suppressProfilerSampling(false),
+ hadOutOfMemory(false),
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+ runningOOMTest(false),
+#endif
+ allowRelazificationForTesting(false),
+ defaultFreeOp_(nullptr),
+ debuggerMutations(0),
+ securityCallbacks(&NullSecurityCallbacks),
+ DOMcallbacks(nullptr),
+ destroyPrincipals(nullptr),
+ readPrincipals(nullptr),
+ warningReporter(nullptr),
+ buildIdOp(nullptr),
+ propertyRemovals(0),
+#if !EXPOSE_INTL_API
+ thousandsSeparator(0),
+ decimalSeparator(0),
+ numGrouping(0),
+#endif
+ keepAtoms_(0),
+ trustedPrincipals_(nullptr),
+ beingDestroyed_(false),
+ atoms_(nullptr),
+ atomsCompartment_(nullptr),
+ staticStrings(nullptr),
+ commonNames(nullptr),
+ permanentAtoms(nullptr),
+ wellKnownSymbols(nullptr),
+ wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
+ preserveWrapperCallback(nullptr),
+ jitSupportsFloatingPoint(false),
+ jitSupportsUnalignedAccesses(false),
+ jitSupportsSimd(false),
+ ionPcScriptCache(nullptr),
+ scriptEnvironmentPreparer(nullptr),
+ ctypesActivityCallback(nullptr),
+ windowProxyClass_(nullptr),
+ offthreadIonCompilationEnabled_(true),
+ parallelParsingEnabled_(true),
+ autoWritableJitCodeActive_(false),
+#ifdef DEBUG
+ enteredPolicy(nullptr),
+#endif
+ largeAllocationFailureCallback(nullptr),
+ oomCallback(nullptr),
+ debuggerMallocSizeOf(ReturnZeroSize),
+ lastAnimationTime(0),
+ performanceMonitoring(thisFromCtor()),
+ ionLazyLinkListSize_(0),
+ stackFormat_(parentRuntime ? js::StackFormat::Default
+ : js::StackFormat::SpiderMonkey)
+{
+ setGCStoreBufferPtr(&gc.storeBuffer);
+
+ liveRuntimesCount++;
+
+ /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
+ JS_INIT_CLIST(&onNewGlobalObjectWatchers);
+
+ PodArrayZero(nativeStackQuota);
+ PodZero(&asmJSCacheOps);
+ lcovOutput.init();
+}
+
+bool
+JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
+{
+ MOZ_ASSERT(ownerThread_ == js::ThisThread::GetId());
+
+ // Get a platform-native handle for the owner thread, used by
+ // js::InterruptRunningJitCode to halt the runtime's main thread.
+#ifdef XP_WIN
+ size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION;
+ HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
+ if (!self)
+ return false;
+ static_assert(sizeof(HANDLE) <= sizeof(ownerThreadNative_), "need bigger field");
+ ownerThreadNative_ = (size_t)self;
+#else
+ static_assert(sizeof(pthread_t) <= sizeof(ownerThreadNative_), "need bigger field");
+ ownerThreadNative_ = (size_t)pthread_self();
+#endif
+
+ if (!mainThread.init())
+ return false;
+
+ if (!regexpStack.init())
+ return false;
+
+ if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
+ return false;
+
+ js::TlsPerThreadData.set(&mainThread);
+
+ defaultFreeOp_ = js_new<js::FreeOp>(this);
+ if (!defaultFreeOp_)
+ return false;
+
+ if (!gc.init(maxbytes, maxNurseryBytes))
+ return false;
+
+ ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
+ if (!atomsZone || !atomsZone->init(true))
+ return false;
+
+ JS::CompartmentOptions options;
+ ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
+ if (!atomsCompartment || !atomsCompartment->init(nullptr))
+ return false;
+
+ if (!gc.zones.append(atomsZone.get()))
+ return false;
+ if (!atomsZone->compartments.append(atomsCompartment.get()))
+ return false;
+
+ atomsCompartment->setIsSystem(true);
+ atomsCompartment->setIsAtomsCompartment();
+
+ atomsZone.forget();
+ this->atomsCompartment_ = atomsCompartment.forget();
+
+ if (!symbolRegistry_.init())
+ return false;
+
+ if (!scriptDataTable_.init())
+ return false;
+
+ /* The garbage collector depends on everything before this point being initialized. */
+ gcInitialized = true;
+
+ if (!InitRuntimeNumberState(this))
+ return false;
+
+ JS::ResetTimeZone();
+
+#ifdef JS_SIMULATOR
+ simulator_ = js::jit::Simulator::Create(contextFromMainThread());
+ if (!simulator_)
+ return false;
+#endif
+
+ jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
+ jitSupportsUnalignedAccesses = js::jit::JitSupportsUnalignedAccesses();
+ jitSupportsSimd = js::jit::JitSupportsSimd();
+
+ if (!wasm::EnsureSignalHandlers(this))
+ return false;
+
+ if (!spsProfiler.init())
+ return false;
+
+ if (!fx.initInstance())
+ return false;
+
+ if (!parentRuntime) {
+ sharedImmutableStrings_ = js::SharedImmutableStringsCache::Create();
+ if (!sharedImmutableStrings_)
+ return false;
+ }
+
+ return true;
+}
+
+void
+JSRuntime::destroyRuntime()
+{
+ MOZ_ASSERT(!isHeapBusy());
+ MOZ_ASSERT(childRuntimeCount == 0);
+
+ fx.destroyInstance();
+
+ sharedIntlData.destroyInstance();
+
+ if (gcInitialized) {
+ /*
+ * Finish any in-progress GCs first. This ensures the parseWaitingOnGC
+ * list is empty in CancelOffThreadParses.
+ */
+ JSContext* cx = contextFromMainThread();
+ if (JS::IsIncrementalGCInProgress(cx))
+ FinishGC(cx);
+
+ /* Free source hook early, as its destructor may want to delete roots. */
+ sourceHook = nullptr;
+
+ /*
+ * Cancel any pending, in progress or completed Ion compilations and
+ * parse tasks. Waiting for wasm and compression tasks is done
+ * synchronously (on the main thread or during parse tasks), so no
+ * explicit canceling is needed for these.
+ */
+ CancelOffThreadIonCompile(this);
+ CancelOffThreadParses(this);
+
+ /* Remove persistent GC roots. */
+ gc.finishRoots();
+
+ /*
+ * Flag us as being destroyed. This allows the GC to free things like
+ * interned atoms and Ion trampolines.
+ */
+ beingDestroyed_ = true;
+
+ /* Allow the GC to release scripts that were being profiled. */
+ profilingScripts = false;
+
+ /* Set the profiler sampler buffer generation to invalid. */
+ profilerSampleBufferGen_ = UINT32_MAX;
+
+ JS::PrepareForFullGC(contextFromMainThread());
+ gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
+ }
+
+ MOZ_ASSERT(ionLazyLinkListSize_ == 0);
+ MOZ_ASSERT(ionLazyLinkList_.isEmpty());
+
+ MOZ_ASSERT(!numExclusiveThreads);
+ AutoLockForExclusiveAccess lock(this);
+
+ /*
+ * Even though all objects in the compartment are dead, we may have keep
+ * some filenames around because of gcKeepAtoms.
+ */
+ FreeScriptData(this, lock);
+
+#if !EXPOSE_INTL_API
+ FinishRuntimeNumberState(this);
+#endif
+
+ gc.finish();
+ atomsCompartment_ = nullptr;
+
+ js_delete(defaultFreeOp_);
+
+ js_free(defaultLocale);
+ js_delete(jitRuntime_);
+
+ js_delete(ionPcScriptCache);
+
+ gc.storeBuffer.disable();
+ gc.nursery.disable();
+
+#ifdef JS_SIMULATOR
+ js::jit::Simulator::Destroy(simulator_);
+#endif
+
+ DebugOnly<size_t> oldCount = liveRuntimesCount--;
+ MOZ_ASSERT(oldCount > 0);
+
+#ifdef JS_TRACE_LOGGING
+ DestroyTraceLoggerMainThread(this);
+#endif
+
+ js::TlsPerThreadData.set(nullptr);
+
+#ifdef XP_WIN
+ if (ownerThreadNative_)
+ CloseHandle((HANDLE)ownerThreadNative_);
+#endif
+}
+
+void
+JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
+{
+ if (telemetryCallback)
+ (*telemetryCallback)(id, sample, key);
+}
+
+void
+JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback)
+{
+ rt->telemetryCallback = callback;
+}
+
+void
+JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
+{
+ // Several tables in the runtime enumerated below can be used off thread.
+ AutoLockForExclusiveAccess lock(this);
+
+ // For now, measure the size of the derived class (JSContext).
+ // TODO (bug 1281529): make memory reporting reflect the new
+ // JSContext/JSRuntime world better.
+ JSContext* cx = unsafeContextFromAnyThread();
+ rtSizes->object += mallocSizeOf(cx);
+
+ rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
+
+ if (!parentRuntime) {
+ rtSizes->atomsTable += mallocSizeOf(staticStrings);
+ rtSizes->atomsTable += mallocSizeOf(commonNames);
+ rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
+ }
+
+ rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
+
+ rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
+
+ rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
+
+ if (MathCache* cache = cx->caches.maybeGetMathCache())
+ rtSizes->mathCache += cache->sizeOfIncludingThis(mallocSizeOf);
+
+ if (sharedImmutableStrings_) {
+ rtSizes->sharedImmutableStringsCache +=
+ sharedImmutableStrings_->sizeOfExcludingThis(mallocSizeOf);
+ }
+
+ rtSizes->sharedIntlData += sharedIntlData.sizeOfExcludingThis(mallocSizeOf);
+
+ rtSizes->uncompressedSourceCache +=
+ cx->caches.uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
+
+
+ rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
+ for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
+ rtSizes->scriptData += mallocSizeOf(r.front());
+
+ if (jitRuntime_) {
+ jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
+ jitRuntime_->backedgeExecAlloc().addSizeOfCode(&rtSizes->code);
+ }
+
+ rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf);
+ rtSizes->gc.nurseryCommitted += gc.nursery.sizeOfHeapCommitted();
+ rtSizes->gc.nurseryMallocedBuffers += gc.nursery.sizeOfMallocedBuffers(mallocSizeOf);
+ gc.storeBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
+}
+
+static bool
+InvokeInterruptCallback(JSContext* cx)
+{
+ MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
+
+ cx->runtime()->gc.gcIfRequested();
+
+ // A worker thread may have requested an interrupt after finishing an Ion
+ // compilation.
+ jit::AttachFinishedCompilations(cx);
+
+ // Important: Additional callbacks can occur inside the callback handler
+ // if it re-enters the JS engine. The embedding must ensure that the
+ // callback is disconnected before attempting such re-entry.
+ if (cx->runtime()->interruptCallbackDisabled)
+ return true;
+
+ bool stop = false;
+ for (JSInterruptCallback cb : cx->runtime()->interruptCallbacks) {
+ if (!cb(cx))
+ stop = true;
+ }
+
+ if (!stop) {
+ // Debugger treats invoking the interrupt callback as a "step", so
+ // invoke the onStep handler.
+ if (cx->compartment()->isDebuggee()) {
+ ScriptFrameIter iter(cx);
+ if (!iter.done() &&
+ cx->compartment() == iter.compartment() &&
+ iter.script()->stepModeEnabled())
+ {
+ RootedValue rval(cx);
+ switch (Debugger::onSingleStep(cx, &rval)) {
+ case JSTRAP_ERROR:
+ return false;
+ case JSTRAP_CONTINUE:
+ return true;
+ case JSTRAP_RETURN:
+ // See note in Debugger::propagateForcedReturn.
+ Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
+ return false;
+ case JSTRAP_THROW:
+ cx->setPendingException(rval);
+ return false;
+ default:;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // No need to set aside any pending exception here: ComputeStackString
+ // already does that.
+ JSString* stack = ComputeStackString(cx);
+ JSFlatString* flat = stack ? stack->ensureFlat(cx) : nullptr;
+
+ const char16_t* chars;
+ AutoStableStringChars stableChars(cx);
+ if (flat && stableChars.initTwoByte(cx, flat))
+ chars = stableChars.twoByteRange().begin().get();
+ else
+ chars = u"(stack not available)";
+ JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
+ JSMSG_TERMINATED, chars);
+
+ return false;
+}
+
+void
+JSRuntime::requestInterrupt(InterruptMode mode)
+{
+ interrupt_ = true;
+ jitStackLimit_ = UINTPTR_MAX;
+
+ if (mode == JSRuntime::RequestInterruptUrgent) {
+ // If this interrupt is urgent (slow script dialog and garbage
+ // collection among others), take additional steps to
+ // interrupt corner cases where the above fields are not
+ // regularly polled. Wake both ilooping JIT code and
+ // Atomics.wait().
+ fx.lock();
+ if (fx.isWaiting())
+ fx.wake(FutexRuntime::WakeForJSInterrupt);
+ fx.unlock();
+ InterruptRunningJitCode(this);
+ }
+}
+
+bool
+JSRuntime::handleInterrupt(JSContext* cx)
+{
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
+ if (interrupt_ || jitStackLimit_ == UINTPTR_MAX) {
+ interrupt_ = false;
+ cx->resetJitStackLimit();
+ return InvokeInterruptCallback(cx);
+ }
+ return true;
+}
+
+bool
+JSRuntime::setDefaultLocale(const char* locale)
+{
+ if (!locale)
+ return false;
+ resetDefaultLocale();
+ defaultLocale = JS_strdup(contextFromMainThread(), locale);
+ return defaultLocale != nullptr;
+}
+
+void
+JSRuntime::resetDefaultLocale()
+{
+ js_free(defaultLocale);
+ defaultLocale = nullptr;
+}
+
+const char*
+JSRuntime::getDefaultLocale()
+{
+ if (defaultLocale)
+ return defaultLocale;
+
+ const char* locale;
+#ifdef HAVE_SETLOCALE
+ locale = setlocale(LC_ALL, nullptr);
+#else
+ locale = getenv("LANG");
+#endif
+ // convert to a well-formed BCP 47 language tag
+ if (!locale || !strcmp(locale, "C"))
+ locale = "und";
+
+ char* lang = JS_strdup(contextFromMainThread(), locale);
+ if (!lang)
+ return nullptr;
+
+ char* p;
+ if ((p = strchr(lang, '.')))
+ *p = '\0';
+ while ((p = strchr(lang, '_')))
+ *p = '-';
+
+ defaultLocale = lang;
+ return defaultLocale;
+}
+
+void
+JSRuntime::traceSharedIntlData(JSTracer* trc)
+{
+ sharedIntlData.trace(trc);
+}
+
+void
+JSRuntime::triggerActivityCallback(bool active)
+{
+ if (!activityCallback)
+ return;
+
+ /*
+ * The activity callback must not trigger a GC: it would create a cirular
+ * dependency between entering a request and Rooted's requirement of being
+ * in a request. In practice this callback already cannot trigger GC. The
+ * suppression serves to inform the exact rooting hazard analysis of this
+ * property and ensures that it remains true in the future.
+ */
+ AutoSuppressGC suppress(contextFromMainThread());
+
+ activityCallback(activityCallbackArg, active);
+}
+
+FreeOp::FreeOp(JSRuntime* maybeRuntime)
+ : JSFreeOp(maybeRuntime)
+{
+ MOZ_ASSERT_IF(maybeRuntime, CurrentThreadCanAccessRuntime(maybeRuntime));
+}
+
+FreeOp::~FreeOp()
+{
+ for (size_t i = 0; i < freeLaterList.length(); i++)
+ free_(freeLaterList[i]);
+
+ if (!jitPoisonRanges.empty())
+ jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
+}
+
+bool
+FreeOp::isDefaultFreeOp() const
+{
+ return runtime_ && runtime_->defaultFreeOp() == this;
+}
+
+JSObject*
+JSRuntime::getIncumbentGlobal(JSContext* cx)
+{
+ MOZ_ASSERT(cx->runtime()->getIncumbentGlobalCallback,
+ "Must set a callback using JS_SetGetIncumbentGlobalCallback before using Promises");
+
+ return cx->runtime()->getIncumbentGlobalCallback(cx);
+}
+
+bool
+JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, HandleObject promise,
+ HandleObject incumbentGlobal)
+{
+ MOZ_ASSERT(cx->runtime()->enqueuePromiseJobCallback,
+ "Must set a callback using JS_SetEnqeueuPromiseJobCallback before using Promises");
+ MOZ_ASSERT_IF(incumbentGlobal, !IsWrapper(incumbentGlobal) && !IsWindowProxy(incumbentGlobal));
+
+ void* data = cx->runtime()->enqueuePromiseJobCallbackData;
+ RootedObject allocationSite(cx);
+ if (promise) {
+ RootedObject unwrappedPromise(cx, promise);
+ // While the job object is guaranteed to be unwrapped, the promise
+ // might be wrapped. See the comments in
+ // intrinsic_EnqueuePromiseReactionJob for details.
+ if (IsWrapper(promise))
+ unwrappedPromise = UncheckedUnwrap(promise);
+ if (unwrappedPromise->is<PromiseObject>())
+ allocationSite = JS::GetPromiseAllocationSite(unwrappedPromise);
+ }
+ return cx->runtime()->enqueuePromiseJobCallback(cx, job, allocationSite, incumbentGlobal, data);
+}
+
+void
+JSRuntime::addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
+{
+ MOZ_ASSERT(promise->is<PromiseObject>());
+ if (!cx->runtime()->promiseRejectionTrackerCallback)
+ return;
+
+ void* data = cx->runtime()->promiseRejectionTrackerCallbackData;
+ cx->runtime()->promiseRejectionTrackerCallback(cx, promise,
+ PromiseRejectionHandlingState::Unhandled, data);
+}
+
+void
+JSRuntime::removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
+{
+ MOZ_ASSERT(promise->is<PromiseObject>());
+ if (!cx->runtime()->promiseRejectionTrackerCallback)
+ return;
+
+ void* data = cx->runtime()->promiseRejectionTrackerCallbackData;
+ cx->runtime()->promiseRejectionTrackerCallback(cx, promise,
+ PromiseRejectionHandlingState::Handled, data);
+}
+
+mozilla::non_crypto::XorShift128PlusRNG&
+JSRuntime::randomKeyGenerator()
+{
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+ if (randomKeyGenerator_.isNothing()) {
+ mozilla::Array<uint64_t, 2> seed;
+ GenerateXorShift128PlusSeed(seed);
+ randomKeyGenerator_.emplace(seed[0], seed[1]);
+ }
+ return randomKeyGenerator_.ref();
+}
+
+mozilla::HashCodeScrambler
+JSRuntime::randomHashCodeScrambler()
+{
+ auto& rng = randomKeyGenerator();
+ return mozilla::HashCodeScrambler(rng.next(), rng.next());
+}
+
+mozilla::non_crypto::XorShift128PlusRNG
+JSRuntime::forkRandomKeyGenerator()
+{
+ auto& rng = randomKeyGenerator();
+ return mozilla::non_crypto::XorShift128PlusRNG(rng.next(), rng.next());
+}
+
+void
+JSRuntime::updateMallocCounter(size_t nbytes)
+{
+ updateMallocCounter(nullptr, nbytes);
+}
+
+void
+JSRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes)
+{
+ gc.updateMallocCounter(zone, nbytes);
+}
+
+JS_FRIEND_API(void*)
+JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr,
+ JSContext* maybecx)
+{
+ MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+
+ if (isHeapBusy())
+ return nullptr;
+
+ if (!oom::IsSimulatedOOMAllocation()) {
+ /*
+ * Retry when we are done with the background sweeping and have stopped
+ * all the allocations and released the empty GC chunks.
+ */
+ gc.onOutOfMallocMemory();
+ void* p;
+ switch (allocFunc) {
+ case AllocFunction::Malloc:
+ p = js_malloc(nbytes);
+ break;
+ case AllocFunction::Calloc:
+ p = js_calloc(nbytes);
+ break;
+ case AllocFunction::Realloc:
+ p = js_realloc(reallocPtr, nbytes);
+ break;
+ default:
+ MOZ_CRASH();
+ }
+ if (p)
+ return p;
+ }
+
+ if (maybecx)
+ ReportOutOfMemory(maybecx);
+ return nullptr;
+}
+
+void*
+JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
+{
+ if (largeAllocationFailureCallback && bytes >= LARGE_ALLOCATION)
+ largeAllocationFailureCallback(largeAllocationFailureCallbackData);
+ return onOutOfMemory(allocFunc, bytes, reallocPtr);
+}
+
+bool
+JSRuntime::activeGCInAtomsZone()
+{
+ Zone* zone = atomsCompartment_->zone();
+ return (zone->needsIncrementalBarrier() && !gc.isVerifyPreBarriersEnabled()) ||
+ zone->wasGCStarted();
+}
+
+void
+JSRuntime::setUsedByExclusiveThread(Zone* zone)
+{
+ MOZ_ASSERT(!zone->usedByExclusiveThread);
+ zone->usedByExclusiveThread = true;
+ numExclusiveThreads++;
+}
+
+void
+JSRuntime::clearUsedByExclusiveThread(Zone* zone)
+{
+ MOZ_ASSERT(zone->usedByExclusiveThread);
+ zone->usedByExclusiveThread = false;
+ numExclusiveThreads--;
+ if (gc.fullGCForAtomsRequested() && !keepAtoms())
+ gc.triggerFullGCForAtoms();
+}
+
+bool
+js::CurrentThreadCanAccessRuntime(const JSRuntime* rt)
+{
+ return rt->ownerThread_ == js::ThisThread::GetId();
+}
+
+bool
+js::CurrentThreadCanAccessZone(Zone* zone)
+{
+ if (CurrentThreadCanAccessRuntime(zone->runtime_))
+ return true;
+
+ // Only zones in use by an exclusive thread can be used off the main thread.
+ // We don't keep track of which thread owns such zones though, so this check
+ // is imperfect.
+ return zone->usedByExclusiveThread;
+}
+
+#ifdef DEBUG
+bool
+js::CurrentThreadIsPerformingGC()
+{
+ return TlsPerThreadData.get()->performingGC;
+}
+#endif
+
+JS_FRIEND_API(void)
+JS::UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation,
+ uint32_t lapCount)
+{
+ cx->setProfilerSampleBufferGen(generation);
+ cx->updateProfilerSampleBufferLapCount(lapCount);
+}
+
+JS_FRIEND_API(bool)
+JS::IsProfilingEnabledForContext(JSContext* cx)
+{
+ MOZ_ASSERT(cx);
+ return cx->spsProfiler.enabled();
+}
+
+JSRuntime::IonBuilderList&
+JSRuntime::ionLazyLinkList()
+{
+ MOZ_ASSERT(TlsPerThreadData.get()->runtimeFromMainThread(),
+ "Should only be mutated by the main thread.");
+ return ionLazyLinkList_;
+}
+
+void
+JSRuntime::ionLazyLinkListRemove(jit::IonBuilder* builder)
+{
+ MOZ_ASSERT(TlsPerThreadData.get()->runtimeFromMainThread(),
+ "Should only be mutated by the main thread.");
+ MOZ_ASSERT(ionLazyLinkListSize_ > 0);
+
+ builder->removeFrom(ionLazyLinkList());
+ ionLazyLinkListSize_--;
+
+ MOZ_ASSERT(ionLazyLinkList().isEmpty() == (ionLazyLinkListSize_ == 0));
+}
+
+void
+JSRuntime::ionLazyLinkListAdd(jit::IonBuilder* builder)
+{
+ MOZ_ASSERT(TlsPerThreadData.get()->runtimeFromMainThread(),
+ "Should only be mutated by the main thread.");
+ ionLazyLinkList().insertFront(builder);
+ ionLazyLinkListSize_++;
+}
+
+JSContext*
+PerThreadData::contextFromMainThread()
+{
+ return runtime_->contextFromMainThread();
+}
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
new file mode 100644
index 000000000..4f7755b9d
--- /dev/null
+++ b/js/src/vm/Runtime.h
@@ -0,0 +1,1777 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Runtime_h
+#define vm_Runtime_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/LinkedList.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/Scoped.h"
+#include "mozilla/ThreadLocal.h"
+#include "mozilla/Vector.h"
+
+#include <setjmp.h>
+
+#include "jsatom.h"
+#include "jsclist.h"
+#include "jsscript.h"
+
+#ifdef XP_DARWIN
+# include "wasm/WasmSignalHandlers.h"
+#endif
+#include "builtin/AtomicsObject.h"
+#include "builtin/Intl.h"
+#include "builtin/Promise.h"
+#include "ds/FixedSizeHash.h"
+#include "frontend/NameCollections.h"
+#include "gc/GCRuntime.h"
+#include "gc/Tracer.h"
+#include "irregexp/RegExpStack.h"
+#include "js/Debug.h"
+#include "js/GCVector.h"
+#include "js/HashTable.h"
+#ifdef DEBUG
+# include "js/Proxy.h" // For AutoEnterPolicy
+#endif
+#include "js/UniquePtr.h"
+#include "js/Vector.h"
+#include "threading/Thread.h"
+#include "vm/CodeCoverage.h"
+#include "vm/CommonPropertyNames.h"
+#include "vm/DateTime.h"
+#include "vm/MallocProvider.h"
+#include "vm/Scope.h"
+#include "vm/SharedImmutableStringsCache.h"
+#include "vm/SPSProfiler.h"
+#include "vm/Stack.h"
+#include "vm/Stopwatch.h"
+#include "vm/Symbol.h"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
+#endif
+
+namespace js {
+
+class PerThreadData;
+class ExclusiveContext;
+class AutoKeepAtoms;
+class EnterDebuggeeNoExecute;
+#ifdef JS_TRACE_LOGGING
+class TraceLoggerThread;
+#endif
+
+typedef Vector<UniquePtr<PromiseTask>, 0, SystemAllocPolicy> PromiseTaskPtrVector;
+
+/* Thread Local Storage slot for storing the runtime for a thread. */
+extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData;
+
+} // namespace js
+
+struct DtoaState;
+
+#ifdef JS_SIMULATOR_ARM64
+namespace vixl {
+class Simulator;
+}
+#endif
+
+namespace js {
+
+extern MOZ_COLD void
+ReportOutOfMemory(ExclusiveContext* cx);
+
+extern MOZ_COLD void
+ReportAllocationOverflow(ExclusiveContext* maybecx);
+
+extern MOZ_COLD void
+ReportOverRecursed(ExclusiveContext* cx);
+
+class Activation;
+class ActivationIterator;
+class WasmActivation;
+
+namespace jit {
+class JitRuntime;
+class JitActivation;
+struct PcScriptCache;
+struct AutoFlushICache;
+class CompileRuntime;
+
+#ifdef JS_SIMULATOR_ARM64
+typedef vixl::Simulator Simulator;
+#elif defined(JS_SIMULATOR)
+class Simulator;
+#endif
+} // namespace jit
+
+/*
+ * A FreeOp can do one thing: free memory. For convenience, it has delete_
+ * convenience methods that also call destructors.
+ *
+ * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not
+ * need to pass a JSContext to those hooks.
+ */
+class FreeOp : public JSFreeOp
+{
+ Vector<void*, 0, SystemAllocPolicy> freeLaterList;
+ jit::JitPoisonRangeVector jitPoisonRanges;
+
+ public:
+ static FreeOp* get(JSFreeOp* fop) {
+ return static_cast<FreeOp*>(fop);
+ }
+
+ explicit FreeOp(JSRuntime* maybeRuntime);
+ ~FreeOp();
+
+ bool onMainThread() const {
+ return runtime_ != nullptr;
+ }
+
+ bool maybeOffMainThread() const {
+ // Sometimes background finalization happens on the main thread so
+ // runtime_ being null doesn't always mean we are off the main thread.
+ return !runtime_;
+ }
+
+ bool isDefaultFreeOp() const;
+
+ inline void free_(void* p);
+ inline void freeLater(void* p);
+
+ inline bool appendJitPoisonRange(const jit::JitPoisonRange& range);
+
+ template <class T>
+ inline void delete_(T* p) {
+ if (p) {
+ p->~T();
+ free_(p);
+ }
+ }
+};
+
+} /* namespace js */
+
+namespace JS {
+struct RuntimeSizes;
+} // namespace JS
+
+/* Various built-in or commonly-used names pinned on first context. */
+struct JSAtomState
+{
+#define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id;
+ FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+#define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name;
+ JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+#define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+#define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr Symbol_##name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+
+ js::ImmutablePropertyNamePtr* wellKnownSymbolNames() {
+#define FIRST_PROPERTYNAME_FIELD(name) return &name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD)
+#undef FIRST_PROPERTYNAME_FIELD
+ }
+
+ js::ImmutablePropertyNamePtr* wellKnownSymbolDescriptions() {
+#define FIRST_PROPERTYNAME_FIELD(name) return &Symbol_ ##name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD)
+#undef FIRST_PROPERTYNAME_FIELD
+ }
+};
+
+namespace js {
+
+/*
+ * Storage for well-known symbols. It's a separate struct from the Runtime so
+ * that it can be shared across multiple runtimes. As in JSAtomState, each
+ * field is a smart pointer that's immutable once initialized.
+ * `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
+ *
+ * Well-known symbols are never GC'd. The description() of each well-known
+ * symbol is a permanent atom.
+ */
+struct WellKnownSymbols
+{
+#define DECLARE_SYMBOL(name) js::ImmutableSymbolPtr name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(DECLARE_SYMBOL)
+#undef DECLARE_SYMBOL
+
+ const ImmutableSymbolPtr& get(size_t u) const {
+ MOZ_ASSERT(u < JS::WellKnownSymbolLimit);
+ const ImmutableSymbolPtr* symbols = reinterpret_cast<const ImmutableSymbolPtr*>(this);
+ return symbols[u];
+ }
+
+ const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
+ return get(size_t(code));
+ }
+
+ WellKnownSymbols() {}
+ WellKnownSymbols(const WellKnownSymbols&) = delete;
+ WellKnownSymbols& operator=(const WellKnownSymbols&) = delete;
+};
+
+#define NAME_OFFSET(name) offsetof(JSAtomState, name)
+
+inline HandlePropertyName
+AtomStateOffsetToName(const JSAtomState& atomState, size_t offset)
+{
+ return *reinterpret_cast<js::ImmutablePropertyNamePtr*>((char*)&atomState + offset);
+}
+
+// There are several coarse locks in the enum below. These may be either
+// per-runtime or per-process. When acquiring more than one of these locks,
+// the acquisition must be done in the order below to avoid deadlocks.
+enum RuntimeLock {
+ ExclusiveAccessLock,
+ HelperThreadStateLock,
+ GCLock
+};
+
+inline bool
+CanUseExtraThreads()
+{
+ extern bool gCanUseExtraThreads;
+ return gCanUseExtraThreads;
+}
+
+void DisableExtraThreads();
+
+/*
+ * Encapsulates portions of the runtime/context that are tied to a
+ * single active thread. Instances of this structure can occur for
+ * the main thread as |JSRuntime::mainThread|, for select operations
+ * performed off thread, such as parsing.
+ */
+class PerThreadData
+{
+ /*
+ * Backpointer to the full shared JSRuntime* with which this
+ * thread is associated. This is private because accessing the
+ * fields of this runtime can provoke race conditions, so the
+ * intention is that access will be mediated through safe
+ * functions like |runtimeFromMainThread| and |associatedWith()| below.
+ */
+ JSRuntime* runtime_;
+
+ public:
+#ifdef JS_TRACE_LOGGING
+ TraceLoggerMainThread* traceLogger;
+#endif
+
+ /* Pointer to the current AutoFlushICache. */
+ js::jit::AutoFlushICache* autoFlushICache_;
+
+ public:
+ /* State used by jsdtoa.cpp. */
+ DtoaState* dtoaState;
+
+ /*
+ * When this flag is non-zero, any attempt to GC will be skipped. It is used
+ * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
+ * debugging facilities that cannot tolerate a GC and would rather OOM
+ * immediately, such as utilities exposed to GDB. Setting this flag is
+ * extremely dangerous and should only be used when in an OOM situation or
+ * in non-exposed debugging facilities.
+ */
+ int32_t suppressGC;
+
+#ifdef DEBUG
+ // Whether this thread is actively Ion compiling.
+ bool ionCompiling;
+
+ // Whether this thread is actively Ion compiling in a context where a minor
+ // GC could happen simultaneously. If this is true, this thread cannot use
+ // any pointers into the nursery.
+ bool ionCompilingSafeForMinorGC;
+
+ // Whether this thread is currently performing GC. This thread could be the
+ // main thread or a helper thread while the main thread is running the
+ // collector.
+ bool performingGC;
+
+ // Whether this thread is currently sweeping GC things. This thread could
+ // be the main thread or a helper thread while the main thread is running
+ // the mutator. This is used to assert that destruction of GCPtr only
+ // happens when we are sweeping.
+ bool gcSweeping;
+#endif
+
+ // Pools used for recycling name maps and vectors when parsing and
+ // emitting bytecode. Purged on GC when there are no active script
+ // compilations.
+ frontend::NameCollectionPool frontendCollectionPool;
+
+ explicit PerThreadData(JSRuntime* runtime);
+ ~PerThreadData();
+
+ bool init();
+
+ bool associatedWith(const JSRuntime* rt) { return runtime_ == rt; }
+ inline JSRuntime* runtimeFromMainThread();
+ inline JSRuntime* runtimeIfOnOwnerThread();
+
+ JSContext* contextFromMainThread();
+
+ inline bool exclusiveThreadsPresent();
+
+ // For threads which may be associated with different runtimes, depending
+ // on the work they are doing.
+ class MOZ_STACK_CLASS AutoEnterRuntime
+ {
+ PerThreadData* pt;
+
+ public:
+ AutoEnterRuntime(PerThreadData* pt, JSRuntime* rt)
+ : pt(pt)
+ {
+ MOZ_ASSERT(!pt->runtime_);
+ pt->runtime_ = rt;
+ }
+
+ ~AutoEnterRuntime() {
+ pt->runtime_ = nullptr;
+ }
+ };
+
+ js::jit::AutoFlushICache* autoFlushICache() const;
+ void setAutoFlushICache(js::jit::AutoFlushICache* afc);
+
+#ifdef JS_SIMULATOR
+ js::jit::Simulator* simulator() const;
+#endif
+};
+
+using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
+
+class AutoLockForExclusiveAccess;
+} // namespace js
+
+struct JSRuntime : public JS::shadow::Runtime,
+ public js::MallocProvider<JSRuntime>
+{
+ /*
+ * Per-thread data for the main thread that is associated with
+ * this JSRuntime, as opposed to any worker threads used in
+ * parallel sections. See definition of |PerThreadData| struct
+ * above for more details.
+ *
+ * NB: This field is statically asserted to be at offset
+ * sizeof(js::shadow::Runtime). See
+ * PerThreadDataFriendFields::getMainThread.
+ */
+ js::PerThreadData mainThread;
+
+ /*
+ * If Baseline or Ion code is on the stack, and has called into C++, this
+ * will be aligned to an exit frame.
+ */
+ uint8_t* jitTop;
+
+ /*
+ * Points to the most recent JitActivation pushed on the thread.
+ * See JitActivation constructor in vm/Stack.cpp
+ */
+ js::jit::JitActivation* jitActivation;
+
+ /* See comment for JSRuntime::interrupt_. */
+ protected:
+ mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
+
+ // Like jitStackLimit_, but not reset to trigger interrupts.
+ uintptr_t jitStackLimitNoInterrupt_;
+
+ public:
+ uintptr_t jitStackLimit() const { return jitStackLimit_; }
+
+ // For read-only JIT use:
+ void* addressOfJitStackLimit() { return &jitStackLimit_; }
+ static size_t offsetOfJitStackLimit() { return offsetof(JSRuntime, jitStackLimit_); }
+
+ void* addressOfJitStackLimitNoInterrupt() { return &jitStackLimitNoInterrupt_; }
+
+ // Information about the heap allocated backtrack stack used by RegExp JIT code.
+ js::irregexp::RegExpStack regexpStack;
+
+#ifdef DEBUG
+ private:
+ // The number of possible bailing places encounters before forcefully bailing
+ // in that place. Zero means inactive.
+ uint32_t ionBailAfter_;
+
+ public:
+ void* addressOfIonBailAfter() { return &ionBailAfter_; }
+
+ // Set after how many bailing places we should forcefully bail.
+ // Zero disables this feature.
+ void setIonBailAfter(uint32_t after) {
+ ionBailAfter_ = after;
+ }
+#endif
+
+ private:
+ friend class js::Activation;
+ friend class js::ActivationIterator;
+ friend class js::jit::JitActivation;
+ friend class js::WasmActivation;
+ friend class js::jit::CompileRuntime;
+
+ protected:
+ /*
+ * Points to the most recent activation running on the thread.
+ * See Activation comment in vm/Stack.h.
+ */
+ js::Activation* activation_;
+
+ /*
+ * Points to the most recent profiling activation running on the
+ * thread.
+ */
+ js::Activation * volatile profilingActivation_;
+
+ /*
+ * The profiler sampler generation after the latest sample.
+ *
+ * The lapCount indicates the number of largest number of 'laps'
+ * (wrapping from high to low) that occurred when writing entries
+ * into the sample buffer. All JitcodeGlobalMap entries referenced
+ * from a given sample are assigned the generation of the sample buffer
+ * at the START of the run. If multiple laps occur, then some entries
+ * (towards the end) will be written out with the "wrong" generation.
+ * The lapCount indicates the required fudge factor to use to compare
+ * entry generations with the sample buffer generation.
+ */
+ mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferGen_;
+ mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferLapCount_;
+
+ /* See WasmActivation comment. */
+ js::WasmActivation * volatile wasmActivationStack_;
+
+ public:
+ /* If non-null, report JavaScript entry points to this monitor. */
+ JS::dbg::AutoEntryMonitor* entryMonitor;
+
+ /*
+ * Stack of debuggers that currently disallow debuggee execution.
+ *
+ * When we check for NX we are inside the debuggee compartment, and thus a
+ * stack of Debuggers that have prevented execution need to be tracked to
+ * enter the correct Debugger compartment to report the error.
+ */
+ js::EnterDebuggeeNoExecute* noExecuteDebuggerTop;
+
+ js::Activation* const* addressOfActivation() const {
+ return &activation_;
+ }
+ static unsigned offsetOfActivation() {
+ return offsetof(JSRuntime, activation_);
+ }
+
+ js::Activation* profilingActivation() const {
+ return profilingActivation_;
+ }
+ void* addressOfProfilingActivation() {
+ return (void*) &profilingActivation_;
+ }
+ static unsigned offsetOfProfilingActivation() {
+ return offsetof(JSRuntime, profilingActivation_);
+ }
+
+ uint32_t profilerSampleBufferGen() {
+ return profilerSampleBufferGen_;
+ }
+ void resetProfilerSampleBufferGen() {
+ profilerSampleBufferGen_ = 0;
+ }
+ void setProfilerSampleBufferGen(uint32_t gen) {
+ // May be called from sampler thread or signal handler; use
+ // compareExchange to make sure we have monotonic increase.
+ for (;;) {
+ uint32_t curGen = profilerSampleBufferGen_;
+ if (curGen >= gen)
+ break;
+
+ if (profilerSampleBufferGen_.compareExchange(curGen, gen))
+ break;
+ }
+ }
+
+ uint32_t profilerSampleBufferLapCount() {
+ MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
+ return profilerSampleBufferLapCount_;
+ }
+ void resetProfilerSampleBufferLapCount() {
+ profilerSampleBufferLapCount_ = 1;
+ }
+ void updateProfilerSampleBufferLapCount(uint32_t lapCount) {
+ MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
+
+ // May be called from sampler thread or signal handler; use
+ // compareExchange to make sure we have monotonic increase.
+ for (;;) {
+ uint32_t curLapCount = profilerSampleBufferLapCount_;
+ if (curLapCount >= lapCount)
+ break;
+
+ if (profilerSampleBufferLapCount_.compareExchange(curLapCount, lapCount))
+ break;
+ }
+ }
+
+ js::WasmActivation* wasmActivationStack() const {
+ return wasmActivationStack_;
+ }
+ static js::WasmActivation* innermostWasmActivation() {
+ js::PerThreadData* ptd = js::TlsPerThreadData.get();
+ return ptd ? ptd->runtimeFromMainThread()->wasmActivationStack_ : nullptr;
+ }
+
+ js::Activation* activation() const {
+ return activation_;
+ }
+
+ /*
+ * If non-null, another runtime guaranteed to outlive this one and whose
+ * permanent data may be used by this one where possible.
+ */
+ JSRuntime* parentRuntime;
+
+ private:
+#ifdef DEBUG
+ /* The number of child runtimes that have this runtime as their parent. */
+ mozilla::Atomic<size_t> childRuntimeCount;
+
+ class AutoUpdateChildRuntimeCount
+ {
+ JSRuntime* parent_;
+
+ public:
+ explicit AutoUpdateChildRuntimeCount(JSRuntime* parent)
+ : parent_(parent)
+ {
+ if (parent_)
+ parent_->childRuntimeCount++;
+ }
+
+ ~AutoUpdateChildRuntimeCount() {
+ if (parent_)
+ parent_->childRuntimeCount--;
+ }
+ };
+
+ AutoUpdateChildRuntimeCount updateChildRuntimeCount;
+#endif
+
+ mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
+
+ /* Call this to accumulate telemetry data. */
+ JSAccumulateTelemetryDataCallback telemetryCallback;
+ public:
+ // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
+ // histogram. |key| provides an additional key to identify the histogram.
+ // |sample| is the data to add to the histogram.
+ void addTelemetry(int id, uint32_t sample, const char* key = nullptr);
+
+ void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
+
+ enum InterruptMode {
+ RequestInterruptUrgent,
+ RequestInterruptCanWait
+ };
+
+ // Any thread can call requestInterrupt() to request that the main JS thread
+ // stop running and call the interrupt callback (allowing the interrupt
+ // callback to halt execution). To stop the main JS thread, requestInterrupt
+ // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
+ // UINTPTR_MAX). The JS engine must continually poll one of these fields
+ // and call handleInterrupt if either field has the interrupt value. (The
+ // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
+ // needs to guard on jitStackLimit_ in every function prologue to avoid
+ // stack overflow, so we avoid a second branch on interrupt_ by setting
+ // jitStackLimit_ to a value that is guaranteed to fail the guard.)
+ //
+ // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
+ // Atomic so, while the writes are guaranteed to eventually be visible to
+ // the main thread, it can happen in any order. handleInterrupt calls the
+ // interrupt callback if either is set, so it really doesn't matter as long
+ // as the JS engine is continually polling at least one field. In corner
+ // cases, this relaxed ordering could lead to an interrupt handler being
+ // called twice in succession after a single requestInterrupt call, but
+ // that's fine.
+ void requestInterrupt(InterruptMode mode);
+ bool handleInterrupt(JSContext* cx);
+
+ MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
+ return interrupt_;
+ }
+
+ // For read-only JIT use:
+ void* addressOfInterruptUint32() {
+ static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers");
+ return &interrupt_;
+ }
+
+ // Set when handling a segfault in the wasm signal handler.
+ bool handlingSegFault;
+
+ private:
+ // Set when we're handling an interrupt of JIT/wasm code in
+ // InterruptRunningJitCode.
+ mozilla::Atomic<bool> handlingJitInterrupt_;
+
+ public:
+ bool startHandlingJitInterrupt() {
+ // Return true if we changed handlingJitInterrupt_ from
+ // false to true.
+ return handlingJitInterrupt_.compareExchange(false, true);
+ }
+ void finishHandlingJitInterrupt() {
+ MOZ_ASSERT(handlingJitInterrupt_);
+ handlingJitInterrupt_ = false;
+ }
+ bool handlingJitInterrupt() const {
+ return handlingJitInterrupt_;
+ }
+
+ using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
+ InterruptCallbackVector interruptCallbacks;
+ bool interruptCallbackDisabled;
+
+ JSGetIncumbentGlobalCallback getIncumbentGlobalCallback;
+ JSEnqueuePromiseJobCallback enqueuePromiseJobCallback;
+ void* enqueuePromiseJobCallbackData;
+
+ JSPromiseRejectionTrackerCallback promiseRejectionTrackerCallback;
+ void* promiseRejectionTrackerCallbackData;
+
+ JS::StartAsyncTaskCallback startAsyncTaskCallback;
+ JS::FinishAsyncTaskCallback finishAsyncTaskCallback;
+ js::ExclusiveData<js::PromiseTaskPtrVector> promiseTasksToDestroy;
+
+ private:
+ /*
+ * Lock taken when using per-runtime or per-zone data that could otherwise
+ * be accessed simultaneously by both the main thread and another thread
+ * with an ExclusiveContext.
+ *
+ * Locking this only occurs if there is actually a thread other than the
+ * main thread with an ExclusiveContext which could access such data.
+ */
+ js::Mutex exclusiveAccessLock;
+#ifdef DEBUG
+ bool mainThreadHasExclusiveAccess;
+#endif
+
+ /* Number of non-main threads with an ExclusiveContext. */
+ size_t numExclusiveThreads;
+
+ friend class js::AutoLockForExclusiveAccess;
+
+ public:
+ void setUsedByExclusiveThread(JS::Zone* zone);
+ void clearUsedByExclusiveThread(JS::Zone* zone);
+
+ bool exclusiveThreadsPresent() const {
+ return numExclusiveThreads > 0;
+ }
+
+ // How many compartments there are across all zones. This number includes
+ // ExclusiveContext compartments, so it isn't necessarily equal to the
+ // number of compartments visited by CompartmentsIter.
+ size_t numCompartments;
+
+ /* Locale-specific callbacks for string conversion. */
+ const JSLocaleCallbacks* localeCallbacks;
+
+ /* Default locale for Internationalization API */
+ char* defaultLocale;
+
+ /* Default JSVersion. */
+ JSVersion defaultVersion_;
+
+ /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */
+ js::FutexRuntime fx;
+
+ private:
+ /* See comment for JS_AbortIfWrongThread in jsapi.h. */
+ js::Thread::Id ownerThread_;
+ size_t ownerThreadNative_;
+ friend bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt);
+ public:
+
+ size_t ownerThreadNative() const {
+ return ownerThreadNative_;
+ }
+
+ /* Temporary arena pool used while compiling and decompiling. */
+ static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
+ js::LifoAlloc tempLifoAlloc;
+
+ private:
+ js::jit::JitRuntime* jitRuntime_;
+
+ /*
+ * Self-hosting state cloned on demand into other compartments. Shared with the parent
+ * runtime if there is one.
+ */
+ js::NativeObject* selfHostingGlobal_;
+
+ static js::GlobalObject*
+ createSelfHostingGlobal(JSContext* cx);
+
+ bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name,
+ js::MutableHandleValue vp);
+ JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name);
+
+ /* Space for interpreter frames. */
+ js::InterpreterStack interpreterStack_;
+
+ js::jit::JitRuntime* createJitRuntime(JSContext* cx);
+
+ public:
+ js::jit::JitRuntime* getJitRuntime(JSContext* cx) {
+ return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx);
+ }
+ js::jit::JitRuntime* jitRuntime() const {
+ return jitRuntime_;
+ }
+ bool hasJitRuntime() const {
+ return !!jitRuntime_;
+ }
+ js::InterpreterStack& interpreterStack() {
+ return interpreterStack_;
+ }
+
+ inline JSContext* unsafeContextFromAnyThread();
+ inline JSContext* contextFromMainThread();
+
+ JSObject* getIncumbentGlobal(JSContext* cx);
+ bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise,
+ js::HandleObject incumbentGlobal);
+ void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
+ void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
+
+ private:
+ // Used to generate random keys for hash tables.
+ mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_;
+ mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator();
+
+ public:
+ mozilla::HashCodeScrambler randomHashCodeScrambler();
+ mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator();
+
+ //-------------------------------------------------------------------------
+ // Self-hosting support
+ //-------------------------------------------------------------------------
+
+ bool hasInitializedSelfHosting() const {
+ return selfHostingGlobal_;
+ }
+
+ bool initSelfHosting(JSContext* cx);
+ void finishSelfHosting();
+ void markSelfHostingGlobal(JSTracer* trc);
+ bool isSelfHostingGlobal(JSObject* global) {
+ return global == selfHostingGlobal_;
+ }
+ bool isSelfHostingCompartment(JSCompartment* comp) const;
+ bool isSelfHostingZone(const JS::Zone* zone) const;
+ bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
+ js::HandleAtom name, unsigned nargs,
+ js::HandleObject proto,
+ js::NewObjectKind newKind,
+ js::MutableHandleFunction fun);
+ bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
+ js::Handle<JSFunction*> targetFun);
+ bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
+ js::MutableHandleValue vp);
+ void assertSelfHostedFunctionHasCanonicalName(JSContext* cx, js::HandlePropertyName name);
+
+ //-------------------------------------------------------------------------
+ // Locale information
+ //-------------------------------------------------------------------------
+
+ /*
+ * Set the default locale for the ECMAScript Internationalization API
+ * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
+ * Note that the Internationalization API encourages clients to
+ * specify their own locales.
+ * The locale string remains owned by the caller.
+ */
+ bool setDefaultLocale(const char* locale);
+
+ /* Reset the default locale to OS defaults. */
+ void resetDefaultLocale();
+
+ /* Gets current default locale. String remains owned by context. */
+ const char* getDefaultLocale();
+
+ /* Shared Intl data for this runtime. */
+ js::SharedIntlData sharedIntlData;
+
+ void traceSharedIntlData(JSTracer* trc);
+
+ JSVersion defaultVersion() const { return defaultVersion_; }
+ void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
+
+ /* Base address of the native stack for the current thread. */
+ const uintptr_t nativeStackBase;
+
+ /* The native stack size limit that runtime should not exceed. */
+ size_t nativeStackQuota[js::StackKindCount];
+
+ /* Compartment destroy callback. */
+ JSDestroyCompartmentCallback destroyCompartmentCallback;
+
+ /* Compartment memory reporting callback. */
+ JSSizeOfIncludingThisCompartmentCallback sizeOfIncludingThisCompartmentCallback;
+
+ /* Zone destroy callback. */
+ JSZoneCallback destroyZoneCallback;
+
+ /* Zone sweep callback. */
+ JSZoneCallback sweepZoneCallback;
+
+ /* Call this to get the name of a compartment. */
+ JSCompartmentNameCallback compartmentNameCallback;
+
+ js::ActivityCallback activityCallback;
+ void* activityCallbackArg;
+ void triggerActivityCallback(bool active);
+
+ /* The request depth for this thread. */
+ unsigned requestDepth;
+
+#ifdef DEBUG
+ unsigned checkRequestDepth;
+#endif
+
+ /* Garbage collector state, used by jsgc.c. */
+ js::gc::GCRuntime gc;
+
+ /* Garbage collector state has been successfully initialized. */
+ bool gcInitialized;
+
+ bool hasZealMode(js::gc::ZealMode mode) { return gc.hasZealMode(mode); }
+
+ void lockGC() {
+ gc.lockGC();
+ }
+
+ void unlockGC() {
+ gc.unlockGC();
+ }
+
+#ifdef JS_SIMULATOR
+ js::jit::Simulator* simulator_;
+#endif
+
+ public:
+#ifdef JS_SIMULATOR
+ js::jit::Simulator* simulator() const;
+ uintptr_t* addressOfSimulatorStackLimit();
+#endif
+
+ /* Strong references on scripts held for PCCount profiling API. */
+ JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector;
+
+ /* Code coverage output. */
+ js::coverage::LCovRuntime lcovOutput;
+
+ /* Well-known numbers. */
+ const js::Value NaNValue;
+ const js::Value negativeInfinityValue;
+ const js::Value positiveInfinityValue;
+
+ js::PropertyName* emptyString;
+
+ mozilla::UniquePtr<js::SourceHook> sourceHook;
+
+ /* SPS profiling metadata */
+ js::SPSProfiler spsProfiler;
+
+ /* If true, new scripts must be created with PC counter information. */
+ bool profilingScripts;
+
+ /* Whether sampling should be enabled or not. */
+ private:
+ mozilla::Atomic<bool, mozilla::SequentiallyConsistent> suppressProfilerSampling;
+
+ public:
+ bool isProfilerSamplingEnabled() const {
+ return !suppressProfilerSampling;
+ }
+ void disableProfilerSampling() {
+ suppressProfilerSampling = true;
+ }
+ void enableProfilerSampling() {
+ suppressProfilerSampling = false;
+ }
+
+ /* Had an out-of-memory error which did not populate an exception. */
+ bool hadOutOfMemory;
+
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+ /* We are currently running a simulated OOM test. */
+ bool runningOOMTest;
+#endif
+
+ /*
+ * Allow relazifying functions in compartments that are active. This is
+ * only used by the relazifyFunctions() testing function.
+ */
+ bool allowRelazificationForTesting;
+
+ /* Linked list of all Debugger objects in the runtime. */
+ mozilla::LinkedList<js::Debugger> debuggerList;
+
+ /*
+ * Head of circular list of all enabled Debuggers that have
+ * onNewGlobalObject handler methods established.
+ */
+ JSCList onNewGlobalObjectWatchers;
+
+#if defined(XP_DARWIN)
+ js::wasm::MachExceptionHandler wasmMachExceptionHandler;
+#endif
+
+ private:
+ js::FreeOp* defaultFreeOp_;
+
+ public:
+ js::FreeOp* defaultFreeOp() {
+ MOZ_ASSERT(defaultFreeOp_);
+ return defaultFreeOp_;
+ }
+
+ uint32_t debuggerMutations;
+
+ const JSSecurityCallbacks* securityCallbacks;
+ const js::DOMCallbacks* DOMcallbacks;
+ JSDestroyPrincipalsOp destroyPrincipals;
+ JSReadPrincipalsOp readPrincipals;
+
+ /* Optional warning reporter. */
+ JS::WarningReporter warningReporter;
+
+ JS::BuildIdOp buildIdOp;
+
+ /* AsmJSCache callbacks are runtime-wide. */
+ JS::AsmJSCacheOps asmJSCacheOps;
+
+ /*
+ * The propertyRemovals counter is incremented for every JSObject::clear,
+ * and for each JSObject::remove method call that frees a slot in the given
+ * object. See js_NativeGet and js_NativeSet in jsobj.cpp.
+ */
+ uint32_t propertyRemovals;
+
+#if !EXPOSE_INTL_API
+ /* Number localization, used by jsnum.cpp. */
+ const char* thousandsSeparator;
+ const char* decimalSeparator;
+ const char* numGrouping;
+#endif
+
+ private:
+ mozilla::Maybe<js::SharedImmutableStringsCache> sharedImmutableStrings_;
+
+ public:
+ // If this particular JSRuntime has a SharedImmutableStringsCache, return a
+ // pointer to it, otherwise return nullptr.
+ js::SharedImmutableStringsCache* maybeThisRuntimeSharedImmutableStrings() {
+ return sharedImmutableStrings_.isSome() ? &*sharedImmutableStrings_ : nullptr;
+ }
+
+ // Get a reference to this JSRuntime's or its parent's
+ // SharedImmutableStringsCache.
+ js::SharedImmutableStringsCache& sharedImmutableStrings() {
+ MOZ_ASSERT_IF(parentRuntime, !sharedImmutableStrings_);
+ MOZ_ASSERT_IF(!parentRuntime, sharedImmutableStrings_);
+ return parentRuntime ? parentRuntime->sharedImmutableStrings() : *sharedImmutableStrings_;
+ }
+
+ // Count of AutoKeepAtoms instances on the main thread's stack. When any
+ // instances exist, atoms in the runtime will not be collected. Threads
+ // with an ExclusiveContext do not increment this value, but the presence
+ // of any such threads also inhibits collection of atoms. We don't scan the
+ // stacks of exclusive threads, so we need to avoid collecting their
+ // objects in another way. The only GC thing pointers they have are to
+ // their exclusive compartment (which is not collected) or to the atoms
+ // compartment. Therefore, we avoid collecting the atoms compartment when
+ // exclusive threads are running.
+ private:
+ unsigned keepAtoms_;
+ friend class js::AutoKeepAtoms;
+ public:
+ bool keepAtoms() {
+ return keepAtoms_ != 0 || exclusiveThreadsPresent();
+ }
+
+ private:
+ const JSPrincipals* trustedPrincipals_;
+ public:
+ void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
+ const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
+
+ private:
+ bool beingDestroyed_;
+ public:
+ bool isBeingDestroyed() const {
+ return beingDestroyed_;
+ }
+
+ private:
+ // Set of all atoms other than those in permanentAtoms and staticStrings.
+ // Reading or writing this set requires the calling thread to have an
+ // ExclusiveContext and hold a lock. Use AutoLockForExclusiveAccess.
+ js::AtomSet* atoms_;
+
+ // Compartment and associated zone containing all atoms in the runtime, as
+ // well as runtime wide IonCode stubs. Modifying the contents of this
+ // compartment requires the calling thread to have an ExclusiveContext and
+ // hold a lock. Use AutoLockForExclusiveAccess.
+ JSCompartment* atomsCompartment_;
+
+ // Set of all live symbols produced by Symbol.for(). All such symbols are
+ // allocated in the atomsCompartment. Reading or writing the symbol
+ // registry requires the calling thread to have an ExclusiveContext and
+ // hold a lock. Use AutoLockForExclusiveAccess.
+ js::SymbolRegistry symbolRegistry_;
+
+ public:
+ bool initializeAtoms(JSContext* cx);
+ void finishAtoms();
+ bool atomsAreFinished() const { return !atoms_; }
+
+ void sweepAtoms();
+
+ js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
+ return *atoms_;
+ }
+ JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) {
+ return atomsCompartment_;
+ }
+
+ bool isAtomsCompartment(JSCompartment* comp) {
+ return comp == atomsCompartment_;
+ }
+
+ // The atoms compartment is the only one in its zone.
+ inline bool isAtomsZone(const JS::Zone* zone) const;
+
+ bool activeGCInAtomsZone();
+
+ js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
+ return symbolRegistry_;
+ }
+
+ // Permanent atoms are fixed during initialization of the runtime and are
+ // not modified or collected until the runtime is destroyed. These may be
+ // shared with another, longer living runtime through |parentRuntime| and
+ // can be freely accessed with no locking necessary.
+
+ // Permanent atoms pre-allocated for general use.
+ js::StaticStrings* staticStrings;
+
+ // Cached pointers to various permanent property names.
+ JSAtomState* commonNames;
+
+ // All permanent atoms in the runtime, other than those in staticStrings.
+ // Unlike |atoms_|, access to this does not require
+ // AutoLockForExclusiveAccess because it is frozen and thus read-only.
+ js::FrozenAtomSet* permanentAtoms;
+
+ bool transformToPermanentAtoms(JSContext* cx);
+
+ // Cached well-known symbols (ES6 rev 24 6.1.5.1). Like permanent atoms,
+ // these are shared with the parentRuntime, if any.
+ js::WellKnownSymbols* wellKnownSymbols;
+
+ const JSWrapObjectCallbacks* wrapObjectCallbacks;
+ js::PreserveWrapperCallback preserveWrapperCallback;
+
+ // Table of bytecode and other data that may be shared across scripts
+ // within the runtime. This may be modified by threads with an
+ // ExclusiveContext and requires a lock.
+ private:
+ js::ScriptDataTable scriptDataTable_;
+ public:
+ js::ScriptDataTable& scriptDataTable(js::AutoLockForExclusiveAccess& lock) {
+ return scriptDataTable_;
+ }
+
+ bool jitSupportsFloatingPoint;
+ bool jitSupportsUnalignedAccesses;
+ bool jitSupportsSimd;
+
+ // Cache for jit::GetPcScript().
+ js::jit::PcScriptCache* ionPcScriptCache;
+
+ js::ScriptEnvironmentPreparer* scriptEnvironmentPreparer;
+
+ js::CTypesActivityCallback ctypesActivityCallback;
+
+ private:
+ static mozilla::Atomic<size_t> liveRuntimesCount;
+
+ public:
+ static bool hasLiveRuntimes() {
+ return liveRuntimesCount > 0;
+ }
+
+ protected:
+ explicit JSRuntime(JSRuntime* parentRuntime);
+
+ // destroyRuntime is used instead of a destructor, to ensure the downcast
+ // to JSContext remains valid. The final GC triggered here depends on this.
+ void destroyRuntime();
+
+ bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
+
+ JSRuntime* thisFromCtor() { return this; }
+
+ public:
+ /*
+ * Call this after allocating memory held by GC things, to update memory
+ * pressure counters or report the OOM error if necessary. If oomError and
+ * cx is not null the function also reports OOM error.
+ *
+ * The function must be called outside the GC lock and in case of OOM error
+ * the caller must ensure that no deadlock possible during OOM reporting.
+ */
+ void updateMallocCounter(size_t nbytes);
+ void updateMallocCounter(JS::Zone* zone, size_t nbytes);
+
+ void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
+
+ /*
+ * This should be called after system malloc/calloc/realloc returns nullptr
+ * to try to recove some memory or to report an error. For realloc, the
+ * original pointer must be passed as reallocPtr.
+ *
+ * The function must be called outside the GC lock.
+ */
+ JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
+ void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
+
+ /* onOutOfMemory but can call the largeAllocationFailureCallback. */
+ JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
+ void* reallocPtr = nullptr);
+
+ void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime);
+
+ private:
+ const js::Class* windowProxyClass_;
+
+ // Settings for how helper threads can be used.
+ bool offthreadIonCompilationEnabled_;
+ bool parallelParsingEnabled_;
+
+ bool autoWritableJitCodeActive_;
+
+ public:
+
+ // Note: these values may be toggled dynamically (in response to about:config
+ // prefs changing).
+ void setOffthreadIonCompilationEnabled(bool value) {
+ offthreadIonCompilationEnabled_ = value;
+ }
+ bool canUseOffthreadIonCompilation() const {
+ return offthreadIonCompilationEnabled_;
+ }
+ void setParallelParsingEnabled(bool value) {
+ parallelParsingEnabled_ = value;
+ }
+ bool canUseParallelParsing() const {
+ return parallelParsingEnabled_;
+ }
+
+ void toggleAutoWritableJitCodeActive(bool b) {
+ MOZ_ASSERT(autoWritableJitCodeActive_ != b, "AutoWritableJitCode should not be nested.");
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+ autoWritableJitCodeActive_ = b;
+ }
+
+ const js::Class* maybeWindowProxyClass() const {
+ return windowProxyClass_;
+ }
+ void setWindowProxyClass(const js::Class* clasp) {
+ windowProxyClass_ = clasp;
+ }
+
+#ifdef DEBUG
+ public:
+ js::AutoEnterPolicy* enteredPolicy;
+#endif
+
+ /* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */
+ JS::LargeAllocationFailureCallback largeAllocationFailureCallback;
+ void* largeAllocationFailureCallbackData;
+
+ /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
+ JS::OutOfMemoryCallback oomCallback;
+ void* oomCallbackData;
+
+ /*
+ * These variations of malloc/calloc/realloc will call the
+ * large-allocation-failure callback on OOM and retry the allocation.
+ */
+
+ static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
+
+ template <typename T>
+ T* pod_callocCanGC(size_t numElems) {
+ T* p = pod_calloc<T>(numElems);
+ if (MOZ_LIKELY(!!p))
+ return p;
+ size_t bytes;
+ if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
+ reportAllocationOverflow();
+ return nullptr;
+ }
+ return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
+ }
+
+ template <typename T>
+ T* pod_reallocCanGC(T* p, size_t oldSize, size_t newSize) {
+ T* p2 = pod_realloc<T>(p, oldSize, newSize);
+ if (MOZ_LIKELY(!!p2))
+ return p2;
+ size_t bytes;
+ if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
+ reportAllocationOverflow();
+ return nullptr;
+ }
+ return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p));
+ }
+
+ /*
+ * Debugger.Memory functions like takeCensus use this embedding-provided
+ * function to assess the size of malloc'd blocks of memory.
+ */
+ mozilla::MallocSizeOf debuggerMallocSizeOf;
+
+ /* Last time at which an animation was played for this runtime. */
+ int64_t lastAnimationTime;
+
+ public:
+ js::PerformanceMonitoring performanceMonitoring;
+
+ private:
+ /* List of Ion compilation waiting to get linked. */
+ typedef mozilla::LinkedList<js::jit::IonBuilder> IonBuilderList;
+
+ IonBuilderList ionLazyLinkList_;
+ size_t ionLazyLinkListSize_;
+
+ public:
+ IonBuilderList& ionLazyLinkList();
+
+ size_t ionLazyLinkListSize() {
+ return ionLazyLinkListSize_;
+ }
+
+ void ionLazyLinkListRemove(js::jit::IonBuilder* builder);
+ void ionLazyLinkListAdd(js::jit::IonBuilder* builder);
+
+ private:
+ /* The stack format for the current runtime. Only valid on non-child
+ * runtimes. */
+ mozilla::Atomic<js::StackFormat, mozilla::ReleaseAcquire> stackFormat_;
+
+ public:
+ js::StackFormat stackFormat() const {
+ const JSRuntime* rt = this;
+ while (rt->parentRuntime) {
+ MOZ_ASSERT(rt->stackFormat_ == js::StackFormat::Default);
+ rt = rt->parentRuntime;
+ }
+ MOZ_ASSERT(rt->stackFormat_ != js::StackFormat::Default);
+ return rt->stackFormat_;
+ }
+ void setStackFormat(js::StackFormat format) {
+ MOZ_ASSERT(!parentRuntime);
+ MOZ_ASSERT(format != js::StackFormat::Default);
+ stackFormat_ = format;
+ }
+
+ // For inherited heap state accessors.
+ friend class js::gc::AutoTraceSession;
+ friend class JS::AutoEnterCycleCollection;
+};
+
+namespace js {
+
+static inline JSContext*
+GetJSContextFromMainThread()
+{
+ return js::TlsPerThreadData.get()->contextFromMainThread();
+}
+
+/*
+ * Flags accompany script version data so that a) dynamically created scripts
+ * can inherit their caller's compile-time properties and b) scripts can be
+ * appropriately compared in the eval cache across global option changes. An
+ * example of the latter is enabling the top-level-anonymous-function-is-error
+ * option: subsequent evals of the same, previously-valid script text may have
+ * become invalid.
+ */
+namespace VersionFlags {
+static const unsigned MASK = 0x0FFF; /* see JSVersion in jspubtd.h */
+} /* namespace VersionFlags */
+
+static inline JSVersion
+VersionNumber(JSVersion version)
+{
+ return JSVersion(uint32_t(version) & VersionFlags::MASK);
+}
+
+static inline JSVersion
+VersionExtractFlags(JSVersion version)
+{
+ return JSVersion(uint32_t(version) & ~VersionFlags::MASK);
+}
+
+static inline void
+VersionCopyFlags(JSVersion* version, JSVersion from)
+{
+ *version = JSVersion(VersionNumber(*version) | VersionExtractFlags(from));
+}
+
+static inline bool
+VersionHasFlags(JSVersion version)
+{
+ return !!VersionExtractFlags(version);
+}
+
+static inline bool
+VersionIsKnown(JSVersion version)
+{
+ return VersionNumber(version) != JSVERSION_UNKNOWN;
+}
+
+inline void
+FreeOp::free_(void* p)
+{
+ js_free(p);
+}
+
+inline void
+FreeOp::freeLater(void* p)
+{
+ // FreeOps other than the defaultFreeOp() are constructed on the stack,
+ // and won't hold onto the pointers to free indefinitely.
+ MOZ_ASSERT(!isDefaultFreeOp());
+
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!freeLaterList.append(p))
+ oomUnsafe.crash("FreeOp::freeLater");
+}
+
+inline bool
+FreeOp::appendJitPoisonRange(const jit::JitPoisonRange& range)
+{
+ // FreeOps other than the defaultFreeOp() are constructed on the stack,
+ // and won't hold onto the pointers to free indefinitely.
+ MOZ_ASSERT(!isDefaultFreeOp());
+
+ return jitPoisonRanges.append(range);
+}
+
+/*
+ * RAII class that takes the GC lock while it is live.
+ *
+ * Note that the lock may be temporarily released by use of AutoUnlockGC when
+ * passed a non-const reference to this class.
+ */
+class MOZ_RAII AutoLockGC
+{
+ public:
+ explicit AutoLockGC(JSRuntime* rt
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : runtime_(rt)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ lock();
+ }
+
+ ~AutoLockGC() {
+ unlock();
+ }
+
+ void lock() {
+ MOZ_ASSERT(lockGuard_.isNothing());
+ lockGuard_.emplace(runtime_->gc.lock);
+ }
+
+ void unlock() {
+ MOZ_ASSERT(lockGuard_.isSome());
+ lockGuard_.reset();
+ }
+
+ js::LockGuard<js::Mutex>& guard() {
+ return lockGuard_.ref();
+ }
+
+ private:
+ JSRuntime* runtime_;
+ mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ AutoLockGC(const AutoLockGC&) = delete;
+ AutoLockGC& operator=(const AutoLockGC&) = delete;
+};
+
+class MOZ_RAII AutoUnlockGC
+{
+ public:
+ explicit AutoUnlockGC(AutoLockGC& lock
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : lock(lock)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ lock.unlock();
+ }
+
+ ~AutoUnlockGC() {
+ lock.lock();
+ }
+
+ private:
+ AutoLockGC& lock;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ AutoUnlockGC(const AutoUnlockGC&) = delete;
+ AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
+};
+
+class MOZ_RAII AutoKeepAtoms
+{
+ PerThreadData* pt;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ public:
+ explicit AutoKeepAtoms(PerThreadData* pt
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : pt(pt)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) {
+ rt->keepAtoms_++;
+ } else {
+ // This should be a thread with an exclusive context, which will
+ // always inhibit collection of atoms.
+ MOZ_ASSERT(pt->exclusiveThreadsPresent());
+ }
+ }
+ ~AutoKeepAtoms() {
+ if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) {
+ MOZ_ASSERT(rt->keepAtoms_);
+ rt->keepAtoms_--;
+ if (rt->gc.fullGCForAtomsRequested() && !rt->keepAtoms())
+ rt->gc.triggerFullGCForAtoms();
+ }
+ }
+};
+
+inline JSRuntime*
+PerThreadData::runtimeFromMainThread()
+{
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
+ return runtime_;
+}
+
+inline JSRuntime*
+PerThreadData::runtimeIfOnOwnerThread()
+{
+ return (runtime_ && CurrentThreadCanAccessRuntime(runtime_)) ? runtime_ : nullptr;
+}
+
+inline bool
+PerThreadData::exclusiveThreadsPresent()
+{
+ return runtime_->exclusiveThreadsPresent();
+}
+
+/************************************************************************/
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(Value* vec, size_t len)
+{
+ mozilla::PodZero(vec, len);
+}
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(Value* beg, Value* end)
+{
+ mozilla::PodZero(beg, end - beg);
+}
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(jsid* beg, jsid* end)
+{
+ for (jsid* id = beg; id != end; ++id)
+ *id = INT_TO_JSID(0);
+}
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(jsid* vec, size_t len)
+{
+ MakeRangeGCSafe(vec, vec + len);
+}
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(Shape** beg, Shape** end)
+{
+ mozilla::PodZero(beg, end - beg);
+}
+
+static MOZ_ALWAYS_INLINE void
+MakeRangeGCSafe(Shape** vec, size_t len)
+{
+ mozilla::PodZero(vec, len);
+}
+
+static MOZ_ALWAYS_INLINE void
+SetValueRangeToUndefined(Value* beg, Value* end)
+{
+ for (Value* v = beg; v != end; ++v)
+ v->setUndefined();
+}
+
+static MOZ_ALWAYS_INLINE void
+SetValueRangeToUndefined(Value* vec, size_t len)
+{
+ SetValueRangeToUndefined(vec, vec + len);
+}
+
+static MOZ_ALWAYS_INLINE void
+SetValueRangeToNull(Value* beg, Value* end)
+{
+ for (Value* v = beg; v != end; ++v)
+ v->setNull();
+}
+
+static MOZ_ALWAYS_INLINE void
+SetValueRangeToNull(Value* vec, size_t len)
+{
+ SetValueRangeToNull(vec, vec + len);
+}
+
+/*
+ * Allocation policy that uses JSRuntime::pod_malloc and friends, so that
+ * memory pressure is properly accounted for. This is suitable for
+ * long-lived objects owned by the JSRuntime.
+ *
+ * Since it doesn't hold a JSContext (those may not live long enough), it
+ * can't report out-of-memory conditions itself; the caller must check for
+ * OOM and take the appropriate action.
+ *
+ * FIXME bug 647103 - replace these *AllocPolicy names.
+ */
+class RuntimeAllocPolicy
+{
+ JSRuntime* const runtime;
+
+ public:
+ MOZ_IMPLICIT RuntimeAllocPolicy(JSRuntime* rt) : runtime(rt) {}
+
+ template <typename T>
+ T* maybe_pod_malloc(size_t numElems) {
+ return runtime->maybe_pod_malloc<T>(numElems);
+ }
+
+ template <typename T>
+ T* maybe_pod_calloc(size_t numElems) {
+ return runtime->maybe_pod_calloc<T>(numElems);
+ }
+
+ template <typename T>
+ T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
+ return runtime->maybe_pod_realloc<T>(p, oldSize, newSize);
+ }
+
+ template <typename T>
+ T* pod_malloc(size_t numElems) {
+ return runtime->pod_malloc<T>(numElems);
+ }
+
+ template <typename T>
+ T* pod_calloc(size_t numElems) {
+ return runtime->pod_calloc<T>(numElems);
+ }
+
+ template <typename T>
+ T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
+ return runtime->pod_realloc<T>(p, oldSize, newSize);
+ }
+
+ void free_(void* p) { js_free(p); }
+ void reportAllocOverflow() const {}
+
+ bool checkSimulatedOOM() const {
+ return !js::oom::ShouldFailWithOOM();
+ }
+};
+
+extern const JSSecurityCallbacks NullSecurityCallbacks;
+
+// Debugging RAII class which marks the current thread as performing an Ion
+// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
+class MOZ_RAII AutoEnterIonCompilation
+{
+ public:
+ explicit AutoEnterIonCompilation(bool safeForMinorGC
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+#ifdef DEBUG
+ PerThreadData* pt = js::TlsPerThreadData.get();
+ MOZ_ASSERT(!pt->ionCompiling);
+ MOZ_ASSERT(!pt->ionCompilingSafeForMinorGC);
+ pt->ionCompiling = true;
+ pt->ionCompilingSafeForMinorGC = safeForMinorGC;
+#endif
+ }
+
+ ~AutoEnterIonCompilation() {
+#ifdef DEBUG
+ PerThreadData* pt = js::TlsPerThreadData.get();
+ MOZ_ASSERT(pt->ionCompiling);
+ pt->ionCompiling = false;
+ pt->ionCompilingSafeForMinorGC = false;
+#endif
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+namespace gc {
+
+// In debug builds, set/unset the performing GC flag for the current thread.
+struct MOZ_RAII AutoSetThreadIsPerformingGC
+{
+#ifdef DEBUG
+ AutoSetThreadIsPerformingGC()
+ : threadData_(js::TlsPerThreadData.get())
+ {
+ MOZ_ASSERT(!threadData_->performingGC);
+ threadData_->performingGC = true;
+ }
+
+ ~AutoSetThreadIsPerformingGC() {
+ MOZ_ASSERT(threadData_->performingGC);
+ threadData_->performingGC = false;
+ }
+
+ private:
+ PerThreadData* threadData_;
+#else
+ AutoSetThreadIsPerformingGC() {}
+#endif
+};
+
+// In debug builds, set/unset the GC sweeping flag for the current thread.
+struct MOZ_RAII AutoSetThreadIsSweeping
+{
+#ifdef DEBUG
+ AutoSetThreadIsSweeping()
+ : threadData_(js::TlsPerThreadData.get())
+ {
+ MOZ_ASSERT(!threadData_->gcSweeping);
+ threadData_->gcSweeping = true;
+ }
+
+ ~AutoSetThreadIsSweeping() {
+ MOZ_ASSERT(threadData_->gcSweeping);
+ threadData_->gcSweeping = false;
+ }
+
+ private:
+ PerThreadData* threadData_;
+#else
+ AutoSetThreadIsSweeping() {}
+#endif
+};
+
+} // namespace gc
+
+/*
+ * Provides a delete policy that can be used for objects which have their
+ * lifetime managed by the GC and can only safely be destroyed while the nursery
+ * is empty.
+ *
+ * This is necessary when initializing such an object may fail after the initial
+ * allocation. The partially-initialized object must be destroyed, but it may
+ * not be safe to do so at the current time. This policy puts the object on a
+ * queue to be destroyed at a safe time.
+ */
+template <typename T>
+struct GCManagedDeletePolicy
+{
+ void operator()(const T* ptr) {
+ if (ptr) {
+ JSRuntime* rt = TlsPerThreadData.get()->runtimeIfOnOwnerThread();
+ if (rt && rt->gc.nursery.isEnabled()) {
+ // The object may contain nursery pointers and must only be
+ // destroyed after a minor GC.
+ rt->gc.callAfterMinorGC(deletePtr, const_cast<T*>(ptr));
+ } else {
+ // The object cannot contain nursery pointers so can be
+ // destroyed immediately.
+ gc::AutoSetThreadIsSweeping threadIsSweeping;
+ js_delete(const_cast<T*>(ptr));
+ }
+ }
+ }
+
+ private:
+ static void deletePtr(void* data) {
+ js_delete(reinterpret_cast<T*>(data));
+ }
+};
+
+} /* namespace js */
+
+namespace JS {
+
+template <typename T>
+struct DeletePolicy<js::GCPtr<T>> : public js::GCManagedDeletePolicy<js::GCPtr<T>>
+{};
+
+// Scope data that contain GCPtrs must use the correct DeletePolicy.
+//
+// This is defined here because vm/Scope.h cannot #include "vm/Runtime.h"
+
+template <>
+struct DeletePolicy<js::FunctionScope::Data>
+ : public js::GCManagedDeletePolicy<js::FunctionScope::Data>
+{ };
+
+template <>
+struct DeletePolicy<js::ModuleScope::Data>
+ : public js::GCManagedDeletePolicy<js::ModuleScope::Data>
+{ };
+
+} /* namespace JS */
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif /* vm_Runtime_h */
diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp
new file mode 100644
index 000000000..8872af8d2
--- /dev/null
+++ b/js/src/vm/SPSProfiler.cpp
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SPSProfiler.h"
+
+#include "mozilla/DebugOnly.h"
+
+#include "jsnum.h"
+#include "jsprf.h"
+#include "jsscript.h"
+
+#include "jit/BaselineFrame.h"
+#include "jit/BaselineJIT.h"
+#include "jit/JitcodeMap.h"
+#include "jit/JitFrameIterator.h"
+#include "jit/JitFrames.h"
+#include "vm/StringBuffer.h"
+
+using namespace js;
+
+using mozilla::DebugOnly;
+
+SPSProfiler::SPSProfiler(JSRuntime* rt)
+ : rt(rt),
+ strings(mutexid::SPSProfilerStrings),
+ stack_(nullptr),
+ size_(nullptr),
+ max_(0),
+ slowAssertions(false),
+ enabled_(false),
+ eventMarker_(nullptr)
+{
+ MOZ_ASSERT(rt != nullptr);
+}
+
+bool
+SPSProfiler::init()
+{
+ auto locked = strings.lock();
+ if (!locked->init())
+ return false;
+
+ return true;
+}
+
+void
+SPSProfiler::setProfilingStack(ProfileEntry* stack, uint32_t* size, uint32_t max)
+{
+ MOZ_ASSERT_IF(size_ && *size_ != 0, !enabled());
+ MOZ_ASSERT(strings.lock()->initialized());
+
+ stack_ = stack;
+ size_ = size;
+ max_ = max;
+}
+
+void
+SPSProfiler::setEventMarker(void (*fn)(const char*))
+{
+ eventMarker_ = fn;
+}
+
+void
+SPSProfiler::enable(bool enabled)
+{
+ MOZ_ASSERT(installed());
+
+ if (enabled_ == enabled)
+ return;
+
+ /*
+ * Ensure all future generated code will be instrumented, or that all
+ * currently instrumented code is discarded
+ */
+ ReleaseAllJITCode(rt->defaultFreeOp());
+
+ // This function is called when the Gecko profiler makes a new TableTicker
+ // (and thus, a new circular buffer). Set all current entries in the
+ // JitcodeGlobalTable as expired and reset the buffer generation and lap
+ // count.
+ if (rt->hasJitRuntime() && rt->jitRuntime()->hasJitcodeGlobalTable())
+ rt->jitRuntime()->getJitcodeGlobalTable()->setAllEntriesAsExpired(rt);
+ rt->resetProfilerSampleBufferGen();
+ rt->resetProfilerSampleBufferLapCount();
+
+ // Ensure that lastProfilingFrame is null before 'enabled' becomes true.
+ if (rt->jitActivation) {
+ rt->jitActivation->setLastProfilingFrame(nullptr);
+ rt->jitActivation->setLastProfilingCallSite(nullptr);
+ }
+
+ enabled_ = enabled;
+
+ /* Toggle SPS-related jumps on baseline jitcode.
+ * The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not
+ * jitcode for scripts with active frames on the stack. These scripts need to have
+ * their profiler state toggled so they behave properly.
+ */
+ jit::ToggleBaselineProfiling(rt, enabled);
+
+ /* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
+ * stack.
+ */
+ if (rt->jitActivation) {
+ // Walk through all activations, and set their lastProfilingFrame appropriately.
+ if (enabled) {
+ void* lastProfilingFrame = GetTopProfilingJitFrame(rt->jitTop);
+ jit::JitActivation* jitActivation = rt->jitActivation;
+ while (jitActivation) {
+ jitActivation->setLastProfilingFrame(lastProfilingFrame);
+ jitActivation->setLastProfilingCallSite(nullptr);
+
+ lastProfilingFrame = GetTopProfilingJitFrame(jitActivation->prevJitTop());
+ jitActivation = jitActivation->prevJitActivation();
+ }
+ } else {
+ jit::JitActivation* jitActivation = rt->jitActivation;
+ while (jitActivation) {
+ jitActivation->setLastProfilingFrame(nullptr);
+ jitActivation->setLastProfilingCallSite(nullptr);
+ jitActivation = jitActivation->prevJitActivation();
+ }
+ }
+ }
+}
+
+/* Lookup the string for the function/script, creating one if necessary */
+const char*
+SPSProfiler::profileString(JSScript* script, JSFunction* maybeFun)
+{
+ auto locked = strings.lock();
+ MOZ_ASSERT(locked->initialized());
+
+ ProfileStringMap::AddPtr s = locked->lookupForAdd(script);
+
+ if (!s) {
+ auto str = allocProfileString(script, maybeFun);
+ if (!str || !locked->add(s, script, mozilla::Move(str)))
+ return nullptr;
+ }
+
+ return s->value().get();
+}
+
+void
+SPSProfiler::onScriptFinalized(JSScript* script)
+{
+ /*
+ * This function is called whenever a script is destroyed, regardless of
+ * whether profiling has been turned on, so don't invoke a function on an
+ * invalid hash set. Also, even if profiling was enabled but then turned
+ * off, we still want to remove the string, so no check of enabled() is
+ * done.
+ */
+ auto locked = strings.lock();
+ if (!locked->initialized())
+ return;
+ if (ProfileStringMap::Ptr entry = locked->lookup(script))
+ locked->remove(entry);
+}
+
+void
+SPSProfiler::markEvent(const char* event)
+{
+ MOZ_ASSERT(enabled());
+ if (eventMarker_) {
+ JS::AutoSuppressGCAnalysis nogc;
+ eventMarker_(event);
+ }
+}
+
+bool
+SPSProfiler::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
+{
+ const char* str = profileString(script, maybeFun);
+ if (str == nullptr) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+#ifdef DEBUG
+ // In debug builds, assert the JS pseudo frames already on the stack
+ // have a non-null pc. Only look at the top frames to avoid quadratic
+ // behavior.
+ if (*size_ > 0 && *size_ - 1 < max_) {
+ size_t start = (*size_ > 4) ? *size_ - 4 : 0;
+ for (size_t i = start; i < *size_ - 1; i++)
+ MOZ_ASSERT_IF(stack_[i].isJs(), stack_[i].pc() != nullptr);
+ }
+#endif
+
+ push(str, nullptr, script, script->code(), /* copy = */ true);
+ return true;
+}
+
+void
+SPSProfiler::exit(JSScript* script, JSFunction* maybeFun)
+{
+ pop();
+
+#ifdef DEBUG
+ /* Sanity check to make sure push/pop balanced */
+ if (*size_ < max_) {
+ const char* str = profileString(script, maybeFun);
+ /* Can't fail lookup because we should already be in the set */
+ MOZ_ASSERT(str != nullptr);
+
+ // Bug 822041
+ if (!stack_[*size_].isJs()) {
+ fprintf(stderr, "--- ABOUT TO FAIL ASSERTION ---\n");
+ fprintf(stderr, " stack=%p size=%d/%d\n", (void*) stack_, *size_, max_);
+ for (int32_t i = *size_; i >= 0; i--) {
+ if (stack_[i].isJs())
+ fprintf(stderr, " [%d] JS %s\n", i, stack_[i].label());
+ else
+ fprintf(stderr, " [%d] C line %d %s\n", i, stack_[i].line(), stack_[i].label());
+ }
+ }
+
+ MOZ_ASSERT(stack_[*size_].isJs());
+ MOZ_ASSERT(stack_[*size_].script() == script);
+ MOZ_ASSERT(strcmp((const char*) stack_[*size_].label(), str) == 0);
+ stack_[*size_].setLabel(nullptr);
+ stack_[*size_].setPC(nullptr);
+ }
+#endif
+}
+
+void
+SPSProfiler::beginPseudoJS(const char* string, void* sp)
+{
+ /* these operations cannot be re-ordered, so volatile-ize operations */
+ volatile ProfileEntry* stack = stack_;
+ volatile uint32_t* size = size_;
+ uint32_t current = *size;
+
+ MOZ_ASSERT(installed());
+ if (current < max_) {
+ stack[current].setLabel(string);
+ stack[current].initCppFrame(sp, 0);
+ stack[current].setFlag(ProfileEntry::BEGIN_PSEUDO_JS);
+ }
+ *size = current + 1;
+}
+
+void
+SPSProfiler::push(const char* string, void* sp, JSScript* script, jsbytecode* pc, bool copy,
+ ProfileEntry::Category category)
+{
+ MOZ_ASSERT_IF(sp != nullptr, script == nullptr && pc == nullptr);
+ MOZ_ASSERT_IF(sp == nullptr, script != nullptr && pc != nullptr);
+
+ /* these operations cannot be re-ordered, so volatile-ize operations */
+ volatile ProfileEntry* stack = stack_;
+ volatile uint32_t* size = size_;
+ uint32_t current = *size;
+
+ MOZ_ASSERT(installed());
+ if (current < max_) {
+ volatile ProfileEntry& entry = stack[current];
+
+ if (sp != nullptr) {
+ entry.initCppFrame(sp, 0);
+ MOZ_ASSERT(entry.flags() == js::ProfileEntry::IS_CPP_ENTRY);
+ }
+ else {
+ entry.initJsFrame(script, pc);
+ MOZ_ASSERT(entry.flags() == 0);
+ }
+
+ entry.setLabel(string);
+ entry.setCategory(category);
+
+ // Track if mLabel needs a copy.
+ if (copy)
+ entry.setFlag(js::ProfileEntry::FRAME_LABEL_COPY);
+ else
+ entry.unsetFlag(js::ProfileEntry::FRAME_LABEL_COPY);
+ }
+ *size = current + 1;
+}
+
+void
+SPSProfiler::pop()
+{
+ MOZ_ASSERT(installed());
+ MOZ_ASSERT(*size_ > 0);
+ (*size_)--;
+}
+
+/*
+ * Serializes the script/function pair into a "descriptive string" which is
+ * allowed to fail. This function cannot trigger a GC because it could finalize
+ * some scripts, resize the hash table of profile strings, and invalidate the
+ * AddPtr held while invoking allocProfileString.
+ */
+UniqueChars
+SPSProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
+{
+ // Note: this profiler string is regexp-matched by
+ // devtools/client/profiler/cleopatra/js/parserWorker.js.
+
+ // Get the function name, if any.
+ JSAtom* atom = maybeFun ? maybeFun->displayAtom() : nullptr;
+
+ // Get the script filename, if any, and its length.
+ const char* filename = script->filename();
+ if (filename == nullptr)
+ filename = "<unknown>";
+ size_t lenFilename = strlen(filename);
+
+ // Get the line number and its length as a string.
+ uint64_t lineno = script->lineno();
+ size_t lenLineno = 1;
+ for (uint64_t i = lineno; i /= 10; lenLineno++);
+
+ // Determine the required buffer size.
+ size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them.
+ if (atom) {
+ len += JS::GetDeflatedUTF8StringLength(atom) + 3; // +3 for the " (" and ")" it adds.
+ }
+
+ // Allocate the buffer.
+ UniqueChars cstr(js_pod_malloc<char>(len + 1));
+ if (!cstr)
+ return nullptr;
+
+ // Construct the descriptive string.
+ DebugOnly<size_t> ret;
+ if (atom) {
+ UniqueChars atomStr = StringToNewUTF8CharsZ(nullptr, *atom);
+ if (!atomStr)
+ return nullptr;
+
+ ret = snprintf(cstr.get(), len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno);
+ } else {
+ ret = snprintf(cstr.get(), len + 1, "%s:%" PRIu64, filename, lineno);
+ }
+
+ MOZ_ASSERT(ret == len, "Computed length should match actual length!");
+
+ return cstr;
+}
+
+void
+SPSProfiler::trace(JSTracer* trc)
+{
+ if (stack_) {
+ size_t limit = Min(*size_, max_);
+ for (size_t i = 0; i < limit; i++)
+ stack_[i].trace(trc);
+ }
+}
+
+void
+SPSProfiler::fixupStringsMapAfterMovingGC()
+{
+ auto locked = strings.lock();
+ if (!locked->initialized())
+ return;
+
+ for (ProfileStringMap::Enum e(locked.get()); !e.empty(); e.popFront()) {
+ JSScript* script = e.front().key();
+ if (IsForwarded(script)) {
+ script = Forwarded(script);
+ e.rekeyFront(script);
+ }
+ }
+}
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+void
+SPSProfiler::checkStringsMapAfterMovingGC()
+{
+ auto locked = strings.lock();
+ if (!locked->initialized())
+ return;
+
+ for (auto r = locked->all(); !r.empty(); r.popFront()) {
+ JSScript* script = r.front().key();
+ CheckGCThingAfterMovingGC(script);
+ auto ptr = locked->lookup(script);
+ MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
+ }
+}
+#endif
+
+void
+ProfileEntry::trace(JSTracer* trc)
+{
+ if (isJs()) {
+ JSScript* s = rawScript();
+ TraceNullableRoot(trc, &s, "ProfileEntry script");
+ spOrScript = s;
+ }
+}
+
+SPSEntryMarker::SPSEntryMarker(JSRuntime* rt,
+ JSScript* script
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : profiler(&rt->spsProfiler)
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (!profiler->installed()) {
+ profiler = nullptr;
+ return;
+ }
+ size_before = *profiler->size_;
+ // We want to push a CPP frame so the profiler can correctly order JS and native stacks.
+ profiler->beginPseudoJS("js::RunScript", this);
+ profiler->push("js::RunScript", nullptr, script, script->code(), /* copy = */ false);
+}
+
+SPSEntryMarker::~SPSEntryMarker()
+{
+ if (profiler == nullptr)
+ return;
+
+ profiler->pop();
+ profiler->endPseudoJS();
+ MOZ_ASSERT(size_before == *profiler->size_);
+}
+
+AutoSPSEntry::AutoSPSEntry(JSRuntime* rt, const char* label, ProfileEntry::Category category
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : profiler_(&rt->spsProfiler)
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (!profiler_->installed()) {
+ profiler_ = nullptr;
+ return;
+ }
+ sizeBefore_ = *profiler_->size_;
+ profiler_->beginPseudoJS(label, this);
+ profiler_->push(label, this, nullptr, nullptr, /* copy = */ false, category);
+}
+
+AutoSPSEntry::~AutoSPSEntry()
+{
+ if (!profiler_)
+ return;
+
+ profiler_->pop();
+ profiler_->endPseudoJS();
+ MOZ_ASSERT(sizeBefore_ == *profiler_->size_);
+}
+
+SPSBaselineOSRMarker::SPSBaselineOSRMarker(JSRuntime* rt, bool hasSPSFrame
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : profiler(&rt->spsProfiler)
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (!hasSPSFrame || !profiler->enabled() ||
+ profiler->size() >= profiler->maxSize())
+ {
+ profiler = nullptr;
+ return;
+ }
+
+ size_before = profiler->size();
+ if (profiler->size() == 0)
+ return;
+
+ ProfileEntry& entry = profiler->stack()[profiler->size() - 1];
+ MOZ_ASSERT(entry.isJs());
+ entry.setOSR();
+}
+
+SPSBaselineOSRMarker::~SPSBaselineOSRMarker()
+{
+ if (profiler == nullptr)
+ return;
+
+ MOZ_ASSERT(size_before == *profiler->size_);
+ if (profiler->size() == 0)
+ return;
+
+ ProfileEntry& entry = profiler->stack()[profiler->size() - 1];
+ MOZ_ASSERT(entry.isJs());
+ entry.unsetOSR();
+}
+
+JS_PUBLIC_API(JSScript*)
+ProfileEntry::script() const volatile
+{
+ MOZ_ASSERT(isJs());
+ auto script = reinterpret_cast<JSScript*>(spOrScript);
+ if (!script)
+ return nullptr;
+
+ // If profiling is supressed then we can't trust the script pointers to be
+ // valid as they could be in the process of being moved by a compacting GC
+ // (although it's still OK to get the runtime from them).
+ JSRuntime* rt = script->zoneFromAnyThread()->runtimeFromAnyThread();
+ if (!rt->isProfilerSamplingEnabled())
+ return nullptr;
+
+ MOZ_ASSERT(!IsForwarded(script));
+ return script;
+}
+
+JS_FRIEND_API(jsbytecode*)
+ProfileEntry::pc() const volatile
+{
+ MOZ_ASSERT(isJs());
+ if (lineOrPcOffset == NullPCOffset)
+ return nullptr;
+
+ JSScript* script = this->script();
+ return script ? script->offsetToPC(lineOrPcOffset) : nullptr;
+}
+
+JS_FRIEND_API(void)
+ProfileEntry::setPC(jsbytecode* pc) volatile
+{
+ MOZ_ASSERT(isJs());
+ JSScript* script = this->script();
+ MOZ_ASSERT(script); // This should not be called while profiling is suppressed.
+ lineOrPcOffset = pc == nullptr ? NullPCOffset : script->pcToOffset(pc);
+}
+
+JS_FRIEND_API(void)
+js::SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size, uint32_t max)
+{
+ cx->spsProfiler.setProfilingStack(stack, size, max);
+}
+
+JS_FRIEND_API(void)
+js::EnableContextProfilingStack(JSContext* cx, bool enabled)
+{
+ cx->spsProfiler.enable(enabled);
+}
+
+JS_FRIEND_API(void)
+js::RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*))
+{
+ MOZ_ASSERT(cx->spsProfiler.enabled());
+ cx->spsProfiler.setEventMarker(fn);
+}
+
+JS_FRIEND_API(jsbytecode*)
+js::ProfilingGetPC(JSContext* cx, JSScript* script, void* ip)
+{
+ return cx->spsProfiler.ipToPC(script, size_t(ip));
+}
+
+AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSContext* cx
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : rt_(cx->runtime()),
+ previouslyEnabled_(rt_->isProfilerSamplingEnabled())
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (previouslyEnabled_)
+ rt_->disableProfilerSampling();
+}
+
+AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSRuntime* rt
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : rt_(rt),
+ previouslyEnabled_(rt_->isProfilerSamplingEnabled())
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ if (previouslyEnabled_)
+ rt_->disableProfilerSampling();
+}
+
+AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
+{
+ if (previouslyEnabled_)
+ rt_->enableProfilerSampling();
+}
+
+void*
+js::GetTopProfilingJitFrame(uint8_t* exitFramePtr)
+{
+ // For null exitFrame, there is no previous exit frame, just return.
+ if (!exitFramePtr)
+ return nullptr;
+
+ jit::JitProfilingFrameIterator iter(exitFramePtr);
+ MOZ_ASSERT(!iter.done());
+ return iter.fp();
+}
diff --git a/js/src/vm/SPSProfiler.h b/js/src/vm/SPSProfiler.h
new file mode 100644
index 000000000..b3d00a6d8
--- /dev/null
+++ b/js/src/vm/SPSProfiler.h
@@ -0,0 +1,341 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SPSProfiler_h
+#define vm_SPSProfiler_h
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/GuardObjects.h"
+
+#include <stddef.h>
+
+#include "jsscript.h"
+
+#include "js/ProfilingStack.h"
+#include "threading/ExclusiveData.h"
+#include "vm/MutexIDs.h"
+
+/*
+ * SPS Profiler integration with the JS Engine
+ * https://developer.mozilla.org/en/Performance/Profiling_with_the_Built-in_Profiler
+ *
+ * The SPS profiler (found in tools/profiler) is an implementation of a profiler
+ * which has the ability to walk the C++ stack as well as use instrumentation to
+ * gather information. When dealing with JS, however, SPS needs integration
+ * with the engine because otherwise it is very difficult to figure out what
+ * javascript is executing.
+ *
+ * The current method of integration with SPS is a form of instrumentation:
+ * every time a JS function is entered, a bit of information is pushed onto a
+ * stack that SPS owns and maintains. This information is then popped at the end
+ * of the JS function. SPS informs the JS engine of this stack at runtime, and
+ * it can by turned on/off dynamically.
+ *
+ * The SPS stack has three parameters: a base pointer, a size, and a maximum
+ * size. The stack is the ProfileEntry stack which will have information written
+ * to it. The size location is a pointer to an integer which represents the
+ * current size of the stack (number of valid frames). This size will be
+ * modified when JS functions are called. The maximum specified is the maximum
+ * capacity of the ProfileEntry stack.
+ *
+ * Throughout execution, the size of the stack recorded in memory may exceed the
+ * maximum. The JS engine will not write any information past the maximum limit,
+ * but it will still maintain the size of the stack. SPS code is aware of this
+ * and iterates the stack accordingly.
+ *
+ * There is some information pushed on the SPS stack for every JS function that
+ * is entered. First is a char* pointer of a description of what function was
+ * entered. Currently this string is of the form "function (file:line)" if
+ * there's a function name, or just "file:line" if there's no function name
+ * available. The other bit of information is the relevant C++ (native) stack
+ * pointer. This stack pointer is what enables the interleaving of the C++ and
+ * the JS stack. Finally, throughout execution of the function, some extra
+ * information may be updated on the ProfileEntry structure.
+ *
+ * = Profile Strings
+ *
+ * The profile strings' allocations and deallocation must be carefully
+ * maintained, and ideally at a very low overhead cost. For this reason, the JS
+ * engine maintains a mapping of all known profile strings. These strings are
+ * keyed in lookup by a JSScript*, but are serialized with a JSFunction*,
+ * JSScript* pair. A JSScript will destroy its corresponding profile string when
+ * the script is finalized.
+ *
+ * For this reason, a char* pointer pushed on the SPS stack is valid only while
+ * it is on the SPS stack. SPS uses sampling to read off information from this
+ * instrumented stack, and it therefore copies the string byte for byte when a
+ * JS function is encountered during sampling.
+ *
+ * = Native Stack Pointer
+ *
+ * The actual value pushed as the native pointer is nullptr for most JS
+ * functions. The reason for this is that there's actually very little
+ * correlation between the JS stack and the C++ stack because many JS functions
+ * all run in the same C++ frame, or can even go backwards in C++ when going
+ * from the JIT back to the interpreter.
+ *
+ * To alleviate this problem, all JS functions push nullptr as their "native
+ * stack pointer" to indicate that it's a JS function call. The function
+ * RunScript(), however, pushes an actual C++ stack pointer onto the SPS stack.
+ * This way when interleaving C++ and JS, if SPS sees a nullptr native stack
+ * pointer on the SPS stack, it looks backwards for the first non-nullptr
+ * pointer and uses that for all subsequent nullptr native stack pointers.
+ *
+ * = Line Numbers
+ *
+ * One goal of sampling is to get both a backtrace of the JS stack, but also
+ * know where within each function on the stack execution currently is. For
+ * this, each ProfileEntry has a 'pc' field to tell where its execution
+ * currently is. This field is updated whenever a call is made to another JS
+ * function, and for the JIT it is also updated whenever the JIT is left.
+ *
+ * This field is in a union with a uint32_t 'line' so that C++ can make use of
+ * the field as well. It was observed that tracking 'line' via PCToLineNumber in
+ * JS was far too expensive, so that is why the pc instead of the translated
+ * line number is stored.
+ *
+ * As an invariant, if the pc is nullptr, then the JIT is currently executing
+ * generated code. Otherwise execution is in another JS function or in C++. With
+ * this in place, only the top entry of the stack can ever have nullptr as its
+ * pc. Additionally with this invariant, it is possible to maintain mappings of
+ * JIT code to pc which can be accessed safely because they will only be
+ * accessed from a signal handler when the JIT code is executing.
+ */
+
+namespace js {
+
+// The `ProfileStringMap` weakly holds its `JSScript*` keys and owns its string
+// values. Entries are removed when the `JSScript` is finalized; see
+// `SPSProfiler::onScriptFinalized`.
+using ProfileStringMap = HashMap<JSScript*,
+ UniqueChars,
+ DefaultHasher<JSScript*>,
+ SystemAllocPolicy>;
+
+class AutoSPSEntry;
+class SPSEntryMarker;
+class SPSBaselineOSRMarker;
+
+class SPSProfiler
+{
+ friend class AutoSPSEntry;
+ friend class SPSEntryMarker;
+ friend class SPSBaselineOSRMarker;
+
+ JSRuntime* rt;
+ ExclusiveData<ProfileStringMap> strings;
+ ProfileEntry* stack_;
+ uint32_t* size_;
+ uint32_t max_;
+ bool slowAssertions;
+ uint32_t enabled_;
+ void (*eventMarker_)(const char*);
+
+ UniqueChars allocProfileString(JSScript* script, JSFunction* function);
+ void push(const char* string, void* sp, JSScript* script, jsbytecode* pc, bool copy,
+ ProfileEntry::Category category = ProfileEntry::Category::JS);
+ void pop();
+
+ public:
+ explicit SPSProfiler(JSRuntime* rt);
+
+ bool init();
+
+ uint32_t** addressOfSizePointer() {
+ return &size_;
+ }
+
+ uint32_t* addressOfMaxSize() {
+ return &max_;
+ }
+
+ ProfileEntry** addressOfStack() {
+ return &stack_;
+ }
+
+ uint32_t* sizePointer() { return size_; }
+ uint32_t maxSize() { return max_; }
+ uint32_t size() { MOZ_ASSERT(installed()); return *size_; }
+ ProfileEntry* stack() { return stack_; }
+
+ /* management of whether instrumentation is on or off */
+ bool enabled() { MOZ_ASSERT_IF(enabled_, installed()); return enabled_; }
+ bool installed() { return stack_ != nullptr && size_ != nullptr; }
+ void enable(bool enabled);
+ void enableSlowAssertions(bool enabled) { slowAssertions = enabled; }
+ bool slowAssertionsEnabled() { return slowAssertions; }
+
+ /*
+ * Functions which are the actual instrumentation to track run information
+ *
+ * - enter: a function has started to execute
+ * - updatePC: updates the pc information about where a function
+ * is currently executing
+ * - exit: this function has ceased execution, and no further
+ * entries/exits will be made
+ */
+ bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun);
+ void exit(JSScript* script, JSFunction* maybeFun);
+ void updatePC(JSScript* script, jsbytecode* pc) {
+ if (enabled() && *size_ - 1 < max_) {
+ MOZ_ASSERT(*size_ > 0);
+ MOZ_ASSERT(stack_[*size_ - 1].rawScript() == script);
+ stack_[*size_ - 1].setPC(pc);
+ }
+ }
+
+ /* Enter wasm code */
+ void beginPseudoJS(const char* string, void* sp);
+ void endPseudoJS() { pop(); }
+
+ jsbytecode* ipToPC(JSScript* script, size_t ip) { return nullptr; }
+
+ void setProfilingStack(ProfileEntry* stack, uint32_t* size, uint32_t max);
+ void setEventMarker(void (*fn)(const char*));
+ const char* profileString(JSScript* script, JSFunction* maybeFun);
+ void onScriptFinalized(JSScript* script);
+
+ void markEvent(const char* event);
+
+ /* meant to be used for testing, not recommended to call in normal code */
+ size_t stringsCount();
+ void stringsReset();
+
+ uint32_t* addressOfEnabled() {
+ return &enabled_;
+ }
+
+ void trace(JSTracer* trc);
+ void fixupStringsMapAfterMovingGC();
+#ifdef JSGC_HASH_TABLE_CHECKS
+ void checkStringsMapAfterMovingGC();
+#endif
+};
+
+/*
+ * This class is used to suppress profiler sampling during
+ * critical sections where stack state is not valid.
+ */
+class MOZ_RAII AutoSuppressProfilerSampling
+{
+ public:
+ explicit AutoSuppressProfilerSampling(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ explicit AutoSuppressProfilerSampling(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+ ~AutoSuppressProfilerSampling();
+
+ private:
+ JSRuntime* rt_;
+ bool previouslyEnabled_;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+inline size_t
+SPSProfiler::stringsCount()
+{
+ return strings.lock()->count();
+}
+
+inline void
+SPSProfiler::stringsReset()
+{
+ strings.lock()->clear();
+}
+
+/*
+ * This class is used in RunScript() to push the marker onto the sampling stack
+ * that we're about to enter JS function calls. This is the only time in which a
+ * valid stack pointer is pushed to the sampling stack.
+ */
+class MOZ_RAII SPSEntryMarker
+{
+ public:
+ explicit SPSEntryMarker(JSRuntime* rt,
+ JSScript* script
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ ~SPSEntryMarker();
+
+ private:
+ SPSProfiler* profiler;
+ mozilla::DebugOnly<uint32_t> size_before;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * RAII class to automatically add SPS psuedo frame entries.
+ *
+ * NB: The `label` string must be statically allocated.
+ */
+class MOZ_NONHEAP_CLASS AutoSPSEntry
+{
+ public:
+ explicit AutoSPSEntry(JSRuntime* rt, const char* label,
+ ProfileEntry::Category category = ProfileEntry::Category::JS
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ ~AutoSPSEntry();
+
+ private:
+ SPSProfiler* profiler_;
+ mozilla::DebugOnly<uint32_t> sizeBefore_;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * This class is used in the interpreter to bound regions where the baseline JIT
+ * being entered via OSR. It marks the current top pseudostack entry as
+ * OSR-ed
+ */
+class MOZ_RAII SPSBaselineOSRMarker
+{
+ public:
+ explicit SPSBaselineOSRMarker(JSRuntime* rt, bool hasSPSFrame
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ ~SPSBaselineOSRMarker();
+
+ private:
+ SPSProfiler* profiler;
+ mozilla::DebugOnly<uint32_t> size_before;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * SPS is the profiling backend used by the JS engine to enable time profiling.
+ * More information can be found in vm/SPSProfiler.{h,cpp}. This class manages
+ * the instrumentation portion of the profiling for JIT code.
+ *
+ * The instrumentation tracks entry into functions, leaving those functions via
+ * a function call, reentering the functions from a function call, and exiting
+ * the functions from returning. This class also handles inline frames and
+ * manages the instrumentation which needs to be attached to them as well.
+ *
+ * The basic methods which emit instrumentation are at the end of this class,
+ * and the management functions are all described in the middle.
+ */
+template<class Assembler, class Register>
+class SPSInstrumentation
+{
+ SPSProfiler* profiler_; // Instrumentation location management
+
+ public:
+ /*
+ * Creates instrumentation which writes information out the the specified
+ * profiler's stack and constituent fields.
+ */
+ explicit SPSInstrumentation(SPSProfiler* profiler) : profiler_(profiler) {}
+
+ /* Small proxies around SPSProfiler */
+ bool enabled() { return profiler_ && profiler_->enabled(); }
+ SPSProfiler* profiler() { MOZ_ASSERT(enabled()); return profiler_; }
+ void disable() { profiler_ = nullptr; }
+};
+
+
+/* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
+void* GetTopProfilingJitFrame(uint8_t* exitFramePtr);
+
+} /* namespace js */
+
+#endif /* vm_SPSProfiler_h */
diff --git a/js/src/vm/SavedFrame.h b/js/src/vm/SavedFrame.h
new file mode 100644
index 000000000..ee4cfe03d
--- /dev/null
+++ b/js/src/vm/SavedFrame.h
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SavedFrame_h
+#define vm_SavedFrame_h
+
+#include "mozilla/Attributes.h"
+
+#include "jswrapper.h"
+
+#include "js/GCHashTable.h"
+#include "js/UbiNode.h"
+
+namespace js {
+
+class SavedFrame : public NativeObject {
+ friend class SavedStacks;
+ friend struct ::JSStructuredCloneReader;
+
+ static const ClassSpec classSpec_;
+
+ public:
+ static const Class class_;
+ static const JSPropertySpec protoAccessors[];
+ static const JSFunctionSpec protoFunctions[];
+ static const JSFunctionSpec staticFunctions[];
+
+ // Prototype methods and properties to be exposed to JS.
+ static bool construct(JSContext* cx, unsigned argc, Value* vp);
+ static bool sourceProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool lineProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool columnProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool asyncParentProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool parentProperty(JSContext* cx, unsigned argc, Value* vp);
+ static bool toStringMethod(JSContext* cx, unsigned argc, Value* vp);
+
+ static void finalize(FreeOp* fop, JSObject* obj);
+
+ // Convenient getters for SavedFrame's reserved slots for use from C++.
+ JSAtom* getSource();
+ uint32_t getLine();
+ uint32_t getColumn();
+ JSAtom* getFunctionDisplayName();
+ JSAtom* getAsyncCause();
+ SavedFrame* getParent() const;
+ JSPrincipals* getPrincipals();
+ bool isSelfHosted(JSContext* cx);
+
+ // Iterators for use with C++11 range based for loops, eg:
+ //
+ // SavedFrame* stack = getSomeSavedFrameStack();
+ // for (const SavedFrame* frame : *stack) {
+ // ...
+ // }
+ //
+ // If you need to keep each frame rooted during iteration, you can use
+ // `SavedFrame::RootedRange`. Each frame yielded by
+ // `SavedFrame::RootedRange` is only a valid handle to a rooted `SavedFrame`
+ // within the loop's block for a single loop iteration. When the next
+ // iteration begins, the value is invalidated.
+ //
+ // RootedSavedFrame stack(cx, getSomeSavedFrameStack());
+ // for (HandleSavedFrame frame : SavedFrame::RootedRange(cx, stack)) {
+ // ...
+ // }
+
+ class Iterator {
+ SavedFrame* frame_;
+ public:
+ explicit Iterator(SavedFrame* frame) : frame_(frame) { }
+ SavedFrame& operator*() const { MOZ_ASSERT(frame_); return *frame_; }
+ bool operator!=(const Iterator& rhs) const { return rhs.frame_ != frame_; }
+ inline void operator++();
+ };
+
+ Iterator begin() { return Iterator(this); }
+ Iterator end() { return Iterator(nullptr); }
+
+ class ConstIterator {
+ const SavedFrame* frame_;
+ public:
+ explicit ConstIterator(const SavedFrame* frame) : frame_(frame) { }
+ const SavedFrame& operator*() const { MOZ_ASSERT(frame_); return *frame_; }
+ bool operator!=(const ConstIterator& rhs) const { return rhs.frame_ != frame_; }
+ inline void operator++();
+ };
+
+ ConstIterator begin() const { return ConstIterator(this); }
+ ConstIterator end() const { return ConstIterator(nullptr); }
+
+ class RootedRange;
+
+ class MOZ_STACK_CLASS RootedIterator {
+ friend class RootedRange;
+ RootedRange* range_;
+ // For use by RootedRange::end() only.
+ explicit RootedIterator() : range_(nullptr) { }
+
+ public:
+ explicit RootedIterator(RootedRange& range) : range_(&range) { }
+ HandleSavedFrame operator*() { MOZ_ASSERT(range_); return range_->frame_; }
+ bool operator!=(const RootedIterator& rhs) const {
+ // We should only ever compare to the null range, aka we are just
+ // testing if this range is done.
+ MOZ_ASSERT(rhs.range_ == nullptr);
+ return range_->frame_ != nullptr;
+ }
+ inline void operator++();
+ };
+
+ class MOZ_STACK_CLASS RootedRange {
+ friend class RootedIterator;
+ RootedSavedFrame frame_;
+
+ public:
+ RootedRange(JSContext* cx, HandleSavedFrame frame) : frame_(cx, frame) { }
+ RootedIterator begin() { return RootedIterator(*this); }
+ RootedIterator end() { return RootedIterator(); }
+ };
+
+ static bool isSavedFrameAndNotProto(JSObject& obj) {
+ return obj.is<SavedFrame>() &&
+ !obj.as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull();
+ }
+
+ static bool isSavedFrameOrWrapperAndNotProto(JSObject& obj) {
+ auto unwrapped = CheckedUnwrap(&obj);
+ if (!unwrapped)
+ return false;
+ return isSavedFrameAndNotProto(*unwrapped);
+ }
+
+ struct Lookup;
+ struct HashPolicy;
+
+ typedef JS::GCHashSet<ReadBarriered<SavedFrame*>,
+ HashPolicy,
+ SystemAllocPolicy> Set;
+
+ class AutoLookupVector;
+
+ class MOZ_STACK_CLASS HandleLookup {
+ friend class AutoLookupVector;
+
+ Lookup& lookup;
+
+ explicit HandleLookup(Lookup& lookup) : lookup(lookup) { }
+
+ public:
+ inline Lookup& get() { return lookup; }
+ inline Lookup* operator->() { return &lookup; }
+ };
+
+ private:
+ static SavedFrame* create(JSContext* cx);
+ static MOZ_MUST_USE bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto);
+ void initFromLookup(HandleLookup lookup);
+ void initSource(JSAtom* source);
+ void initLine(uint32_t line);
+ void initColumn(uint32_t column);
+ void initFunctionDisplayName(JSAtom* maybeName);
+ void initAsyncCause(JSAtom* maybeCause);
+ void initParent(SavedFrame* maybeParent);
+ void initPrincipalsAlreadyHeld(JSPrincipals* principals);
+ void initPrincipals(JSPrincipals* principals);
+
+ enum {
+ // The reserved slots in the SavedFrame class.
+ JSSLOT_SOURCE,
+ JSSLOT_LINE,
+ JSSLOT_COLUMN,
+ JSSLOT_FUNCTIONDISPLAYNAME,
+ JSSLOT_ASYNCCAUSE,
+ JSSLOT_PARENT,
+ JSSLOT_PRINCIPALS,
+
+ // The total number of reserved slots in the SavedFrame class.
+ JSSLOT_COUNT
+ };
+};
+
+struct SavedFrame::HashPolicy
+{
+ typedef SavedFrame::Lookup Lookup;
+ typedef MovableCellHasher<SavedFrame*> SavedFramePtrHasher;
+ typedef PointerHasher<JSPrincipals*, 3> JSPrincipalsPtrHasher;
+
+ static bool hasHash(const Lookup& l);
+ static bool ensureHash(const Lookup& l);
+ static HashNumber hash(const Lookup& lookup);
+ static bool match(SavedFrame* existing, const Lookup& lookup);
+
+ typedef ReadBarriered<SavedFrame*> Key;
+ static void rekey(Key& key, const Key& newKey);
+};
+
+template <>
+struct FallibleHashMethods<SavedFrame::HashPolicy>
+{
+ template <typename Lookup> static bool hasHash(Lookup&& l) {
+ return SavedFrame::HashPolicy::hasHash(mozilla::Forward<Lookup>(l));
+ }
+ template <typename Lookup> static bool ensureHash(Lookup&& l) {
+ return SavedFrame::HashPolicy::ensureHash(mozilla::Forward<Lookup>(l));
+ }
+};
+
+// Assert that if the given object is not null, that it must be either a
+// SavedFrame object or wrapper (Xray or CCW) around a SavedFrame object.
+inline void AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack);
+
+// When we reconstruct a SavedFrame stack from a JS::ubi::StackFrame, we may not
+// have access to the principals that the original stack was captured
+// with. Instead, we use these two singleton principals based on whether
+// JS::ubi::StackFrame::isSystem or not. These singletons should never be passed
+// to the subsumes callback, and should be special cased with a shortcut before
+// that.
+struct ReconstructedSavedFramePrincipals : public JSPrincipals
+{
+ explicit ReconstructedSavedFramePrincipals()
+ : JSPrincipals()
+ {
+ MOZ_ASSERT(is(this));
+ this->refcount = 1;
+ }
+
+ MOZ_MUST_USE bool write(JSContext* cx, JSStructuredCloneWriter* writer) override {
+ MOZ_ASSERT(false, "ReconstructedSavedFramePrincipals should never be exposed to embedders");
+ return false;
+ }
+
+ static ReconstructedSavedFramePrincipals IsSystem;
+ static ReconstructedSavedFramePrincipals IsNotSystem;
+
+ // Return true if the given JSPrincipals* points to one of the
+ // ReconstructedSavedFramePrincipals singletons, false otherwise.
+ static bool is(JSPrincipals* p) { return p == &IsSystem || p == &IsNotSystem; }
+
+ // Get the appropriate ReconstructedSavedFramePrincipals singleton for the
+ // given JS::ubi::StackFrame that is being reconstructed as a SavedFrame
+ // stack.
+ static JSPrincipals* getSingleton(JS::ubi::StackFrame& f) {
+ return f.isSystem() ? &IsSystem : &IsNotSystem;
+ }
+};
+
+inline void
+SavedFrame::Iterator::operator++()
+{
+ frame_ = frame_->getParent();
+}
+
+inline void
+SavedFrame::ConstIterator::operator++()
+{
+ frame_ = frame_->getParent();
+}
+
+inline void
+SavedFrame::RootedIterator::operator++()
+{
+ MOZ_ASSERT(range_);
+ range_->frame_ = range_->frame_->getParent();
+}
+
+} // namespace js
+
+namespace JS {
+namespace ubi {
+
+using js::SavedFrame;
+
+// A concrete JS::ubi::StackFrame that is backed by a live SavedFrame object.
+template<>
+class ConcreteStackFrame<SavedFrame> : public BaseStackFrame {
+ explicit ConcreteStackFrame(SavedFrame* ptr) : BaseStackFrame(ptr) { }
+ SavedFrame& get() const { return *static_cast<SavedFrame*>(ptr); }
+
+ public:
+ static void construct(void* storage, SavedFrame* ptr) { new (storage) ConcreteStackFrame(ptr); }
+
+ StackFrame parent() const override { return get().getParent(); }
+ uint32_t line() const override { return get().getLine(); }
+ uint32_t column() const override { return get().getColumn(); }
+
+ AtomOrTwoByteChars source() const override {
+ auto source = get().getSource();
+ return AtomOrTwoByteChars(source);
+ }
+
+ AtomOrTwoByteChars functionDisplayName() const override {
+ auto name = get().getFunctionDisplayName();
+ return AtomOrTwoByteChars(name);
+ }
+
+ void trace(JSTracer* trc) override {
+ JSObject* prev = &get();
+ JSObject* next = prev;
+ js::TraceRoot(trc, &next, "ConcreteStackFrame<SavedFrame>::ptr");
+ if (next != prev)
+ ptr = next;
+ }
+
+ bool isSelfHosted(JSContext* cx) const override {
+ return get().isSelfHosted(cx);
+ }
+
+ bool isSystem() const override;
+
+ MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx,
+ MutableHandleObject outSavedFrameStack)
+ const override;
+};
+
+} // namespace ubi
+} // namespace JS
+
+#endif // vm_SavedFrame_h
diff --git a/js/src/vm/SavedStacks-inl.h b/js/src/vm/SavedStacks-inl.h
new file mode 100644
index 000000000..29b565757
--- /dev/null
+++ b/js/src/vm/SavedStacks-inl.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SavedStacksInl_h
+#define vm_SavedStacksInl_h
+
+#include "vm/SavedStacks.h"
+
+// Assert that if the given object is not null, it's Class is the
+// SavedFrame::class_ or the given object is a cross-compartment or Xray wrapper
+// around such an object.
+//
+// We allow wrappers here because the JSAPI functions for working with
+// SavedFrame objects and the SavedFrame accessors themselves handle wrappers
+// and use the original caller's compartment's principals to determine what
+// level of data to present. Unwrapping and entering the referent's compartment
+// would mess that up. See the module level documentation in
+// `js/src/vm/SavedStacks.h` as well as the comments in `js/src/jsapi.h`.
+inline void
+js::AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack)
+{
+ if (stack)
+ MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameOrWrapperAndNotProto(*stack));
+}
+
+#endif // vm_SavedStacksInl_h
diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp
new file mode 100644
index 000000000..84be0f221
--- /dev/null
+++ b/js/src/vm/SavedStacks.cpp
@@ -0,0 +1,1758 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SavedStacks.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Move.h"
+
+#include <algorithm>
+#include <math.h>
+
+#include "jsapi.h"
+#include "jscompartment.h"
+#include "jsfriendapi.h"
+#include "jshashutil.h"
+#include "jsmath.h"
+#include "jsnum.h"
+#include "jsscript.h"
+
+#include "gc/Marking.h"
+#include "gc/Policy.h"
+#include "gc/Rooting.h"
+#include "js/CharacterEncoding.h"
+#include "js/Vector.h"
+#include "vm/Debugger.h"
+#include "vm/SavedFrame.h"
+#include "vm/SPSProfiler.h"
+#include "vm/StringBuffer.h"
+#include "vm/Time.h"
+#include "vm/WrapperObject.h"
+
+#include "jscntxtinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Stack-inl.h"
+
+using mozilla::AddToHash;
+using mozilla::DebugOnly;
+using mozilla::HashString;
+using mozilla::Maybe;
+using mozilla::Move;
+using mozilla::Nothing;
+using mozilla::Some;
+
+namespace js {
+
+/**
+ * Maximum number of saved frames returned for an async stack.
+ */
+const uint32_t ASYNC_STACK_MAX_FRAME_COUNT = 60;
+
+/* static */ Maybe<LiveSavedFrameCache::FramePtr>
+LiveSavedFrameCache::getFramePtr(FrameIter& iter)
+{
+ if (iter.hasUsableAbstractFramePtr())
+ return Some(FramePtr(iter.abstractFramePtr()));
+
+ if (iter.isPhysicalIonFrame())
+ return Some(FramePtr(iter.physicalIonFrame()));
+
+ return Nothing();
+}
+
+void
+LiveSavedFrameCache::trace(JSTracer* trc)
+{
+ if (!initialized())
+ return;
+
+ for (auto* entry = frames->begin(); entry < frames->end(); entry++) {
+ TraceEdge(trc,
+ &entry->savedFrame,
+ "LiveSavedFrameCache::frames SavedFrame");
+ }
+}
+
+bool
+LiveSavedFrameCache::insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc,
+ HandleSavedFrame savedFrame)
+{
+ MOZ_ASSERT(initialized());
+
+ if (!frames->emplaceBack(framePtr, pc, savedFrame)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ // Safe to dereference the cache key because the stack frames are still
+ // live. After this point, they should never be dereferenced again.
+ if (framePtr.is<AbstractFramePtr>())
+ framePtr.as<AbstractFramePtr>().setHasCachedSavedFrame();
+ else
+ framePtr.as<jit::CommonFrameLayout*>()->setHasCachedSavedFrame();
+
+ return true;
+}
+
+void
+LiveSavedFrameCache::find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const
+{
+ MOZ_ASSERT(initialized());
+ MOZ_ASSERT(!frameIter.done());
+ MOZ_ASSERT(frameIter.hasCachedSavedFrame());
+
+ Maybe<FramePtr> maybeFramePtr = getFramePtr(frameIter);
+ MOZ_ASSERT(maybeFramePtr.isSome());
+
+ FramePtr framePtr(*maybeFramePtr);
+ jsbytecode* pc = frameIter.pc();
+ size_t numberStillValid = 0;
+
+ frame.set(nullptr);
+ for (auto* p = frames->begin(); p < frames->end(); p++) {
+ numberStillValid++;
+ if (framePtr == p->framePtr && pc == p->pc) {
+ frame.set(p->savedFrame);
+ break;
+ }
+ }
+
+ if (!frame) {
+ frames->clear();
+ return;
+ }
+
+ MOZ_ASSERT(0 < numberStillValid && numberStillValid <= frames->length());
+
+ if (frame->compartment() != cx->compartment()) {
+ frame.set(nullptr);
+ numberStillValid--;
+ }
+
+ // Everything after the cached SavedFrame are stale younger frames we have
+ // since popped.
+ frames->shrinkBy(frames->length() - numberStillValid);
+}
+
+struct SavedFrame::Lookup {
+ Lookup(JSAtom* source, uint32_t line, uint32_t column,
+ JSAtom* functionDisplayName, JSAtom* asyncCause, SavedFrame* parent,
+ JSPrincipals* principals, Maybe<LiveSavedFrameCache::FramePtr> framePtr = Nothing(),
+ jsbytecode* pc = nullptr, Activation* activation = nullptr)
+ : source(source),
+ line(line),
+ column(column),
+ functionDisplayName(functionDisplayName),
+ asyncCause(asyncCause),
+ parent(parent),
+ principals(principals),
+ framePtr(framePtr),
+ pc(pc),
+ activation(activation)
+ {
+ MOZ_ASSERT(source);
+ MOZ_ASSERT_IF(framePtr.isSome(), pc);
+ MOZ_ASSERT_IF(framePtr.isSome(), activation);
+
+#ifdef JS_MORE_DETERMINISTIC
+ column = 0;
+#endif
+ }
+
+ explicit Lookup(SavedFrame& savedFrame)
+ : source(savedFrame.getSource()),
+ line(savedFrame.getLine()),
+ column(savedFrame.getColumn()),
+ functionDisplayName(savedFrame.getFunctionDisplayName()),
+ asyncCause(savedFrame.getAsyncCause()),
+ parent(savedFrame.getParent()),
+ principals(savedFrame.getPrincipals()),
+ framePtr(Nothing()),
+ pc(nullptr),
+ activation(nullptr)
+ {
+ MOZ_ASSERT(source);
+ }
+
+ JSAtom* source;
+ uint32_t line;
+ uint32_t column;
+ JSAtom* functionDisplayName;
+ JSAtom* asyncCause;
+ SavedFrame* parent;
+ JSPrincipals* principals;
+
+ // These are used only by the LiveSavedFrameCache and not used for identity or
+ // hashing.
+ Maybe<LiveSavedFrameCache::FramePtr> framePtr;
+ jsbytecode* pc;
+ Activation* activation;
+
+ void trace(JSTracer* trc) {
+ TraceManuallyBarrieredEdge(trc, &source, "SavedFrame::Lookup::source");
+ if (functionDisplayName) {
+ TraceManuallyBarrieredEdge(trc, &functionDisplayName,
+ "SavedFrame::Lookup::functionDisplayName");
+ }
+ if (asyncCause)
+ TraceManuallyBarrieredEdge(trc, &asyncCause, "SavedFrame::Lookup::asyncCause");
+ if (parent)
+ TraceManuallyBarrieredEdge(trc, &parent, "SavedFrame::Lookup::parent");
+ }
+};
+
+class MOZ_STACK_CLASS SavedFrame::AutoLookupVector : public JS::CustomAutoRooter {
+ public:
+ explicit AutoLookupVector(JSContext* cx)
+ : JS::CustomAutoRooter(cx),
+ lookups(cx)
+ { }
+
+ typedef Vector<Lookup, ASYNC_STACK_MAX_FRAME_COUNT> LookupVector;
+ inline LookupVector* operator->() { return &lookups; }
+ inline HandleLookup operator[](size_t i) { return HandleLookup(lookups[i]); }
+
+ private:
+ LookupVector lookups;
+
+ virtual void trace(JSTracer* trc) {
+ for (size_t i = 0; i < lookups.length(); i++)
+ lookups[i].trace(trc);
+ }
+};
+
+/* static */ bool
+SavedFrame::HashPolicy::hasHash(const Lookup& l)
+{
+ return SavedFramePtrHasher::hasHash(l.parent);
+}
+
+/* static */ bool
+SavedFrame::HashPolicy::ensureHash(const Lookup& l)
+{
+ return SavedFramePtrHasher::ensureHash(l.parent);
+}
+
+/* static */ HashNumber
+SavedFrame::HashPolicy::hash(const Lookup& lookup)
+{
+ JS::AutoCheckCannotGC nogc;
+ // Assume that we can take line mod 2^32 without losing anything of
+ // interest. If that assumption changes, we'll just need to start with 0
+ // and add another overload of AddToHash with more arguments.
+ return AddToHash(lookup.line,
+ lookup.column,
+ lookup.source,
+ lookup.functionDisplayName,
+ lookup.asyncCause,
+ SavedFramePtrHasher::hash(lookup.parent),
+ JSPrincipalsPtrHasher::hash(lookup.principals));
+}
+
+/* static */ bool
+SavedFrame::HashPolicy::match(SavedFrame* existing, const Lookup& lookup)
+{
+ MOZ_ASSERT(existing);
+
+ if (existing->getLine() != lookup.line)
+ return false;
+
+ if (existing->getColumn() != lookup.column)
+ return false;
+
+ if (existing->getParent() != lookup.parent)
+ return false;
+
+ if (existing->getPrincipals() != lookup.principals)
+ return false;
+
+ JSAtom* source = existing->getSource();
+ if (source != lookup.source)
+ return false;
+
+ JSAtom* functionDisplayName = existing->getFunctionDisplayName();
+ if (functionDisplayName != lookup.functionDisplayName)
+ return false;
+
+ JSAtom* asyncCause = existing->getAsyncCause();
+ if (asyncCause != lookup.asyncCause)
+ return false;
+
+ return true;
+}
+
+/* static */ void
+SavedFrame::HashPolicy::rekey(Key& key, const Key& newKey)
+{
+ key = newKey;
+}
+
+/* static */ bool
+SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto)
+{
+ // The only object with the SavedFrame::class_ that doesn't have a source
+ // should be the prototype.
+ proto->as<NativeObject>().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
+
+ return FreezeObject(cx, proto);
+}
+
+static const ClassOps SavedFrameClassOps = {
+ nullptr, // addProperty
+ nullptr, // delProperty
+ nullptr, // getProperty
+ nullptr, // setProperty
+ nullptr, // enumerate
+ nullptr, // resolve
+ nullptr, // mayResolve
+ SavedFrame::finalize, // finalize
+ nullptr, // call
+ nullptr, // hasInstance
+ nullptr, // construct
+ nullptr, // trace
+};
+
+const ClassSpec SavedFrame::classSpec_ = {
+ GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
+ GenericCreatePrototype,
+ SavedFrame::staticFunctions,
+ nullptr,
+ SavedFrame::protoFunctions,
+ SavedFrame::protoAccessors,
+ SavedFrame::finishSavedFrameInit,
+ ClassSpec::DontDefineConstructor
+};
+
+/* static */ const Class SavedFrame::class_ = {
+ "SavedFrame",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
+ JSCLASS_IS_ANONYMOUS |
+ JSCLASS_FOREGROUND_FINALIZE,
+ &SavedFrameClassOps,
+ &SavedFrame::classSpec_
+};
+
+/* static */ const JSFunctionSpec
+SavedFrame::staticFunctions[] = {
+ JS_FS_END
+};
+
+/* static */ const JSFunctionSpec
+SavedFrame::protoFunctions[] = {
+ JS_FN("constructor", SavedFrame::construct, 0, 0),
+ JS_FN("toString", SavedFrame::toStringMethod, 0, 0),
+ JS_FS_END
+};
+
+/* static */ const JSPropertySpec
+SavedFrame::protoAccessors[] = {
+ JS_PSG("source", SavedFrame::sourceProperty, 0),
+ JS_PSG("line", SavedFrame::lineProperty, 0),
+ JS_PSG("column", SavedFrame::columnProperty, 0),
+ JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0),
+ JS_PSG("asyncCause", SavedFrame::asyncCauseProperty, 0),
+ JS_PSG("asyncParent", SavedFrame::asyncParentProperty, 0),
+ JS_PSG("parent", SavedFrame::parentProperty, 0),
+ JS_PS_END
+};
+
+/* static */ void
+SavedFrame::finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->onMainThread());
+ JSPrincipals* p = obj->as<SavedFrame>().getPrincipals();
+ if (p) {
+ JSRuntime* rt = obj->runtimeFromMainThread();
+ JS_DropPrincipals(rt->contextFromMainThread(), p);
+ }
+}
+
+JSAtom*
+SavedFrame::getSource()
+{
+ const Value& v = getReservedSlot(JSSLOT_SOURCE);
+ JSString* s = v.toString();
+ return &s->asAtom();
+}
+
+uint32_t
+SavedFrame::getLine()
+{
+ const Value& v = getReservedSlot(JSSLOT_LINE);
+ return v.toPrivateUint32();
+}
+
+uint32_t
+SavedFrame::getColumn()
+{
+ const Value& v = getReservedSlot(JSSLOT_COLUMN);
+ return v.toPrivateUint32();
+}
+
+JSAtom*
+SavedFrame::getFunctionDisplayName()
+{
+ const Value& v = getReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME);
+ if (v.isNull())
+ return nullptr;
+ JSString* s = v.toString();
+ return &s->asAtom();
+}
+
+JSAtom*
+SavedFrame::getAsyncCause()
+{
+ const Value& v = getReservedSlot(JSSLOT_ASYNCCAUSE);
+ if (v.isNull())
+ return nullptr;
+ JSString* s = v.toString();
+ return &s->asAtom();
+}
+
+SavedFrame*
+SavedFrame::getParent() const
+{
+ const Value& v = getReservedSlot(JSSLOT_PARENT);
+ return v.isObject() ? &v.toObject().as<SavedFrame>() : nullptr;
+}
+
+JSPrincipals*
+SavedFrame::getPrincipals()
+{
+ const Value& v = getReservedSlot(JSSLOT_PRINCIPALS);
+ if (v.isUndefined())
+ return nullptr;
+ return static_cast<JSPrincipals*>(v.toPrivate());
+}
+
+void
+SavedFrame::initSource(JSAtom* source)
+{
+ MOZ_ASSERT(source);
+ initReservedSlot(JSSLOT_SOURCE, StringValue(source));
+}
+
+void
+SavedFrame::initLine(uint32_t line)
+{
+ initReservedSlot(JSSLOT_LINE, PrivateUint32Value(line));
+}
+
+void
+SavedFrame::initColumn(uint32_t column)
+{
+#ifdef JS_MORE_DETERMINISTIC
+ column = 0;
+#endif
+ initReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(column));
+}
+
+void
+SavedFrame::initPrincipals(JSPrincipals* principals)
+{
+ if (principals)
+ JS_HoldPrincipals(principals);
+ initPrincipalsAlreadyHeld(principals);
+}
+
+void
+SavedFrame::initPrincipalsAlreadyHeld(JSPrincipals* principals)
+{
+ MOZ_ASSERT_IF(principals, principals->refcount > 0);
+ initReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(principals));
+}
+
+void
+SavedFrame::initFunctionDisplayName(JSAtom* maybeName)
+{
+ initReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME, maybeName ? StringValue(maybeName) : NullValue());
+}
+
+void
+SavedFrame::initAsyncCause(JSAtom* maybeCause)
+{
+ initReservedSlot(JSSLOT_ASYNCCAUSE, maybeCause ? StringValue(maybeCause) : NullValue());
+}
+
+void
+SavedFrame::initParent(SavedFrame* maybeParent)
+{
+ initReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(maybeParent));
+}
+
+void
+SavedFrame::initFromLookup(SavedFrame::HandleLookup lookup)
+{
+ initSource(lookup->source);
+ initLine(lookup->line);
+ initColumn(lookup->column);
+ initFunctionDisplayName(lookup->functionDisplayName);
+ initAsyncCause(lookup->asyncCause);
+ initParent(lookup->parent);
+ initPrincipals(lookup->principals);
+}
+
+/* static */ SavedFrame*
+SavedFrame::create(JSContext* cx)
+{
+ RootedGlobalObject global(cx, cx->global());
+ assertSameCompartment(cx, global);
+
+ // Ensure that we don't try to capture the stack again in the
+ // `SavedStacksMetadataBuilder` for this new SavedFrame object, and
+ // accidentally cause O(n^2) behavior.
+ SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
+
+ RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
+ if (!proto)
+ return nullptr;
+ assertSameCompartment(cx, proto);
+
+ RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto,
+ TenuredObject));
+ if (!frameObj)
+ return nullptr;
+
+ return &frameObj->as<SavedFrame>();
+}
+
+bool
+SavedFrame::isSelfHosted(JSContext* cx)
+{
+ JSAtom* source = getSource();
+ return source == cx->names().selfHosted;
+}
+
+/* static */ bool
+SavedFrame::construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
+ "SavedFrame");
+ return false;
+}
+
+static bool
+SavedFrameSubsumedByCaller(JSContext* cx, HandleSavedFrame frame)
+{
+ auto subsumes = cx->runtime()->securityCallbacks->subsumes;
+ if (!subsumes)
+ return true;
+
+ auto currentCompartmentPrincipals = cx->compartment()->principals();
+ MOZ_ASSERT(!ReconstructedSavedFramePrincipals::is(currentCompartmentPrincipals));
+
+ auto framePrincipals = frame->getPrincipals();
+
+ // Handle SavedFrames that have been reconstructed from stacks in a heap
+ // snapshot.
+ if (framePrincipals == &ReconstructedSavedFramePrincipals::IsSystem)
+ return cx->runningWithTrustedPrincipals();
+ if (framePrincipals == &ReconstructedSavedFramePrincipals::IsNotSystem)
+ return true;
+
+ return subsumes(currentCompartmentPrincipals, framePrincipals);
+}
+
+// Return the first SavedFrame in the chain that starts with |frame| whose
+// principals are subsumed by |principals|, according to |subsumes|. If there is
+// no such frame, return nullptr. |skippedAsync| is set to true if any of the
+// skipped frames had the |asyncCause| property set, otherwise it is explicitly
+// set to false.
+static SavedFrame*
+GetFirstSubsumedFrame(JSContext* cx, HandleSavedFrame frame, JS::SavedFrameSelfHosted selfHosted,
+ bool& skippedAsync)
+{
+ skippedAsync = false;
+
+ RootedSavedFrame rootedFrame(cx, frame);
+ while (rootedFrame) {
+ if ((selfHosted == JS::SavedFrameSelfHosted::Include ||
+ !rootedFrame->isSelfHosted(cx)) &&
+ SavedFrameSubsumedByCaller(cx, rootedFrame))
+ {
+ return rootedFrame;
+ }
+
+ if (rootedFrame->getAsyncCause())
+ skippedAsync = true;
+
+ rootedFrame = rootedFrame->getParent();
+ }
+
+ return nullptr;
+}
+
+JS_FRIEND_API(JSObject*)
+GetFirstSubsumedSavedFrame(JSContext* cx, HandleObject savedFrame,
+ JS::SavedFrameSelfHosted selfHosted)
+{
+ if (!savedFrame)
+ return nullptr;
+ bool skippedAsync;
+ RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
+ return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync);
+}
+
+static MOZ_MUST_USE bool
+SavedFrame_checkThis(JSContext* cx, CallArgs& args, const char* fnName,
+ MutableHandleObject frame)
+{
+ const Value& thisValue = args.thisv();
+
+ if (!thisValue.isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
+ InformalValueTypeName(thisValue));
+ return false;
+ }
+
+ JSObject* thisObject = CheckedUnwrap(&thisValue.toObject());
+ if (!thisObject || !thisObject->is<SavedFrame>()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ SavedFrame::class_.name, fnName,
+ thisObject ? thisObject->getClass()->name : "object");
+ return false;
+ }
+
+ // Check for SavedFrame.prototype, which has the same class as SavedFrame
+ // instances, however doesn't actually represent a captured stack frame. It
+ // is the only object that is<SavedFrame>() but doesn't have a source.
+ if (!SavedFrame::isSavedFrameAndNotProto(*thisObject)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ SavedFrame::class_.name, fnName, "prototype object");
+ return false;
+ }
+
+ // Now set "frame" to the actual object we were invoked in (which may be a
+ // wrapper), not the unwrapped version. Consumers will need to know what
+ // that original object was, and will do principal checks as needed.
+ frame.set(&thisValue.toObject());
+ return true;
+}
+
+// Get the SavedFrame * from the current this value and handle any errors that
+// might occur therein.
+//
+// These parameters must already exist when calling this macro:
+// - JSContext* cx
+// - unsigned argc
+// - Value* vp
+// - const char* fnName
+// These parameters will be defined after calling this macro:
+// - CallArgs args
+// - Rooted<SavedFrame*> frame (will be non-null)
+#define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ RootedObject frame(cx); \
+ if (!SavedFrame_checkThis(cx, args, fnName, &frame)) \
+ return false;
+
+} /* namespace js */
+
+namespace JS {
+
+namespace {
+
+// It's possible that our caller is privileged (and hence would see the entire
+// stack) but we're working with an SavedFrame object that was captured in
+// unprivileged code. If so, drop privileges down to its level. The idea is
+// that this way devtools code that's asking an exception object for a stack to
+// display will end up with the stack the web developer would see via doing
+// .stack in a web page, with Firefox implementation details excluded.
+//
+// We want callers to pass us the object they were actually passed, not an
+// unwrapped form of it. That way Xray access to SavedFrame objects should not
+// be affected by AutoMaybeEnterFrameCompartment and the only things that will
+// be affected will be cases in which privileged code works with some C++ object
+// that then pokes at an unprivileged StackFrame it has on hand.
+class MOZ_STACK_CLASS AutoMaybeEnterFrameCompartment
+{
+public:
+ AutoMaybeEnterFrameCompartment(JSContext* cx,
+ HandleObject obj
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+ MOZ_RELEASE_ASSERT(cx->compartment());
+ if (obj)
+ MOZ_RELEASE_ASSERT(obj->compartment());
+
+ // Note that obj might be null here, since we're doing this before
+ // UnwrapSavedFrame.
+ if (obj && cx->compartment() != obj->compartment())
+ {
+ JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
+ if (subsumes && subsumes(cx->compartment()->principals(),
+ obj->compartment()->principals()))
+ {
+ ac_.emplace(cx, obj);
+ }
+ }
+ }
+
+ private:
+ Maybe<JSAutoCompartment> ac_;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+} // namespace
+
+static inline js::SavedFrame*
+UnwrapSavedFrame(JSContext* cx, HandleObject obj, SavedFrameSelfHosted selfHosted,
+ bool& skippedAsync)
+{
+ if (!obj)
+ return nullptr;
+
+ RootedObject savedFrameObj(cx, CheckedUnwrap(obj));
+ if (!savedFrameObj)
+ return nullptr;
+
+ MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*savedFrameObj));
+ js::RootedSavedFrame frame(cx, &savedFrameObj->as<js::SavedFrame>());
+ return GetFirstSubsumedFrame(cx, frame, selfHosted, skippedAsync);
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ sourcep.set(cx->runtime()->emptyString);
+ return SavedFrameResult::AccessDenied;
+ }
+ sourcep.set(frame->getSource());
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+ MOZ_ASSERT(linep);
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ *linep = 0;
+ return SavedFrameResult::AccessDenied;
+ }
+ *linep = frame->getLine();
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+ MOZ_ASSERT(columnp);
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ *columnp = 0;
+ return SavedFrameResult::AccessDenied;
+ }
+ *columnp = frame->getColumn();
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ namep.set(nullptr);
+ return SavedFrameResult::AccessDenied;
+ }
+ namep.set(frame->getFunctionDisplayName());
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep,
+ SavedFrameSelfHosted unused_ /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ // This function is always called with self-hosted frames excluded by
+ // GetValueIfNotCached in dom/bindings/Exceptions.cpp. However, we want
+ // to include them because our Promise implementation causes us to have
+ // the async cause on a self-hosted frame. So we just ignore the
+ // parameter and always include self-hosted frames.
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, SavedFrameSelfHosted::Include,
+ skippedAsync));
+ if (!frame) {
+ asyncCausep.set(nullptr);
+ return SavedFrameResult::AccessDenied;
+ }
+ asyncCausep.set(frame->getAsyncCause());
+ if (!asyncCausep && skippedAsync)
+ asyncCausep.set(cx->names().Async);
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ asyncParentp.set(nullptr);
+ return SavedFrameResult::AccessDenied;
+ }
+ js::RootedSavedFrame parent(cx, frame->getParent());
+
+ // The current value of |skippedAsync| is not interesting, because we are
+ // interested in whether we would cross any async parents to get from here
+ // to the first subsumed parent frame instead.
+ js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted,
+ skippedAsync));
+
+ // Even if |parent| is not subsumed, we still want to return a pointer to it
+ // rather than |subsumedParent| so it can pick up any |asyncCause| from the
+ // inaccessible part of the chain.
+ if (subsumedParent && (subsumedParent->getAsyncCause() || skippedAsync))
+ asyncParentp.set(parent);
+ else
+ asyncParentp.set(nullptr);
+ return SavedFrameResult::Ok;
+}
+
+JS_PUBLIC_API(SavedFrameResult)
+GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp,
+ SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ AutoMaybeEnterFrameCompartment ac(cx, savedFrame);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, savedFrame, selfHosted, skippedAsync));
+ if (!frame) {
+ parentp.set(nullptr);
+ return SavedFrameResult::AccessDenied;
+ }
+ js::RootedSavedFrame parent(cx, frame->getParent());
+
+ // The current value of |skippedAsync| is not interesting, because we are
+ // interested in whether we would cross any async parents to get from here
+ // to the first subsumed parent frame instead.
+ js::RootedSavedFrame subsumedParent(cx, GetFirstSubsumedFrame(cx, parent, selfHosted,
+ skippedAsync));
+
+ // Even if |parent| is not subsumed, we still want to return a pointer to it
+ // rather than |subsumedParent| so it can pick up any |asyncCause| from the
+ // inaccessible part of the chain.
+ if (subsumedParent && !(subsumedParent->getAsyncCause() || skippedAsync))
+ parentp.set(parent);
+ else
+ parentp.set(nullptr);
+ return SavedFrameResult::Ok;
+}
+
+static bool
+FormatSpiderMonkeyStackFrame(JSContext* cx, js::StringBuffer& sb,
+ js::HandleSavedFrame frame, size_t indent,
+ bool skippedAsync)
+{
+ RootedString asyncCause(cx, frame->getAsyncCause());
+ if (!asyncCause && skippedAsync)
+ asyncCause.set(cx->names().Async);
+
+ js::RootedAtom name(cx, frame->getFunctionDisplayName());
+ return (!indent || sb.appendN(' ', indent))
+ && (!asyncCause || (sb.append(asyncCause) && sb.append('*')))
+ && (!name || sb.append(name))
+ && sb.append('@')
+ && sb.append(frame->getSource())
+ && sb.append(':')
+ && NumberValueToStringBuffer(cx, NumberValue(frame->getLine()), sb)
+ && sb.append(':')
+ && NumberValueToStringBuffer(cx, NumberValue(frame->getColumn()), sb)
+ && sb.append('\n');
+}
+
+static bool
+FormatV8StackFrame(JSContext* cx, js::StringBuffer& sb,
+ js::HandleSavedFrame frame, size_t indent, bool lastFrame)
+{
+ js::RootedAtom name(cx, frame->getFunctionDisplayName());
+ return sb.appendN(' ', indent + 4)
+ && sb.append('a')
+ && sb.append('t')
+ && sb.append(' ')
+ && (!name || (sb.append(name) &&
+ sb.append(' ') &&
+ sb.append('(')))
+ && sb.append(frame->getSource())
+ && sb.append(':')
+ && NumberValueToStringBuffer(cx, NumberValue(frame->getLine()), sb)
+ && sb.append(':')
+ && NumberValueToStringBuffer(cx, NumberValue(frame->getColumn()), sb)
+ && (!name || sb.append(')'))
+ && (lastFrame || sb.append('\n'));
+}
+
+JS_PUBLIC_API(bool)
+BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
+ size_t indent, js::StackFormat format)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ MOZ_RELEASE_ASSERT(cx->compartment());
+
+ js::StringBuffer sb(cx);
+
+ if (format == js::StackFormat::Default)
+ format = cx->stackFormat();
+ MOZ_ASSERT(format != js::StackFormat::Default);
+
+ // Enter a new block to constrain the scope of possibly entering the stack's
+ // compartment. This ensures that when we finish the StringBuffer, we are
+ // back in the cx's original compartment, and fulfill our contract with
+ // callers to place the output string in the cx's current compartment.
+ {
+ AutoMaybeEnterFrameCompartment ac(cx, stack);
+ bool skippedAsync;
+ js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, stack, SavedFrameSelfHosted::Exclude,
+ skippedAsync));
+ if (!frame) {
+ stringp.set(cx->runtime()->emptyString);
+ return true;
+ }
+
+ js::RootedSavedFrame parent(cx);
+ do {
+ MOZ_ASSERT(SavedFrameSubsumedByCaller(cx, frame));
+ MOZ_ASSERT(!frame->isSelfHosted(cx));
+
+ parent = frame->getParent();
+ bool skippedNextAsync;
+ js::RootedSavedFrame nextFrame(cx, js::GetFirstSubsumedFrame(cx, parent,
+ SavedFrameSelfHosted::Exclude, skippedNextAsync));
+
+ switch (format) {
+ case js::StackFormat::SpiderMonkey:
+ if (!FormatSpiderMonkeyStackFrame(cx, sb, frame, indent, skippedAsync))
+ return false;
+ break;
+ case js::StackFormat::V8:
+ if (!FormatV8StackFrame(cx, sb, frame, indent, !nextFrame))
+ return false;
+ break;
+ case js::StackFormat::Default:
+ MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected value");
+ break;
+ }
+
+ frame = nextFrame;
+ skippedAsync = skippedNextAsync;
+ } while (frame);
+ }
+
+ JSString* str = sb.finishString();
+ if (!str)
+ return false;
+ assertSameCompartment(cx, str);
+ stringp.set(str);
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+IsSavedFrame(JSObject* obj)
+{
+ if (!obj)
+ return false;
+
+ JSObject* unwrapped = js::CheckedUnwrap(obj);
+ if (!unwrapped)
+ return false;
+
+ return js::SavedFrame::isSavedFrameAndNotProto(*unwrapped);
+}
+
+} /* namespace JS */
+
+namespace js {
+
+/* static */ bool
+SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame);
+ RootedString source(cx);
+ if (JS::GetSavedFrameSource(cx, frame, &source) == JS::SavedFrameResult::Ok) {
+ if (!cx->compartment()->wrap(cx, &source))
+ return false;
+ args.rval().setString(source);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+/* static */ bool
+SavedFrame::lineProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame);
+ uint32_t line;
+ if (JS::GetSavedFrameLine(cx, frame, &line) == JS::SavedFrameResult::Ok)
+ args.rval().setNumber(line);
+ else
+ args.rval().setNull();
+ return true;
+}
+
+/* static */ bool
+SavedFrame::columnProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame);
+ uint32_t column;
+ if (JS::GetSavedFrameColumn(cx, frame, &column) == JS::SavedFrameResult::Ok)
+ args.rval().setNumber(column);
+ else
+ args.rval().setNull();
+ return true;
+}
+
+/* static */ bool
+SavedFrame::functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame);
+ RootedString name(cx);
+ JS::SavedFrameResult result = JS::GetSavedFrameFunctionDisplayName(cx, frame, &name);
+ if (result == JS::SavedFrameResult::Ok && name) {
+ if (!cx->compartment()->wrap(cx, &name))
+ return false;
+ args.rval().setString(name);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+/* static */ bool
+SavedFrame::asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get asyncCause)", args, frame);
+ RootedString asyncCause(cx);
+ JS::SavedFrameResult result = JS::GetSavedFrameAsyncCause(cx, frame, &asyncCause);
+ if (result == JS::SavedFrameResult::Ok && asyncCause) {
+ if (!cx->compartment()->wrap(cx, &asyncCause))
+ return false;
+ args.rval().setString(asyncCause);
+ } else {
+ args.rval().setNull();
+ }
+ return true;
+}
+
+/* static */ bool
+SavedFrame::asyncParentProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get asyncParent)", args, frame);
+ RootedObject asyncParent(cx);
+ (void) JS::GetSavedFrameAsyncParent(cx, frame, &asyncParent);
+ if (!cx->compartment()->wrap(cx, &asyncParent))
+ return false;
+ args.rval().setObjectOrNull(asyncParent);
+ return true;
+}
+
+/* static */ bool
+SavedFrame::parentProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame);
+ RootedObject parent(cx);
+ (void) JS::GetSavedFrameParent(cx, frame, &parent);
+ if (!cx->compartment()->wrap(cx, &parent))
+ return false;
+ args.rval().setObjectOrNull(parent);
+ return true;
+}
+
+/* static */ bool
+SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame);
+ RootedString string(cx);
+ if (!JS::BuildStackString(cx, frame, &string))
+ return false;
+ args.rval().setString(string);
+ return true;
+}
+
+bool
+SavedStacks::init()
+{
+ return frames.init() &&
+ pcLocationMap.init();
+}
+
+bool
+SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
+ JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
+{
+ MOZ_ASSERT(initialized());
+ MOZ_RELEASE_ASSERT(cx->compartment());
+ assertSameCompartment(cx, this);
+
+ if (creatingSavedFrame ||
+ cx->isExceptionPending() ||
+ !cx->global() ||
+ !cx->global()->isStandardClassResolved(JSProto_Object))
+ {
+ frame.set(nullptr);
+ return true;
+ }
+
+ AutoSPSEntry psuedoFrame(cx->runtime(), "js::SavedStacks::saveCurrentStack");
+ FrameIter iter(cx);
+ return insertFrames(cx, iter, frame, mozilla::Move(capture));
+}
+
+bool
+SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
+ MutableHandleSavedFrame adoptedStack, uint32_t maxFrameCount)
+{
+ MOZ_ASSERT(initialized());
+ MOZ_RELEASE_ASSERT(cx->compartment());
+ assertSameCompartment(cx, this);
+
+ RootedObject asyncStackObj(cx, CheckedUnwrap(asyncStack));
+ MOZ_RELEASE_ASSERT(asyncStackObj);
+ MOZ_RELEASE_ASSERT(js::SavedFrame::isSavedFrameAndNotProto(*asyncStackObj));
+ RootedSavedFrame frame(cx, &asyncStackObj->as<js::SavedFrame>());
+
+ return adoptAsyncStack(cx, frame, asyncCause, adoptedStack, maxFrameCount);
+}
+
+void
+SavedStacks::sweep()
+{
+ frames.sweep();
+ pcLocationMap.sweep();
+}
+
+void
+SavedStacks::trace(JSTracer* trc)
+{
+ pcLocationMap.trace(trc);
+}
+
+uint32_t
+SavedStacks::count()
+{
+ MOZ_ASSERT(initialized());
+ return frames.count();
+}
+
+void
+SavedStacks::clear()
+{
+ frames.clear();
+}
+
+size_t
+SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ return frames.sizeOfExcludingThis(mallocSizeOf) +
+ pcLocationMap.sizeOfExcludingThis(mallocSizeOf);
+}
+
+// Given that we have captured a stqck frame with the given principals and
+// source, return true if the requested `StackCapture` has been satisfied and
+// stack walking can halt. Return false otherwise (and stack walking and frame
+// capturing should continue).
+static inline bool
+captureIsSatisfied(JSContext* cx, JSPrincipals* principals, const JSAtom* source,
+ JS::StackCapture& capture)
+{
+ class Matcher
+ {
+ JSContext* cx_;
+ JSPrincipals* framePrincipals_;
+ const JSAtom* frameSource_;
+
+ public:
+ Matcher(JSContext* cx, JSPrincipals* principals, const JSAtom* source)
+ : cx_(cx)
+ , framePrincipals_(principals)
+ , frameSource_(source)
+ { }
+
+ bool match(JS::FirstSubsumedFrame& target) {
+ auto subsumes = cx_->runtime()->securityCallbacks->subsumes;
+ return (!subsumes || subsumes(target.principals, framePrincipals_)) &&
+ (!target.ignoreSelfHosted || frameSource_ != cx_->names().selfHosted);
+ }
+
+ bool match(JS::MaxFrames& target) {
+ return target.maxFrames == 1;
+ }
+
+ bool match(JS::AllFrames&) {
+ return false;
+ }
+ };
+
+ Matcher m(cx, principals, source);
+ return capture.match(m);
+}
+
+bool
+SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFrame frame,
+ JS::StackCapture&& capture)
+{
+ // In order to lookup a cached SavedFrame object, we need to have its parent
+ // SavedFrame, which means we need to walk the stack from oldest frame to
+ // youngest. However, FrameIter walks the stack from youngest frame to
+ // oldest. The solution is to append stack frames to a vector as we walk the
+ // stack with FrameIter, and then do a second pass through that vector in
+ // reverse order after the traversal has completed and get or create the
+ // SavedFrame objects at that time.
+ //
+ // To avoid making many copies of FrameIter (whose copy constructor is
+ // relatively slow), we use a vector of `SavedFrame::Lookup` objects, which
+ // only contain the FrameIter data we need. The `SavedFrame::Lookup`
+ // objects are partially initialized with everything except their parent
+ // pointers on the first pass, and then we fill in the parent pointers as we
+ // return in the second pass.
+
+ Activation* asyncActivation = nullptr;
+ RootedSavedFrame asyncStack(cx, nullptr);
+ RootedString asyncCause(cx, nullptr);
+ bool parentIsInCache = false;
+ RootedSavedFrame cachedFrame(cx, nullptr);
+
+ // Accumulate the vector of Lookup objects in |stackChain|.
+ SavedFrame::AutoLookupVector stackChain(cx);
+ while (!iter.done()) {
+ Activation& activation = *iter.activation();
+
+ if (asyncActivation && asyncActivation != &activation) {
+ // We found an async stack in the previous activation, and we
+ // walked past the oldest frame of that activation, we're done.
+ // However, we only want to use the async parent if it was
+ // explicitly requested; if we got here otherwise, we have
+ // a direct parent, which we prefer.
+ if (asyncActivation->asyncCallIsExplicit())
+ break;
+ asyncActivation = nullptr;
+ }
+
+ if (!asyncActivation) {
+ asyncStack = activation.asyncStack();
+ if (asyncStack) {
+ // While walking from the youngest to the oldest frame, we found
+ // an activation that has an async stack set. We will use the
+ // youngest frame of the async stack as the parent of the oldest
+ // frame of this activation. We still need to iterate over other
+ // frames in this activation before reaching the oldest frame.
+ AutoCompartment ac(cx, iter.compartment());
+ const char* cause = activation.asyncCause();
+ UTF8Chars utf8Chars(cause, strlen(cause));
+ size_t twoByteCharsLen = 0;
+ char16_t* twoByteChars = UTF8CharsToNewTwoByteCharsZ(cx, utf8Chars,
+ &twoByteCharsLen).get();
+ if (!twoByteChars)
+ return false;
+
+ // We expect that there will be a relatively small set of
+ // asyncCause reasons ("setTimeout", "promise", etc.), so we
+ // atomize the cause here in hopes of being able to benefit
+ // from reuse.
+ asyncCause = JS_AtomizeUCStringN(cx, twoByteChars, twoByteCharsLen);
+ js_free(twoByteChars);
+ if (!asyncCause)
+ return false;
+ asyncActivation = &activation;
+ }
+ }
+
+ Rooted<LocationValue> location(cx);
+ {
+ AutoCompartment ac(cx, iter.compartment());
+ if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
+ return false;
+ }
+
+ // The bit set means that the next older parent (frame, pc) pair *must*
+ // be in the cache.
+ if (capture.is<JS::AllFrames>())
+ parentIsInCache = iter.hasCachedSavedFrame();
+
+ auto principals = iter.compartment()->principals();
+ auto displayAtom = iter.isFunctionFrame() ? iter.functionDisplayAtom() : nullptr;
+ if (!stackChain->emplaceBack(location.source(),
+ location.line(),
+ location.column(),
+ displayAtom,
+ nullptr,
+ nullptr,
+ principals,
+ LiveSavedFrameCache::getFramePtr(iter),
+ iter.pc(),
+ &activation))
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ if (captureIsSatisfied(cx, principals, location.source(), capture)) {
+ // The frame we just saved was the last one we were asked to save.
+ // If we had an async stack, ensure we don't use any of its frames.
+ asyncStack.set(nullptr);
+ break;
+ }
+
+ ++iter;
+
+ if (parentIsInCache &&
+ !iter.done() &&
+ iter.hasCachedSavedFrame())
+ {
+ auto* cache = activation.getLiveSavedFrameCache(cx);
+ if (!cache)
+ return false;
+ cache->find(cx, iter, &cachedFrame);
+ if (cachedFrame)
+ break;
+ }
+
+ if (capture.is<JS::MaxFrames>())
+ capture.as<JS::MaxFrames>().maxFrames--;
+ }
+
+ // Limit the depth of the async stack, if any, and ensure that the
+ // SavedFrame instances we use are stored in the same compartment as the
+ // rest of the synchronous stack chain.
+ RootedSavedFrame parentFrame(cx, cachedFrame);
+ if (asyncStack && !capture.is<JS::FirstSubsumedFrame>()) {
+ uint32_t maxAsyncFrames = capture.is<JS::MaxFrames>()
+ ? capture.as<JS::MaxFrames>().maxFrames
+ : ASYNC_STACK_MAX_FRAME_COUNT;
+ if (!adoptAsyncStack(cx, asyncStack, asyncCause, &parentFrame, maxAsyncFrames))
+ return false;
+ }
+
+ // Iterate through |stackChain| in reverse order and get or create the
+ // actual SavedFrame instances.
+ for (size_t i = stackChain->length(); i != 0; i--) {
+ SavedFrame::HandleLookup lookup = stackChain[i-1];
+ lookup->parent = parentFrame;
+ parentFrame.set(getOrCreateSavedFrame(cx, lookup));
+ if (!parentFrame)
+ return false;
+
+ if (capture.is<JS::AllFrames>() && lookup->framePtr && parentFrame != cachedFrame) {
+ auto* cache = lookup->activation->getLiveSavedFrameCache(cx);
+ if (!cache || !cache->insert(cx, *lookup->framePtr, lookup->pc, parentFrame))
+ return false;
+ }
+ }
+
+ frame.set(parentFrame);
+ return true;
+}
+
+bool
+SavedStacks::adoptAsyncStack(JSContext* cx, HandleSavedFrame asyncStack,
+ HandleString asyncCause,
+ MutableHandleSavedFrame adoptedStack,
+ uint32_t maxFrameCount)
+{
+ RootedAtom asyncCauseAtom(cx, AtomizeString(cx, asyncCause));
+ if (!asyncCauseAtom)
+ return false;
+
+ // If maxFrameCount is zero, the caller asked for an unlimited number of
+ // stack frames, but async stacks are not limited by the available stack
+ // memory, so we need to set an arbitrary limit when collecting them. We
+ // still don't enforce an upper limit if the caller requested more frames.
+ uint32_t maxFrames = maxFrameCount > 0 ? maxFrameCount : ASYNC_STACK_MAX_FRAME_COUNT;
+
+ // Accumulate the vector of Lookup objects in |stackChain|.
+ SavedFrame::AutoLookupVector stackChain(cx);
+ SavedFrame* currentSavedFrame = asyncStack;
+ SavedFrame* firstSavedFrameParent = nullptr;
+ for (uint32_t i = 0; i < maxFrames && currentSavedFrame; i++) {
+ if (!stackChain->emplaceBack(*currentSavedFrame)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ currentSavedFrame = currentSavedFrame->getParent();
+
+ // Attach the asyncCause to the youngest frame.
+ if (i == 0) {
+ stackChain->back().asyncCause = asyncCauseAtom;
+ firstSavedFrameParent = currentSavedFrame;
+ }
+ }
+
+ // This is the 1-based index of the oldest frame we care about.
+ size_t oldestFramePosition = stackChain->length();
+ RootedSavedFrame parentFrame(cx, nullptr);
+
+ if (currentSavedFrame == nullptr &&
+ asyncStack->compartment() == cx->compartment()) {
+ // If we consumed the full async stack, and the stack is in the same
+ // compartment as the one requested, we don't need to rebuild the full
+ // chain again using the lookup objects, we can just reference the
+ // existing chain and change the asyncCause on the younger frame.
+ oldestFramePosition = 1;
+ parentFrame = firstSavedFrameParent;
+ } else if (maxFrameCount == 0 &&
+ oldestFramePosition == ASYNC_STACK_MAX_FRAME_COUNT) {
+ // If we captured the maximum number of frames and the caller requested
+ // no specific limit, we only return half of them. This means that for
+ // the next iterations, it's likely we can use the optimization above.
+ oldestFramePosition = ASYNC_STACK_MAX_FRAME_COUNT / 2;
+ }
+
+ // Iterate through |stackChain| in reverse order and get or create the
+ // actual SavedFrame instances.
+ for (size_t i = oldestFramePosition; i != 0; i--) {
+ SavedFrame::HandleLookup lookup = stackChain[i-1];
+ lookup->parent = parentFrame;
+ parentFrame.set(getOrCreateSavedFrame(cx, lookup));
+ if (!parentFrame)
+ return false;
+ }
+
+ adoptedStack.set(parentFrame);
+ return true;
+}
+
+SavedFrame*
+SavedStacks::getOrCreateSavedFrame(JSContext* cx, SavedFrame::HandleLookup lookup)
+{
+ const SavedFrame::Lookup& lookupInstance = lookup.get();
+ DependentAddPtr<SavedFrame::Set> p(cx, frames, lookupInstance);
+ if (p) {
+ MOZ_ASSERT(*p);
+ return *p;
+ }
+
+ RootedSavedFrame frame(cx, createFrameFromLookup(cx, lookup));
+ if (!frame)
+ return nullptr;
+
+ if (!p.add(cx, frames, lookupInstance, frame))
+ return nullptr;
+
+ return frame;
+}
+
+SavedFrame*
+SavedStacks::createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup lookup)
+{
+ RootedSavedFrame frame(cx, SavedFrame::create(cx));
+ if (!frame)
+ return nullptr;
+ frame->initFromLookup(lookup);
+
+ if (!FreezeObject(cx, frame))
+ return nullptr;
+
+ return frame;
+}
+
+bool
+SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
+ MutableHandle<LocationValue> locationp)
+{
+ // We should only ever be caching location values for scripts in this
+ // compartment. Otherwise, we would get dead cross-compartment scripts in
+ // the cache because our compartment's sweep method isn't called when their
+ // compartment gets collected.
+ assertSameCompartment(cx, this, iter.compartment());
+
+ // When we have a |JSScript| for this frame, use a potentially memoized
+ // location from our PCLocationMap and copy it into |locationp|. When we do
+ // not have a |JSScript| for this frame (wasm frames), we take a slow path
+ // that doesn't employ memoization, and update |locationp|'s slots directly.
+
+ if (!iter.hasScript()) {
+ if (const char16_t* displayURL = iter.displayURL()) {
+ locationp.setSource(AtomizeChars(cx, displayURL, js_strlen(displayURL)));
+ } else {
+ const char* filename = iter.filename() ? iter.filename() : "";
+ locationp.setSource(Atomize(cx, filename, strlen(filename)));
+ }
+ if (!locationp.source())
+ return false;
+
+ uint32_t column = 0;
+ locationp.setLine(iter.computeLine(&column));
+ // XXX: Make the column 1-based as in other browsers, instead of 0-based
+ // which is how SpiderMonkey stores it internally. This will be
+ // unnecessary once bug 1144340 is fixed.
+ locationp.setColumn(column + 1);
+ return true;
+ }
+
+ RootedScript script(cx, iter.script());
+ jsbytecode* pc = iter.pc();
+
+ PCKey key(script, pc);
+ PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key);
+
+ if (!p) {
+ RootedAtom source(cx);
+ if (const char16_t* displayURL = iter.displayURL()) {
+ source = AtomizeChars(cx, displayURL, js_strlen(displayURL));
+ } else {
+ const char* filename = script->filename() ? script->filename() : "";
+ source = Atomize(cx, filename, strlen(filename));
+ }
+ if (!source)
+ return false;
+
+ uint32_t column;
+ uint32_t line = PCToLineNumber(script, pc, &column);
+
+ // Make the column 1-based. See comment above.
+ LocationValue value(source, line, column + 1);
+ if (!pcLocationMap.add(p, key, value)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ locationp.set(p->value());
+ return true;
+}
+
+void
+SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
+{
+ GlobalObject* global = compartment->maybeGlobal();
+ if (!global)
+ return;
+
+ GlobalObject::DebuggerVector* dbgs = global->getDebuggers();
+ if (!dbgs || dbgs->empty())
+ return;
+
+ mozilla::DebugOnly<ReadBarriered<Debugger*>*> begin = dbgs->begin();
+ mozilla::DebugOnly<bool> foundAnyDebuggers = false;
+
+ double probability = 0;
+ for (auto dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
+ // The set of debuggers had better not change while we're iterating,
+ // such that the vector gets reallocated.
+ MOZ_ASSERT(dbgs->begin() == begin);
+
+ if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled) {
+ foundAnyDebuggers = true;
+ probability = std::max((*dbgp)->allocationSamplingProbability,
+ probability);
+ }
+ }
+ MOZ_ASSERT(foundAnyDebuggers);
+
+ if (!bernoulliSeeded) {
+ mozilla::Array<uint64_t, 2> seed;
+ GenerateXorShift128PlusSeed(seed);
+ bernoulli.setRandomState(seed[0], seed[1]);
+ bernoulliSeeded = true;
+ }
+
+ bernoulli.setProbability(probability);
+}
+
+JSObject*
+SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
+ AutoEnterOOMUnsafeRegion& oomUnsafe) const
+{
+ RootedObject obj(cx, target);
+
+ SavedStacks& stacks = cx->compartment()->savedStacks();
+ if (!stacks.bernoulli.trial())
+ return nullptr;
+
+ RootedSavedFrame frame(cx);
+ if (!stacks.saveCurrentStack(cx, &frame))
+ oomUnsafe.crash("SavedStacksMetadataBuilder");
+
+ if (!Debugger::onLogAllocationSite(cx, obj, frame, JS_GetCurrentEmbedderTime()))
+ oomUnsafe.crash("SavedStacksMetadataBuilder");
+
+ MOZ_ASSERT_IF(frame, !frame->is<WrapperObject>());
+ return frame;
+}
+
+const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
+
+#ifdef JS_CRASH_DIAGNOSTICS
+void
+CompartmentChecker::check(SavedStacks* stacks)
+{
+ if (&compartment->savedStacks() != stacks) {
+ printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
+ (void*) &compartment->savedStacks(), stacks);
+ MOZ_CRASH();
+ }
+}
+#endif /* JS_CRASH_DIAGNOSTICS */
+
+/* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsSystem;
+/* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem;
+
+UTF8CharsZ
+BuildUTF8StackString(JSContext* cx, HandleObject stack)
+{
+ RootedString stackStr(cx);
+ if (!JS::BuildStackString(cx, stack, &stackStr))
+ return UTF8CharsZ();
+
+ char* chars = JS_EncodeStringToUTF8(cx, stackStr);
+ return UTF8CharsZ(chars, strlen(chars));
+}
+
+} /* namespace js */
+
+namespace JS {
+namespace ubi {
+
+bool
+ConcreteStackFrame<SavedFrame>::isSystem() const
+{
+ auto trustedPrincipals = get().runtimeFromAnyThread()->trustedPrincipals();
+ return get().getPrincipals() == trustedPrincipals ||
+ get().getPrincipals() == &js::ReconstructedSavedFramePrincipals::IsSystem;
+}
+
+bool
+ConcreteStackFrame<SavedFrame>::constructSavedFrameStack(JSContext* cx,
+ MutableHandleObject outSavedFrameStack)
+ const
+{
+ outSavedFrameStack.set(&get());
+ if (!cx->compartment()->wrap(cx, outSavedFrameStack)) {
+ outSavedFrameStack.set(nullptr);
+ return false;
+ }
+ return true;
+}
+
+// A `mozilla::Variant` matcher that converts the inner value of a
+// `JS::ubi::AtomOrTwoByteChars` string to a `JSAtom*`.
+struct MOZ_STACK_CLASS AtomizingMatcher
+{
+ JSContext* cx;
+ size_t length;
+
+ explicit AtomizingMatcher(JSContext* cx, size_t length)
+ : cx(cx)
+ , length(length)
+ { }
+
+ JSAtom* match(JSAtom* atom) {
+ MOZ_ASSERT(atom);
+ return atom;
+ }
+
+ JSAtom* match(const char16_t* chars) {
+ MOZ_ASSERT(chars);
+ return AtomizeChars(cx, chars, length);
+ }
+};
+
+JS_PUBLIC_API(bool)
+ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame,
+ MutableHandleObject outSavedFrameStack)
+{
+ SavedFrame::AutoLookupVector stackChain(cx);
+ Rooted<JS::ubi::StackFrame> ubiFrame(cx, frame);
+
+ while (ubiFrame.get()) {
+ // Convert the source and functionDisplayName strings to atoms.
+
+ js::RootedAtom source(cx);
+ AtomizingMatcher atomizer(cx, ubiFrame.get().sourceLength());
+ source = ubiFrame.get().source().match(atomizer);
+ if (!source)
+ return false;
+
+ js::RootedAtom functionDisplayName(cx);
+ auto nameLength = ubiFrame.get().functionDisplayNameLength();
+ if (nameLength > 0) {
+ AtomizingMatcher atomizer(cx, nameLength);
+ functionDisplayName = ubiFrame.get().functionDisplayName().match(atomizer);
+ if (!functionDisplayName)
+ return false;
+ }
+
+ auto principals = js::ReconstructedSavedFramePrincipals::getSingleton(ubiFrame.get());
+
+ if (!stackChain->emplaceBack(source, ubiFrame.get().line(), ubiFrame.get().column(),
+ functionDisplayName, /* asyncCause */ nullptr,
+ /* parent */ nullptr, principals))
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ ubiFrame = ubiFrame.get().parent();
+ }
+
+ js::RootedSavedFrame parentFrame(cx);
+ for (size_t i = stackChain->length(); i != 0; i--) {
+ SavedFrame::HandleLookup lookup = stackChain[i-1];
+ lookup->parent = parentFrame;
+ parentFrame = cx->compartment()->savedStacks().getOrCreateSavedFrame(cx, lookup);
+ if (!parentFrame)
+ return false;
+ }
+
+ outSavedFrameStack.set(parentFrame);
+ return true;
+}
+
+
+} // namespace ubi
+} // namespace JS
diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h
new file mode 100644
index 000000000..57b56081b
--- /dev/null
+++ b/js/src/vm/SavedStacks.h
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SavedStacks_h
+#define vm_SavedStacks_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/FastBernoulliTrial.h"
+
+#include "jscntxt.h"
+#include "jsmath.h"
+#include "jswrapper.h"
+#include "js/HashTable.h"
+#include "vm/SavedFrame.h"
+#include "vm/Stack.h"
+
+namespace js {
+
+// # Saved Stacks
+//
+// The `SavedStacks` class provides a compact way to capture and save JS stacks
+// as `SavedFrame` `JSObject` subclasses. A single `SavedFrame` object
+// represents one frame that was on the stack, and has a strong reference to its
+// parent `SavedFrame` (the next youngest frame). This reference is null when
+// the `SavedFrame` object is the oldest frame that was on the stack.
+//
+// This comment documents implementation. For usage documentation, see the
+// `js/src/doc/SavedFrame/SavedFrame.md` file and relevant `SavedFrame`
+// functions in `js/src/jsapi.h`.
+//
+// ## Compact
+//
+// Older saved stack frame tails are shared via hash consing, to deduplicate
+// structurally identical data. `SavedStacks` contains a hash table of weakly
+// held `SavedFrame` objects, and when the owning compartment is swept, it
+// removes entries from this table that aren't held alive in any other way. When
+// saving new stacks, we use this table to find pre-existing `SavedFrame`
+// objects. If such an object is already extant, it is reused; otherwise a new
+// `SavedFrame` is allocated and inserted into the table.
+//
+// Naive | Hash Consing
+// --------------+------------------
+// c -> b -> a | c -> b -> a
+// | ^
+// d -> b -> a | d ---|
+// | |
+// e -> b -> a | e ---'
+//
+// This technique is effective because of the nature of the events that trigger
+// capturing the stack. Currently, these events consist primarily of `JSObject`
+// allocation (when an observing `Debugger` has such tracking), `Promise`
+// settlement, and `Error` object creation. While these events may occur many
+// times, they tend to occur only at a few locations in the JS source. For
+// example, if we enable Object allocation tracking and run the esprima
+// JavaScript parser on its own JavaScript source, there are approximately 54700
+// total `Object` allocations, but just ~1400 unique JS stacks at allocation
+// time. There's only ~200 allocation sites if we capture only the youngest
+// stack frame.
+//
+// ## Security and Wrappers
+//
+// We save every frame on the stack, regardless of whether the `SavedStack`'s
+// compartment's principals subsume the frame's compartment's principals or
+// not. This gives us maximum flexibility down the line when accessing and
+// presenting captured stacks, but at the price of some complication involved in
+// preventing the leakage of privileged stack frames to unprivileged callers.
+//
+// When a `SavedFrame` method or accessor is called, we compare the caller's
+// compartment's principals to each `SavedFrame`'s captured principals. We avoid
+// using the usual `CallNonGenericMethod` and `nativeCall` machinery which
+// enters the `SavedFrame` object's compartment before we can check these
+// principals, because we need access to the original caller's compartment's
+// principals (unlike other `CallNonGenericMethod` users) to determine what view
+// of the stack to present. Instead, we take a similar approach to that used by
+// DOM methods, and manually unwrap wrappers until we get the underlying
+// `SavedFrame` object, find the first `SavedFrame` in its stack whose captured
+// principals are subsumed by the caller's principals, access the reserved slots
+// we care about, and then rewrap return values as necessary.
+//
+// Consider the following diagram:
+//
+//                                     Content Compartment
+//                                    +---------------------------------------+
+//                                    |              |
+//                                    |           +------------------------+  |
+//      Chrome Compartment            |           |                        |  |
+//    +--------------------+          |           | SavedFrame C (content) |  |
+//    |                    |          |           |                        |  |
+//    |                  +--------------+         +------------------------+ |
+//    |                  |              |                    ^                |
+//    |     var x -----> | Xray Wrapper |-----.              |                |
+//    |                  |              |     |              |                |
+//    |                  +--------------+     |   +------------------------+  |
+//    |                    |          |       |   |                        |  |
+//    |                  +--------------+     |   | SavedFrame B (content) |  |
+//    |                  |              |     |   |                        |  |
+//    |     var y -----> | CCW (waived) |--.  |   +------------------------+  |
+//    |                  |              |  |  |              ^               |
+//    |                  +--------------+  |  |              |               |
+//    |                    |          |    |  |              |                |
+//    +--------------------+          |    |  |   +------------------------+  |
+//                                    |    |  '-> |                        |  |
+//                                    |    |      | SavedFrame A (chrome)  |  |
+//                                    |    '----> |                        |  |
+//                                    |           +------------------------+  |
+//                                    |                      ^                |
+//                                    |                      |                |
+//                                    |           var z -----'                |
+//                                    |                                       |
+//                                    +---------------------------------------+
+//
+// CCW is a plain cross-compartment wrapper, yielded by waiving Xray vision. A
+// is the youngest `SavedFrame` and represents a frame that was from the chrome
+// compartment, while B and C are from frames from the content compartment. C is
+// the oldest frame.
+//
+// Note that it is always safe to waive an Xray around a SavedFrame object,
+// because SavedFrame objects and the SavedFrame prototype are always frozen you
+// will never run untrusted code.
+//
+// Depending on who the caller is, the view of the stack will be different, and
+// is summarized in the table below.
+//
+// Var | View
+// -----+------------
+// x | A -> B -> C
+// y, z | B -> C
+//
+// In the case of x, the `SavedFrame` accessors are called with an Xray wrapper
+// around the `SavedFrame` object as the `this` value, and the chrome
+// compartment as the cx's current principals. Because the chrome compartment's
+// principals subsume both itself and the content compartment's principals, x
+// has the complete view of the stack.
+//
+// In the case of y, the cross-compartment machinery automatically enters the
+// content compartment, and calls the `SavedFrame` accessors with the wrapped
+// `SavedFrame` object as the `this` value. Because the cx's current compartment
+// is the content compartment, and the content compartment's principals do not
+// subsume the chrome compartment's principals, it can only see the B and C
+// frames.
+//
+// In the case of z, the `SavedFrame` accessors are called with the `SavedFrame`
+// object in the `this` value, and the content compartment as the cx's current
+// compartment. Similar to the case of y, only the B and C frames are exposed
+// because the cx's current compartment's principals do not subsume A's captured
+// principals.
+
+class SavedStacks {
+ friend class SavedFrame;
+ friend bool JS::ubi::ConstructSavedFrameStackSlow(JSContext* cx,
+ JS::ubi::StackFrame& ubiFrame,
+ MutableHandleObject outSavedFrameStack);
+
+ public:
+ SavedStacks()
+ : frames(),
+ bernoulliSeeded(false),
+ bernoulli(1.0, 0x59fdad7f6b4cc573, 0x91adf38db96a9354),
+ creatingSavedFrame(false)
+ { }
+
+ MOZ_MUST_USE bool init();
+ bool initialized() const { return frames.initialized(); }
+ MOZ_MUST_USE bool saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
+ JS::StackCapture&& capture = JS::StackCapture(JS::AllFrames()));
+ MOZ_MUST_USE bool copyAsyncStack(JSContext* cx, HandleObject asyncStack,
+ HandleString asyncCause,
+ MutableHandleSavedFrame adoptedStack,
+ uint32_t maxFrameCount = 0);
+ void sweep();
+ void trace(JSTracer* trc);
+ uint32_t count();
+ void clear();
+ void chooseSamplingProbability(JSCompartment*);
+
+ // Set the sampling random number generator's state to |state0| and
+ // |state1|. One or the other must be non-zero. See the comments for
+ // mozilla::non_crypto::XorShift128PlusRNG::setState for details.
+ void setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ // An alloction metadata builder that marks cells with the JavaScript stack
+ // at which they were allocated.
+ struct MetadataBuilder : public AllocationMetadataBuilder {
+ MetadataBuilder() : AllocationMetadataBuilder() { }
+ virtual JSObject* build(JSContext *cx, HandleObject obj,
+ AutoEnterOOMUnsafeRegion& oomUnsafe) const override;
+ };
+
+ static const MetadataBuilder metadataBuilder;
+
+ private:
+ SavedFrame::Set frames;
+ bool bernoulliSeeded;
+ mozilla::FastBernoulliTrial bernoulli;
+ bool creatingSavedFrame;
+
+ // Similar to mozilla::ReentrancyGuard, but instead of asserting against
+ // reentrancy, just change the behavior of SavedStacks::saveCurrentStack to
+ // return a nullptr SavedFrame.
+ struct MOZ_RAII AutoReentrancyGuard {
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
+ SavedStacks& stacks;
+
+ explicit AutoReentrancyGuard(SavedStacks& stacks MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : stacks(stacks)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ stacks.creatingSavedFrame = true;
+ }
+
+ ~AutoReentrancyGuard()
+ {
+ stacks.creatingSavedFrame = false;
+ }
+ };
+
+ MOZ_MUST_USE bool insertFrames(JSContext* cx, FrameIter& iter,
+ MutableHandleSavedFrame frame,
+ JS::StackCapture&& capture);
+ MOZ_MUST_USE bool adoptAsyncStack(JSContext* cx, HandleSavedFrame asyncStack,
+ HandleString asyncCause,
+ MutableHandleSavedFrame adoptedStack,
+ uint32_t maxFrameCount);
+ SavedFrame* getOrCreateSavedFrame(JSContext* cx, SavedFrame::HandleLookup lookup);
+ SavedFrame* createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup lookup);
+
+ // Cache for memoizing PCToLineNumber lookups.
+
+ struct PCKey {
+ PCKey(JSScript* script, jsbytecode* pc) : script(script), pc(pc) { }
+
+ HeapPtr<JSScript*> script;
+ jsbytecode* pc;
+
+ void trace(JSTracer* trc) { /* PCKey is weak. */ }
+ bool needsSweep() { return IsAboutToBeFinalized(&script); }
+ };
+
+ public:
+ struct LocationValue {
+ LocationValue() : source(nullptr), line(0), column(0) { }
+ LocationValue(JSAtom* source, size_t line, uint32_t column)
+ : source(source), line(line), column(column)
+ { }
+
+ void trace(JSTracer* trc) {
+ TraceNullableEdge(trc, &source, "SavedStacks::LocationValue::source");
+ }
+
+ bool needsSweep() {
+ // LocationValue is always held strongly, but in a weak map.
+ // Assert that it has been marked already, but allow it to be
+ // ejected from the map when the key dies.
+ MOZ_ASSERT(source);
+ MOZ_ASSERT(!IsAboutToBeFinalized(&source));
+ return true;
+ }
+
+ HeapPtr<JSAtom*> source;
+ size_t line;
+ uint32_t column;
+ };
+
+ template <typename Outer>
+ struct LocationValueOperations {
+ JSAtom* source() const { return loc().source; }
+ size_t line() const { return loc().line; }
+ uint32_t column() const { return loc().column; }
+ private:
+ const LocationValue& loc() const { return static_cast<const Outer*>(this)->get(); }
+ };
+
+ template <typename Outer>
+ struct MutableLocationValueOperations : public LocationValueOperations<Outer> {
+ void setSource(JSAtom* v) { loc().source = v; }
+ void setLine(size_t v) { loc().line = v; }
+ void setColumn(uint32_t v) { loc().column = v; }
+ private:
+ LocationValue& loc() { return static_cast<Outer*>(this)->get(); }
+ };
+
+ private:
+ struct PCLocationHasher : public DefaultHasher<PCKey> {
+ using ScriptPtrHasher = DefaultHasher<JSScript*>;
+ using BytecodePtrHasher = DefaultHasher<jsbytecode*>;
+
+ static HashNumber hash(const PCKey& key) {
+ return mozilla::AddToHash(ScriptPtrHasher::hash(key.script),
+ BytecodePtrHasher::hash(key.pc));
+ }
+
+ static bool match(const PCKey& l, const PCKey& k) {
+ return ScriptPtrHasher::match(l.script, k.script) &&
+ BytecodePtrHasher::match(l.pc, k.pc);
+ }
+ };
+
+ // We eagerly Atomize the script source stored in LocationValue because
+ // wasm does not always have a JSScript and the source might not be
+ // available when we need it later. However, since the JSScript does not
+ // actually hold this atom, we have to trace it strongly to keep it alive.
+ // Thus, it takes two GC passes to fully clean up this table: the first GC
+ // removes the dead script; the second will clear out the source atom since
+ // it is no longer held by the table.
+ using PCLocationMap = GCHashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy>;
+ PCLocationMap pcLocationMap;
+
+ MOZ_MUST_USE bool getLocation(JSContext* cx, const FrameIter& iter,
+ MutableHandle<LocationValue> locationp);
+};
+
+template <>
+class RootedBase<SavedStacks::LocationValue>
+ : public SavedStacks::MutableLocationValueOperations<JS::Rooted<SavedStacks::LocationValue>>
+{};
+
+template <>
+class MutableHandleBase<SavedStacks::LocationValue>
+ : public SavedStacks::MutableLocationValueOperations<JS::MutableHandle<SavedStacks::LocationValue>>
+{};
+
+UTF8CharsZ
+BuildUTF8StackString(JSContext* cx, HandleObject stack);
+
+} /* namespace js */
+
+#endif /* vm_SavedStacks_h */
diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
new file mode 100644
index 000000000..112b34586
--- /dev/null
+++ b/js/src/vm/Scope.cpp
@@ -0,0 +1,1460 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Scope.h"
+
+#include "mozilla/ScopeExit.h"
+
+#include "jsscript.h"
+#include "builtin/ModuleObject.h"
+#include "gc/Allocator.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/Runtime.h"
+
+#include "vm/Shape-inl.h"
+
+using namespace js;
+
+using mozilla::Maybe;
+using mozilla::MakeScopeExit;
+using mozilla::Move;
+using mozilla::Nothing;
+using mozilla::Some;
+
+const char*
+js::BindingKindString(BindingKind kind)
+{
+ switch (kind) {
+ case BindingKind::Import:
+ return "import";
+ case BindingKind::FormalParameter:
+ return "formal parameter";
+ case BindingKind::Var:
+ return "var";
+ case BindingKind::Let:
+ return "let";
+ case BindingKind::Const:
+ return "const";
+ case BindingKind::NamedLambdaCallee:
+ return "named lambda callee";
+ }
+ MOZ_CRASH("Bad BindingKind");
+}
+
+const char*
+js::ScopeKindString(ScopeKind kind)
+{
+ switch (kind) {
+ case ScopeKind::Function:
+ return "function";
+ case ScopeKind::FunctionBodyVar:
+ return "function body var";
+ case ScopeKind::ParameterExpressionVar:
+ return "parameter expression var";
+ case ScopeKind::Lexical:
+ return "lexical";
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ return "catch";
+ case ScopeKind::NamedLambda:
+ return "named lambda";
+ case ScopeKind::StrictNamedLambda:
+ return "strict named lambda";
+ case ScopeKind::With:
+ return "with";
+ case ScopeKind::Eval:
+ return "eval";
+ case ScopeKind::StrictEval:
+ return "strict eval";
+ case ScopeKind::Global:
+ return "global";
+ case ScopeKind::NonSyntactic:
+ return "non-syntactic";
+ case ScopeKind::Module:
+ return "module";
+ }
+ MOZ_CRASH("Bad ScopeKind");
+}
+
+static Shape*
+EmptyEnvironmentShape(ExclusiveContext* cx, const Class* cls, uint32_t numSlots,
+ uint32_t baseShapeFlags)
+{
+ // Put as many slots into the object header as possible.
+ uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
+ return EmptyShape::getInitialShape(cx, cls, TaggedProto(nullptr), numFixed,
+ baseShapeFlags);
+}
+
+static Shape*
+NextEnvironmentShape(ExclusiveContext* cx, HandleAtom name, BindingKind bindKind, uint32_t slot,
+ StackBaseShape& stackBase, HandleShape shape)
+{
+ UnownedBaseShape* base = BaseShape::getUnowned(cx, stackBase);
+ if (!base)
+ return nullptr;
+
+ unsigned attrs = JSPROP_PERMANENT | JSPROP_ENUMERATE;
+ switch (bindKind) {
+ case BindingKind::Const:
+ case BindingKind::NamedLambdaCallee:
+ attrs |= JSPROP_READONLY;
+ break;
+ default:
+ break;
+ }
+
+ jsid id = NameToId(name->asPropertyName());
+ Rooted<StackShape> child(cx, StackShape(base, id, slot, attrs, 0));
+ return cx->zone()->propertyTree.getChild(cx, shape, child);
+}
+
+static Shape*
+CreateEnvironmentShape(ExclusiveContext* cx, BindingIter& bi, const Class* cls,
+ uint32_t numSlots, uint32_t baseShapeFlags)
+{
+ RootedShape shape(cx, EmptyEnvironmentShape(cx, cls, numSlots, baseShapeFlags));
+ if (!shape)
+ return nullptr;
+
+ RootedAtom name(cx);
+ StackBaseShape stackBase(cx, cls, baseShapeFlags);
+ for (; bi; bi++) {
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Environment) {
+ name = bi.name();
+ shape = NextEnvironmentShape(cx, name, bi.kind(), loc.slot(), stackBase, shape);
+ if (!shape)
+ return nullptr;
+ }
+ }
+
+ return shape;
+}
+
+template <typename ConcreteScope>
+static UniquePtr<typename ConcreteScope::Data>
+CopyScopeData(ExclusiveContext* cx, Handle<typename ConcreteScope::Data*> data)
+{
+ size_t dataSize = ConcreteScope::sizeOfData(data->length);
+ size_t headerSize = sizeof(typename ConcreteScope::Data);
+ MOZ_ASSERT(dataSize >= headerSize);
+ size_t extraSize = dataSize - headerSize;
+
+ uint8_t* copyBytes = cx->zone()->pod_malloc<uint8_t>(dataSize);
+ if (!copyBytes) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ auto dataCopy = reinterpret_cast<typename ConcreteScope::Data*>(copyBytes);
+ new (dataCopy) typename ConcreteScope::Data(*data);
+
+ uint8_t* extra = reinterpret_cast<uint8_t*>(data.get()) + headerSize;
+ uint8_t* extraCopy = copyBytes + headerSize;
+
+ mozilla::PodCopy<uint8_t>(extraCopy, extra, extraSize);
+ return UniquePtr<typename ConcreteScope::Data>(dataCopy);
+}
+
+template <typename ConcreteScope>
+static bool
+PrepareScopeData(ExclusiveContext* cx, BindingIter& bi, Handle<UniquePtr<typename ConcreteScope::Data>> data,
+ const Class* cls, uint32_t baseShapeFlags, MutableHandleShape envShape)
+{
+ // Copy a fresh BindingIter for use below.
+ BindingIter freshBi(bi);
+
+ // Iterate through all bindings. This counts the number of environment
+ // slots needed and computes the maximum frame slot.
+ while (bi)
+ bi++;
+ data->nextFrameSlot = bi.canHaveFrameSlots() ? bi.nextFrameSlot() : LOCALNO_LIMIT;
+
+ // Make a new environment shape if any environment slots were used.
+ if (bi.nextEnvironmentSlot() == JSSLOT_FREE(cls)) {
+ envShape.set(nullptr);
+ } else {
+ envShape.set(CreateEnvironmentShape(cx, freshBi, cls, bi.nextEnvironmentSlot(),
+ baseShapeFlags));
+ if (!envShape)
+ return false;
+ }
+
+ return true;
+}
+
+template <typename ConcreteScope>
+static UniquePtr<typename ConcreteScope::Data>
+NewEmptyScopeData(ExclusiveContext* cx, uint32_t length = 0)
+{
+ uint8_t* bytes = cx->zone()->pod_calloc<uint8_t>(ConcreteScope::sizeOfData(length));
+ if (!bytes)
+ ReportOutOfMemory(cx);
+ auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
+ if (data)
+ new (data) typename ConcreteScope::Data();
+ return UniquePtr<typename ConcreteScope::Data>(data);
+}
+
+static bool
+XDRBindingName(XDRState<XDR_ENCODE>* xdr, BindingName* bindingName)
+{
+ JSContext* cx = xdr->cx();
+
+ RootedAtom atom(cx, bindingName->name());
+ bool hasAtom = !!atom;
+
+ uint8_t u8 = uint8_t(hasAtom << 1) | uint8_t(bindingName->closedOver());
+ if (!xdr->codeUint8(&u8))
+ return false;
+
+ if (atom && !XDRAtom(xdr, &atom))
+ return false;
+
+ return true;
+}
+
+static bool
+XDRBindingName(XDRState<XDR_DECODE>* xdr, BindingName* bindingName)
+{
+ JSContext* cx = xdr->cx();
+
+ uint8_t u8;
+ if (!xdr->codeUint8(&u8))
+ return false;
+
+ bool closedOver = u8 & 1;
+ bool hasAtom = u8 >> 1;
+
+ RootedAtom atom(cx);
+ if (hasAtom && !XDRAtom(xdr, &atom))
+ return false;
+
+ *bindingName = BindingName(atom, closedOver);
+
+ return true;
+}
+
+template <typename ConcreteScopeData>
+static void
+DeleteScopeData(ConcreteScopeData* data)
+{
+ // Some scope Data classes have GCManagedDeletePolicy because then contain
+ // GCPtrs. Dispose of them in the appropriate way.
+ JS::DeletePolicy<ConcreteScopeData>()(data);
+}
+
+template <typename ConcreteScope, XDRMode mode>
+/* static */ bool
+Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
+ MutableHandle<typename ConcreteScope::Data*> data)
+{
+ MOZ_ASSERT(!data);
+
+ JSContext* cx = xdr->cx();
+
+ uint32_t length;
+ if (mode == XDR_ENCODE)
+ length = scope->data().length;
+ if (!xdr->codeUint32(&length))
+ return false;
+
+ if (mode == XDR_ENCODE) {
+ data.set(&scope->data());
+ } else {
+ data.set(NewEmptyScopeData<ConcreteScope>(cx, length).release());
+ if (!data)
+ return false;
+ data->length = length;
+ }
+
+ for (uint32_t i = 0; i < length; i++) {
+ if (!XDRBindingName(xdr, &data->names[i])) {
+ if (mode == XDR_DECODE) {
+ DeleteScopeData(data.get());
+ data.set(nullptr);
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */ Scope*
+Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
+{
+ Scope* scope = Allocate<Scope>(cx);
+ if (scope)
+ new (scope) Scope(kind, enclosing, envShape);
+ return scope;
+}
+
+template <typename T, typename D>
+/* static */ Scope*
+Scope::create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
+ HandleShape envShape, mozilla::UniquePtr<T, D> data)
+{
+ Scope* scope = create(cx, kind, enclosing, envShape);
+ if (!scope)
+ return nullptr;
+
+ // It is an invariant that all Scopes that have data (currently, all
+ // ScopeKinds except With) must have non-null data.
+ MOZ_ASSERT(data);
+ scope->initData(Move(data));
+
+ return scope;
+}
+
+uint32_t
+Scope::chainLength() const
+{
+ uint32_t length = 0;
+ for (ScopeIter si(const_cast<Scope*>(this)); si; si++)
+ length++;
+ return length;
+}
+
+uint32_t
+Scope::environmentChainLength() const
+{
+ uint32_t length = 0;
+ for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
+ if (si.hasSyntacticEnvironment())
+ length++;
+ }
+ return length;
+}
+
+Shape*
+Scope::maybeCloneEnvironmentShape(JSContext* cx)
+{
+ // Clone the environment shape if cloning into a different zone.
+ if (environmentShape_ && environmentShape_->zoneFromAnyThread() != cx->zone()) {
+ BindingIter bi(this);
+ return CreateEnvironmentShape(cx, bi,
+ environmentShape_->getObjectClass(),
+ environmentShape_->slotSpan(),
+ environmentShape_->getObjectFlags());
+ }
+ return environmentShape_;
+}
+
+/* static */ Scope*
+Scope::clone(JSContext* cx, HandleScope scope, HandleScope enclosing)
+{
+ RootedShape envShape(cx);
+ if (scope->environmentShape()) {
+ envShape = scope->maybeCloneEnvironmentShape(cx);
+ if (!envShape)
+ return nullptr;
+ }
+
+ switch (scope->kind_) {
+ case ScopeKind::Function:
+ MOZ_CRASH("Use FunctionScope::clone.");
+ break;
+
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar: {
+ Rooted<VarScope::Data*> original(cx, &scope->as<VarScope>().data());
+ UniquePtr<VarScope::Data> dataClone = CopyScopeData<VarScope>(cx, original);
+ if (!dataClone)
+ return nullptr;
+ return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
+ }
+
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda: {
+ Rooted<LexicalScope::Data*> original(cx, &scope->as<LexicalScope>().data());
+ UniquePtr<LexicalScope::Data> dataClone = CopyScopeData<LexicalScope>(cx, original);
+ if (!dataClone)
+ return nullptr;
+ return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
+ }
+
+ case ScopeKind::With:
+ return create(cx, scope->kind_, enclosing, envShape);
+
+ case ScopeKind::Eval:
+ case ScopeKind::StrictEval: {
+ Rooted<EvalScope::Data*> original(cx, &scope->as<EvalScope>().data());
+ UniquePtr<EvalScope::Data> dataClone = CopyScopeData<EvalScope>(cx, original);
+ if (!dataClone)
+ return nullptr;
+ return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
+ }
+
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ MOZ_CRASH("Use GlobalScope::clone.");
+ break;
+
+ case ScopeKind::Module:
+ MOZ_CRASH("NYI");
+ break;
+ }
+
+ return nullptr;
+}
+
+void
+Scope::finalize(FreeOp* fop)
+{
+ MOZ_ASSERT(CurrentThreadIsGCSweeping());
+ if (data_) {
+ // We don't need to call the destructors for any GCPtrs in Data because
+ // this only happens during a GC.
+ fop->free_(reinterpret_cast<void*>(data_));
+ data_ = 0;
+ }
+}
+
+size_t
+Scope::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ if (data_)
+ return mallocSizeOf(reinterpret_cast<void*>(data_));
+ return 0;
+}
+
+void
+Scope::dump()
+{
+ for (ScopeIter si(this); si; si++) {
+ fprintf(stderr, "%s [%p]", ScopeKindString(si.kind()), si.scope());
+ if (si.scope()->enclosing())
+ fprintf(stderr, " -> ");
+ }
+ fprintf(stderr, "\n");
+}
+
+uint32_t
+LexicalScope::firstFrameSlot() const
+{
+ switch (kind()) {
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ // For intra-frame scopes, find the enclosing scope's next frame slot.
+ return nextFrameSlot(enclosing());
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda:
+ // Named lambda scopes cannot have frame slots.
+ return LOCALNO_LIMIT;
+ default:
+ // Otherwise start at 0.
+ break;
+ }
+ return 0;
+}
+
+/* static */ uint32_t
+LexicalScope::nextFrameSlot(Scope* scope)
+{
+ for (ScopeIter si(scope); si; si++) {
+ switch (si.kind()) {
+ case ScopeKind::Function:
+ return si.scope()->as<FunctionScope>().nextFrameSlot();
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar:
+ return si.scope()->as<VarScope>().nextFrameSlot();
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ return si.scope()->as<LexicalScope>().nextFrameSlot();
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda:
+ // Named lambda scopes cannot have frame slots.
+ return 0;
+ case ScopeKind::With:
+ continue;
+ case ScopeKind::Eval:
+ case ScopeKind::StrictEval:
+ return si.scope()->as<EvalScope>().nextFrameSlot();
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ return 0;
+ case ScopeKind::Module:
+ return si.scope()->as<ModuleScope>().nextFrameSlot();
+ }
+ }
+ MOZ_CRASH("Not an enclosing intra-frame Scope");
+}
+
+/* static */ LexicalScope*
+LexicalScope::create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data,
+ uint32_t firstFrameSlot, HandleScope enclosing)
+{
+ MOZ_ASSERT(data, "LexicalScopes should not be created if there are no bindings.");
+
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ Rooted<UniquePtr<Data>> copy(cx, CopyScopeData<LexicalScope>(cx, data));
+ if (!copy)
+ return nullptr;
+
+ return createWithData(cx, kind, &copy, firstFrameSlot, enclosing);
+}
+
+/* static */ LexicalScope*
+LexicalScope::createWithData(ExclusiveContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
+ uint32_t firstFrameSlot, HandleScope enclosing)
+{
+ bool isNamedLambda = kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda;
+
+ MOZ_ASSERT_IF(!isNamedLambda && firstFrameSlot != 0,
+ firstFrameSlot == nextFrameSlot(enclosing));
+ MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT);
+
+ RootedShape envShape(cx);
+ BindingIter bi(*data, firstFrameSlot, isNamedLambda);
+ if (!PrepareScopeData<LexicalScope>(cx, bi, data, &LexicalEnvironmentObject::class_,
+ BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE, &envShape))
+ {
+ return nullptr;
+ }
+
+ Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(data.get()));
+ if (!scope)
+ return nullptr;
+ MOZ_ASSERT(scope->as<LexicalScope>().firstFrameSlot() == firstFrameSlot);
+ return &scope->as<LexicalScope>();
+}
+
+/* static */ Shape*
+LexicalScope::getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx)
+{
+ const Class* cls = &LexicalEnvironmentObject::class_;
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), BaseShape::DELEGATE);
+}
+
+template <XDRMode mode>
+/* static */ bool
+LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope)
+{
+ JSContext* cx = xdr->cx();
+
+ Rooted<Data*> data(cx);
+ if (!XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data))
+ return false;
+
+ {
+ Maybe<Rooted<UniquePtr<Data>>> uniqueData;
+ if (mode == XDR_DECODE)
+ uniqueData.emplace(cx, data);
+
+ uint32_t firstFrameSlot;
+ uint32_t nextFrameSlot;
+ if (mode == XDR_ENCODE) {
+ firstFrameSlot = scope->as<LexicalScope>().firstFrameSlot();
+ nextFrameSlot = data->nextFrameSlot;
+ }
+
+ if (!xdr->codeUint32(&data->constStart))
+ return false;
+ if (!xdr->codeUint32(&firstFrameSlot))
+ return false;
+ if (!xdr->codeUint32(&nextFrameSlot))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, enclosing));
+ if (!scope)
+ return false;
+
+ // nextFrameSlot is used only for this correctness check.
+ MOZ_ASSERT(nextFrameSlot == scope->as<LexicalScope>().data().nextFrameSlot);
+ }
+ }
+
+ return true;
+}
+
+template
+/* static */ bool
+LexicalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+template
+/* static */ bool
+LexicalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+static inline uint32_t
+FunctionScopeEnvShapeFlags(bool hasParameterExprs)
+{
+ if (hasParameterExprs)
+ return BaseShape::DELEGATE;
+ return BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
+}
+
+/* static */ FunctionScope*
+FunctionScope::create(ExclusiveContext* cx, Handle<Data*> dataArg,
+ bool hasParameterExprs, bool needsEnvironment,
+ HandleFunction fun, HandleScope enclosing)
+{
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<FunctionScope>(cx, dataArg)
+ : NewEmptyScopeData<FunctionScope>(cx));
+ if (!data)
+ return nullptr;
+
+ return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun, enclosing);
+}
+
+/* static */ FunctionScope*
+FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
+ bool hasParameterExprs, bool needsEnvironment,
+ HandleFunction fun, HandleScope enclosing)
+{
+ MOZ_ASSERT(data);
+ MOZ_ASSERT(fun->isTenured());
+
+ // FunctionScope::Data has GCManagedDeletePolicy because it contains a
+ // GCPtr. Destruction of |data| below may trigger calls into the GC.
+ Rooted<FunctionScope*> funScope(cx);
+
+ {
+ RootedShape envShape(cx);
+
+ BindingIter bi(*data, hasParameterExprs);
+ uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
+ if (!PrepareScopeData<FunctionScope>(cx, bi, data, &CallObject::class_, shapeFlags,
+ &envShape))
+ {
+ return nullptr;
+ }
+
+ data->hasParameterExprs = hasParameterExprs;
+ data->canonicalFunction.init(fun);
+
+ // An environment may be needed regardless of existence of any closed over
+ // bindings:
+ // - Extensible scopes (i.e., due to direct eval)
+ // - Needing a home object
+ // - Being a derived class constructor
+ // - Being a generator
+ if (!envShape && needsEnvironment) {
+ envShape = getEmptyEnvironmentShape(cx, hasParameterExprs);
+ if (!envShape)
+ return nullptr;
+ }
+
+ Scope* scope = Scope::create(cx, ScopeKind::Function, enclosing, envShape);
+ if (!scope)
+ return nullptr;
+
+ funScope = &scope->as<FunctionScope>();
+ funScope->initData(Move(data.get()));
+ }
+
+ return funScope;
+}
+
+JSScript*
+FunctionScope::script() const
+{
+ return canonicalFunction()->nonLazyScript();
+}
+
+/* static */ Shape*
+FunctionScope::getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs)
+{
+ const Class* cls = &CallObject::class_;
+ uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), shapeFlags);
+}
+
+/* static */ FunctionScope*
+FunctionScope::clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
+ HandleScope enclosing)
+{
+ MOZ_ASSERT(fun != scope->canonicalFunction());
+
+ // FunctionScope::Data has GCManagedDeletePolicy because it contains a
+ // GCPtr. Destruction of |dataClone| below may trigger calls into the GC.
+ Rooted<FunctionScope*> funScopeClone(cx);
+
+ {
+ RootedShape envShape(cx);
+ if (scope->environmentShape()) {
+ envShape = scope->maybeCloneEnvironmentShape(cx);
+ if (!envShape)
+ return nullptr;
+ }
+
+ Rooted<Data*> dataOriginal(cx, &scope->as<FunctionScope>().data());
+ Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<FunctionScope>(cx, dataOriginal));
+ if (!dataClone)
+ return nullptr;
+
+ dataClone->canonicalFunction.init(fun);
+
+ Scope* scopeClone = Scope::create(cx, scope->kind(), enclosing, envShape);
+ if (!scopeClone)
+ return nullptr;
+
+ funScopeClone = &scopeClone->as<FunctionScope>();
+ funScopeClone->initData(Move(dataClone.get()));
+ }
+
+ return funScopeClone;
+}
+
+template <XDRMode mode>
+/* static */ bool
+FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
+ MutableHandleScope scope)
+{
+ JSContext* cx = xdr->cx();
+ Rooted<Data*> data(cx);
+ if (!XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data))
+ return false;
+
+ {
+ Maybe<Rooted<UniquePtr<Data>>> uniqueData;
+ if (mode == XDR_DECODE)
+ uniqueData.emplace(cx, data);
+
+ uint8_t needsEnvironment;
+ uint8_t hasParameterExprs;
+ uint32_t nextFrameSlot;
+ if (mode == XDR_ENCODE) {
+ needsEnvironment = scope->hasEnvironment();
+ hasParameterExprs = data->hasParameterExprs;
+ nextFrameSlot = data->nextFrameSlot;
+ }
+ if (!xdr->codeUint8(&needsEnvironment))
+ return false;
+ if (!xdr->codeUint8(&hasParameterExprs))
+ return false;
+ if (!xdr->codeUint16(&data->nonPositionalFormalStart))
+ return false;
+ if (!xdr->codeUint16(&data->varStart))
+ return false;
+ if (!xdr->codeUint32(&nextFrameSlot))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ if (!data->length) {
+ MOZ_ASSERT(!data->nonPositionalFormalStart);
+ MOZ_ASSERT(!data->varStart);
+ MOZ_ASSERT(!data->nextFrameSlot);
+ }
+
+ scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, needsEnvironment, fun,
+ enclosing));
+ if (!scope)
+ return false;
+
+ // nextFrameSlot is used only for this correctness check.
+ MOZ_ASSERT(nextFrameSlot == scope->as<FunctionScope>().data().nextFrameSlot);
+ }
+ }
+
+ return true;
+}
+
+template
+/* static */ bool
+FunctionScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleFunction fun, HandleScope enclosing,
+ MutableHandleScope scope);
+
+template
+/* static */ bool
+FunctionScope::XDR(XDRState<XDR_DECODE>* xdr, HandleFunction fun, HandleScope enclosing,
+ MutableHandleScope scope);
+
+static const uint32_t VarScopeEnvShapeFlags =
+ BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
+
+static UniquePtr<VarScope::Data>
+NewEmptyVarScopeData(ExclusiveContext* cx, uint32_t firstFrameSlot)
+{
+ UniquePtr<VarScope::Data> data(NewEmptyScopeData<VarScope>(cx));
+ if (data)
+ data->nextFrameSlot = firstFrameSlot;
+
+ return data;
+}
+
+/* static */ VarScope*
+VarScope::create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> dataArg,
+ uint32_t firstFrameSlot, bool needsEnvironment, HandleScope enclosing)
+{
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<VarScope>(cx, dataArg)
+ : NewEmptyVarScopeData(cx, firstFrameSlot));
+ if (!data)
+ return nullptr;
+
+ return createWithData(cx, kind, &data, firstFrameSlot, needsEnvironment, enclosing);
+}
+
+/* static */ VarScope*
+VarScope::createWithData(ExclusiveContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
+ uint32_t firstFrameSlot, bool needsEnvironment, HandleScope enclosing)
+{
+ MOZ_ASSERT(data);
+
+ RootedShape envShape(cx);
+ BindingIter bi(*data, firstFrameSlot);
+ if (!PrepareScopeData<VarScope>(cx, bi, data, &VarEnvironmentObject::class_, VarScopeEnvShapeFlags,
+ &envShape))
+ {
+ return nullptr;
+ }
+
+ // An environment may be needed regardless of existence of any closed over
+ // bindings:
+ // - Extensible scopes (i.e., due to direct eval)
+ // - Being a generator
+ if (!envShape && needsEnvironment) {
+ envShape = getEmptyEnvironmentShape(cx);
+ if (!envShape)
+ return nullptr;
+ }
+
+ Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(data.get()));
+ if (!scope)
+ return nullptr;
+ return &scope->as<VarScope>();
+}
+
+/* static */ Shape*
+VarScope::getEmptyEnvironmentShape(ExclusiveContext* cx)
+{
+ const Class* cls = &VarEnvironmentObject::class_;
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), VarScopeEnvShapeFlags);
+}
+
+uint32_t
+VarScope::firstFrameSlot() const
+{
+ if (enclosing()->is<FunctionScope>())
+ return enclosing()->as<FunctionScope>().nextFrameSlot();
+ return 0;
+}
+
+template <XDRMode mode>
+/* static */ bool
+VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope)
+{
+ JSContext* cx = xdr->cx();
+ Rooted<Data*> data(cx);
+ if (!XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data))
+ return false;
+
+ {
+ Maybe<Rooted<UniquePtr<Data>>> uniqueData;
+ if (mode == XDR_DECODE)
+ uniqueData.emplace(cx, data);
+
+ uint8_t needsEnvironment;
+ uint32_t firstFrameSlot;
+ uint32_t nextFrameSlot;
+ if (mode == XDR_ENCODE) {
+ needsEnvironment = scope->hasEnvironment();
+ firstFrameSlot = scope->as<VarScope>().firstFrameSlot();
+ nextFrameSlot = data->nextFrameSlot;
+ }
+ if (!xdr->codeUint8(&needsEnvironment))
+ return false;
+ if (!xdr->codeUint32(&firstFrameSlot))
+ return false;
+ if (!xdr->codeUint32(&nextFrameSlot))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ if (!data->length) {
+ MOZ_ASSERT(!data->nextFrameSlot);
+ }
+
+ scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, needsEnvironment,
+ enclosing));
+ if (!scope)
+ return false;
+
+ // nextFrameSlot is used only for this correctness check.
+ MOZ_ASSERT(nextFrameSlot == scope->as<VarScope>().data().nextFrameSlot);
+ }
+ }
+
+ return true;
+}
+
+template
+/* static */ bool
+VarScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+template
+/* static */ bool
+VarScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+/* static */ GlobalScope*
+GlobalScope::create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> dataArg)
+{
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<GlobalScope>(cx, dataArg)
+ : NewEmptyScopeData<GlobalScope>(cx));
+ if (!data)
+ return nullptr;
+
+ return createWithData(cx, kind, &data);
+}
+
+/* static */ GlobalScope*
+GlobalScope::createWithData(ExclusiveContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data)
+{
+ MOZ_ASSERT(data);
+
+ // The global scope has no environment shape. Its environment is the
+ // global lexical scope and the global object or non-syntactic objects
+ // created by embedding, all of which are not only extensible but may
+ // have names on them deleted.
+ Scope* scope = Scope::create(cx, kind, nullptr, nullptr, Move(data.get()));
+ if (!scope)
+ return nullptr;
+ return &scope->as<GlobalScope>();
+}
+
+/* static */ GlobalScope*
+GlobalScope::clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind)
+{
+ Rooted<Data*> dataOriginal(cx, &scope->as<GlobalScope>().data());
+ Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<GlobalScope>(cx, dataOriginal));
+ if (!dataClone)
+ return nullptr;
+
+ Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr, Move(dataClone.get()));
+ if (!scopeClone)
+ return nullptr;
+ return &scopeClone->as<GlobalScope>();
+}
+
+template <XDRMode mode>
+/* static */ bool
+GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
+{
+ MOZ_ASSERT((mode == XDR_DECODE) == !scope);
+
+ JSContext* cx = xdr->cx();
+ Rooted<Data*> data(cx);
+ if (!XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data))
+ return false;
+
+ {
+ Maybe<Rooted<UniquePtr<Data>>> uniqueData;
+ if (mode == XDR_DECODE)
+ uniqueData.emplace(cx, data);
+
+ if (!xdr->codeUint32(&data->letStart))
+ return false;
+ if (!xdr->codeUint32(&data->constStart))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ if (!data->length) {
+ MOZ_ASSERT(!data->letStart);
+ MOZ_ASSERT(!data->constStart);
+ }
+
+ scope.set(createWithData(cx, kind, &uniqueData.ref()));
+ if (!scope)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template
+/* static */ bool
+GlobalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, MutableHandleScope scope);
+
+template
+/* static */ bool
+GlobalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, MutableHandleScope scope);
+
+/* static */ WithScope*
+WithScope::create(ExclusiveContext* cx, HandleScope enclosing)
+{
+ Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr);
+ return static_cast<WithScope*>(scope);
+}
+
+static const uint32_t EvalScopeEnvShapeFlags =
+ BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
+
+/* static */ EvalScope*
+EvalScope::create(ExclusiveContext* cx, ScopeKind scopeKind, Handle<Data*> dataArg,
+ HandleScope enclosing)
+{
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<EvalScope>(cx, dataArg)
+ : NewEmptyScopeData<EvalScope>(cx));
+ if (!data)
+ return nullptr;
+
+ return createWithData(cx, scopeKind, &data, enclosing);
+}
+
+/* static */ EvalScope*
+EvalScope::createWithData(ExclusiveContext* cx, ScopeKind scopeKind, MutableHandle<UniquePtr<Data>> data,
+ HandleScope enclosing)
+{
+ MOZ_ASSERT(data);
+
+ RootedShape envShape(cx);
+ if (scopeKind == ScopeKind::StrictEval) {
+ BindingIter bi(*data, true);
+ if (!PrepareScopeData<EvalScope>(cx, bi, data, &VarEnvironmentObject::class_,
+ EvalScopeEnvShapeFlags, &envShape))
+ {
+ return nullptr;
+ }
+ }
+
+ // Strict eval and direct eval in parameter expressions always get their own
+ // var environment even if there are no bindings.
+ if (!envShape && scopeKind == ScopeKind::StrictEval) {
+ envShape = getEmptyEnvironmentShape(cx);
+ if (!envShape)
+ return nullptr;
+ }
+
+ Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape, Move(data.get()));
+ if (!scope)
+ return nullptr;
+ return &scope->as<EvalScope>();
+}
+
+/* static */ Scope*
+EvalScope::nearestVarScopeForDirectEval(Scope* scope)
+{
+ for (ScopeIter si(scope); si; si++) {
+ switch (si.kind()) {
+ case ScopeKind::Function:
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar:
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ return scope;
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
+/* static */ Shape*
+EvalScope::getEmptyEnvironmentShape(ExclusiveContext* cx)
+{
+ const Class* cls = &VarEnvironmentObject::class_;
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), EvalScopeEnvShapeFlags);
+}
+
+template <XDRMode mode>
+/* static */ bool
+EvalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope)
+{
+ JSContext* cx = xdr->cx();
+ Rooted<Data*> data(cx);
+
+ {
+ Maybe<Rooted<UniquePtr<Data>>> uniqueData;
+ if (mode == XDR_DECODE)
+ uniqueData.emplace(cx, data);
+
+ if (!XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ if (!data->length)
+ MOZ_ASSERT(!data->nextFrameSlot);
+
+ scope.set(createWithData(cx, kind, &uniqueData.ref(), enclosing));
+ if (!scope)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template
+/* static */ bool
+EvalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+template
+/* static */ bool
+EvalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+static const uint32_t ModuleScopeEnvShapeFlags =
+ BaseShape::NOT_EXTENSIBLE | BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
+
+/* static */ ModuleScope*
+ModuleScope::create(ExclusiveContext* cx, Handle<Data*> dataArg,
+ HandleModuleObject module, HandleScope enclosing)
+{
+ Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<ModuleScope>(cx, dataArg)
+ : NewEmptyScopeData<ModuleScope>(cx));
+ if (!data)
+ return nullptr;
+
+ return createWithData(cx, &data, module, enclosing);
+}
+
+/* static */ ModuleScope*
+ModuleScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
+ HandleModuleObject module, HandleScope enclosing)
+{
+ MOZ_ASSERT(data);
+ MOZ_ASSERT(enclosing->is<GlobalScope>());
+
+ // ModuleScope::Data has GCManagedDeletePolicy because it contains a
+ // GCPtr. Destruction of |copy| below may trigger calls into the GC.
+ Rooted<ModuleScope*> moduleScope(cx);
+
+ {
+ // The data that's passed in is be from the frontend and is LifoAlloc'd.
+ // Copy it now that we're creating a permanent VM scope.
+ RootedShape envShape(cx);
+ BindingIter bi(*data);
+ if (!PrepareScopeData<ModuleScope>(cx, bi, data, &ModuleEnvironmentObject::class_,
+ ModuleScopeEnvShapeFlags, &envShape))
+ {
+ return nullptr;
+ }
+
+ // Modules always need an environment object for now.
+ if (!envShape) {
+ envShape = getEmptyEnvironmentShape(cx);
+ if (!envShape)
+ return nullptr;
+ }
+
+ Scope* scope = Scope::create(cx, ScopeKind::Module, enclosing, envShape);
+ if (!scope)
+ return nullptr;
+
+ data->module.init(module);
+
+ moduleScope = &scope->as<ModuleScope>();
+ moduleScope->initData(Move(data.get()));
+ }
+
+ return moduleScope;
+}
+
+/* static */ Shape*
+ModuleScope::getEmptyEnvironmentShape(ExclusiveContext* cx)
+{
+ const Class* cls = &ModuleEnvironmentObject::class_;
+ return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), ModuleScopeEnvShapeFlags);
+}
+
+JSScript*
+ModuleScope::script() const
+{
+ return module()->script();
+}
+
+ScopeIter::ScopeIter(JSScript* script)
+ : scope_(script->bodyScope())
+{ }
+
+bool
+ScopeIter::hasSyntacticEnvironment() const
+{
+ return scope()->hasEnvironment() && scope()->kind() != ScopeKind::NonSyntactic;
+}
+
+BindingIter::BindingIter(Scope* scope)
+{
+ switch (scope->kind()) {
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ init(scope->as<LexicalScope>().data(),
+ scope->as<LexicalScope>().firstFrameSlot(), 0);
+ break;
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda:
+ init(scope->as<LexicalScope>().data(), LOCALNO_LIMIT, IsNamedLambda);
+ break;
+ case ScopeKind::With:
+ // With scopes do not have bindings.
+ index_ = length_ = 0;
+ MOZ_ASSERT(done());
+ break;
+ case ScopeKind::Function: {
+ uint8_t flags = IgnoreDestructuredFormalParameters;
+ if (scope->as<FunctionScope>().hasParameterExprs())
+ flags |= HasFormalParameterExprs;
+ init(scope->as<FunctionScope>().data(), flags);
+ break;
+ }
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar:
+ init(scope->as<VarScope>().data(),
+ scope->as<VarScope>().firstFrameSlot());
+ break;
+ case ScopeKind::Eval:
+ case ScopeKind::StrictEval:
+ init(scope->as<EvalScope>().data(), scope->kind() == ScopeKind::StrictEval);
+ break;
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ init(scope->as<GlobalScope>().data());
+ break;
+ case ScopeKind::Module:
+ init(scope->as<ModuleScope>().data());
+ break;
+ }
+}
+
+BindingIter::BindingIter(JSScript* script)
+ : BindingIter(script->bodyScope())
+{ }
+
+void
+BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t flags)
+{
+ // Named lambda scopes can only have environment slots. If the callee
+ // isn't closed over, it is accessed via JSOP_CALLEE.
+ if (flags & IsNamedLambda) {
+ // Named lambda binding is weird. Normal BindingKind ordering rules
+ // don't apply.
+ init(0, 0, 0, 0, 0, 0,
+ CanHaveEnvironmentSlots | flags,
+ firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
+ data.names, data.length);
+ } else {
+ // imports - [0, 0)
+ // positional formals - [0, 0)
+ // other formals - [0, 0)
+ // top-level funcs - [0, 0)
+ // vars - [0, 0)
+ // lets - [0, data.constStart)
+ // consts - [data.constStart, data.length)
+ init(0, 0, 0, 0, 0, data.constStart,
+ CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
+ firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
+ data.names, data.length);
+ }
+}
+
+void
+BindingIter::init(FunctionScope::Data& data, uint8_t flags)
+{
+ flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags;
+ if (!(flags & HasFormalParameterExprs))
+ flags |= CanHaveArgumentSlots;
+
+ // imports - [0, 0)
+ // positional formals - [0, data.nonPositionalFormalStart)
+ // other formals - [data.nonPositionalParamStart, data.varStart)
+ // top-level funcs - [data.varStart, data.varStart)
+ // vars - [data.varStart, data.length)
+ // lets - [data.length, data.length)
+ // consts - [data.length, data.length)
+ init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length,
+ flags,
+ 0, JSSLOT_FREE(&CallObject::class_),
+ data.names, data.length);
+}
+
+void
+BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot)
+{
+ // imports - [0, 0)
+ // positional formals - [0, 0)
+ // other formals - [0, 0)
+ // top-level funcs - [0, 0)
+ // vars - [0, data.length)
+ // lets - [data.length, data.length)
+ // consts - [data.length, data.length)
+ init(0, 0, 0, 0, data.length, data.length,
+ CanHaveFrameSlots | CanHaveEnvironmentSlots,
+ firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_),
+ data.names, data.length);
+}
+
+void
+BindingIter::init(GlobalScope::Data& data)
+{
+ // imports - [0, 0)
+ // positional formals - [0, 0)
+ // other formals - [0, 0)
+ // top-level funcs - [0, data.varStart)
+ // vars - [data.varStart, data.letStart)
+ // lets - [data.letStart, data.constStart)
+ // consts - [data.constStart, data.length)
+ init(0, 0, 0, data.varStart, data.letStart, data.constStart,
+ CannotHaveSlots,
+ UINT32_MAX, UINT32_MAX,
+ data.names, data.length);
+}
+
+void
+BindingIter::init(EvalScope::Data& data, bool strict)
+{
+ uint32_t flags;
+ uint32_t firstFrameSlot;
+ uint32_t firstEnvironmentSlot;
+ if (strict) {
+ flags = CanHaveFrameSlots | CanHaveEnvironmentSlots;
+ firstFrameSlot = 0;
+ firstEnvironmentSlot = JSSLOT_FREE(&VarEnvironmentObject::class_);
+ } else {
+ flags = CannotHaveSlots;
+ firstFrameSlot = UINT32_MAX;
+ firstEnvironmentSlot = UINT32_MAX;
+ }
+
+ // imports - [0, 0)
+ // positional formals - [0, 0)
+ // other formals - [0, 0)
+ // top-level funcs - [0, data.varStart)
+ // vars - [data.varStart, data.length)
+ // lets - [data.length, data.length)
+ // consts - [data.length, data.length)
+ init(0, 0, 0, data.varStart, data.length, data.length,
+ flags, firstFrameSlot, firstEnvironmentSlot,
+ data.names, data.length);
+}
+
+void
+BindingIter::init(ModuleScope::Data& data)
+{
+ // imports - [0, data.varStart)
+ // positional formals - [data.varStart, data.varStart)
+ // other formals - [data.varStart, data.varStart)
+ // top-level funcs - [data.varStart, data.varStart)
+ // vars - [data.varStart, data.letStart)
+ // lets - [data.letStart, data.constStart)
+ // consts - [data.constStart, data.length)
+ init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
+ CanHaveFrameSlots | CanHaveEnvironmentSlots,
+ 0, JSSLOT_FREE(&ModuleEnvironmentObject::class_),
+ data.names, data.length);
+}
+
+PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script)
+ : BindingIter(script)
+{
+ // Reinit with flags = 0, i.e., iterate over all positional parameters.
+ if (script->bodyScope()->is<FunctionScope>())
+ init(script->bodyScope()->as<FunctionScope>().data(), /* flags = */ 0);
+ settle();
+}
+
+void
+js::DumpBindings(JSContext* cx, Scope* scopeArg)
+{
+ RootedScope scope(cx, scopeArg);
+ for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
+ JSAutoByteString bytes;
+ if (!AtomToPrintableString(cx, bi.name(), &bytes))
+ return;
+ fprintf(stderr, "%s %s ", BindingKindString(bi.kind()), bytes.ptr());
+ switch (bi.location().kind()) {
+ case BindingLocation::Kind::Global:
+ fprintf(stderr, "global\n");
+ break;
+ case BindingLocation::Kind::Argument:
+ fprintf(stderr, "arg slot %u\n", bi.location().argumentSlot());
+ break;
+ case BindingLocation::Kind::Frame:
+ fprintf(stderr, "frame slot %u\n", bi.location().slot());
+ break;
+ case BindingLocation::Kind::Environment:
+ fprintf(stderr, "env slot %u\n", bi.location().slot());
+ break;
+ case BindingLocation::Kind::NamedLambdaCallee:
+ fprintf(stderr, "named lambda callee\n");
+ break;
+ case BindingLocation::Kind::Import:
+ fprintf(stderr, "import\n");
+ break;
+ }
+ }
+}
+
+static JSAtom*
+GetFrameSlotNameInScope(Scope* scope, uint32_t slot)
+{
+ for (BindingIter bi(scope); bi; bi++) {
+ BindingLocation loc = bi.location();
+ if (loc.kind() == BindingLocation::Kind::Frame && loc.slot() == slot)
+ return bi.name();
+ }
+ return nullptr;
+}
+
+JSAtom*
+js::FrameSlotName(JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(IsLocalOp(JSOp(*pc)));
+ uint32_t slot = GET_LOCALNO(pc);
+ MOZ_ASSERT(slot < script->nfixed());
+
+ // Look for it in the body scope first.
+ if (JSAtom* name = GetFrameSlotNameInScope(script->bodyScope(), slot))
+ return name;
+
+ // If this is a function script and there is an extra var scope, look for
+ // it there.
+ if (script->functionHasExtraBodyVarScope()) {
+ if (JSAtom* name = GetFrameSlotNameInScope(script->functionExtraBodyVarScope(), slot))
+ return name;
+ }
+
+ // If not found, look for it in a lexical scope.
+ for (ScopeIter si(script->innermostScope(pc)); si; si++) {
+ if (!si.scope()->is<LexicalScope>())
+ continue;
+ LexicalScope& lexicalScope = si.scope()->as<LexicalScope>();
+
+ // Is the slot within bounds of the current lexical scope?
+ if (slot < lexicalScope.firstFrameSlot())
+ continue;
+ if (slot >= lexicalScope.nextFrameSlot())
+ break;
+
+ // If so, get the name.
+ if (JSAtom* name = GetFrameSlotNameInScope(&lexicalScope, slot))
+ return name;
+ }
+
+ MOZ_CRASH("Frame slot not found");
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<Scope>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ return js::gc::Arena::thingSize(get().asTenured().getAllocKind()) +
+ get().sizeOfExcludingThis(mallocSizeOf);
+}
diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
new file mode 100644
index 000000000..5304d6713
--- /dev/null
+++ b/js/src/vm/Scope.h
@@ -0,0 +1,1451 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Scope_h
+#define vm_Scope_h
+
+#include "mozilla/Maybe.h"
+#include "mozilla/Variant.h"
+
+#include "jsobj.h"
+#include "jsopcode.h"
+
+#include "gc/Heap.h"
+#include "gc/Policy.h"
+#include "js/UbiNode.h"
+#include "js/UniquePtr.h"
+#include "vm/Xdr.h"
+
+namespace js {
+
+class ModuleObject;
+
+enum class BindingKind : uint8_t
+{
+ Import,
+ FormalParameter,
+ Var,
+ Let,
+ Const,
+
+ // So you think named lambda callee names are consts? Nope! They don't
+ // throw when being assigned to in sloppy mode.
+ NamedLambdaCallee
+};
+
+static inline bool
+BindingKindIsLexical(BindingKind kind)
+{
+ return kind == BindingKind::Let || kind == BindingKind::Const;
+}
+
+enum class ScopeKind : uint8_t
+{
+ // FunctionScope
+ Function,
+
+ // VarScope
+ FunctionBodyVar,
+ ParameterExpressionVar,
+
+ // LexicalScope
+ Lexical,
+ SimpleCatch,
+ Catch,
+ NamedLambda,
+ StrictNamedLambda,
+
+ // WithScope
+ With,
+
+ // EvalScope
+ Eval,
+ StrictEval,
+
+ // GlobalScope
+ Global,
+ NonSyntactic,
+
+ // ModuleScope
+ Module
+};
+
+static inline bool
+ScopeKindIsCatch(ScopeKind kind)
+{
+ return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
+}
+
+const char* BindingKindString(BindingKind kind);
+const char* ScopeKindString(ScopeKind kind);
+
+class BindingName
+{
+ // A JSAtom* with its low bit used as a tag for whether it is closed over
+ // (i.e., exists in the environment shape).
+ uintptr_t bits_;
+
+ static const uintptr_t ClosedOverFlag = 0x1;
+ static const uintptr_t FlagMask = 0x1;
+
+ public:
+ BindingName()
+ : bits_(0)
+ { }
+
+ BindingName(JSAtom* name, bool closedOver)
+ : bits_(uintptr_t(name) | (closedOver ? ClosedOverFlag : 0x0))
+ { }
+
+ JSAtom* name() const {
+ return reinterpret_cast<JSAtom*>(bits_ & ~FlagMask);
+ }
+
+ bool closedOver() const {
+ return bits_ & ClosedOverFlag;
+ }
+
+ void trace(JSTracer* trc);
+};
+
+class BindingLocation
+{
+ public:
+ enum class Kind {
+ Global,
+ Argument,
+ Frame,
+ Environment,
+ Import,
+ NamedLambdaCallee
+ };
+
+ private:
+ Kind kind_;
+ uint32_t slot_;
+
+ BindingLocation(Kind kind, uint32_t slot)
+ : kind_(kind),
+ slot_(slot)
+ { }
+
+ public:
+ static BindingLocation Global() {
+ return BindingLocation(Kind::Global, UINT32_MAX);
+ }
+
+ static BindingLocation Argument(uint16_t slot) {
+ return BindingLocation(Kind::Argument, slot);
+ }
+
+ static BindingLocation Frame(uint32_t slot) {
+ MOZ_ASSERT(slot < LOCALNO_LIMIT);
+ return BindingLocation(Kind::Frame, slot);
+ }
+
+ static BindingLocation Environment(uint32_t slot) {
+ MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
+ return BindingLocation(Kind::Environment, slot);
+ }
+
+ static BindingLocation Import() {
+ return BindingLocation(Kind::Import, UINT32_MAX);
+ }
+
+ static BindingLocation NamedLambdaCallee() {
+ return BindingLocation(Kind::NamedLambdaCallee, UINT32_MAX);
+ }
+
+ bool operator==(const BindingLocation& other) const {
+ return kind_ == other.kind_ && slot_ == other.slot_;
+ }
+
+ bool operator!=(const BindingLocation& other) const {
+ return !operator==(other);
+ }
+
+ Kind kind() const {
+ return kind_;
+ }
+
+ uint32_t slot() const {
+ MOZ_ASSERT(kind_ == Kind::Frame || kind_ == Kind::Environment);
+ return slot_;
+ }
+
+ uint16_t argumentSlot() const {
+ MOZ_ASSERT(kind_ == Kind::Argument);
+ return mozilla::AssertedCast<uint16_t>(slot_);
+ }
+};
+
+//
+// The base class of all Scopes.
+//
+class Scope : public js::gc::TenuredCell
+{
+ friend class GCMarker;
+
+ // The kind determines data_.
+ ScopeKind kind_;
+
+ // The enclosing scope or nullptr.
+ GCPtrScope enclosing_;
+
+ // If there are any aliased bindings, the shape for the
+ // EnvironmentObject. Otherwise nullptr.
+ GCPtrShape environmentShape_;
+
+ protected:
+ uintptr_t data_;
+
+ Scope(ScopeKind kind, Scope* enclosing, Shape* environmentShape)
+ : kind_(kind),
+ enclosing_(enclosing),
+ environmentShape_(environmentShape),
+ data_(0)
+ { }
+
+ static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
+ HandleShape envShape);
+
+ template <typename T, typename D>
+ static Scope* create(ExclusiveContext* cx, ScopeKind kind, HandleScope enclosing,
+ HandleShape envShape, mozilla::UniquePtr<T, D> data);
+
+ template <typename ConcreteScope, XDRMode mode>
+ static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
+ MutableHandle<typename ConcreteScope::Data*> data);
+
+ Shape* maybeCloneEnvironmentShape(JSContext* cx);
+
+ template <typename T, typename D>
+ void initData(mozilla::UniquePtr<T, D> data) {
+ MOZ_ASSERT(!data_);
+ data_ = reinterpret_cast<uintptr_t>(data.release());
+ }
+
+ public:
+ static const JS::TraceKind TraceKind = JS::TraceKind::Scope;
+
+ template <typename T>
+ bool is() const {
+ return kind_ == T::classScopeKind_;
+ }
+
+ template <typename T>
+ T& as() {
+ MOZ_ASSERT(this->is<T>());
+ return *static_cast<T*>(this);
+ }
+
+ template <typename T>
+ const T& as() const {
+ MOZ_ASSERT(this->is<T>());
+ return *static_cast<const T*>(this);
+ }
+
+ ScopeKind kind() const {
+ return kind_;
+ }
+
+ Scope* enclosing() const {
+ return enclosing_;
+ }
+
+ Shape* environmentShape() const {
+ return environmentShape_;
+ }
+
+ bool hasEnvironment() const {
+ switch (kind()) {
+ case ScopeKind::With:
+ case ScopeKind::Global:
+ case ScopeKind::NonSyntactic:
+ return true;
+ default:
+ // If there's a shape, an environment must be created for this scope.
+ return environmentShape_ != nullptr;
+ }
+ }
+
+ uint32_t chainLength() const;
+ uint32_t environmentChainLength() const;
+
+ template <typename T>
+ bool hasOnChain() const {
+ for (const Scope* it = this; it; it = it->enclosing()) {
+ if (it->is<T>())
+ return true;
+ }
+ return false;
+ }
+
+ bool hasOnChain(ScopeKind kind) const {
+ for (const Scope* it = this; it; it = it->enclosing()) {
+ if (it->kind() == kind)
+ return true;
+ }
+ return false;
+ }
+
+ static Scope* clone(JSContext* cx, HandleScope scope, HandleScope enclosing);
+
+ void traceChildren(JSTracer* trc);
+ void finalize(FreeOp* fop);
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+ void dump();
+};
+
+//
+// A lexical scope that holds let and const bindings. There are 4 kinds of
+// LexicalScopes.
+//
+// Lexical
+// A plain lexical scope.
+//
+// SimpleCatch
+// Holds the single catch parameter of a catch block.
+//
+// Catch
+// Holds the catch parameters (and only the catch parameters) of a catch
+// block.
+//
+// NamedLambda
+// StrictNamedLambda
+// Holds the single name of the callee for a named lambda expression.
+//
+// All kinds of LexicalScopes correspond to LexicalEnvironmentObjects on the
+// environment chain.
+//
+class LexicalScope : public Scope
+{
+ friend class Scope;
+ friend class BindingIter;
+
+ public:
+ // Data is public because it is created by the frontend. See
+ // Parser<FullParseHandler>::newLexicalScopeData.
+ struct Data
+ {
+ // Bindings are sorted by kind in both frames and environments.
+ //
+ // lets - [0, constStart)
+ // consts - [constStart, length)
+ uint32_t constStart;
+ uint32_t length;
+
+ // Frame slots [0, nextFrameSlot) are live when this is the innermost
+ // scope.
+ uint32_t nextFrameSlot;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static LexicalScope* create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data,
+ uint32_t firstFrameSlot, HandleScope enclosing);
+
+ template <XDRMode mode>
+ static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+ private:
+ static LexicalScope* createWithData(ExclusiveContext* cx, ScopeKind kind,
+ MutableHandle<UniquePtr<Data>> data,
+ uint32_t firstFrameSlot, HandleScope enclosing);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ static uint32_t nextFrameSlot(Scope* start);
+
+ public:
+ uint32_t firstFrameSlot() const;
+
+ uint32_t nextFrameSlot() const {
+ return data().nextFrameSlot;
+ }
+
+ // Returns an empty shape for extensible global and non-syntactic lexical
+ // scopes.
+ static Shape* getEmptyExtensibleEnvironmentShape(ExclusiveContext* cx);
+};
+
+template <>
+inline bool
+Scope::is<LexicalScope>() const
+{
+ return kind_ == ScopeKind::Lexical ||
+ kind_ == ScopeKind::SimpleCatch ||
+ kind_ == ScopeKind::Catch ||
+ kind_ == ScopeKind::NamedLambda ||
+ kind_ == ScopeKind::StrictNamedLambda;
+}
+
+//
+// Scope corresponding to a function. Holds formal parameter names and, if the
+// function parameters contain no expressions that might possibly be
+// evaluated, the function's var bindings. For example, in these functions,
+// the FunctionScope will store a/b/c bindings but not d/e/f bindings:
+//
+// function f1(a, b) {
+// var c;
+// let e;
+// const f = 3;
+// }
+// function f2([a], b = 4, ...c) {
+// var d, e, f; // stored in VarScope
+// }
+//
+// Corresponds to CallObject on environment chain.
+//
+class FunctionScope : public Scope
+{
+ friend class GCMarker;
+ friend class BindingIter;
+ friend class PositionalFormalParameterIter;
+ friend class Scope;
+ static const ScopeKind classScopeKind_ = ScopeKind::Function;
+
+ public:
+ // Data is public because it is created by the
+ // frontend. See Parser<FullParseHandler>::newFunctionScopeData.
+ struct Data
+ {
+ // The canonical function of the scope, as during a scope walk we
+ // often query properties of the JSFunction (e.g., is the function an
+ // arrow).
+ GCPtrFunction canonicalFunction;
+
+ // If parameter expressions are present, parameters act like lexical
+ // bindings.
+ bool hasParameterExprs;
+
+ // Bindings are sorted by kind in both frames and environments.
+ //
+ // Positional formal parameter names are those that are not
+ // destructured. They may be referred to by argument slots if
+ // !script()->hasParameterExprs().
+ //
+ // An argument slot that needs to be skipped due to being destructured
+ // or having defaults will have a nullptr name in the name array to
+ // advance the argument slot.
+ //
+ // positional formals - [0, nonPositionalFormalStart)
+ // other formals - [nonPositionalParamStart, varStart)
+ // vars - [varStart, length)
+ uint16_t nonPositionalFormalStart;
+ uint16_t varStart;
+ uint32_t length;
+
+ // Frame slots [0, nextFrameSlot) are live when this is the innermost
+ // scope.
+ uint32_t nextFrameSlot;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static FunctionScope* create(ExclusiveContext* cx, Handle<Data*> data,
+ bool hasParameterExprs, bool needsEnvironment,
+ HandleFunction fun, HandleScope enclosing);
+
+ static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
+ HandleScope enclosing);
+
+ template <XDRMode mode>
+ static bool XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
+ MutableHandleScope scope);
+
+ private:
+ static FunctionScope* createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
+ bool hasParameterExprs, bool needsEnvironment,
+ HandleFunction fun, HandleScope enclosing);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
+ uint32_t nextFrameSlot() const {
+ return data().nextFrameSlot;
+ }
+
+ JSFunction* canonicalFunction() const {
+ return data().canonicalFunction;
+ }
+
+ JSScript* script() const;
+
+ bool hasParameterExprs() const {
+ return data().hasParameterExprs;
+ }
+
+ uint32_t numPositionalFormalParameters() const {
+ return data().nonPositionalFormalStart;
+ }
+
+ static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs);
+};
+
+//
+// Scope holding only vars. There are 2 kinds of VarScopes.
+//
+// FunctionBodyVar
+// Corresponds to the extra var scope present in functions with parameter
+// expressions. See examples in comment above FunctionScope.
+//
+// ParameterExpressionVar
+// Each parameter expression is evaluated in its own var environment. For
+// example, f() below will print 'fml', then 'global'. That's right.
+//
+// var a = 'global';
+// function f(x = (eval(`var a = 'fml'`), a), y = a) {
+// print(x);
+// print(y);
+// };
+//
+// Corresponds to VarEnvironmentObject on environment chain.
+//
+class VarScope : public Scope
+{
+ friend class GCMarker;
+ friend class BindingIter;
+ friend class Scope;
+
+ public:
+ // Data is public because it is created by the
+ // frontend. See Parser<FullParseHandler>::newVarScopeData.
+ struct Data
+ {
+ // All bindings are vars.
+ uint32_t length;
+
+ // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is
+ // the innermost scope.
+ uint32_t nextFrameSlot;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static VarScope* create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data,
+ uint32_t firstFrameSlot, bool needsEnvironment,
+ HandleScope enclosing);
+
+ template <XDRMode mode>
+ static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+ private:
+ static VarScope* createWithData(ExclusiveContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
+ uint32_t firstFrameSlot, bool needsEnvironment,
+ HandleScope enclosing);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
+ uint32_t firstFrameSlot() const;
+
+ uint32_t nextFrameSlot() const {
+ return data().nextFrameSlot;
+ }
+
+ static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx);
+};
+
+template <>
+inline bool
+Scope::is<VarScope>() const
+{
+ return kind_ == ScopeKind::FunctionBodyVar || kind_ == ScopeKind::ParameterExpressionVar;
+}
+
+//
+// Scope corresponding to both the global object scope and the global lexical
+// scope.
+//
+// Both are extensible and are singletons across <script> tags, so these
+// scopes are a fragment of the names in global scope. In other words, two
+// global scripts may have two different GlobalScopes despite having the same
+// GlobalObject.
+//
+// There are 2 kinds of GlobalScopes.
+//
+// Global
+// Corresponds to a GlobalObject and its global LexicalEnvironmentObject on
+// the environment chain.
+//
+// NonSyntactic
+// Corresponds to a non-GlobalObject created by the embedding on the
+// environment chain. This distinction is important for optimizations.
+//
+class GlobalScope : public Scope
+{
+ friend class Scope;
+ friend class BindingIter;
+
+ public:
+ // Data is public because it is created by the frontend. See
+ // Parser<FullParseHandler>::newGlobalScopeData.
+ struct Data
+ {
+ // Bindings are sorted by kind.
+ //
+ // top-level funcs - [0, varStart)
+ // vars - [varStart, letStart)
+ // lets - [letStart, constStart)
+ // consts - [constStart, length)
+ uint32_t varStart;
+ uint32_t letStart;
+ uint32_t constStart;
+ uint32_t length;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static GlobalScope* create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data);
+
+ static GlobalScope* createEmpty(ExclusiveContext* cx, ScopeKind kind) {
+ return create(cx, kind, nullptr);
+ }
+
+ static GlobalScope* clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind);
+
+ template <XDRMode mode>
+ static bool XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope);
+
+ private:
+ static GlobalScope* createWithData(ExclusiveContext* cx, ScopeKind kind,
+ MutableHandle<UniquePtr<Data>> data);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
+ bool isSyntactic() const {
+ return kind() != ScopeKind::NonSyntactic;
+ }
+
+ bool hasBindings() const {
+ return data().length > 0;
+ }
+};
+
+template <>
+inline bool
+Scope::is<GlobalScope>() const
+{
+ return kind_ == ScopeKind::Global || kind_ == ScopeKind::NonSyntactic;
+}
+
+//
+// Scope of a 'with' statement. Has no bindings.
+//
+// Corresponds to a WithEnvironmentObject on the environment chain.
+class WithScope : public Scope
+{
+ friend class Scope;
+ static const ScopeKind classScopeKind_ = ScopeKind::With;
+
+ public:
+ static WithScope* create(ExclusiveContext* cx, HandleScope enclosing);
+};
+
+//
+// Scope of an eval. Holds var bindings. There are 2 kinds of EvalScopes.
+//
+// StrictEval
+// A strict eval. Corresponds to a VarEnvironmentObject, where its var
+// bindings lives.
+//
+// Eval
+// A sloppy eval. This is an empty scope, used only in the frontend, to
+// detect redeclaration errors. It has no Environment. Any `var`s declared
+// in the eval code are bound on the nearest enclosing var environment.
+//
+class EvalScope : public Scope
+{
+ friend class Scope;
+ friend class BindingIter;
+
+ public:
+ // Data is public because it is created by the frontend. See
+ // Parser<FullParseHandler>::newEvalScopeData.
+ struct Data
+ {
+ // All bindings in an eval script are 'var' bindings. The implicit
+ // lexical scope around the eval is present regardless of strictness
+ // and is its own LexicalScope. However, we need to track top-level
+ // functions specially for redeclaration checks.
+ //
+ // top-level funcs - [0, varStart)
+ // vars - [varStart, length)
+ uint32_t varStart;
+ uint32_t length;
+
+ // Frame slots [0, nextFrameSlot) are live when this is the innermost
+ // scope.
+ uint32_t nextFrameSlot;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static EvalScope* create(ExclusiveContext* cx, ScopeKind kind, Handle<Data*> data,
+ HandleScope enclosing);
+
+ template <XDRMode mode>
+ static bool XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
+ MutableHandleScope scope);
+
+ private:
+ static EvalScope* createWithData(ExclusiveContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
+ HandleScope enclosing);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
+ // Starting a scope, the nearest var scope that a direct eval can
+ // introduce vars on.
+ static Scope* nearestVarScopeForDirectEval(Scope* scope);
+
+ uint32_t nextFrameSlot() const {
+ return data().nextFrameSlot;
+ }
+
+ bool strict() const {
+ return kind() == ScopeKind::StrictEval;
+ }
+
+ bool hasBindings() const {
+ return data().length > 0;
+ }
+
+ bool isNonGlobal() const {
+ if (strict())
+ return true;
+ return !nearestVarScopeForDirectEval(enclosing())->is<GlobalScope>();
+ }
+
+ static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx);
+};
+
+template <>
+inline bool
+Scope::is<EvalScope>() const
+{
+ return kind_ == ScopeKind::Eval || kind_ == ScopeKind::StrictEval;
+}
+
+//
+// Scope corresponding to the toplevel script in an ES module.
+//
+// Like GlobalScopes, these scopes contain both vars and lexical bindings, as
+// the treating of imports and exports requires putting them in one scope.
+//
+// Corresponds to a ModuleEnvironmentObject on the environment chain.
+//
+class ModuleScope : public Scope
+{
+ friend class GCMarker;
+ friend class BindingIter;
+ friend class Scope;
+ static const ScopeKind classScopeKind_ = ScopeKind::Module;
+
+ public:
+ // Data is public because it is created by the frontend. See
+ // Parser<FullParseHandler>::newModuleScopeData.
+ struct Data
+ {
+ // The module of the scope.
+ GCPtr<ModuleObject*> module;
+
+ // Bindings are sorted by kind.
+ //
+ // imports - [0, varStart)
+ // vars - [varStart, letStart)
+ // lets - [letStart, constStart)
+ // consts - [constStart, length)
+ uint32_t varStart;
+ uint32_t letStart;
+ uint32_t constStart;
+ uint32_t length;
+
+ // Frame slots [0, nextFrameSlot) are live when this is the innermost
+ // scope.
+ uint32_t nextFrameSlot;
+
+ // The array of tagged JSAtom* names, allocated beyond the end of the
+ // struct.
+ BindingName names[1];
+
+ void trace(JSTracer* trc);
+ };
+
+ static size_t sizeOfData(uint32_t length) {
+ return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
+ }
+
+ static ModuleScope* create(ExclusiveContext* cx, Handle<Data*> data,
+ Handle<ModuleObject*> module, HandleScope enclosing);
+
+ private:
+ static ModuleScope* createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data,
+ Handle<ModuleObject*> module, HandleScope enclosing);
+
+ Data& data() {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ const Data& data() const {
+ return *reinterpret_cast<Data*>(data_);
+ }
+
+ public:
+ uint32_t nextFrameSlot() const {
+ return data().nextFrameSlot;
+ }
+
+ ModuleObject* module() const {
+ return data().module;
+ }
+
+ JSScript* script() const;
+
+ static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx);
+};
+
+//
+// An iterator for a Scope's bindings. This is the source of truth for frame
+// and environment object layout.
+//
+// It may be placed in GC containers; for example:
+//
+// for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
+// use(bi);
+// SomeMayGCOperation();
+// use(bi);
+// }
+//
+class BindingIter
+{
+ protected:
+ // Bindings are sorted by kind. Because different Scopes have differently
+ // laid out Data for packing, BindingIter must handle all binding kinds.
+ //
+ // Kind ranges:
+ //
+ // imports - [0, positionalFormalStart)
+ // positional formals - [positionalFormalStart, nonPositionalFormalStart)
+ // other formals - [nonPositionalParamStart, topLevelFunctionStart)
+ // top-level funcs - [topLevelFunctionStart, varStart)
+ // vars - [varStart, letStart)
+ // lets - [letStart, constStart)
+ // consts - [constStart, length)
+ //
+ // Access method when not closed over:
+ //
+ // imports - name
+ // positional formals - argument slot
+ // other formals - frame slot
+ // top-level funcs - frame slot
+ // vars - frame slot
+ // lets - frame slot
+ // consts - frame slot
+ //
+ // Access method when closed over:
+ //
+ // imports - name
+ // positional formals - environment slot or name
+ // other formals - environment slot or name
+ // top-level funcs - environment slot or name
+ // vars - environment slot or name
+ // lets - environment slot or name
+ // consts - environment slot or name
+ uint32_t positionalFormalStart_;
+ uint32_t nonPositionalFormalStart_;
+ uint32_t topLevelFunctionStart_;
+ uint32_t varStart_;
+ uint32_t letStart_;
+ uint32_t constStart_;
+ uint32_t length_;
+
+ uint32_t index_;
+
+ enum Flags : uint8_t {
+ CannotHaveSlots = 0,
+ CanHaveArgumentSlots = 1 << 0,
+ CanHaveFrameSlots = 1 << 1,
+ CanHaveEnvironmentSlots = 1 << 2,
+
+ // See comment in settle below.
+ HasFormalParameterExprs = 1 << 3,
+ IgnoreDestructuredFormalParameters = 1 << 4,
+
+ // Truly I hate named lambdas.
+ IsNamedLambda = 1 << 5
+ };
+
+ static const uint8_t CanHaveSlotsMask = 0x7;
+
+ uint8_t flags_;
+ uint16_t argumentSlot_;
+ uint32_t frameSlot_;
+ uint32_t environmentSlot_;
+
+ BindingName* names_;
+
+ void init(uint32_t positionalFormalStart, uint32_t nonPositionalFormalStart,
+ uint32_t topLevelFunctionStart, uint32_t varStart,
+ uint32_t letStart, uint32_t constStart,
+ uint8_t flags, uint32_t firstFrameSlot, uint32_t firstEnvironmentSlot,
+ BindingName* names, uint32_t length)
+ {
+ positionalFormalStart_ = positionalFormalStart;
+ nonPositionalFormalStart_ = nonPositionalFormalStart;
+ topLevelFunctionStart_ = topLevelFunctionStart;
+ varStart_ = varStart;
+ letStart_ = letStart;
+ constStart_ = constStart;
+ length_ = length;
+ index_ = 0;
+ flags_ = flags;
+ argumentSlot_ = 0;
+ frameSlot_ = firstFrameSlot;
+ environmentSlot_ = firstEnvironmentSlot;
+ names_ = names;
+
+ settle();
+ }
+
+ void init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t flags);
+ void init(FunctionScope::Data& data, uint8_t flags);
+ void init(VarScope::Data& data, uint32_t firstFrameSlot);
+ void init(GlobalScope::Data& data);
+ void init(EvalScope::Data& data, bool strict);
+ void init(ModuleScope::Data& data);
+
+ bool hasFormalParameterExprs() const {
+ return flags_ & HasFormalParameterExprs;
+ }
+
+ bool ignoreDestructuredFormalParameters() const {
+ return flags_ & IgnoreDestructuredFormalParameters;
+ }
+
+ bool isNamedLambda() const {
+ return flags_ & IsNamedLambda;
+ }
+
+ void increment() {
+ MOZ_ASSERT(!done());
+ if (flags_ & CanHaveSlotsMask) {
+ if (canHaveArgumentSlots()) {
+ if (index_ < nonPositionalFormalStart_) {
+ MOZ_ASSERT(index_ >= positionalFormalStart_);
+ argumentSlot_++;
+ }
+ }
+ if (closedOver()) {
+ // Imports must not be given known slots. They are
+ // indirect bindings.
+ MOZ_ASSERT(kind() != BindingKind::Import);
+ MOZ_ASSERT(canHaveEnvironmentSlots());
+ environmentSlot_++;
+ } else if (canHaveFrameSlots()) {
+ // Usually positional formal parameters don't have frame
+ // slots, except when there are parameter expressions, in
+ // which case they act like lets.
+ if (index_ >= nonPositionalFormalStart_ || (hasFormalParameterExprs() && name()))
+ frameSlot_++;
+ }
+ }
+ index_++;
+ }
+
+ void settle() {
+ if (ignoreDestructuredFormalParameters()) {
+ while (!done() && !name())
+ increment();
+ }
+ }
+
+ public:
+ explicit BindingIter(Scope* scope);
+ explicit BindingIter(JSScript* script);
+
+ BindingIter(LexicalScope::Data& data, uint32_t firstFrameSlot, bool isNamedLambda) {
+ init(data, firstFrameSlot, isNamedLambda ? IsNamedLambda : 0);
+ }
+
+ BindingIter(FunctionScope::Data& data, bool hasParameterExprs) {
+ init(data,
+ IgnoreDestructuredFormalParameters |
+ (hasParameterExprs ? HasFormalParameterExprs : 0));
+ }
+
+ BindingIter(VarScope::Data& data, uint32_t firstFrameSlot) {
+ init(data, firstFrameSlot);
+ }
+
+ explicit BindingIter(GlobalScope::Data& data) {
+ init(data);
+ }
+
+ explicit BindingIter(ModuleScope::Data& data) {
+ init(data);
+ }
+
+ BindingIter(EvalScope::Data& data, bool strict) {
+ init(data, strict);
+ }
+
+ explicit BindingIter(const BindingIter& bi) = default;
+
+ bool done() const {
+ return index_ == length_;
+ }
+
+ explicit operator bool() const {
+ return !done();
+ }
+
+ void operator++(int) {
+ increment();
+ settle();
+ }
+
+ bool isLast() const {
+ MOZ_ASSERT(!done());
+ return index_ + 1 == length_;
+ }
+
+ bool canHaveArgumentSlots() const {
+ return flags_ & CanHaveArgumentSlots;
+ }
+
+ bool canHaveFrameSlots() const {
+ return flags_ & CanHaveFrameSlots;
+ }
+
+ bool canHaveEnvironmentSlots() const {
+ return flags_ & CanHaveEnvironmentSlots;
+ }
+
+ JSAtom* name() const {
+ MOZ_ASSERT(!done());
+ return names_[index_].name();
+ }
+
+ bool closedOver() const {
+ MOZ_ASSERT(!done());
+ return names_[index_].closedOver();
+ }
+
+ BindingLocation location() const {
+ MOZ_ASSERT(!done());
+ if (!(flags_ & CanHaveSlotsMask))
+ return BindingLocation::Global();
+ if (index_ < positionalFormalStart_)
+ return BindingLocation::Import();
+ if (closedOver()) {
+ MOZ_ASSERT(canHaveEnvironmentSlots());
+ return BindingLocation::Environment(environmentSlot_);
+ }
+ if (index_ < nonPositionalFormalStart_ && canHaveArgumentSlots())
+ return BindingLocation::Argument(argumentSlot_);
+ if (canHaveFrameSlots())
+ return BindingLocation::Frame(frameSlot_);
+ MOZ_ASSERT(isNamedLambda());
+ return BindingLocation::NamedLambdaCallee();
+ }
+
+ BindingKind kind() const {
+ MOZ_ASSERT(!done());
+ if (index_ < positionalFormalStart_)
+ return BindingKind::Import;
+ if (index_ < topLevelFunctionStart_) {
+ // When the parameter list has expressions, the parameters act
+ // like lexical bindings and have TDZ.
+ if (hasFormalParameterExprs())
+ return BindingKind::Let;
+ return BindingKind::FormalParameter;
+ }
+ if (index_ < letStart_)
+ return BindingKind::Var;
+ if (index_ < constStart_)
+ return BindingKind::Let;
+ if (isNamedLambda())
+ return BindingKind::NamedLambdaCallee;
+ return BindingKind::Const;
+ }
+
+ bool isTopLevelFunction() const {
+ MOZ_ASSERT(!done());
+ return index_ >= topLevelFunctionStart_ && index_ < varStart_;
+ }
+
+ bool hasArgumentSlot() const {
+ MOZ_ASSERT(!done());
+ if (hasFormalParameterExprs())
+ return false;
+ return index_ >= positionalFormalStart_ && index_ < nonPositionalFormalStart_;
+ }
+
+ uint16_t argumentSlot() const {
+ MOZ_ASSERT(canHaveArgumentSlots());
+ return mozilla::AssertedCast<uint16_t>(index_);
+ }
+
+ uint32_t nextFrameSlot() const {
+ MOZ_ASSERT(canHaveFrameSlots());
+ return frameSlot_;
+ }
+
+ uint32_t nextEnvironmentSlot() const {
+ MOZ_ASSERT(canHaveEnvironmentSlots());
+ return environmentSlot_;
+ }
+
+ void trace(JSTracer* trc);
+};
+
+void DumpBindings(JSContext* cx, Scope* scope);
+JSAtom* FrameSlotName(JSScript* script, jsbytecode* pc);
+
+//
+// A refinement BindingIter that only iterates over positional formal
+// parameters of a function.
+//
+class PositionalFormalParameterIter : public BindingIter
+{
+ void settle() {
+ if (index_ >= nonPositionalFormalStart_)
+ index_ = length_;
+ }
+
+ public:
+ explicit PositionalFormalParameterIter(JSScript* script);
+
+ void operator++(int) {
+ BindingIter::operator++(1);
+ settle();
+ }
+
+ bool isDestructured() const {
+ return !name();
+ }
+};
+
+//
+// Iterator for walking the scope chain.
+//
+// It may be placed in GC containers; for example:
+//
+// for (Rooted<ScopeIter> si(cx, ScopeIter(scope)); si; si++) {
+// use(si);
+// SomeMayGCOperation();
+// use(si);
+// }
+//
+class MOZ_STACK_CLASS ScopeIter
+{
+ Scope* scope_;
+
+ public:
+ explicit ScopeIter(Scope* scope)
+ : scope_(scope)
+ { }
+
+ explicit ScopeIter(JSScript* script);
+
+ explicit ScopeIter(const ScopeIter& si)
+ : scope_(si.scope_)
+ { }
+
+ bool done() const {
+ return !scope_;
+ }
+
+ explicit operator bool() const {
+ return !done();
+ }
+
+ void operator++(int) {
+ MOZ_ASSERT(!done());
+ scope_ = scope_->enclosing();
+ }
+
+ Scope* scope() const {
+ MOZ_ASSERT(!done());
+ return scope_;
+ }
+
+ ScopeKind kind() const {
+ MOZ_ASSERT(!done());
+ return scope_->kind();
+ }
+
+ // Returns the shape of the environment if it is known. It is possible to
+ // hasSyntacticEnvironment and to have no known shape, e.g., eval.
+ Shape* environmentShape() const {
+ return scope()->environmentShape();
+ }
+
+ // Returns whether this scope has a syntactic environment (i.e., an
+ // Environment that isn't a non-syntactic With or NonSyntacticVariables)
+ // on the environment chain.
+ bool hasSyntacticEnvironment() const;
+
+ void trace(JSTracer* trc) {
+ if (scope_)
+ TraceRoot(trc, &scope_, "scope iter scope");
+ }
+};
+
+//
+// Specializations of Rooted containers for the iterators.
+//
+
+template <typename Outer>
+class BindingIterOperations
+{
+ const BindingIter& iter() const { return static_cast<const Outer*>(this)->get(); }
+
+ public:
+ bool done() const { return iter().done(); }
+ explicit operator bool() const { return !done(); }
+ bool isLast() const { return iter().isLast(); }
+ bool canHaveArgumentSlots() const { return iter().canHaveArgumentSlots(); }
+ bool canHaveFrameSlots() const { return iter().canHaveFrameSlots(); }
+ bool canHaveEnvironmentSlots() const { return iter().canHaveEnvironmentSlots(); }
+ JSAtom* name() const { return iter().name(); }
+ bool closedOver() const { return iter().closedOver(); }
+ BindingLocation location() const { return iter().location(); }
+ BindingKind kind() const { return iter().kind(); }
+ bool isTopLevelFunction() const { return iter().isTopLevelFunction(); }
+ bool hasArgumentSlot() const { return iter().hasArgumentSlot(); }
+ uint16_t argumentSlot() const { return iter().argumentSlot(); }
+ uint32_t nextFrameSlot() const { return iter().nextFrameSlot(); }
+ uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
+};
+
+template <typename Outer>
+class MutableBindingIterOperations : public BindingIterOperations<Outer>
+{
+ BindingIter& iter() { return static_cast<Outer*>(this)->get(); }
+
+ public:
+ void operator++(int) { iter().operator++(1); }
+};
+
+template <typename Outer>
+class ScopeIterOperations
+{
+ const ScopeIter& iter() const { return static_cast<const Outer*>(this)->get(); }
+
+ public:
+ bool done() const { return iter().done(); }
+ explicit operator bool() const { return !done(); }
+ Scope* scope() const { return iter().scope(); }
+ ScopeKind kind() const { return iter().kind(); }
+ Shape* environmentShape() const { return iter().environmentShape(); }
+ bool hasSyntacticEnvironment() const { return iter().hasSyntacticEnvironment(); }
+};
+
+template <typename Outer>
+class MutableScopeIterOperations : public ScopeIterOperations<Outer>
+{
+ ScopeIter& iter() { return static_cast<Outer*>(this)->get(); }
+
+ public:
+ void operator++(int) { iter().operator++(1); }
+};
+
+#define SPECIALIZE_ROOTING_CONTAINERS(Iter, BaseIter) \
+ template <> \
+ class RootedBase<Iter> \
+ : public Mutable##BaseIter##Operations<JS::Rooted<Iter>> \
+ { }; \
+ \
+ template <> \
+ class MutableHandleBase<Iter> \
+ : public Mutable##BaseIter##Operations<JS::MutableHandle<Iter>> \
+ { }; \
+ \
+ template <> \
+ class HandleBase<Iter> \
+ : public BaseIter##Operations<JS::Handle<Iter>> \
+ { }; \
+ \
+ template <> \
+ class PersistentRootedBase<Iter> \
+ : public Mutable##BaseIter##Operations<JS::PersistentRooted<Iter>> \
+ { }
+
+SPECIALIZE_ROOTING_CONTAINERS(BindingIter, BindingIter);
+SPECIALIZE_ROOTING_CONTAINERS(PositionalFormalParameterIter, BindingIter);
+SPECIALIZE_ROOTING_CONTAINERS(ScopeIter, ScopeIter);
+
+#undef SPECIALIZE_ROOTING_CONTAINERS
+
+//
+// Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
+//
+
+template <typename Outer>
+struct ScopeCastOperation
+{
+ template <class U>
+ JS::Handle<U*> as() const {
+ const Outer& self = *static_cast<const Outer*>(this);
+ MOZ_ASSERT_IF(self, self->template is<U>());
+ return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
+ }
+};
+
+template <>
+class RootedBase<Scope*> : public ScopeCastOperation<JS::Rooted<Scope*>>
+{ };
+
+template <>
+class HandleBase<Scope*> : public ScopeCastOperation<JS::Handle<Scope*>>
+{ };
+
+template <>
+class MutableHandleBase<Scope*> : public ScopeCastOperation<JS::MutableHandle<Scope*>>
+{ };
+
+} // namespace js
+
+namespace JS {
+
+template <>
+struct GCPolicy<js::ScopeKind> : public IgnoreGCPolicy<js::ScopeKind>
+{ };
+
+template <typename T>
+struct ScopeDataGCPolicy
+{
+ static T initial() {
+ return nullptr;
+ }
+
+ static void trace(JSTracer* trc, T* vp, const char* name) {
+ if (*vp)
+ (*vp)->trace(trc);
+ }
+};
+
+#define DEFINE_SCOPE_DATA_GCPOLICY(Data) \
+ template <> \
+ struct MapTypeToRootKind<Data*> { \
+ static const RootKind kind = RootKind::Traceable; \
+ }; \
+ template <> \
+ struct GCPolicy<Data*> : public ScopeDataGCPolicy<Data*> \
+ { }
+
+DEFINE_SCOPE_DATA_GCPOLICY(js::LexicalScope::Data);
+DEFINE_SCOPE_DATA_GCPOLICY(js::FunctionScope::Data);
+DEFINE_SCOPE_DATA_GCPOLICY(js::VarScope::Data);
+DEFINE_SCOPE_DATA_GCPOLICY(js::GlobalScope::Data);
+DEFINE_SCOPE_DATA_GCPOLICY(js::EvalScope::Data);
+DEFINE_SCOPE_DATA_GCPOLICY(js::ModuleScope::Data);
+
+#undef DEFINE_SCOPE_DATA_GCPOLICY
+
+namespace ubi {
+
+template <>
+class Concrete<js::Scope> : TracerConcrete<js::Scope>
+{
+ protected:
+ explicit Concrete(js::Scope* ptr) : TracerConcrete<js::Scope>(ptr) { }
+
+ public:
+ static void construct(void* storage, js::Scope* ptr) {
+ new (storage) Concrete(ptr);
+ }
+
+ CoarseType coarseType() const final { return CoarseType::Script; }
+
+ Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+ const char16_t* typeName() const override { return concreteTypeName; }
+ static const char16_t concreteTypeName[];
+};
+
+} // namespace ubi
+} // namespace JS
+
+#endif // vm_Scope_h
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
new file mode 100644
index 000000000..6737e774c
--- /dev/null
+++ b/js/src/vm/SelfHosting.cpp
@@ -0,0 +1,3109 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SelfHosting.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Casting.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Maybe.h"
+
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsdate.h"
+#include "jsfriendapi.h"
+#include "jsfun.h"
+#include "jshashutil.h"
+#include "jsstr.h"
+#include "jsweakmap.h"
+#include "jswrapper.h"
+#include "selfhosted.out.h"
+
+#include "builtin/Intl.h"
+#include "builtin/MapObject.h"
+#include "builtin/ModuleObject.h"
+#include "builtin/Object.h"
+#include "builtin/Reflect.h"
+#include "builtin/SelfHostingDefines.h"
+#include "builtin/SIMD.h"
+#include "builtin/TypedObject.h"
+#include "builtin/WeakSetObject.h"
+#include "gc/Marking.h"
+#include "gc/Policy.h"
+#include "jit/AtomicOperations.h"
+#include "jit/InlinableNatives.h"
+#include "js/CharacterEncoding.h"
+#include "js/Date.h"
+#include "vm/Compression.h"
+#include "vm/GeneratorObject.h"
+#include "vm/Interpreter.h"
+#include "vm/RegExpObject.h"
+#include "vm/String.h"
+#include "vm/StringBuffer.h"
+#include "vm/TypedArrayCommon.h"
+#include "vm/WrapperObject.h"
+
+#include "jsatominlines.h"
+#include "jsfuninlines.h"
+#include "jsobjinlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/BooleanObject-inl.h"
+#include "vm/NativeObject-inl.h"
+#include "vm/NumberObject-inl.h"
+#include "vm/StringObject-inl.h"
+
+using namespace js;
+using namespace js::selfhosted;
+
+using JS::AutoCheckCannotGC;
+using mozilla::IsInRange;
+using mozilla::Maybe;
+using mozilla::PodMove;
+using mozilla::Maybe;
+
+static void
+selfHosting_WarningReporter(JSContext* cx, JSErrorReport* report)
+{
+ MOZ_ASSERT(report);
+ MOZ_ASSERT(JSREPORT_IS_WARNING(report->flags));
+
+ PrintError(cx, stderr, JS::ConstUTF8CharsZ(), report, true);
+}
+
+static bool
+intrinsic_ToObject(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedValue val(cx, args[0]);
+ RootedObject obj(cx, ToObject(cx, val));
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+}
+
+static bool
+intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ Value val = args[0];
+ bool isObject = val.isObject();
+ args.rval().setBoolean(isObject);
+ return true;
+}
+
+static bool
+intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedValue val(cx, args[0]);
+ if (val.isObject()) {
+ RootedObject obj(cx, &val.toObject());
+ bool isArray = false;
+ if (!IsArray(cx, obj, &isArray))
+ return false;
+ args.rval().setBoolean(isArray);
+ } else {
+ args.rval().setBoolean(false);
+ }
+ return true;
+}
+
+static bool
+intrinsic_IsWrappedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ bool result = false;
+ if (!IsWrappedArrayConstructor(cx, args[0], &result))
+ return false;
+ args.rval().setBoolean(result);
+ return true;
+}
+
+static bool
+intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ double result;
+ if (!ToInteger(cx, args[0], &result))
+ return false;
+ args.rval().setNumber(result);
+ return true;
+}
+
+static bool
+intrinsic_ToString(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedString str(cx);
+ str = ToString<CanGC>(cx, args[0]);
+ if (!str)
+ return false;
+ args.rval().setString(str);
+ return true;
+}
+
+static bool
+intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedId id(cx);
+ if (!ToPropertyKey(cx, args[0], &id))
+ return false;
+
+ args.rval().set(IdToValue(id));
+ return true;
+}
+
+static bool
+intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ args.rval().setBoolean(IsCallable(args[0]));
+ return true;
+}
+
+static bool
+intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ args.rval().setBoolean(IsConstructor(args[0]));
+ return true;
+}
+
+template<typename T>
+static bool
+intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ args.rval().setBoolean(args[0].toObject().is<T>());
+ return true;
+}
+
+/**
+ * Self-hosting intrinsic returning the original constructor for a builtin
+ * the name of which is the first and only argument.
+ *
+ * The return value is guaranteed to be the original constructor even if
+ * content code changed the named binding on the global object.
+ *
+ * This intrinsic shouldn't be called directly. Instead, the
+ * `GetBuiltinConstructor` and `GetBuiltinPrototype` helper functions in
+ * Utilities.js should be used, as they cache results, improving performance.
+ */
+static bool
+intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedString str(cx, args[0].toString());
+ JSAtom* atom;
+ if (str->isAtom()) {
+ atom = &str->asAtom();
+ } else {
+ atom = AtomizeString(cx, str);
+ if (!atom)
+ return false;
+ }
+ RootedId id(cx, AtomToId(atom));
+ JSProtoKey key = JS_IdToProtoKey(cx, id);
+ MOZ_ASSERT(key != JSProto_Null);
+ RootedObject ctor(cx);
+ if (!GetBuiltinConstructor(cx, key, &ctor))
+ return false;
+ args.rval().setObject(*ctor);
+ return true;
+}
+
+static bool
+intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args[0].isString());
+ MOZ_ASSERT(args[1].isInt32());
+ MOZ_ASSERT(args[2].isInt32());
+
+ RootedString str(cx, args[0].toString());
+ int32_t begin = args[1].toInt32();
+ int32_t length = args[2].toInt32();
+
+ JSString* substr = SubstringKernel(cx, str, begin, length);
+ if (!substr)
+ return false;
+
+ args.rval().setString(substr);
+ return true;
+}
+
+static bool
+intrinsic_OwnPropertyKeys(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[1].isInt32());
+ return GetOwnPropertyKeys(cx, args, args[1].toInt32());
+}
+
+static void
+ThrowErrorWithType(JSContext* cx, JSExnType type, const CallArgs& args)
+{
+ uint32_t errorNumber = args[0].toInt32();
+
+#ifdef DEBUG
+ const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
+ MOZ_ASSERT(efs->argCount == args.length() - 1);
+ MOZ_ASSERT(efs->exnType == type, "error-throwing intrinsic and error number are inconsistent");
+#endif
+
+ JSAutoByteString errorArgs[3];
+ for (unsigned i = 1; i < 4 && i < args.length(); i++) {
+ RootedValue val(cx, args[i]);
+ if (val.isInt32()) {
+ JSString* str = ToString<CanGC>(cx, val);
+ if (!str)
+ return;
+ errorArgs[i - 1].encodeLatin1(cx, str);
+ } else if (val.isString()) {
+ errorArgs[i - 1].encodeLatin1(cx, val.toString());
+ } else {
+ UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
+ if (!bytes)
+ return;
+ errorArgs[i - 1].initBytes(bytes.release());
+ }
+ if (!errorArgs[i - 1])
+ return;
+ }
+
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber,
+ errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
+}
+
+static bool
+intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 1);
+
+ ThrowErrorWithType(cx, JSEXN_RANGEERR, args);
+ return false;
+}
+
+static bool
+intrinsic_ThrowTypeError(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 1);
+
+ ThrowErrorWithType(cx, JSEXN_TYPEERR, args);
+ return false;
+}
+
+static bool
+intrinsic_ThrowSyntaxError(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 1);
+
+ ThrowErrorWithType(cx, JSEXN_SYNTAXERR, args);
+ return false;
+}
+
+static bool
+intrinsic_ThrowInternalError(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 1);
+
+ ThrowErrorWithType(cx, JSEXN_INTERNALERR, args);
+ return false;
+}
+
+/**
+ * Handles an assertion failure in self-hosted code just like an assertion
+ * failure in C++ code. Information about the failure can be provided in args[0].
+ */
+static bool
+intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp)
+{
+#ifdef DEBUG
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (args.length() > 0) {
+ // try to dump the informative string
+ JSString* str = ToString<CanGC>(cx, args[0]);
+ if (str) {
+ fprintf(stderr, "Self-hosted JavaScript assertion info: ");
+ str->dumpCharsNoNewline();
+ fputc('\n', stderr);
+ }
+ }
+#endif
+ MOZ_ASSERT(false);
+ return false;
+}
+
+/**
+ * Dumps a message to stderr, after stringifying it. Doesn't append a newline.
+ */
+static bool
+intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+#ifdef DEBUG
+ if (args.length() > 0) {
+ // try to dump the informative string
+ JSString* str = ToString<CanGC>(cx, args[0]);
+ if (str) {
+ str->dumpCharsNoNewline();
+ fputc('\n', stderr);
+ } else {
+ cx->recoverFromOutOfMemory();
+ }
+ }
+#endif
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_MakeConstructible(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[0].toObject().is<JSFunction>());
+ MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
+ MOZ_ASSERT(args[1].isObjectOrNull());
+
+ // Normal .prototype properties aren't enumerable. But for this to clone
+ // correctly, it must be enumerable.
+ RootedObject ctor(cx, &args[0].toObject());
+ if (!DefineProperty(cx, ctor, cx->names().prototype, args[1],
+ nullptr, nullptr,
+ JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
+ {
+ return false;
+ }
+
+ ctor->as<JSFunction>().setIsConstructor();
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_MakeDefaultConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
+
+ RootedFunction ctor(cx, &args[0].toObject().as<JSFunction>());
+
+ ctor->nonLazyScript()->setIsDefaultClassConstructor();
+
+ // Because self-hosting code does not allow top-level lexicals,
+ // class constructors are class expressions in top-level vars.
+ // Because of this, we give them a guessed atom. Since they
+ // will always be cloned, and given an explicit atom, instead
+ // overrule that.
+ ctor->clearGuessedAtom();
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/*
+ * Used to mark bound functions as such and make them constructible if the
+ * target is. Also assigns the prototype and sets the name and correct length.
+ */
+static bool
+intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ MOZ_ASSERT(IsCallable(args[1]));
+ MOZ_ASSERT(args[2].isNumber());
+
+ RootedFunction bound(cx, &args[0].toObject().as<JSFunction>());
+ bound->setIsBoundFunction();
+ RootedObject targetObj(cx, &args[1].toObject());
+ MOZ_ASSERT(bound->getBoundFunctionTarget() == targetObj);
+
+ // 9.4.1.3 BoundFunctionCreate, steps 1, 3-5, 8-12 (Already performed).
+
+ // 9.4.1.3 BoundFunctionCreate, step 6.
+ if (targetObj->isConstructor())
+ bound->setIsConstructor();
+
+ // 9.4.1.3 BoundFunctionCreate, step 2.
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, targetObj, &proto))
+ return false;
+
+ // 9.4.1.3 BoundFunctionCreate, step 7.
+ if (bound->staticPrototype() != proto) {
+ if (!SetPrototype(cx, bound, proto))
+ return false;
+ }
+
+ double argCount = args[2].toNumber();
+ double length = 0.0;
+
+ // Try to avoid invoking the resolve hook.
+ if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedLength()) {
+ RootedValue targetLength(cx);
+ if (!targetObj->as<JSFunction>().getUnresolvedLength(cx, &targetLength))
+ return false;
+
+ length = Max(0.0, targetLength.toNumber() - argCount);
+ } else {
+ // 19.2.3.2 Function.prototype.bind, step 5.
+ bool hasLength;
+ RootedId idRoot(cx, NameToId(cx->names().length));
+ if (!HasOwnProperty(cx, targetObj, idRoot, &hasLength))
+ return false;
+
+ // 19.2.3.2 Function.prototype.bind, step 6.
+ if (hasLength) {
+ RootedValue targetLength(cx);
+ if (!GetProperty(cx, targetObj, targetObj, idRoot, &targetLength))
+ return false;
+
+ if (targetLength.isNumber())
+ length = Max(0.0, JS::ToInteger(targetLength.toNumber()) - argCount);
+ }
+
+ // 19.2.3.2 Function.prototype.bind, step 7 (implicit).
+ }
+
+ // 19.2.3.2 Function.prototype.bind, step 8.
+ bound->setExtendedSlot(BOUND_FUN_LENGTH_SLOT, NumberValue(length));
+
+ // Try to avoid invoking the resolve hook.
+ JSAtom* name = nullptr;
+ if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName())
+ name = targetObj->as<JSFunction>().getUnresolvedName(cx);
+
+ RootedString rootedName(cx);
+ if (name) {
+ rootedName = name;
+ } else {
+ // 19.2.3.2 Function.prototype.bind, step 9.
+ RootedValue targetName(cx);
+ if (!GetProperty(cx, targetObj, targetObj, cx->names().name, &targetName))
+ return false;
+
+ // 19.2.3.2 Function.prototype.bind, step 10.
+ if (targetName.isString())
+ rootedName = targetName.toString();
+ }
+
+ // 19.2.3.2 Function.prototype.bind, step 11 (Inlined SetFunctionName).
+ MOZ_ASSERT(!bound->hasGuessedAtom());
+ if (rootedName && !rootedName->empty()) {
+ StringBuffer sb(cx);
+ if (!sb.append(cx->names().boundWithSpace) || !sb.append(rootedName))
+ return false;
+
+ RootedAtom nameAtom(cx, sb.finishAtom());
+ if (!nameAtom)
+ return false;
+
+ bound->setAtom(nameAtom);
+ } else {
+ bound->setAtom(cx->names().boundWithSpace);
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_SetPrototype(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[1].isObjectOrNull());
+
+ RootedObject obj(cx, &args[0].toObject());
+ RootedObject proto(cx, args[1].toObjectOrNull());
+ if (!SetPrototype(cx, obj, proto))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+/*
+ * Used to decompile values in the nearest non-builtin stack frame, falling
+ * back to decompiling in the current frame. Helpful for printing higher-order
+ * function arguments.
+ *
+ * The user must supply the argument number of the value in question; it
+ * _cannot_ be automatically determined.
+ */
+static bool
+intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedValue value(cx, args[1]);
+ ScopedJSFreePtr<char> str(DecompileArgument(cx, args[0].toInt32(), value));
+ if (!str)
+ return false;
+ RootedAtom atom(cx, Atomize(cx, str, strlen(str)));
+ if (!atom)
+ return false;
+ args.rval().setString(atom);
+ return true;
+}
+
+static bool
+intrinsic_DefineDataProperty(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ MOZ_ASSERT(args.length() >= 3);
+ MOZ_ASSERT(args[0].isObject());
+
+ RootedObject obj(cx, &args[0].toObject());
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, args[1], &id))
+ return false;
+ RootedValue value(cx, args[2]);
+
+ unsigned attrs = 0;
+ if (args.length() >= 4) {
+ unsigned attributes = args[3].toInt32();
+
+ MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != bool(attributes & ATTR_NONENUMERABLE),
+ "_DefineDataProperty must receive either ATTR_ENUMERABLE xor ATTR_NONENUMERABLE");
+ if (attributes & ATTR_ENUMERABLE)
+ attrs |= JSPROP_ENUMERATE;
+
+ MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != bool(attributes & ATTR_NONCONFIGURABLE),
+ "_DefineDataProperty must receive either ATTR_CONFIGURABLE xor "
+ "ATTR_NONCONFIGURABLE");
+ if (attributes & ATTR_NONCONFIGURABLE)
+ attrs |= JSPROP_PERMANENT;
+
+ MOZ_ASSERT(bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE),
+ "_DefineDataProperty must receive either ATTR_WRITABLE xor ATTR_NONWRITABLE");
+ if (attributes & ATTR_NONWRITABLE)
+ attrs |= JSPROP_READONLY;
+ } else {
+ // If the fourth argument is unspecified, the attributes are for a
+ // plain data property.
+ attrs = JSPROP_ENUMERATE;
+ }
+
+ Rooted<PropertyDescriptor> desc(cx);
+ desc.setDataDescriptor(value, attrs);
+ if (!DefineProperty(cx, obj, id, desc))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_ObjectHasPrototype(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ RootedObject obj(cx, &args[0].toObject());
+ RootedObject proto(cx, &args[1].toObject());
+
+ RootedObject actualProto(cx);
+ if (!GetPrototype(cx, obj, &actualProto))
+ return false;
+
+ args.rval().setBoolean(actualProto == proto);
+ return true;
+}
+
+static bool
+intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[1].isInt32());
+
+ args[0].toObject().as<NativeObject>().setReservedSlot(args[1].toPrivateUint32(), args[2]);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_UnsafeGetReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[1].isInt32());
+
+ args.rval().set(args[0].toObject().as<NativeObject>().getReservedSlot(args[1].toPrivateUint32()));
+ return true;
+}
+
+static bool
+intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
+ return false;
+ MOZ_ASSERT(vp->isObject());
+ return true;
+}
+
+static bool
+intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
+ return false;
+ MOZ_ASSERT(vp->isInt32());
+ return true;
+}
+
+static bool
+intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
+ return false;
+ MOZ_ASSERT(vp->isString());
+ return true;
+}
+
+static bool
+intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx, unsigned argc, Value* vp)
+{
+ if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp))
+ return false;
+ MOZ_ASSERT(vp->isBoolean());
+ return true;
+}
+
+/**
+ * Intrinsic for creating an empty array in the compartment of the object
+ * passed as the first argument.
+ *
+ * Returns the array, wrapped in the default wrapper to use between the two
+ * compartments.
+ */
+static bool
+intrinsic_NewArrayInCompartment(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedObject wrapped(cx, &args[0].toObject());
+ MOZ_ASSERT(IsWrapper(wrapped));
+ RootedObject obj(cx, UncheckedUnwrap(wrapped));
+
+ RootedArrayObject arr(cx);
+ {
+ AutoCompartment ac(cx, obj);
+ arr = NewDenseEmptyArray(cx);
+ if (!arr)
+ return false;
+ }
+
+ args.rval().setObject(*arr);
+ return wrapped->compartment()->wrap(cx, args.rval());
+}
+
+static bool
+intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+ args.rval().setBoolean(IsPackedArray(&args[0].toObject()));
+ return true;
+}
+
+static bool
+intrinsic_GetIteratorPrototype(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ JSObject* obj = GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+static bool
+intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ RootedObject proto(cx, GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
+ if (!proto)
+ return false;
+
+ JSObject* obj = NewObjectWithGivenProto(cx, &ArrayIteratorObject::class_, proto);
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+static bool
+intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>());
+ MOZ_ASSERT(args[1].isObject());
+
+ Rooted<MapIteratorObject*> mapIterator(cx, &args[0].toObject().as<MapIteratorObject>());
+ RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
+
+ args.rval().setBoolean(MapIteratorObject::next(mapIterator, result, cx));
+ return true;
+}
+
+static bool
+intrinsic_CreateMapIterationResultPair(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ RootedObject result(cx, MapIteratorObject::createResultPair(cx));
+ if (!result)
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+intrinsic_GetNextSetEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].toObject().is<SetIteratorObject>());
+ MOZ_ASSERT(args[1].isObject());
+
+ Rooted<SetIteratorObject*> setIterator(cx, &args[0].toObject().as<SetIteratorObject>());
+ RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
+
+ args.rval().setBoolean(SetIteratorObject::next(setIterator, result, cx));
+ return true;
+}
+
+static bool
+intrinsic_CreateSetIterationResult(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ RootedObject result(cx, SetIteratorObject::createResult(cx));
+ if (!result)
+ return false;
+
+ args.rval().setObject(*result);
+ return true;
+}
+
+static bool
+intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
+ if (!proto)
+ return false;
+
+ JSObject* obj = NewObjectWithGivenProto(cx, &StringIteratorObject::class_, proto);
+ if (!obj)
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+static bool
+intrinsic_NewListIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ RootedObject proto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, cx->global()));
+ if (!proto)
+ return false;
+
+ RootedObject iterator(cx);
+ iterator = NewObjectWithGivenProto(cx, &ListIteratorObject::class_, proto);
+ if (!iterator)
+ return false;
+
+ args.rval().setObject(*iterator);
+ return true;
+}
+
+static bool
+intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ ScriptFrameIter iter(cx);
+ MOZ_ASSERT(iter.isFunctionFrame());
+ args.rval().setObject(*iter.callee(cx));
+ return true;
+}
+
+static bool
+intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
+ MOZ_ASSERT(fun->isSelfHostedBuiltin());
+ RootedAtom atom(cx, AtomizeString(cx, args[1].toString()));
+ if (!atom)
+ return false;
+
+ fun->setAtom(atom);
+#ifdef DEBUG
+ fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true));
+#endif
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_StarGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ StarGeneratorObject* genObj = &args[0].toObject().as<StarGeneratorObject>();
+ args.rval().setBoolean(genObj->isClosed());
+ return true;
+}
+
+bool
+js::intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ if (!args[0].isObject() || !args[0].toObject().is<StarGeneratorObject>()) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ StarGeneratorObject& genObj = args[0].toObject().as<StarGeneratorObject>();
+ args.rval().setBoolean(!genObj.isClosed() && genObj.isSuspended());
+ return true;
+}
+
+static bool
+intrinsic_LegacyGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ LegacyGeneratorObject* genObj = &args[0].toObject().as<LegacyGeneratorObject>();
+ args.rval().setBoolean(genObj->isClosed());
+ return true;
+}
+
+static bool
+intrinsic_CloseClosingLegacyGeneratorObject(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ LegacyGeneratorObject* genObj = &args[0].toObject().as<LegacyGeneratorObject>();
+ MOZ_ASSERT(genObj->isClosing());
+ genObj->setClosed();
+ return true;
+}
+
+static bool
+intrinsic_ThrowStopIteration(JSContext* cx, unsigned argc, Value* vp)
+{
+ MOZ_ASSERT(CallArgsFromVp(argc, vp).length() == 0);
+
+ return ThrowStopIteration(cx);
+}
+
+static bool
+intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
+ args.rval().setBoolean(genObj->isRunning() || genObj->isClosing());
+ return true;
+}
+
+static bool
+intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
+ genObj->setClosed();
+ return true;
+}
+
+template<typename T>
+static bool
+intrinsic_IsWrappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ if (!args[0].isObject()) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ JSObject* obj = &args[0].toObject();
+ if (!obj->is<WrapperObject>()) {
+ args.rval().setBoolean(false);
+ return true;
+ }
+
+ JSObject* unwrapped = CheckedUnwrap(obj);
+ if (!unwrapped) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ args.rval().setBoolean(unwrapped->is<T>());
+ return true;
+}
+
+template<typename T>
+static bool
+intrinsic_ArrayBufferByteLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+ MOZ_ASSERT(args[0].toObject().is<T>());
+
+ size_t byteLength = args[0].toObject().as<T>().byteLength();
+ args.rval().setInt32(mozilla::AssertedCast<int32_t>(byteLength));
+ return true;
+}
+
+template<typename T>
+static bool
+intrinsic_PossiblyWrappedArrayBufferByteLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ JSObject* obj = CheckedUnwrap(&args[0].toObject());
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ uint32_t length = obj->as<T>().byteLength();
+ args.rval().setInt32(mozilla::AssertedCast<int32_t>(length));
+ return true;
+}
+
+template<typename T>
+static bool
+intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 5);
+
+ bool isWrapped = args[4].toBoolean();
+ Rooted<T*> toBuffer(cx);
+ if (!isWrapped) {
+ toBuffer = &args[0].toObject().as<T>();
+ } else {
+ JSObject* wrapped = &args[0].toObject();
+ MOZ_ASSERT(wrapped->is<WrapperObject>());
+ RootedObject toBufferObj(cx, CheckedUnwrap(wrapped));
+ if (!toBufferObj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+ toBuffer = toBufferObj.as<T>();
+ }
+ Rooted<T*> fromBuffer(cx, &args[1].toObject().as<T>());
+ uint32_t fromIndex = uint32_t(args[2].toInt32());
+ uint32_t count = uint32_t(args[3].toInt32());
+
+ T::copyData(toBuffer, fromBuffer, fromIndex, count);
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_IsSpecificTypedArray(JSContext* cx, unsigned argc, Value* vp, Scalar::Type type)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ JSObject* obj = &args[0].toObject();
+
+ bool isArray = JS_GetArrayBufferViewType(obj) == type;
+
+ args.rval().setBoolean(isArray);
+ return true;
+}
+
+static bool
+intrinsic_IsUint8TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8) ||
+ intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8Clamped);
+}
+
+static bool
+intrinsic_IsInt8TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int8);
+}
+
+static bool
+intrinsic_IsUint16TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint16);
+}
+
+static bool
+intrinsic_IsInt16TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int16);
+}
+
+static bool
+intrinsic_IsUint32TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint32);
+}
+
+static bool
+intrinsic_IsInt32TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int32);
+}
+
+static bool
+intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Float32);
+}
+
+static bool
+intrinsic_IsPossiblyWrappedTypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ bool isTypedArray = false;
+ if (args[0].isObject()) {
+ JSObject* obj = CheckedUnwrap(&args[0].toObject());
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ isTypedArray = obj->is<TypedArrayObject>();
+ }
+
+ args.rval().setBoolean(isTypedArray);
+ return true;
+}
+
+static bool
+intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(TypedArrayObject::is(args[0]));
+
+ Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
+ if (!TypedArrayObject::ensureHasBuffer(cx, tarray))
+ return false;
+
+ args.rval().set(TypedArrayObject::bufferValue(tarray));
+ return true;
+}
+
+static bool
+intrinsic_TypedArrayByteOffset(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(TypedArrayObject::is(args[0]));
+
+ args.rval().set(TypedArrayObject::byteOffsetValue(&args[0].toObject().as<TypedArrayObject>()));
+ return true;
+}
+
+static bool
+intrinsic_TypedArrayElementShift(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(TypedArrayObject::is(args[0]));
+
+ unsigned shift = TypedArrayShift(args[0].toObject().as<TypedArrayObject>().type());
+ MOZ_ASSERT(shift == 0 || shift == 1 || shift == 2 || shift == 3);
+
+ args.rval().setInt32(mozilla::AssertedCast<int32_t>(shift));
+ return true;
+}
+
+// Return the value of [[ArrayLength]] internal slot of the TypedArray
+static bool
+intrinsic_TypedArrayLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ RootedObject obj(cx, &args[0].toObject());
+ MOZ_ASSERT(obj->is<TypedArrayObject>());
+ args.rval().setInt32(obj->as<TypedArrayObject>().length());
+ return true;
+}
+
+static bool
+intrinsic_PossiblyWrappedTypedArrayLength(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ JSObject* obj = CheckedUnwrap(&args[0].toObject());
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ MOZ_ASSERT(obj->is<TypedArrayObject>());
+ uint32_t typedArrayLength = obj->as<TypedArrayObject>().length();
+ args.rval().setInt32(mozilla::AssertedCast<int32_t>(typedArrayLength));
+ return true;
+}
+
+static bool
+intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ JSObject* obj = CheckedUnwrap(&args[0].toObject());
+ if (!obj) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ MOZ_ASSERT(obj->is<TypedArrayObject>());
+ bool detached = obj->as<TypedArrayObject>().hasDetachedBuffer();
+ args.rval().setBoolean(detached);
+ return true;
+}
+
+static bool
+intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 4);
+
+ Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
+ uint32_t to = uint32_t(args[1].toInt32());
+ uint32_t from = uint32_t(args[2].toInt32());
+ uint32_t count = uint32_t(args[3].toInt32());
+
+ MOZ_ASSERT(count > 0,
+ "don't call this method if copying no elements, because then "
+ "the not-detached requirement is wrong");
+
+ if (tarray->hasDetachedBuffer()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Don't multiply by |tarray->bytesPerElement()| in case the compiler can't
+ // strength-reduce multiplication by 1/2/4/8 into the equivalent shift.
+ const size_t ElementShift = TypedArrayShift(tarray->type());
+
+ MOZ_ASSERT((UINT32_MAX >> ElementShift) > to);
+ uint32_t byteDest = to << ElementShift;
+
+ MOZ_ASSERT((UINT32_MAX >> ElementShift) > from);
+ uint32_t byteSrc = from << ElementShift;
+
+ MOZ_ASSERT((UINT32_MAX >> ElementShift) >= count);
+ uint32_t byteSize = count << ElementShift;
+
+#ifdef DEBUG
+ {
+ uint32_t viewByteLength = tarray->byteLength();
+ MOZ_ASSERT(byteSize <= viewByteLength);
+ MOZ_ASSERT(byteDest < viewByteLength);
+ MOZ_ASSERT(byteSrc < viewByteLength);
+ MOZ_ASSERT(byteDest <= viewByteLength - byteSize);
+ MOZ_ASSERT(byteSrc <= viewByteLength - byteSize);
+ }
+#endif
+
+ SharedMem<uint8_t*> data = tarray->viewDataEither().cast<uint8_t*>();
+ jit::AtomicOperations::memmoveSafeWhenRacy(data + byteDest, data + byteSrc, byteSize);
+
+ args.rval().setUndefined();
+ return true;
+}
+
+// Extract the TypedArrayObject* underlying |obj| and return it. This method,
+// in a TOTALLY UNSAFE manner, completely violates the normal compartment
+// boundaries, returning an object not necessarily in the current compartment
+// or in |obj|'s compartment.
+//
+// All callers of this method are expected to sigil this TypedArrayObject*, and
+// all values and information derived from it, with an "unsafe" prefix, to
+// indicate the extreme caution required when dealing with such values.
+//
+// If calling code discipline ever fails to be maintained, it's gonna have a
+// bad time.
+static TypedArrayObject*
+DangerouslyUnwrapTypedArray(JSContext* cx, JSObject* obj)
+{
+ // An unwrapped pointer to an object potentially on the other side of a
+ // compartment boundary! Isn't this such fun?
+ JSObject* unwrapped = CheckedUnwrap(obj);
+ if (!unwrapped->is<TypedArrayObject>()) {
+ // By *appearances* this can't happen, as self-hosted TypedArraySet
+ // checked this. But. Who's to say a GC couldn't happen between
+ // the check that this value was a typed array, and this extraction
+ // occurring? A GC might turn a cross-compartment wrapper |obj| into
+ // |unwrapped == obj|, a dead object no longer connected its typed
+ // array.
+ //
+ // Yeah, yeah, it's pretty unlikely. Are you willing to stake a
+ // sec-critical bug on that assessment, now and forever, against
+ // all changes those pesky GC and JIT people might make?
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+ return nullptr;
+ }
+
+ // Be super-duper careful using this, as we've just punched through
+ // the compartment boundary, and things like buffer() on this aren't
+ // same-compartment with anything else in the calling method.
+ return &unwrapped->as<TypedArrayObject>();
+}
+
+// ES6 draft 20150403 22.2.3.22.2, steps 12-24, 29.
+static bool
+intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 4);
+
+ Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
+ MOZ_ASSERT(!target->hasDetachedBuffer(),
+ "something should have defended against a target viewing a "
+ "detached buffer");
+
+ // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
+ // variables derived from it to counsel extreme caution here.
+ Rooted<TypedArrayObject*> unsafeTypedArrayCrossCompartment(cx);
+ unsafeTypedArrayCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[1].toObject());
+ if (!unsafeTypedArrayCrossCompartment)
+ return false;
+
+ double doubleTargetOffset = args[2].toNumber();
+ MOZ_ASSERT(doubleTargetOffset >= 0, "caller failed to ensure |targetOffset >= 0|");
+
+ uint32_t targetLength = uint32_t(args[3].toInt32());
+
+ // Handle all checks preceding the actual element-setting. A visual skim
+ // of 22.2.3.22.2 should confirm these are the only steps after steps 1-11
+ // that might abort processing (other than for reason of internal error.)
+
+ // Steps 12-13.
+ if (unsafeTypedArrayCrossCompartment->hasDetachedBuffer()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Steps 21, 23.
+ uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
+ if (unsafeSrcLengthCrossCompartment + doubleTargetOffset > targetLength) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+ return false;
+ }
+
+ // Now that that's confirmed, we can use |targetOffset| of a sane type.
+ uint32_t targetOffset = uint32_t(doubleTargetOffset);
+
+ // The remaining steps are unobservable *except* through their effect on
+ // which elements are copied and how.
+
+ Scalar::Type targetType = target->type();
+ Scalar::Type unsafeSrcTypeCrossCompartment = unsafeTypedArrayCrossCompartment->type();
+
+ size_t targetElementSize = TypedArrayElemSize(targetType);
+ SharedMem<uint8_t*> targetData =
+ target->viewDataEither().cast<uint8_t*>() + targetOffset * targetElementSize;
+
+ SharedMem<uint8_t*> unsafeSrcDataCrossCompartment =
+ unsafeTypedArrayCrossCompartment->viewDataEither().cast<uint8_t*>();
+
+ uint32_t unsafeSrcElementSizeCrossCompartment =
+ TypedArrayElemSize(unsafeSrcTypeCrossCompartment);
+ uint32_t unsafeSrcByteLengthCrossCompartment =
+ unsafeSrcLengthCrossCompartment * unsafeSrcElementSizeCrossCompartment;
+
+ // Step 29.
+ //
+ // The same-type case requires exact copying preserving the bit-level
+ // encoding of the source data, so move the values. (We could PodCopy if
+ // we knew the buffers differed, but it's doubtful the work to check
+ // wouldn't swap any minor wins PodCopy would afford. Because of the
+ // TOTALLY UNSAFE CROSS-COMPARTMENT NONSENSE here, comparing buffer
+ // pointers directly could give an incorrect answer.) If this occurs,
+ // the %TypedArray%.prototype.set operation is completely finished.
+ if (targetType == unsafeSrcTypeCrossCompartment) {
+ jit::AtomicOperations::memmoveSafeWhenRacy(targetData,
+ unsafeSrcDataCrossCompartment,
+ unsafeSrcByteLengthCrossCompartment);
+ args.rval().setInt32(JS_SETTYPEDARRAY_SAME_TYPE);
+ return true;
+ }
+
+ // Every other bit of element-copying is handled by step 28. Indicate
+ // whether such copying must take care not to overlap, so that self-hosted
+ // code may correctly perform the copying.
+
+ SharedMem<uint8_t*> unsafeSrcDataLimitCrossCompartment =
+ unsafeSrcDataCrossCompartment + unsafeSrcByteLengthCrossCompartment;
+ SharedMem<uint8_t*> targetDataLimit =
+ target->viewDataEither().cast<uint8_t*>() + targetLength * targetElementSize;
+
+ // Step 24 test (but not steps 24a-d -- the caller handles those).
+ bool overlap =
+ IsInRange(targetData.unwrap(/*safe - used for ptr value*/),
+ unsafeSrcDataCrossCompartment.unwrap(/*safe - ditto*/),
+ unsafeSrcDataLimitCrossCompartment.unwrap(/*safe - ditto*/)) ||
+ IsInRange(unsafeSrcDataCrossCompartment.unwrap(/*safe - ditto*/),
+ targetData.unwrap(/*safe - ditto*/),
+ targetDataLimit.unwrap(/*safe - ditto*/));
+
+ args.rval().setInt32(overlap ? JS_SETTYPEDARRAY_OVERLAPPING : JS_SETTYPEDARRAY_DISJOINT);
+ return true;
+}
+
+template <typename From, typename To>
+static void
+CopyValues(SharedMem<To*> dest, SharedMem<From*> src, uint32_t count)
+{
+#ifdef DEBUG
+ void* destVoid = dest.template cast<void*>().unwrap(/*safe - used for ptr value*/);
+ void* destVoidEnd = (dest + count).template cast<void*>().unwrap(/*safe - ditto*/);
+ const void* srcVoid = src.template cast<void*>().unwrap(/*safe - ditto*/);
+ const void* srcVoidEnd = (src + count).template cast<void*>().unwrap(/*safe - ditto*/);
+ MOZ_ASSERT(!IsInRange(destVoid, srcVoid, srcVoidEnd));
+ MOZ_ASSERT(!IsInRange(srcVoid, destVoid, destVoidEnd));
+#endif
+
+ using namespace jit;
+
+ for (; count > 0; count--) {
+ AtomicOperations::storeSafeWhenRacy(dest++,
+ To(AtomicOperations::loadSafeWhenRacy(src++)));
+ }
+}
+
+struct DisjointElements
+{
+ template <typename To>
+ static void
+ copy(SharedMem<To*> dest, SharedMem<void*> src, Scalar::Type fromType, uint32_t count) {
+ switch (fromType) {
+ case Scalar::Int8:
+ CopyValues(dest, src.cast<int8_t*>(), count);
+ return;
+
+ case Scalar::Uint8:
+ CopyValues(dest, src.cast<uint8_t*>(), count);
+ return;
+
+ case Scalar::Int16:
+ CopyValues(dest, src.cast<int16_t*>(), count);
+ return;
+
+ case Scalar::Uint16:
+ CopyValues(dest, src.cast<uint16_t*>(), count);
+ return;
+
+ case Scalar::Int32:
+ CopyValues(dest, src.cast<int32_t*>(), count);
+ return;
+
+ case Scalar::Uint32:
+ CopyValues(dest, src.cast<uint32_t*>(), count);
+ return;
+
+ case Scalar::Float32:
+ CopyValues(dest, src.cast<float*>(), count);
+ return;
+
+ case Scalar::Float64:
+ CopyValues(dest, src.cast<double*>(), count);
+ return;
+
+ case Scalar::Uint8Clamped:
+ CopyValues(dest, src.cast<uint8_clamped*>(), count);
+ return;
+
+ default:
+ MOZ_CRASH("NonoverlappingSet with bogus from-type");
+ }
+ }
+};
+
+static void
+CopyToDisjointArray(TypedArrayObject* target, uint32_t targetOffset, SharedMem<void*> src,
+ Scalar::Type srcType, uint32_t count)
+{
+ Scalar::Type destType = target->type();
+ SharedMem<uint8_t*> dest = target->viewDataEither().cast<uint8_t*>() + targetOffset * TypedArrayElemSize(destType);
+
+ switch (destType) {
+ case Scalar::Int8: {
+ DisjointElements::copy(dest.cast<int8_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Uint8: {
+ DisjointElements::copy(dest.cast<uint8_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Int16: {
+ DisjointElements::copy(dest.cast<int16_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Uint16: {
+ DisjointElements::copy(dest.cast<uint16_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Int32: {
+ DisjointElements::copy(dest.cast<int32_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Uint32: {
+ DisjointElements::copy(dest.cast<uint32_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Float32: {
+ DisjointElements::copy(dest.cast<float*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Float64: {
+ DisjointElements::copy(dest.cast<double*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::Uint8Clamped: {
+ DisjointElements::copy(dest.cast<uint8_clamped*>(), src, srcType, count);
+ break;
+ }
+
+ default:
+ MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
+ }
+}
+
+// |unsafeSrcCrossCompartment| is produced by |DangerouslyUnwrapTypedArray|,
+// counseling extreme caution when using it. As directed by
+// |DangerouslyUnwrapTypedArray|, sigil this pointer and all variables derived
+// from it to counsel extreme caution here.
+void
+js::SetDisjointTypedElements(TypedArrayObject* target, uint32_t targetOffset,
+ TypedArrayObject* unsafeSrcCrossCompartment)
+{
+ Scalar::Type unsafeSrcTypeCrossCompartment = unsafeSrcCrossCompartment->type();
+
+ SharedMem<void*> unsafeSrcDataCrossCompartment = unsafeSrcCrossCompartment->viewDataEither();
+ uint32_t count = unsafeSrcCrossCompartment->length();
+
+ CopyToDisjointArray(target, targetOffset,
+ unsafeSrcDataCrossCompartment,
+ unsafeSrcTypeCrossCompartment, count);
+}
+
+static bool
+intrinsic_SetDisjointTypedElements(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+
+ Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
+ MOZ_ASSERT(!target->hasDetachedBuffer(),
+ "a typed array viewing a detached buffer has no elements to "
+ "set, so it's nonsensical to be setting them");
+
+ uint32_t targetOffset = uint32_t(args[1].toInt32());
+
+ // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
+ // variables derived from it to counsel extreme caution here.
+ Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
+ unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
+ if (!unsafeSrcCrossCompartment)
+ return false;
+
+ SetDisjointTypedElements(target, targetOffset, unsafeSrcCrossCompartment);
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_SetOverlappingTypedElements(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+
+ Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
+ MOZ_ASSERT(!target->hasDetachedBuffer(),
+ "shouldn't set elements if underlying buffer is detached");
+
+ uint32_t targetOffset = uint32_t(args[1].toInt32());
+
+ // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
+ // variables derived from it to counsel extreme caution here.
+ Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
+ unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
+ if (!unsafeSrcCrossCompartment)
+ return false;
+
+ // Smarter algorithms exist to perform overlapping transfers of the sort
+ // this method performs (for example, v8's self-hosted implementation).
+ // But it seems likely deliberate overlapping transfers are rare enough
+ // that it's not worth the trouble to implement one (and worry about its
+ // safety/correctness!). Make a copy and do a disjoint set from that.
+ uint32_t count = unsafeSrcCrossCompartment->length();
+ Scalar::Type unsafeSrcTypeCrossCompartment = unsafeSrcCrossCompartment->type();
+ size_t sourceByteLen = count * TypedArrayElemSize(unsafeSrcTypeCrossCompartment);
+
+ auto copyOfSrcData = target->zone()->make_pod_array<uint8_t>(sourceByteLen);
+ if (!copyOfSrcData)
+ return false;
+
+ jit::AtomicOperations::memcpySafeWhenRacy(SharedMem<uint8_t*>::unshared(copyOfSrcData.get()),
+ unsafeSrcCrossCompartment->viewDataEither().cast<uint8_t*>(),
+ sourceByteLen);
+
+ CopyToDisjointArray(target, targetOffset, SharedMem<void*>::unshared(copyOfSrcData.get()),
+ unsafeSrcTypeCrossCompartment, count);
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ MOZ_ASSERT(args.length() == 1 || args.length() == 2);
+ MOZ_ASSERT_IF(args.length() == 2, args[1].isString() || args[1].isUndefined());
+ MOZ_ASSERT(!args.isConstructing());
+
+ return RegExpCreate(cx, args[0], args.get(1), args.rval());
+}
+
+static bool
+intrinsic_RegExpGetSubstitution(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ MOZ_ASSERT(args.length() == 6);
+
+ RootedString matched(cx, args[0].toString());
+ RootedString string(cx, args[1].toString());
+
+ int32_t position = int32_t(args[2].toNumber());
+ MOZ_ASSERT(position >= 0);
+
+ RootedObject captures(cx, &args[3].toObject());
+#ifdef DEBUG
+ bool isArray = false;
+ MOZ_ALWAYS_TRUE(IsArray(cx, captures, &isArray));
+ MOZ_ASSERT(isArray);
+#endif
+
+ RootedString replacement(cx, args[4].toString());
+
+ int32_t firstDollarIndex = int32_t(args[5].toNumber());
+ MOZ_ASSERT(firstDollarIndex >= 0);
+
+ RootedLinearString matchedLinear(cx, matched->ensureLinear(cx));
+ if (!matchedLinear)
+ return false;
+ RootedLinearString stringLinear(cx, string->ensureLinear(cx));
+ if (!stringLinear)
+ return false;
+ RootedLinearString replacementLinear(cx, replacement->ensureLinear(cx));
+ if (!replacementLinear)
+ return false;
+
+ return RegExpGetSubstitution(cx, matchedLinear, stringLinear, size_t(position), captures,
+ replacementLinear, size_t(firstDollarIndex), args.rval());
+}
+
+static bool
+intrinsic_StringReplaceString(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+
+ RootedString string(cx, args[0].toString());
+ RootedString pattern(cx, args[1].toString());
+ RootedString replacement(cx, args[2].toString());
+ JSString* result = str_replace_string_raw(cx, string, pattern, replacement);
+ if (!result)
+ return false;
+
+ args.rval().setString(result);
+ return true;
+}
+
+bool
+js::intrinsic_StringSplitString(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedString string(cx, args[0].toString());
+ RootedString sep(cx, args[1].toString());
+
+ RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
+ if (!group)
+ return false;
+
+ RootedObject aobj(cx);
+ aobj = str_split_string(cx, group, string, sep, INT32_MAX);
+ if (!aobj)
+ return false;
+
+ args.rval().setObject(*aobj);
+ return true;
+}
+
+static bool
+intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+
+ RootedString string(cx, args[0].toString());
+ RootedString sep(cx, args[1].toString());
+
+ // args[2] should be already in UInt32 range, but it could be double typed,
+ // because of Ion optimization.
+ uint32_t limit = uint32_t(args[2].toNumber());
+
+ RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
+ if (!group)
+ return false;
+
+ RootedObject aobj(cx);
+ aobj = str_split_string(cx, group, string, sep, limit);
+ if (!aobj)
+ return false;
+
+ args.rval().setObject(*aobj);
+ return true;
+}
+
+bool
+CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args)
+{
+ // This function is called when a self-hosted method is invoked on a
+ // wrapper object, like a CrossCompartmentWrapper. The last argument is
+ // the name of the self-hosted function. The other arguments are the
+ // arguments to pass to this function.
+
+ MOZ_ASSERT(args.length() > 0);
+ RootedPropertyName name(cx, args[args.length() - 1].toString()->asAtom().asPropertyName());
+
+ RootedValue selfHostedFun(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
+ return false;
+
+ MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
+
+ InvokeArgs args2(cx);
+ if (!args2.init(cx, args.length() - 1))
+ return false;
+
+ for (size_t i = 0; i < args.length() - 1; i++)
+ args2[i].set(args[i]);
+
+ return js::Call(cx, selfHostedFun, args.thisv(), args2, args.rval());
+}
+
+bool
+js::CallSelfHostedFunction(JSContext* cx, const char* name, HandleValue thisv,
+ const AnyInvokeArgs& args, MutableHandleValue rval)
+{
+ RootedAtom funAtom(cx, Atomize(cx, name, strlen(name)));
+ if (!funAtom)
+ return false;
+ RootedPropertyName funName(cx, funAtom->asPropertyName());
+ return CallSelfHostedFunction(cx, funName, thisv, args, rval);
+}
+
+bool
+js::CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv,
+ const AnyInvokeArgs& args, MutableHandleValue rval)
+{
+ RootedValue fun(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun))
+ return false;
+ MOZ_ASSERT(fun.toObject().is<JSFunction>());
+
+ return Call(cx, fun, thisv, args, rval);
+}
+
+template<typename T>
+bool
+Is(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<T>();
+}
+
+template<IsAcceptableThis Test>
+static bool
+CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
+}
+
+bool
+js::IsCallSelfHostedNonGenericMethod(NativeImpl impl)
+{
+ return impl == CallSelfHostedNonGenericMethod;
+}
+
+bool
+js::ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args)
+{
+ // The contract for this function is the same as CallSelfHostedNonGenericMethod.
+ // The normal ReportIncompatible function doesn't work for selfhosted functions,
+ // because they always call the different CallXXXMethodIfWrapped methods,
+ // which would be reported as the called function instead.
+
+ // Lookup the selfhosted method that was invoked. But skip over
+ // IsTypedArrayEnsuringArrayBuffer frames, because those are never the
+ // actual self-hosted callee from external code. We can't just skip
+ // self-hosted things until we find a non-self-hosted one because of cases
+ // like array.sort(somethingSelfHosted), where we want to report the error
+ // in the somethingSelfHosted, not in the sort() call.
+ ScriptFrameIter iter(cx);
+ MOZ_ASSERT(iter.isFunctionFrame());
+
+ while (!iter.done()) {
+ MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic() &&
+ !iter.callee(cx)->isBoundFunction());
+ JSAutoByteString funNameBytes;
+ const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
+ if (!funName)
+ return false;
+ if (strcmp(funName, "IsTypedArrayEnsuringArrayBuffer") != 0) {
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
+ funName, "method", InformalValueTypeName(args.thisv()));
+ return false;
+ }
+ ++iter;
+ }
+
+ MOZ_ASSERT_UNREACHABLE("How did we not find a useful self-hosted frame?");
+ return false;
+}
+
+/**
+ * Returns the default locale as a well-formed, but not necessarily canonicalized,
+ * BCP-47 language tag.
+ */
+static bool
+intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ const char* locale = cx->runtime()->getDefaultLocale();
+ if (!locale) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEFAULT_LOCALE_ERROR);
+ return false;
+ }
+
+ RootedString jslocale(cx, JS_NewStringCopyZ(cx, locale));
+ if (!jslocale)
+ return false;
+
+ args.rval().setString(jslocale);
+ return true;
+}
+
+static bool
+intrinsic_AddContentTelemetry(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ int id = args[0].toInt32();
+ MOZ_ASSERT(id < JS_TELEMETRY_END);
+ MOZ_ASSERT(id >= 0);
+
+ if (!cx->compartment()->isProbablySystemOrAddonCode())
+ cx->runtime()->addTelemetry(id, args[1].toInt32());
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_ConstructFunction(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ MOZ_ASSERT(IsConstructor(args[0]));
+ MOZ_ASSERT(IsConstructor(args[1]));
+ MOZ_ASSERT(args[2].toObject().is<ArrayObject>());
+
+ RootedArrayObject argsList(cx, &args[2].toObject().as<ArrayObject>());
+ uint32_t len = argsList->length();
+ ConstructArgs constructArgs(cx);
+ if (!constructArgs.init(cx, len))
+ return false;
+ for (uint32_t index = 0; index < len; index++)
+ constructArgs[index].set(argsList->getDenseElement(index));
+
+ RootedObject res(cx);
+ if (!Construct(cx, args[0], constructArgs, args[1], &res))
+ return false;
+
+ args.rval().setObject(*res);
+ return true;
+}
+
+
+static bool
+intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ ScriptFrameIter iter(cx);
+ bool isConstructing = iter.isConstructing();
+ args.rval().setBoolean(isConstructing);
+ return true;
+}
+
+static bool
+intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ RootedObject object(cx, &args[0].toObject());
+ object = CheckedUnwrap(object);
+ MOZ_ASSERT(object->is<TypedArrayObject>());
+
+ JSProtoKey protoKey = StandardProtoKeyOrNull(object);
+ MOZ_ASSERT(protoKey);
+
+ // While it may seem like an invariant that in any compartment,
+ // seeing a typed array object implies that the TypedArray constructor
+ // for that type is initialized on the compartment's global, this is not
+ // the case. When we construct a typed array given a cross-compartment
+ // ArrayBuffer, we put the constructed TypedArray in the same compartment
+ // as the ArrayBuffer. Since we use the prototype from the initial
+ // compartment, and never call the constructor in the ArrayBuffer's
+ // compartment from script, we are not guaranteed to have initialized
+ // the constructor.
+ RootedObject ctor(cx);
+ if (!GetBuiltinConstructor(cx, protoKey, &ctor))
+ return false;
+
+ args.rval().setObject(*ctor);
+ return true;
+}
+
+static bool
+intrinsic_NameForTypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ RootedObject object(cx, &args[0].toObject());
+ MOZ_ASSERT(object->is<TypedArrayObject>());
+
+ JSProtoKey protoKey = StandardProtoKeyOrNull(object);
+ MOZ_ASSERT(protoKey);
+
+ args.rval().setString(ClassName(protoKey, cx));
+ return true;
+}
+
+static bool
+intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(args[0].toObject().is<ModuleObject>());
+ MOZ_ASSERT(args[1].isString());
+
+ RootedFunction moduleResolveHook(cx, cx->global()->moduleResolveHook());
+ if (!moduleResolveHook) {
+ JS_ReportErrorASCII(cx, "Module resolve hook not set");
+ return false;
+ }
+
+ RootedValue result(cx);
+ if (!JS_CallFunction(cx, nullptr, moduleResolveHook, args, &result))
+ return false;
+
+ if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
+ JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
+ return false;
+ }
+
+ args.rval().set(result);
+ return true;
+}
+
+static bool
+intrinsic_CreateModuleEnvironment(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
+ module->createEnvironment();
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_CreateImportBinding(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 4);
+ RootedModuleEnvironmentObject environment(cx, &args[0].toObject().as<ModuleEnvironmentObject>());
+ RootedAtom importedName(cx, &args[1].toString()->asAtom());
+ RootedModuleObject module(cx, &args[2].toObject().as<ModuleObject>());
+ RootedAtom localName(cx, &args[3].toString()->asAtom());
+ if (!environment->createImportBinding(cx, importedName, module, localName))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_CreateNamespaceBinding(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ RootedModuleEnvironmentObject environment(cx, &args[0].toObject().as<ModuleEnvironmentObject>());
+ RootedId name(cx, AtomToId(&args[1].toString()->asAtom()));
+ MOZ_ASSERT(args[2].toObject().is<ModuleNamespaceObject>());
+ // The property already exists in the evironment but is not writable, so set
+ // the slot directly.
+ RootedShape shape(cx, environment->lookup(cx, name));
+ MOZ_ASSERT(shape);
+ MOZ_ASSERT(environment->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL));
+ environment->setSlot(shape->slot(), args[2]);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_InstantiateModuleFunctionDeclarations(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
+ args.rval().setUndefined();
+ return ModuleObject::instantiateFunctionDeclarations(cx, module);
+}
+
+static bool
+intrinsic_SetModuleState(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
+ ModuleState newState = args[1].toInt32();
+ module->setState(newState);
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_EvaluateModule(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
+ return ModuleObject::evaluate(cx, module, args.rval());
+}
+
+static bool
+intrinsic_NewModuleNamespace(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
+ RootedObject exports(cx, &args[1].toObject());
+ RootedObject namespace_(cx, ModuleObject::createNamespace(cx, module, exports));
+ if (!namespace_)
+ return false;
+
+ args.rval().setObject(*namespace_);
+ return true;
+}
+
+static bool
+intrinsic_AddModuleNamespaceBinding(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 4);
+ RootedModuleNamespaceObject namespace_(cx, &args[0].toObject().as<ModuleNamespaceObject>());
+ RootedAtom exportedName(cx, &args[1].toString()->asAtom());
+ RootedModuleObject targetModule(cx, &args[2].toObject().as<ModuleObject>());
+ RootedAtom localName(cx, &args[3].toString()->asAtom());
+ if (!namespace_->addBinding(cx, exportedName, targetModule, localName))
+ return false;
+
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedModuleNamespaceObject namespace_(cx, &args[0].toObject().as<ModuleNamespaceObject>());
+ args.rval().setObject(namespace_->exports());
+ return true;
+}
+
+// The self-hosting global isn't initialized with the normal set of builtins.
+// Instead, individual C++-implemented functions that're required by
+// self-hosted code are defined as global functions. Accessing these
+// functions via a content compartment's builtins would be unsafe, because
+// content script might have changed the builtins' prototypes' members.
+// Installing the whole set of builtins in the self-hosting compartment, OTOH,
+// would be wasteful: it increases memory usage and initialization time for
+// self-hosting compartment.
+//
+// Additionally, a set of C++-implemented helper functions is defined on the
+// self-hosting global.
+static const JSFunctionSpec intrinsic_functions[] = {
+ JS_INLINABLE_FN("std_Array", array_construct, 1,0, Array),
+ JS_FN("std_Array_join", array_join, 1,0),
+ JS_INLINABLE_FN("std_Array_push", array_push, 1,0, ArrayPush),
+ JS_INLINABLE_FN("std_Array_pop", array_pop, 0,0, ArrayPop),
+ JS_INLINABLE_FN("std_Array_shift", array_shift, 0,0, ArrayShift),
+ JS_FN("std_Array_unshift", array_unshift, 1,0),
+ JS_INLINABLE_FN("std_Array_slice", array_slice, 2,0, ArraySlice),
+ JS_FN("std_Array_sort", array_sort, 1,0),
+ JS_FN("std_Array_reverse", array_reverse, 0,0),
+ JS_INLINABLE_FN("std_Array_splice", array_splice, 2,0, ArraySplice),
+
+ JS_FN("std_Date_now", date_now, 0,0),
+ JS_FN("std_Date_valueOf", date_valueOf, 0,0),
+
+ JS_FN("std_Function_apply", fun_apply, 2,0),
+
+ JS_INLINABLE_FN("std_Math_floor", math_floor, 1,0, MathFloor),
+ JS_INLINABLE_FN("std_Math_max", math_max, 2,0, MathMax),
+ JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
+ JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
+ JS_INLINABLE_FN("std_Math_imul", math_imul, 2,0, MathImul),
+ JS_INLINABLE_FN("std_Math_log2", math_log2, 1,0, MathLog2),
+
+ JS_FN("std_Map_has", MapObject::has, 1,0),
+ JS_FN("std_Map_iterator", MapObject::entries, 0,0),
+
+ JS_FN("std_Number_valueOf", num_valueOf, 0,0),
+
+ JS_INLINABLE_FN("std_Object_create", obj_create, 2, 0, ObjectCreate),
+ JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1,0),
+ JS_FN("std_Object_defineProperty", obj_defineProperty, 3,0),
+ JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
+ JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
+ JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
+ JS_FN("std_Object_setPrototypeOf", intrinsic_SetPrototype, 2,0),
+ JS_FN("std_Object_toString", obj_toString, 0,0),
+
+ JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
+ JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1,0),
+
+ JS_FN("std_Set_has", SetObject::has, 1,0),
+ JS_FN("std_Set_iterator", SetObject::values, 0,0),
+
+ JS_INLINABLE_FN("std_String_fromCharCode", str_fromCharCode, 1,0, StringFromCharCode),
+ JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1,0, StringCharCodeAt),
+ JS_FN("std_String_includes", str_includes, 1,0),
+ JS_FN("std_String_indexOf", str_indexOf, 1,0),
+ JS_FN("std_String_lastIndexOf", str_lastIndexOf, 1,0),
+ JS_FN("std_String_startsWith", str_startsWith, 1,0),
+ JS_FN("std_String_toLowerCase", str_toLowerCase, 0,0),
+ JS_FN("std_String_toUpperCase", str_toUpperCase, 0,0),
+
+ JS_INLINABLE_FN("std_String_charAt", str_charAt, 1,0, StringCharAt),
+ JS_FN("std_String_endsWith", str_endsWith, 1,0),
+ JS_FN("std_String_trim", str_trim, 0,0),
+ JS_FN("std_String_trimLeft", str_trimLeft, 0,0),
+ JS_FN("std_String_trimRight", str_trimRight, 0,0),
+ JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
+ JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
+#if !EXPOSE_INTL_API
+ JS_FN("std_String_localeCompare", str_localeCompare, 1,0),
+#else
+ JS_FN("std_String_normalize", str_normalize, 0,0),
+#endif
+ JS_FN("std_String_concat", str_concat, 1,0),
+
+ JS_FN("std_TypedArray_buffer", js::TypedArray_bufferGetter, 1,0),
+
+ JS_FN("std_WeakMap_has", WeakMap_has, 1,0),
+ JS_FN("std_WeakMap_get", WeakMap_get, 2,0),
+ JS_FN("std_WeakMap_set", WeakMap_set, 2,0),
+ JS_FN("std_WeakMap_delete", WeakMap_delete, 1,0),
+
+ JS_FN("std_SIMD_Int8x16_extractLane", simd_int8x16_extractLane, 2,0),
+ JS_FN("std_SIMD_Int16x8_extractLane", simd_int16x8_extractLane, 2,0),
+ JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane", simd_int32x4_extractLane, 2,0, SimdInt32x4_extractLane),
+ JS_FN("std_SIMD_Uint8x16_extractLane", simd_uint8x16_extractLane, 2,0),
+ JS_FN("std_SIMD_Uint16x8_extractLane", simd_uint16x8_extractLane, 2,0),
+ JS_FN("std_SIMD_Uint32x4_extractLane", simd_uint32x4_extractLane, 2,0),
+ JS_INLINABLE_FN("std_SIMD_Float32x4_extractLane", simd_float32x4_extractLane,2,0, SimdFloat32x4_extractLane),
+ JS_FN("std_SIMD_Float64x2_extractLane", simd_float64x2_extractLane, 2,0),
+ JS_FN("std_SIMD_Bool8x16_extractLane", simd_bool8x16_extractLane, 2,0),
+ JS_FN("std_SIMD_Bool16x8_extractLane", simd_bool16x8_extractLane, 2,0),
+ JS_FN("std_SIMD_Bool32x4_extractLane", simd_bool32x4_extractLane, 2,0),
+ JS_FN("std_SIMD_Bool64x2_extractLane", simd_bool64x2_extractLane, 2,0),
+
+ // Helper funtions after this point.
+ JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject),
+ JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject),
+ JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1,0, ArrayIsArray),
+ JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0,
+ IntrinsicIsWrappedArrayConstructor),
+ JS_INLINABLE_FN("ToInteger", intrinsic_ToInteger, 1,0, IntrinsicToInteger),
+ JS_INLINABLE_FN("ToString", intrinsic_ToString, 1,0, IntrinsicToString),
+ JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1,0),
+ JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable),
+ JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1,0,
+ IntrinsicIsConstructor),
+ JS_FN("IsFunctionObject",intrinsic_IsInstanceOfBuiltin<JSFunction>, 1,0),
+ JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0),
+ JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
+ JS_FN("_ConstructFunction", intrinsic_ConstructFunction, 2,0),
+ JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4,0),
+ JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0),
+ JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4,0),
+ JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4,0),
+ JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
+ JS_FN("DumpMessage", intrinsic_DumpMessage, 1,0),
+ JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
+ JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2,0),
+ JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
+ JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
+ JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
+ JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0),
+ JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
+ JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
+
+ JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
+ IntrinsicIsConstructing),
+ JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0,
+ IntrinsicSubstringKernel),
+ JS_INLINABLE_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0,
+ IntrinsicDefineDataProperty),
+ JS_INLINABLE_FN("ObjectHasPrototype", intrinsic_ObjectHasPrototype, 2,0,
+ IntrinsicObjectHasPrototype),
+ JS_INLINABLE_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3,0,
+ IntrinsicUnsafeSetReservedSlot),
+ JS_INLINABLE_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2,0,
+ IntrinsicUnsafeGetReservedSlot),
+ JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot", intrinsic_UnsafeGetObjectFromReservedSlot, 2,0,
+ IntrinsicUnsafeGetObjectFromReservedSlot),
+ JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot", intrinsic_UnsafeGetInt32FromReservedSlot, 2,0,
+ IntrinsicUnsafeGetInt32FromReservedSlot),
+ JS_INLINABLE_FN("UnsafeGetStringFromReservedSlot", intrinsic_UnsafeGetStringFromReservedSlot, 2,0,
+ IntrinsicUnsafeGetStringFromReservedSlot),
+ JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot", intrinsic_UnsafeGetBooleanFromReservedSlot,2,0,
+ IntrinsicUnsafeGetBooleanFromReservedSlot),
+
+ JS_FN("NewArrayInCompartment", intrinsic_NewArrayInCompartment, 1,0),
+
+ JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0),
+
+ JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
+
+ JS_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0,0),
+ JS_FN("CallArrayIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
+
+ JS_FN("NewListIterator", intrinsic_NewListIterator, 0,0),
+ JS_FN("CallListIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<ListIteratorObject>>, 2,0),
+ JS_FN("ActiveFunction", intrinsic_ActiveFunction, 0,0),
+
+ JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
+
+ JS_INLINABLE_FN("IsArrayIterator",
+ intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
+ IntrinsicIsArrayIterator),
+ JS_INLINABLE_FN("IsMapIterator",
+ intrinsic_IsInstanceOfBuiltin<MapIteratorObject>, 1,0,
+ IntrinsicIsMapIterator),
+ JS_INLINABLE_FN("IsSetIterator",
+ intrinsic_IsInstanceOfBuiltin<SetIteratorObject>, 1,0,
+ IntrinsicIsSetIterator),
+ JS_INLINABLE_FN("IsStringIterator",
+ intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
+ IntrinsicIsStringIterator),
+ JS_INLINABLE_FN("IsListIterator",
+ intrinsic_IsInstanceOfBuiltin<ListIteratorObject>, 1,0,
+ IntrinsicIsListIterator),
+
+ JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
+ JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
+ IntrinsicGetNextMapEntryForIterator),
+ JS_FN("CallMapIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2,0),
+
+ JS_FN("_CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0),
+ JS_INLINABLE_FN("_GetNextSetEntryForIterator", intrinsic_GetNextSetEntryForIterator, 2,0,
+ IntrinsicGetNextSetEntryForIterator),
+ JS_FN("CallSetIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2,0),
+
+
+ JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0),
+ JS_FN("CallStringIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2,0),
+
+ JS_FN("IsStarGeneratorObject",
+ intrinsic_IsInstanceOfBuiltin<StarGeneratorObject>, 1,0),
+ JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
+ JS_FN("IsSuspendedStarGenerator",intrinsic_IsSuspendedStarGenerator,1,0),
+
+ JS_FN("IsLegacyGeneratorObject",
+ intrinsic_IsInstanceOfBuiltin<LegacyGeneratorObject>, 1,0),
+ JS_FN("LegacyGeneratorObjectIsClosed", intrinsic_LegacyGeneratorObjectIsClosed, 1,0),
+ JS_FN("CloseClosingLegacyGeneratorObject", intrinsic_CloseClosingLegacyGeneratorObject, 1,0),
+ JS_FN("ThrowStopIteration", intrinsic_ThrowStopIteration, 0,0),
+
+ JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1,0),
+ JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1,0),
+
+ JS_FN("IsArrayBuffer",
+ intrinsic_IsInstanceOfBuiltin<ArrayBufferObject>, 1,0),
+ JS_FN("IsSharedArrayBuffer",
+ intrinsic_IsInstanceOfBuiltin<SharedArrayBufferObject>, 1,0),
+ JS_FN("IsWrappedArrayBuffer",
+ intrinsic_IsWrappedArrayBuffer<ArrayBufferObject>, 1,0),
+ JS_FN("IsWrappedSharedArrayBuffer",
+ intrinsic_IsWrappedArrayBuffer<SharedArrayBufferObject>, 1,0),
+
+ JS_INLINABLE_FN("ArrayBufferByteLength",
+ intrinsic_ArrayBufferByteLength<ArrayBufferObject>, 1,0,
+ IntrinsicArrayBufferByteLength),
+ JS_INLINABLE_FN("PossiblyWrappedArrayBufferByteLength",
+ intrinsic_PossiblyWrappedArrayBufferByteLength<ArrayBufferObject>, 1,0,
+ IntrinsicPossiblyWrappedArrayBufferByteLength),
+ JS_FN("ArrayBufferCopyData",
+ intrinsic_ArrayBufferCopyData<ArrayBufferObject>, 5,0),
+
+ JS_FN("SharedArrayBufferByteLength",
+ intrinsic_ArrayBufferByteLength<SharedArrayBufferObject>, 1,0),
+ JS_FN("PossiblyWrappedSharedArrayBufferByteLength",
+ intrinsic_PossiblyWrappedArrayBufferByteLength<SharedArrayBufferObject>, 1,0),
+ JS_FN("SharedArrayBufferCopyData",
+ intrinsic_ArrayBufferCopyData<SharedArrayBufferObject>, 5,0),
+
+ JS_FN("IsUint8TypedArray", intrinsic_IsUint8TypedArray, 1,0),
+ JS_FN("IsInt8TypedArray", intrinsic_IsInt8TypedArray, 1,0),
+ JS_FN("IsUint16TypedArray", intrinsic_IsUint16TypedArray, 1,0),
+ JS_FN("IsInt16TypedArray", intrinsic_IsInt16TypedArray, 1,0),
+ JS_FN("IsUint32TypedArray", intrinsic_IsUint32TypedArray, 1,0),
+ JS_FN("IsInt32TypedArray", intrinsic_IsInt32TypedArray, 1,0),
+ JS_FN("IsFloat32TypedArray", intrinsic_IsFloat32TypedArray, 1,0),
+ JS_INLINABLE_FN("IsTypedArray",
+ intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1,0,
+ IntrinsicIsTypedArray),
+ JS_INLINABLE_FN("IsPossiblyWrappedTypedArray",intrinsic_IsPossiblyWrappedTypedArray,1,0,
+ IntrinsicIsPossiblyWrappedTypedArray),
+
+ JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1,0),
+ JS_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1,0),
+ JS_FN("TypedArrayElementShift", intrinsic_TypedArrayElementShift, 1,0),
+
+ JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1,0,
+ IntrinsicTypedArrayLength),
+ JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength", intrinsic_PossiblyWrappedTypedArrayLength,
+ 1, 0, IntrinsicPossiblyWrappedTypedArrayLength),
+ JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer",
+ intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0),
+
+ JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0),
+ JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0),
+ JS_FN("SetOverlappingTypedElements",intrinsic_SetOverlappingTypedElements,3,0),
+
+ JS_INLINABLE_FN("SetDisjointTypedElements",intrinsic_SetDisjointTypedElements,3,0,
+ IntrinsicSetDisjointTypedElements),
+
+ JS_FN("CallArrayBufferMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<ArrayBufferObject>>, 2, 0),
+ JS_FN("CallSharedArrayBufferMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<SharedArrayBufferObject>>, 2, 0),
+ JS_FN("CallTypedArrayMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0),
+
+ JS_FN("CallLegacyGeneratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<LegacyGeneratorObject>>, 2, 0),
+ JS_FN("CallStarGeneratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
+
+ JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
+ JS_FN("CallWeakSetMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
+
+ JS_FN("Promise_static_resolve", Promise_static_resolve, 1, 0),
+ JS_FN("Promise_static_reject", Promise_reject, 1, 0),
+ JS_FN("Promise_then", Promise_then, 2, 0),
+
+ // See builtin/TypedObject.h for descriptors of the typedobj functions.
+ JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
+ JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),
+ JS_FN("TypedObjectBuffer", TypedObject::GetBuffer, 1, 0),
+ JS_FN("TypedObjectByteOffset", TypedObject::GetByteOffset, 1, 0),
+ JS_FN("AttachTypedObject", js::AttachTypedObject, 3, 0),
+ JS_FN("TypedObjectIsAttached", js::TypedObjectIsAttached, 1, 0),
+ JS_FN("TypedObjectTypeDescr", js::TypedObjectTypeDescr, 1, 0),
+ JS_FN("ClampToUint8", js::ClampToUint8, 1, 0),
+ JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
+ JS_FN("GetSimdTypeDescr", js::GetSimdTypeDescr, 1, 0),
+
+ JS_INLINABLE_FN("ObjectIsTypeDescr" , js::ObjectIsTypeDescr, 1, 0,
+ IntrinsicObjectIsTypeDescr),
+ JS_INLINABLE_FN("ObjectIsTypedObject", js::ObjectIsTypedObject, 1, 0,
+ IntrinsicObjectIsTypedObject),
+ JS_INLINABLE_FN("ObjectIsOpaqueTypedObject", js::ObjectIsOpaqueTypedObject, 1, 0,
+ IntrinsicObjectIsOpaqueTypedObject),
+ JS_INLINABLE_FN("ObjectIsTransparentTypedObject", js::ObjectIsTransparentTypedObject, 1, 0,
+ IntrinsicObjectIsTransparentTypedObject),
+ JS_INLINABLE_FN("TypeDescrIsArrayType", js::TypeDescrIsArrayType, 1, 0,
+ IntrinsicTypeDescrIsArrayType),
+ JS_INLINABLE_FN("TypeDescrIsSimpleType", js::TypeDescrIsSimpleType, 1, 0,
+ IntrinsicTypeDescrIsSimpleType),
+ JS_INLINABLE_FN("SetTypedObjectOffset", js::SetTypedObjectOffset, 2, 0,
+ IntrinsicSetTypedObjectOffset),
+
+#define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \
+ JS_FN("Store_" #_name, js::StoreScalar##_type::Func, 3, 0), \
+ JS_FN("Load_" #_name, js::LoadScalar##_type::Func, 3, 0),
+ JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
+#undef LOAD_AND_STORE_SCALAR_FN_DECLS
+
+#define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name) \
+ JS_FN("Store_" #_name, js::StoreReference##_name::Func, 3, 0), \
+ JS_FN("Load_" #_name, js::LoadReference##_name::Func, 3, 0),
+ JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
+#undef LOAD_AND_STORE_REFERENCE_FN_DECLS
+
+ // See builtin/Intl.h for descriptions of the intl_* functions.
+ JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
+ JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
+ JS_FN("intl_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1,0),
+ JS_FN("intl_Collator", intl_Collator, 2,0),
+ JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
+ JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
+ JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
+ JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
+ JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
+ JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
+ JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
+ JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
+ JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
+ JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
+ JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
+ JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
+ JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
+ JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
+
+ JS_INLINABLE_FN("IsRegExpObject",
+ intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1,0,
+ IsRegExpObject),
+ JS_FN("CallRegExpMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2,0),
+ JS_INLINABLE_FN("RegExpMatcher", RegExpMatcher, 4,0,
+ RegExpMatcher),
+ JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 4,0,
+ RegExpSearcher),
+ JS_INLINABLE_FN("RegExpTester", RegExpTester, 4,0,
+ RegExpTester),
+ JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
+ JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
+ RegExpPrototypeOptimizable),
+ JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
+ RegExpInstanceOptimizable),
+ JS_FN("RegExpGetSubstitution", intrinsic_RegExpGetSubstitution, 6,0),
+ JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1,0),
+ JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2,0),
+ JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1,0,
+ GetFirstDollarIndex),
+
+ JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
+ JS_FN("FlatStringSearch", FlatStringSearch, 2,0),
+ JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0,
+ IntrinsicStringReplaceString),
+ JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0,
+ IntrinsicStringSplitString),
+ JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 0),
+
+ // See builtin/RegExp.h for descriptions of the regexp_* functions.
+ JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
+ JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
+ JS_FN("regexp_construct_raw_flags", regexp_construct_raw_flags, 2,0),
+ JS_FN("regexp_clone", regexp_clone, 1,0),
+
+ JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
+ JS_FN("CallModuleMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
+ JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2, 0),
+ JS_FN("IsModuleEnvironment", intrinsic_IsInstanceOfBuiltin<ModuleEnvironmentObject>, 1, 0),
+ JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 1, 0),
+ JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
+ JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
+ JS_FN("InstantiateModuleFunctionDeclarations",
+ intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
+ JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0),
+ JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
+ JS_FN("IsModuleNamespace", intrinsic_IsInstanceOfBuiltin<ModuleNamespaceObject>, 1, 0),
+ JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
+ JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
+ JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
+
+ JS_FS_END
+};
+
+void
+js::FillSelfHostingCompileOptions(CompileOptions& options)
+{
+ /*
+ * In self-hosting mode, scripts use JSOP_GETINTRINSIC instead of
+ * JSOP_GETNAME or JSOP_GETGNAME to access unbound variables.
+ * JSOP_GETINTRINSIC does a name lookup on a special object, whose
+ * properties are filled in lazily upon first access for a given global.
+ *
+ * As that object is inaccessible to client code, the lookups are
+ * guaranteed to return the original objects, ensuring safe implementation
+ * of self-hosted builtins.
+ *
+ * Additionally, the special syntax callFunction(fun, receiver, ...args)
+ * is supported, for which bytecode is emitted that invokes |fun| with
+ * |receiver| as the this-object and ...args as the arguments.
+ */
+ options.setIntroductionType("self-hosted");
+ options.setFileAndLine("self-hosted", 1);
+ options.setSelfHostingMode(true);
+ options.setCanLazilyParse(false);
+ options.setVersion(JSVERSION_LATEST);
+ options.werrorOption = true;
+ options.strictOption = true;
+
+#ifdef DEBUG
+ options.extraWarningsOption = true;
+#endif
+}
+
+GlobalObject*
+JSRuntime::createSelfHostingGlobal(JSContext* cx)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
+
+ JS::CompartmentOptions options;
+ options.creationOptions().setZone(JS::FreshZone);
+ options.behaviors().setDiscardSource(true);
+
+ JSCompartment* compartment = NewCompartment(cx, nullptr, nullptr, options);
+ if (!compartment)
+ return nullptr;
+
+ static const ClassOps shgClassOps = {
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ JS_GlobalObjectTraceHook
+ };
+
+ static const Class shgClass = {
+ "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
+ &shgClassOps
+ };
+
+ AutoCompartment ac(cx, compartment);
+ Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
+ if (!shg)
+ return nullptr;
+
+ cx->runtime()->selfHostingGlobal_ = shg;
+ compartment->isSelfHosting = true;
+ compartment->setIsSystem(true);
+
+ if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions))
+ return nullptr;
+
+ JS_FireOnNewGlobalObject(cx, shg);
+
+ return shg;
+}
+
+static void
+MaybePrintAndClearPendingException(JSContext* cx, FILE* file)
+{
+ if (!cx->isExceptionPending())
+ return;
+
+ AutoClearPendingException acpe(cx);
+
+ RootedValue exn(cx);
+ if (!cx->getPendingException(&exn)) {
+ fprintf(file, "error getting pending exception\n");
+ return;
+ }
+ cx->clearPendingException();
+
+ ErrorReport report(cx);
+ if (!report.init(cx, exn, js::ErrorReport::WithSideEffects)) {
+ fprintf(file, "out of memory initializing ErrorReport\n");
+ return;
+ }
+
+ MOZ_ASSERT(!JSREPORT_IS_WARNING(report.report()->flags));
+ PrintError(cx, file, report.toStringResult(), report.report(), true);
+}
+
+class MOZ_STACK_CLASS AutoSelfHostingErrorReporter
+{
+ JSContext* cx_;
+ JS::WarningReporter oldReporter_;
+
+ public:
+ explicit AutoSelfHostingErrorReporter(JSContext* cx)
+ : cx_(cx)
+ {
+ oldReporter_ = JS::SetWarningReporter(cx_, selfHosting_WarningReporter);
+ }
+ ~AutoSelfHostingErrorReporter() {
+ JS::SetWarningReporter(cx_, oldReporter_);
+
+ // Exceptions in self-hosted code will usually be printed to stderr in
+ // ErrorToException, but not all exceptions are handled there. For
+ // instance, ReportOutOfMemory will throw the "out of memory" string
+ // without going through ErrorToException. We handle these other
+ // exceptions here.
+ MaybePrintAndClearPendingException(cx_, stderr);
+ }
+};
+
+bool
+JSRuntime::initSelfHosting(JSContext* cx)
+{
+ MOZ_ASSERT(!selfHostingGlobal_);
+
+ if (cx->runtime()->parentRuntime) {
+ selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
+ return true;
+ }
+
+ /*
+ * Self hosted state can be accessed from threads for other runtimes
+ * parented to this one, so cannot include state in the nursery.
+ */
+ JS::AutoDisableGenerationalGC disable(cx->runtime());
+
+ Rooted<GlobalObject*> shg(cx, JSRuntime::createSelfHostingGlobal(cx));
+ if (!shg)
+ return false;
+
+ JSAutoCompartment ac(cx, shg);
+
+ /*
+ * Set a temporary error reporter printing to stderr because it is too
+ * early in the startup process for any other reporter to be registered
+ * and we don't want errors in self-hosted code to be silently swallowed.
+ *
+ * This class also overrides the warning reporter to print warnings to
+ * stderr. See selfHosting_WarningReporter.
+ */
+ AutoSelfHostingErrorReporter errorReporter(cx);
+
+ CompileOptions options(cx);
+ FillSelfHostingCompileOptions(options);
+
+ RootedValue rv(cx);
+
+ uint32_t srcLen = GetRawScriptsSize();
+
+ const unsigned char* compressed = compressedSources;
+ uint32_t compressedLen = GetCompressedSize();
+ ScopedJSFreePtr<char> src(selfHostingGlobal_->zone()->pod_malloc<char>(srcLen));
+ if (!src || !DecompressString(compressed, compressedLen,
+ reinterpret_cast<unsigned char*>(src.get()), srcLen))
+ {
+ return false;
+ }
+
+ if (!Evaluate(cx, options, src, srcLen, &rv))
+ return false;
+
+ return true;
+}
+
+void
+JSRuntime::finishSelfHosting()
+{
+ selfHostingGlobal_ = nullptr;
+}
+
+void
+JSRuntime::markSelfHostingGlobal(JSTracer* trc)
+{
+ if (selfHostingGlobal_ && !parentRuntime)
+ TraceRoot(trc, &selfHostingGlobal_, "self-hosting global");
+}
+
+bool
+JSRuntime::isSelfHostingCompartment(JSCompartment* comp) const
+{
+ return selfHostingGlobal_->compartment() == comp;
+}
+
+bool
+JSRuntime::isSelfHostingZone(const JS::Zone* zone) const
+{
+ return selfHostingGlobal_ && selfHostingGlobal_->zoneFromAnyThread() == zone;
+}
+
+static bool
+CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp);
+
+static bool
+GetUnclonedValue(JSContext* cx, HandleNativeObject selfHostedObject,
+ HandleId id, MutableHandleValue vp)
+{
+ vp.setUndefined();
+
+ if (JSID_IS_INT(id)) {
+ size_t index = JSID_TO_INT(id);
+ if (index < selfHostedObject->getDenseInitializedLength() &&
+ !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
+ {
+ vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id)));
+ return true;
+ }
+ }
+
+ // Since all atoms used by self hosting are marked as permanent, any
+ // attempt to look up a non-permanent atom will fail. We should only
+ // see such atoms when code is looking for properties on the self
+ // hosted global which aren't present.
+ if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
+ MOZ_ASSERT(selfHostedObject->is<GlobalObject>());
+ RootedValue value(cx, IdToValue(id));
+ return ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
+ JSDVG_IGNORE_STACK, value, nullptr, nullptr, nullptr);
+ }
+
+ RootedShape shape(cx, selfHostedObject->lookupPure(id));
+ if (!shape) {
+ RootedValue value(cx, IdToValue(id));
+ return ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
+ JSDVG_IGNORE_STACK, value, nullptr, nullptr, nullptr);
+ }
+
+ MOZ_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
+ vp.set(selfHostedObject->getSlot(shape->slot()));
+ return true;
+}
+
+static bool
+CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject, HandleObject clone)
+{
+ AutoIdVector ids(cx);
+ Vector<uint8_t, 16> attrs(cx);
+
+ for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
+ if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
+ if (!ids.append(INT_TO_JSID(i)))
+ return false;
+ if (!attrs.append(JSPROP_ENUMERATE))
+ return false;
+ }
+ }
+
+ Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
+ for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
+ Shape& shape = range.front();
+ if (shape.enumerable() && !shapes.append(&shape))
+ return false;
+ }
+
+ // Now our shapes are in last-to-first order, so....
+ Reverse(shapes.begin(), shapes.end());
+ for (size_t i = 0; i < shapes.length(); ++i) {
+ MOZ_ASSERT(!shapes[i]->isAccessorShape(),
+ "Can't handle cloning accessors here yet.");
+ if (!ids.append(shapes[i]->propid()))
+ return false;
+ uint8_t shapeAttrs =
+ shapes[i]->attributes() & (JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
+ if (!attrs.append(shapeAttrs))
+ return false;
+ }
+
+ RootedId id(cx);
+ RootedValue val(cx);
+ RootedValue selfHostedValue(cx);
+ for (uint32_t i = 0; i < ids.length(); i++) {
+ id = ids[i];
+ if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
+ return false;
+ if (!CloneValue(cx, selfHostedValue, &val) ||
+ !JS_DefinePropertyById(cx, clone, id, val, attrs[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static JSString*
+CloneString(JSContext* cx, JSFlatString* selfHostedString)
+{
+ size_t len = selfHostedString->length();
+ {
+ JS::AutoCheckCannotGC nogc;
+ JSString* clone;
+ if (selfHostedString->hasLatin1Chars())
+ clone = NewStringCopyN<NoGC>(cx, selfHostedString->latin1Chars(nogc), len);
+ else
+ clone = NewStringCopyNDontDeflate<NoGC>(cx, selfHostedString->twoByteChars(nogc), len);
+ if (clone)
+ return clone;
+ }
+
+ AutoStableStringChars chars(cx);
+ if (!chars.init(cx, selfHostedString))
+ return nullptr;
+
+ return chars.isLatin1()
+ ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len)
+ : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len);
+}
+
+static JSObject*
+CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
+{
+#ifdef DEBUG
+ // Object hash identities are owned by the hashed object, which may be on a
+ // different thread than the clone target. In theory, these objects are all
+ // tenured and will not be compacted; however, we simply avoid the issue
+ // altogether by skipping the cycle-detection when off the main thread.
+ mozilla::Maybe<AutoCycleDetector> detect;
+ if (js::CurrentThreadCanAccessZone(selfHostedObject->zoneFromAnyThread())) {
+ detect.emplace(cx, selfHostedObject);
+ if (!detect->init())
+ return nullptr;
+ if (detect->foundCycle())
+ MOZ_CRASH("SelfHosted cloning cannot handle cyclic object graphs.");
+ }
+#endif
+
+ RootedObject clone(cx);
+ if (selfHostedObject->is<JSFunction>()) {
+ RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
+ bool hasName = selfHostedFunction->name() != nullptr;
+
+ // Arrow functions use the first extended slot for their lexical |this| value.
+ MOZ_ASSERT(!selfHostedFunction->isArrow());
+ js::gc::AllocKind kind = hasName
+ ? gc::AllocKind::FUNCTION_EXTENDED
+ : selfHostedFunction->getAllocKind();
+ MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global()));
+ Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment());
+ RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+ clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical, emptyGlobalScope,
+ kind);
+ // To be able to re-lazify the cloned function, its name in the
+ // self-hosting compartment has to be stored on the clone.
+ if (clone && hasName) {
+ clone->as<JSFunction>().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT,
+ StringValue(selfHostedFunction->name()));
+ }
+ } else if (selfHostedObject->is<RegExpObject>()) {
+ RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
+ RootedAtom source(cx, reobj.getSource());
+ MOZ_ASSERT(source->isPermanentAtom());
+ clone = RegExpObject::create(cx, source, reobj.getFlags(), nullptr, cx->tempLifoAlloc());
+ } else if (selfHostedObject->is<DateObject>()) {
+ clone = JS::NewDateObject(cx, selfHostedObject->as<DateObject>().clippedTime());
+ } else if (selfHostedObject->is<BooleanObject>()) {
+ clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
+ } else if (selfHostedObject->is<NumberObject>()) {
+ clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
+ } else if (selfHostedObject->is<StringObject>()) {
+ JSString* selfHostedString = selfHostedObject->as<StringObject>().unbox();
+ if (!selfHostedString->isFlat())
+ MOZ_CRASH();
+ RootedString str(cx, CloneString(cx, &selfHostedString->asFlat()));
+ if (!str)
+ return nullptr;
+ clone = StringObject::create(cx, str);
+ } else if (selfHostedObject->is<ArrayObject>()) {
+ clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
+ } else {
+ MOZ_ASSERT(selfHostedObject->isNative());
+ clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr,
+ selfHostedObject->asTenured().getAllocKind(),
+ SingletonObject);
+ }
+ if (!clone)
+ return nullptr;
+
+ if (!CloneProperties(cx, selfHostedObject, clone))
+ return nullptr;
+ return clone;
+}
+
+static bool
+CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp)
+{
+ if (selfHostedValue.isObject()) {
+ RootedNativeObject selfHostedObject(cx, &selfHostedValue.toObject().as<NativeObject>());
+ JSObject* clone = CloneObject(cx, selfHostedObject);
+ if (!clone)
+ return false;
+ vp.setObject(*clone);
+ } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
+ // Nothing to do here: these are represented inline in the value.
+ vp.set(selfHostedValue);
+ } else if (selfHostedValue.isString()) {
+ if (!selfHostedValue.toString()->isFlat())
+ MOZ_CRASH();
+ JSFlatString* selfHostedString = &selfHostedValue.toString()->asFlat();
+ JSString* clone = CloneString(cx, selfHostedString);
+ if (!clone)
+ return false;
+ vp.setString(clone);
+ } else if (selfHostedValue.isSymbol()) {
+ // Well-known symbols are shared.
+ mozilla::DebugOnly<JS::Symbol*> sym = selfHostedValue.toSymbol();
+ MOZ_ASSERT(sym->isWellKnownSymbol());
+ MOZ_ASSERT(cx->wellKnownSymbols().get(size_t(sym->code())) == sym);
+ vp.set(selfHostedValue);
+ } else {
+ MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
+ }
+ return true;
+}
+
+bool
+JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName,
+ HandleAtom name, unsigned nargs,
+ HandleObject proto, NewObjectKind newKind,
+ MutableHandleFunction fun)
+{
+ MOZ_ASSERT(newKind != GenericObject);
+
+ RootedAtom funName(cx, name);
+ JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName);
+ if (!selfHostedFun)
+ return false;
+
+ if (!selfHostedFun->isClassConstructor() && !selfHostedFun->hasGuessedAtom() &&
+ selfHostedFun->name() != selfHostedName)
+ {
+ MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
+ funName = selfHostedFun->name();
+ }
+
+ fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
+ funName, proto, gc::AllocKind::FUNCTION_EXTENDED, newKind));
+ if (!fun)
+ return false;
+ fun->setIsSelfHostedBuiltin();
+ fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
+ return true;
+}
+
+bool
+JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
+ HandleFunction targetFun)
+{
+ RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(cx, name));
+ if (!sourceFun)
+ return false;
+ // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
+ // aren't any.
+ MOZ_ASSERT(!sourceFun->isGenerator());
+ MOZ_ASSERT(targetFun->isExtended());
+ MOZ_ASSERT(targetFun->isInterpretedLazy());
+ MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
+
+ RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
+ if (!sourceScript)
+ return false;
+
+ // Assert that there are no intervening scopes between the global scope
+ // and the self-hosted script. Toplevel lexicals are explicitly forbidden
+ // by the parser when parsing self-hosted code. The fact they have the
+ // global lexical scope on the scope chain is for uniformity and engine
+ // invariants.
+ MOZ_ASSERT(sourceScript->outermostScope()->enclosing()->kind() == ScopeKind::Global);
+ RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+ if (!CloneScriptIntoFunction(cx, emptyGlobalScope, targetFun, sourceScript))
+ return false;
+ MOZ_ASSERT(!targetFun->isInterpretedLazy());
+
+ MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
+ MOZ_ASSERT(sourceFun->hasRest() == targetFun->hasRest());
+
+ // The target function might have been relazified after its flags changed.
+ targetFun->setFlags(targetFun->flags() | sourceFun->flags());
+ return true;
+}
+
+bool
+JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name,
+ MutableHandleValue vp)
+{
+ RootedId id(cx, NameToId(name));
+ return GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, vp);
+}
+
+JSFunction*
+JSRuntime::getUnclonedSelfHostedFunction(JSContext* cx, HandlePropertyName name)
+{
+ RootedValue selfHostedValue(cx);
+ if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
+ return nullptr;
+
+ return &selfHostedValue.toObject().as<JSFunction>();
+}
+
+bool
+JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
+{
+ RootedValue selfHostedValue(cx);
+ if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
+ return false;
+
+ /*
+ * We don't clone if we're operating in the self-hosting global, as that
+ * means we're currently executing the self-hosting script while
+ * initializing the runtime (see JSRuntime::initSelfHosting).
+ */
+ if (cx->global() == selfHostingGlobal_) {
+ vp.set(selfHostedValue);
+ return true;
+ }
+
+ return CloneValue(cx, selfHostedValue, vp);
+}
+
+void
+JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropertyName name)
+{
+#ifdef DEBUG
+ JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name);
+ MOZ_ASSERT(selfHostedFun);
+ MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
+#endif
+}
+
+JSFunction*
+js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName)
+{
+ RootedValue func(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
+ return nullptr;
+
+ MOZ_ASSERT(func.isObject());
+ MOZ_ASSERT(func.toObject().is<JSFunction>());
+ return &func.toObject().as<JSFunction>();
+}
+
+bool
+js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name)
+{
+ return fun->isSelfHostedBuiltin() && GetSelfHostedFunctionName(fun) == name;
+}
+
+JSAtom*
+js::GetSelfHostedFunctionName(JSFunction* fun)
+{
+ Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT);
+ if (!name.isString())
+ return nullptr;
+ return &name.toString()->asAtom();
+}
+
+static_assert(JSString::MAX_LENGTH <= INT32_MAX,
+ "StringIteratorNext in builtin/String.js assumes the stored index "
+ "into the string is an Int32Value");
diff --git a/js/src/vm/SelfHosting.h b/js/src/vm/SelfHosting.h
new file mode 100644
index 000000000..f4f2a4447
--- /dev/null
+++ b/js/src/vm/SelfHosting.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SelfHosting_h_
+#define vm_SelfHosting_h_
+
+#include "jsapi.h"
+#include "NamespaceImports.h"
+
+#include "vm/Stack.h"
+
+class JSAtom;
+
+namespace js {
+
+/*
+ * Check whether the given JSFunction is a self-hosted function whose
+ * self-hosted name is the given name.
+ */
+bool
+IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
+
+JSAtom*
+GetSelfHostedFunctionName(JSFunction* fun);
+
+bool
+IsCallSelfHostedNonGenericMethod(NativeImpl impl);
+
+bool
+ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args);
+
+/* Get the compile options used when compiling self hosted code. */
+void
+FillSelfHostingCompileOptions(JS::CompileOptions& options);
+
+bool
+CallSelfHostedFunction(JSContext* cx, char const* name, HandleValue thisv,
+ const AnyInvokeArgs& args, MutableHandleValue rval);
+
+bool
+CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv,
+ const AnyInvokeArgs& args, MutableHandleValue rval);
+
+bool
+intrinsic_StringSplitString(JSContext* cx, unsigned argc, JS::Value* vp);
+
+} /* namespace js */
+
+#endif /* vm_SelfHosting_h_ */
diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h
new file mode 100644
index 000000000..b8c48780e
--- /dev/null
+++ b/js/src/vm/Shape-inl.h
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Shape_inl_h
+#define vm_Shape_inl_h
+
+#include "vm/Shape.h"
+
+#include "mozilla/TypeTraits.h"
+
+#include "jsobj.h"
+
+#include "gc/Allocator.h"
+#include "vm/Interpreter.h"
+#include "vm/TypedArrayCommon.h"
+
+#include "jsatominlines.h"
+#include "jscntxtinlines.h"
+
+namespace js {
+
+inline
+AutoKeepShapeTables::AutoKeepShapeTables(ExclusiveContext* cx)
+ : cx_(cx),
+ prev_(cx->zone()->keepShapeTables())
+{
+ cx->zone()->setKeepShapeTables(true);
+}
+
+inline
+AutoKeepShapeTables::~AutoKeepShapeTables()
+{
+ cx_->zone()->setKeepShapeTables(prev_);
+}
+
+inline
+StackBaseShape::StackBaseShape(ExclusiveContext* cx, const Class* clasp, uint32_t objectFlags)
+ : flags(objectFlags),
+ clasp(clasp)
+{}
+
+inline Shape*
+Shape::search(ExclusiveContext* cx, jsid id)
+{
+ return search(cx, this, id);
+}
+
+MOZ_ALWAYS_INLINE bool
+Shape::maybeCreateTableForLookup(ExclusiveContext* cx)
+{
+ if (hasTable())
+ return true;
+
+ if (!inDictionary() && numLinearSearches() < LINEAR_SEARCHES_MAX) {
+ incrementNumLinearSearches();
+ return true;
+ }
+
+ if (!isBigEnoughForAShapeTable())
+ return true;
+
+ return Shape::hashify(cx, this);
+}
+
+template<MaybeAdding Adding>
+/* static */ inline bool
+Shape::search(ExclusiveContext* cx, Shape* start, jsid id, const AutoKeepShapeTables& keep,
+ Shape** pshape, ShapeTable::Entry** pentry)
+{
+ if (start->inDictionary()) {
+ ShapeTable* table = start->ensureTableForDictionary(cx, keep);
+ if (!table)
+ return false;
+ *pentry = &table->search<Adding>(id, keep);
+ *pshape = (*pentry)->shape();
+ return true;
+ }
+
+ *pentry = nullptr;
+ *pshape = Shape::search<Adding>(cx, start, id);
+ return true;
+}
+
+template<MaybeAdding Adding>
+/* static */ inline Shape*
+Shape::search(ExclusiveContext* cx, Shape* start, jsid id)
+{
+ if (start->maybeCreateTableForLookup(cx)) {
+ JS::AutoCheckCannotGC nogc;
+ if (ShapeTable* table = start->maybeTable(nogc)) {
+ ShapeTable::Entry& entry = table->search<Adding>(id, nogc);
+ return entry.shape();
+ }
+ } else {
+ // Just do a linear search.
+ cx->recoverFromOutOfMemory();
+ }
+
+ return start->searchLinear(id);
+}
+
+inline Shape*
+Shape::new_(ExclusiveContext* cx, Handle<StackShape> other, uint32_t nfixed)
+{
+ Shape* shape = other.isAccessorShape()
+ ? js::Allocate<AccessorShape>(cx)
+ : js::Allocate<Shape>(cx);
+ if (!shape) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ if (other.isAccessorShape())
+ new (shape) AccessorShape(other, nfixed);
+ else
+ new (shape) Shape(other, nfixed);
+
+ return shape;
+}
+
+inline void
+Shape::updateBaseShapeAfterMovingGC()
+{
+ BaseShape* base = base_.unbarrieredGet();
+ if (IsForwarded(base))
+ base_.unsafeSet(Forwarded(base));
+}
+
+template<class ObjectSubclass>
+/* static */ inline bool
+EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, Handle<ObjectSubclass*> obj)
+{
+ static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value,
+ "ObjectSubclass must be a subclass of JSObject");
+
+ // If the provided object has a non-empty shape, it was given the cached
+ // initial shape when created: nothing to do.
+ if (!obj->empty())
+ return true;
+
+ // If no initial shape was assigned, do so.
+ RootedShape shape(cx, ObjectSubclass::assignInitialShape(cx, obj));
+ if (!shape)
+ return false;
+ MOZ_ASSERT(!obj->empty());
+
+ // If the object is a standard prototype -- |RegExp.prototype|,
+ // |String.prototype|, |RangeError.prototype|, &c. -- GlobalObject.cpp's
+ // |CreateBlankProto| marked it as a delegate. These are the only objects
+ // of this class that won't use the standard prototype, and there's no
+ // reason to pollute the initial shape cache with entries for them.
+ if (obj->isDelegate())
+ return true;
+
+ // Cache the initial shape for non-prototype objects, however, so that
+ // future instances will begin life with that shape.
+ RootedObject proto(cx, obj->staticPrototype());
+ EmptyShape::insertInitialShape(cx, shape, proto);
+ return true;
+}
+
+inline
+AutoRooterGetterSetter::Inner::Inner(ExclusiveContext* cx, uint8_t attrs,
+ GetterOp* pgetter_, SetterOp* psetter_)
+ : CustomAutoRooter(cx), attrs(attrs),
+ pgetter(pgetter_), psetter(psetter_)
+{}
+
+inline
+AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs,
+ GetterOp* pgetter, SetterOp* psetter
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+{
+ if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
+ inner.emplace(cx, attrs, pgetter, psetter);
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+inline
+AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs,
+ JSNative* pgetter, JSNative* psetter
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+{
+ if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+ inner.emplace(cx, attrs, reinterpret_cast<GetterOp*>(pgetter),
+ reinterpret_cast<SetterOp*>(psetter));
+ }
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+static inline uint8_t
+GetShapeAttributes(JSObject* obj, Shape* shape)
+{
+ MOZ_ASSERT(obj->isNative());
+
+ if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (obj->is<TypedArrayObject>())
+ return JSPROP_ENUMERATE | JSPROP_PERMANENT;
+ return obj->as<NativeObject>().getElementsHeader()->elementAttributes();
+ }
+
+ return shape->attributes();
+}
+
+} /* namespace js */
+
+#endif /* vm_Shape_inl_h */
diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
new file mode 100644
index 000000000..a64dc529a
--- /dev/null
+++ b/js/src/vm/Shape.cpp
@@ -0,0 +1,1782 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* JS symbol tables. */
+
+#include "vm/Shape-inl.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/PodOperations.h"
+
+#include "jsatom.h"
+#include "jscntxt.h"
+#include "jshashutil.h"
+#include "jsobj.h"
+
+#include "gc/Policy.h"
+#include "js/HashTable.h"
+
+#include "jscntxtinlines.h"
+#include "jscompartmentinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/Caches-inl.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::CeilingLog2Size;
+using mozilla::DebugOnly;
+using mozilla::PodZero;
+using mozilla::RotateLeft;
+
+using JS::AutoCheckCannotGC;
+
+Shape* const ShapeTable::Entry::SHAPE_REMOVED = (Shape*)ShapeTable::Entry::SHAPE_COLLISION;
+
+bool
+ShapeTable::init(ExclusiveContext* cx, Shape* lastProp)
+{
+ uint32_t sizeLog2 = CeilingLog2Size(entryCount_);
+ uint32_t size = JS_BIT(sizeLog2);
+ if (entryCount_ >= size - (size >> 2))
+ sizeLog2++;
+ if (sizeLog2 < MIN_SIZE_LOG2)
+ sizeLog2 = MIN_SIZE_LOG2;
+
+ size = JS_BIT(sizeLog2);
+ entries_ = cx->pod_calloc<Entry>(size);
+ if (!entries_)
+ return false;
+
+ MOZ_ASSERT(sizeLog2 <= HASH_BITS);
+ hashShift_ = HASH_BITS - sizeLog2;
+
+ for (Shape::Range<NoGC> r(lastProp); !r.empty(); r.popFront()) {
+ Shape& shape = r.front();
+ Entry& entry = searchUnchecked<MaybeAdding::Adding>(shape.propid());
+
+ /*
+ * Beware duplicate args and arg vs. var conflicts: the youngest shape
+ * (nearest to lastProp) must win. See bug 600067.
+ */
+ if (!entry.shape())
+ entry.setPreservingCollision(&shape);
+ }
+
+ MOZ_ASSERT(capacity() == size);
+ MOZ_ASSERT(size >= MIN_SIZE);
+ MOZ_ASSERT(!needsToGrow());
+ return true;
+}
+
+void
+Shape::removeFromDictionary(NativeObject* obj)
+{
+ MOZ_ASSERT(inDictionary());
+ MOZ_ASSERT(obj->inDictionaryMode());
+ MOZ_ASSERT(listp);
+
+ MOZ_ASSERT(obj->shape_->inDictionary());
+ MOZ_ASSERT(obj->shape_->listp == &obj->shape_);
+
+ if (parent)
+ parent->listp = listp;
+ *listp = parent;
+ listp = nullptr;
+
+ obj->shape_->clearCachedBigEnoughForShapeTable();
+}
+
+void
+Shape::insertIntoDictionary(GCPtrShape* dictp)
+{
+ // Don't assert inDictionaryMode() here because we may be called from
+ // JSObject::toDictionaryMode via JSObject::newDictionaryShape.
+ MOZ_ASSERT(inDictionary());
+ MOZ_ASSERT(!listp);
+
+ MOZ_ASSERT_IF(*dictp, (*dictp)->inDictionary());
+ MOZ_ASSERT_IF(*dictp, (*dictp)->listp == dictp);
+ MOZ_ASSERT_IF(*dictp, zone() == (*dictp)->zone());
+
+ setParent(dictp->get());
+ if (parent)
+ parent->listp = &parent;
+ listp = (GCPtrShape*) dictp;
+ *dictp = this;
+}
+
+bool
+Shape::makeOwnBaseShape(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(!base()->isOwned());
+ MOZ_ASSERT(cx->zone() == zone());
+
+ BaseShape* nbase = Allocate<BaseShape, NoGC>(cx);
+ if (!nbase)
+ return false;
+
+ new (nbase) BaseShape(StackBaseShape(this));
+ nbase->setOwned(base()->toUnowned());
+
+ this->base_ = nbase;
+
+ return true;
+}
+
+void
+Shape::handoffTableTo(Shape* shape)
+{
+ MOZ_ASSERT(inDictionary() && shape->inDictionary());
+
+ if (this == shape)
+ return;
+
+ MOZ_ASSERT(base()->isOwned() && !shape->base()->isOwned());
+
+ BaseShape* nbase = base();
+
+ MOZ_ASSERT_IF(shape->hasSlot(), nbase->slotSpan() > shape->slot());
+
+ this->base_ = nbase->baseUnowned();
+ nbase->adoptUnowned(shape->base()->toUnowned());
+
+ shape->base_ = nbase;
+}
+
+/* static */ bool
+Shape::hashify(ExclusiveContext* cx, Shape* shape)
+{
+ MOZ_ASSERT(!shape->hasTable());
+
+ if (!shape->ensureOwnBaseShape(cx))
+ return false;
+
+ ShapeTable* table = cx->new_<ShapeTable>(shape->entryCount());
+ if (!table)
+ return false;
+
+ if (!table->init(cx, shape)) {
+ js_free(table);
+ return false;
+ }
+
+ shape->base()->setTable(table);
+ return true;
+}
+
+/*
+ * Double hashing needs the second hash code to be relatively prime to table
+ * size, so we simply make hash2 odd.
+ */
+static HashNumber
+Hash1(HashNumber hash0, uint32_t shift)
+{
+ return hash0 >> shift;
+}
+
+static HashNumber
+Hash2(HashNumber hash0, uint32_t log2, uint32_t shift)
+{
+ return ((hash0 << log2) >> shift) | 1;
+}
+
+template<MaybeAdding Adding>
+ShapeTable::Entry&
+ShapeTable::searchUnchecked(jsid id)
+{
+ MOZ_ASSERT(entries_);
+ MOZ_ASSERT(!JSID_IS_EMPTY(id));
+
+ /* Compute the primary hash address. */
+ HashNumber hash0 = HashId(id);
+ HashNumber hash1 = Hash1(hash0, hashShift_);
+ Entry* entry = &getEntry(hash1);
+
+ /* Miss: return space for a new entry. */
+ if (entry->isFree())
+ return *entry;
+
+ /* Hit: return entry. */
+ Shape* shape = entry->shape();
+ if (shape && shape->propidRaw() == id)
+ return *entry;
+
+ /* Collision: double hash. */
+ uint32_t sizeLog2 = HASH_BITS - hashShift_;
+ HashNumber hash2 = Hash2(hash0, sizeLog2, hashShift_);
+ uint32_t sizeMask = JS_BITMASK(sizeLog2);
+
+ /* Save the first removed entry pointer so we can recycle it if adding. */
+ Entry* firstRemoved;
+ if (Adding == MaybeAdding::Adding) {
+ if (entry->isRemoved()) {
+ firstRemoved = entry;
+ } else {
+ firstRemoved = nullptr;
+ if (!entry->hadCollision())
+ entry->flagCollision();
+ }
+ }
+
+#ifdef DEBUG
+ bool collisionFlag = true;
+ if (!entry->isRemoved())
+ collisionFlag = entry->hadCollision();
+#endif
+
+ while (true) {
+ hash1 -= hash2;
+ hash1 &= sizeMask;
+ entry = &getEntry(hash1);
+
+ if (entry->isFree())
+ return (Adding == MaybeAdding::Adding && firstRemoved) ? *firstRemoved : *entry;
+
+ shape = entry->shape();
+ if (shape && shape->propidRaw() == id) {
+ MOZ_ASSERT(collisionFlag);
+ return *entry;
+ }
+
+ if (Adding == MaybeAdding::Adding) {
+ if (entry->isRemoved()) {
+ if (!firstRemoved)
+ firstRemoved = entry;
+ } else {
+ if (!entry->hadCollision())
+ entry->flagCollision();
+ }
+ }
+
+#ifdef DEBUG
+ if (!entry->isRemoved())
+ collisionFlag &= entry->hadCollision();
+#endif
+ }
+
+ MOZ_CRASH("Shape::search failed to find an expected entry.");
+}
+
+template ShapeTable::Entry& ShapeTable::searchUnchecked<MaybeAdding::Adding>(jsid id);
+template ShapeTable::Entry& ShapeTable::searchUnchecked<MaybeAdding::NotAdding>(jsid id);
+
+bool
+ShapeTable::change(ExclusiveContext* cx, int log2Delta)
+{
+ MOZ_ASSERT(entries_);
+ MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
+
+ /*
+ * Grow, shrink, or compress by changing this->entries_.
+ */
+ uint32_t oldLog2 = HASH_BITS - hashShift_;
+ uint32_t newLog2 = oldLog2 + log2Delta;
+ uint32_t oldSize = JS_BIT(oldLog2);
+ uint32_t newSize = JS_BIT(newLog2);
+ Entry* newTable = cx->maybe_pod_calloc<Entry>(newSize);
+ if (!newTable)
+ return false;
+
+ /* Now that we have newTable allocated, update members. */
+ MOZ_ASSERT(newLog2 <= HASH_BITS);
+ hashShift_ = HASH_BITS - newLog2;
+ removedCount_ = 0;
+ Entry* oldTable = entries_;
+ entries_ = newTable;
+
+ /* Copy only live entries, leaving removed and free ones behind. */
+ AutoCheckCannotGC nogc;
+ for (Entry* oldEntry = oldTable; oldSize != 0; oldEntry++) {
+ if (Shape* shape = oldEntry->shape()) {
+ Entry& entry = search<MaybeAdding::Adding>(shape->propid(), nogc);
+ MOZ_ASSERT(entry.isFree());
+ entry.setShape(shape);
+ }
+ oldSize--;
+ }
+
+ MOZ_ASSERT(capacity() == newSize);
+
+ /* Finally, free the old entries storage. */
+ js_free(oldTable);
+ return true;
+}
+
+bool
+ShapeTable::grow(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(needsToGrow());
+
+ uint32_t size = capacity();
+ int delta = removedCount_ < (size >> 2);
+
+ MOZ_ASSERT(entryCount_ + removedCount_ <= size - 1);
+
+ if (!change(cx, delta)) {
+ if (entryCount_ + removedCount_ == size - 1) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+ShapeTable::trace(JSTracer* trc)
+{
+ for (size_t i = 0; i < capacity(); i++) {
+ Entry& entry = getEntry(i);
+ Shape* shape = entry.shape();
+ if (shape) {
+ TraceManuallyBarrieredEdge(trc, &shape, "ShapeTable shape");
+ if (shape != entry.shape())
+ entry.setPreservingCollision(shape);
+ }
+ }
+}
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+
+void
+ShapeTable::checkAfterMovingGC()
+{
+ for (size_t i = 0; i < capacity(); i++) {
+ Entry& entry = getEntry(i);
+ Shape* shape = entry.shape();
+ if (shape)
+ CheckGCThingAfterMovingGC(shape);
+ }
+}
+
+#endif
+
+/* static */ Shape*
+Shape::replaceLastProperty(ExclusiveContext* cx, StackBaseShape& base,
+ TaggedProto proto, HandleShape shape)
+{
+ MOZ_ASSERT(!shape->inDictionary());
+
+ if (!shape->parent) {
+ /* Treat as resetting the initial property of the shape hierarchy. */
+ AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ return EmptyShape::getInitialShape(cx, base.clasp, proto, kind,
+ base.flags & BaseShape::OBJECT_FLAG_MASK);
+ }
+
+ UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return nullptr;
+
+ Rooted<StackShape> child(cx, StackShape(shape));
+ child.setBase(nbase);
+
+ return cx->zone()->propertyTree.getChild(cx, shape->parent, child);
+}
+
+/*
+ * Get or create a property-tree or dictionary child property of |parent|,
+ * which must be lastProperty() if inDictionaryMode(), else parent must be
+ * one of lastProperty() or lastProperty()->parent.
+ */
+/* static */ Shape*
+NativeObject::getChildPropertyOnDictionary(ExclusiveContext* cx, HandleNativeObject obj,
+ HandleShape parent, MutableHandle<StackShape> child)
+{
+ /*
+ * Shared properties have no slot, but slot_ will reflect that of parent.
+ * Unshared properties allocate a slot here but may lose it due to a
+ * JS_ClearScope call.
+ */
+ if (!child.hasSlot()) {
+ child.setSlot(parent->maybeSlot());
+ } else {
+ if (child.hasMissingSlot()) {
+ uint32_t slot;
+ if (!allocSlot(cx, obj, &slot))
+ return nullptr;
+ child.setSlot(slot);
+ } else {
+ /*
+ * Slots can only be allocated out of order on objects in
+ * dictionary mode. Otherwise the child's slot must be after the
+ * parent's slot (if it has one), because slot number determines
+ * slot span for objects with that shape. Usually child slot
+ * *immediately* follows parent slot, but there may be a slot gap
+ * when the object uses some -- but not all -- of its reserved
+ * slots to store properties.
+ */
+ MOZ_ASSERT(obj->inDictionaryMode() ||
+ parent->hasMissingSlot() ||
+ child.slot() == parent->maybeSlot() + 1 ||
+ (parent->maybeSlot() + 1 < JSSLOT_FREE(obj->getClass()) &&
+ child.slot() == JSSLOT_FREE(obj->getClass())));
+ }
+ }
+
+ RootedShape shape(cx);
+
+ if (obj->inDictionaryMode()) {
+ MOZ_ASSERT(parent == obj->lastProperty());
+ shape = child.isAccessorShape() ? Allocate<AccessorShape>(cx) : Allocate<Shape>(cx);
+ if (!shape)
+ return nullptr;
+ if (child.hasSlot() && child.slot() >= obj->lastProperty()->base()->slotSpan()) {
+ if (!obj->setSlotSpan(cx, child.slot() + 1)) {
+ new (shape) Shape(obj->lastProperty()->base()->unowned(), 0);
+ return nullptr;
+ }
+ }
+ shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_);
+ }
+
+ return shape;
+}
+
+/* static */ Shape*
+NativeObject::getChildProperty(ExclusiveContext* cx,
+ HandleNativeObject obj, HandleShape parent,
+ MutableHandle<StackShape> child)
+{
+ Shape* shape = getChildPropertyOnDictionary(cx, obj, parent, child);
+
+ if (!obj->inDictionaryMode()) {
+ shape = cx->zone()->propertyTree.getChild(cx, parent, child);
+ if (!shape)
+ return nullptr;
+ //MOZ_ASSERT(shape->parent == parent);
+ //MOZ_ASSERT_IF(parent != lastProperty(), parent == lastProperty()->parent);
+ if (!obj->setLastProperty(cx, shape))
+ return nullptr;
+ }
+
+ return shape;
+}
+
+bool
+js::NativeObject::toDictionaryMode(ExclusiveContext* cx)
+{
+ MOZ_ASSERT(!inDictionaryMode());
+ MOZ_ASSERT(cx->isInsideCurrentCompartment(this));
+
+ uint32_t span = slotSpan();
+
+ Rooted<NativeObject*> self(cx, this);
+
+ // Clone the shapes into a new dictionary list. Don't update the last
+ // property of this object until done, otherwise a GC triggered while
+ // creating the dictionary will get the wrong slot span for this object.
+ RootedShape root(cx);
+ RootedShape dictionaryShape(cx);
+
+ RootedShape shape(cx, lastProperty());
+ while (shape) {
+ MOZ_ASSERT(!shape->inDictionary());
+
+ Shape* dprop = shape->isAccessorShape() ? Allocate<AccessorShape>(cx) : Allocate<Shape>(cx);
+ if (!dprop) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ GCPtrShape* listp = dictionaryShape ? &dictionaryShape->parent : nullptr;
+ StackShape child(shape);
+ dprop->initDictionaryShape(child, self->numFixedSlots(), listp);
+
+ if (!dictionaryShape)
+ root = dprop;
+
+ MOZ_ASSERT(!dprop->hasTable());
+ dictionaryShape = dprop;
+ shape = shape->previous();
+ }
+
+ if (!Shape::hashify(cx, root)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ if (IsInsideNursery(self) &&
+ !cx->asJSContext()->gc.nursery.queueDictionaryModeObjectToSweep(self))
+ {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ MOZ_ASSERT(root->listp == nullptr);
+ root->listp = &self->shape_;
+ self->shape_ = root;
+
+ MOZ_ASSERT(self->inDictionaryMode());
+ root->base()->setSlotSpan(span);
+
+ return true;
+}
+
+/* static */ Shape*
+NativeObject::addProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ GetterOp getter, SetterOp setter, uint32_t slot, unsigned attrs,
+ unsigned flags, bool allowDictionary)
+{
+ MOZ_ASSERT(!JSID_IS_VOID(id));
+ MOZ_ASSERT(getter != JS_PropertyStub);
+ MOZ_ASSERT(setter != JS_StrictPropertyStub);
+
+ bool extensible;
+ if (!IsExtensible(cx, obj, &extensible))
+ return nullptr;
+ if (!extensible) {
+ if (cx->isJSContext())
+ obj->reportNotExtensible(cx->asJSContext());
+ return nullptr;
+ }
+
+ AutoKeepShapeTables keep(cx);
+ ShapeTable::Entry* entry = nullptr;
+ if (obj->inDictionaryMode()) {
+ ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, keep);
+ if (!table)
+ return nullptr;
+ entry = &table->search<MaybeAdding::Adding>(id, keep);
+ }
+
+ return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, entry,
+ allowDictionary, keep);
+}
+
+static bool
+ShouldConvertToDictionary(NativeObject* obj)
+{
+ /*
+ * Use a lower limit if this object is likely a hashmap (SETELEM was used
+ * to set properties).
+ */
+ if (obj->hadElementsAccess())
+ return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS;
+ return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT;
+}
+
+/* static */ Shape*
+NativeObject::addPropertyInternal(ExclusiveContext* cx,
+ HandleNativeObject obj, HandleId id,
+ GetterOp getter, SetterOp setter,
+ uint32_t slot, unsigned attrs,
+ unsigned flags, ShapeTable::Entry* entry,
+ bool allowDictionary, const AutoKeepShapeTables& keep)
+{
+ MOZ_ASSERT_IF(!allowDictionary, !obj->inDictionaryMode());
+ MOZ_ASSERT(getter != JS_PropertyStub);
+ MOZ_ASSERT(setter != JS_StrictPropertyStub);
+
+ AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+ /*
+ * The code below deals with either converting obj to dictionary mode or
+ * growing an object that's already in dictionary mode. Either way,
+ * dictionray operations are safe if thread local.
+ */
+ ShapeTable* table = nullptr;
+ if (!obj->inDictionaryMode()) {
+ bool stableSlot =
+ (slot == SHAPE_INVALID_SLOT) ||
+ obj->lastProperty()->hasMissingSlot() ||
+ (slot == obj->lastProperty()->maybeSlot() + 1);
+ MOZ_ASSERT_IF(!allowDictionary, stableSlot);
+ if (allowDictionary &&
+ (!stableSlot || ShouldConvertToDictionary(obj)))
+ {
+ if (!obj->toDictionaryMode(cx))
+ return nullptr;
+ table = obj->lastProperty()->maybeTable(keep);
+ entry = &table->search<MaybeAdding::Adding>(id, keep);
+ }
+ } else {
+ table = obj->lastProperty()->ensureTableForDictionary(cx, keep);
+ if (!table)
+ return nullptr;
+ if (table->needsToGrow()) {
+ if (!table->grow(cx))
+ return nullptr;
+ entry = &table->search<MaybeAdding::Adding>(id, keep);
+ MOZ_ASSERT(!entry->shape());
+ }
+ }
+
+ MOZ_ASSERT(!!table == !!entry);
+
+ /* Find or create a property tree node labeled by our arguments. */
+ RootedShape shape(cx);
+ {
+ RootedShape last(cx, obj->lastProperty());
+
+ uint32_t index;
+ bool indexed = IdIsIndex(id, &index);
+
+ Rooted<UnownedBaseShape*> nbase(cx);
+ if (!indexed) {
+ nbase = last->base()->unowned();
+ } else {
+ StackBaseShape base(last->base());
+ base.flags |= BaseShape::INDEXED;
+ nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return nullptr;
+ }
+
+ Rooted<StackShape> child(cx, StackShape(nbase, id, slot, attrs, flags));
+ child.updateGetterSetter(getter, setter);
+ shape = getChildProperty(cx, obj, last, &child);
+ }
+
+ if (shape) {
+ MOZ_ASSERT(shape == obj->lastProperty());
+
+ if (table) {
+ /* Store the tree node pointer in the table entry for id. */
+ entry->setPreservingCollision(shape);
+ table->incEntryCount();
+
+ /* Pass the table along to the new last property, namely shape. */
+ MOZ_ASSERT(shape->parent->maybeTable(keep) == table);
+ shape->parent->handoffTableTo(shape);
+ }
+
+ obj->checkShapeConsistency();
+ return shape;
+ }
+
+ obj->checkShapeConsistency();
+ return nullptr;
+}
+
+Shape*
+js::ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
+ gc::AllocKind allocKind)
+{
+ // Compute the number of fixed slots with the new allocation kind.
+ size_t nfixed = gc::GetGCKindSlots(allocKind, shape->getObjectClass());
+
+ // Get all the ids in the shape, in order.
+ js::AutoIdVector ids(cx);
+ {
+ for (unsigned i = 0; i < shape->slotSpan(); i++) {
+ if (!ids.append(JSID_VOID))
+ return nullptr;
+ }
+ Shape* nshape = shape;
+ while (!nshape->isEmptyShape()) {
+ ids[nshape->slot()].set(nshape->propid());
+ nshape = nshape->previous();
+ }
+ }
+
+ // Construct the new shape, without updating type information.
+ RootedId id(cx);
+ RootedShape newShape(cx, EmptyShape::getInitialShape(cx, shape->getObjectClass(),
+ proto, nfixed, shape->getObjectFlags()));
+ if (!newShape)
+ return nullptr;
+
+ for (unsigned i = 0; i < ids.length(); i++) {
+ id = ids[i];
+
+ uint32_t index;
+ bool indexed = IdIsIndex(id, &index);
+
+ Rooted<UnownedBaseShape*> nbase(cx, newShape->base()->unowned());
+ if (indexed) {
+ StackBaseShape base(nbase);
+ base.flags |= BaseShape::INDEXED;
+ nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return nullptr;
+ }
+
+ Rooted<StackShape> child(cx, StackShape(nbase, id, i, JSPROP_ENUMERATE, 0));
+ newShape = cx->zone()->propertyTree.getChild(cx, newShape, child);
+ if (!newShape)
+ return nullptr;
+ }
+
+ return newShape;
+}
+
+/*
+ * Check and adjust the new attributes for the shape to make sure that our
+ * slot access optimizations are sound. It is responsibility of the callers to
+ * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]].
+ */
+static inline bool
+CheckCanChangeAttrs(ExclusiveContext* cx, JSObject* obj, Shape* shape, unsigned* attrsp)
+{
+ if (shape->configurable())
+ return true;
+
+ /* A permanent property must stay permanent. */
+ *attrsp |= JSPROP_PERMANENT;
+
+ /* Reject attempts to remove a slot from the permanent data property. */
+ if (shape->isDataDescriptor() && shape->hasSlot() &&
+ (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED)))
+ {
+ if (cx->isJSContext())
+ obj->reportNotConfigurable(cx->asJSContext(), shape->propid());
+ return false;
+ }
+
+ return true;
+}
+
+/* static */ Shape*
+NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
+ GetterOp getter, SetterOp setter, uint32_t slot, unsigned attrs,
+ unsigned flags)
+{
+ MOZ_ASSERT(!JSID_IS_VOID(id));
+ MOZ_ASSERT(getter != JS_PropertyStub);
+ MOZ_ASSERT(setter != JS_StrictPropertyStub);
+
+#ifdef DEBUG
+ if (obj->is<ArrayObject>()) {
+ ArrayObject* arr = &obj->as<ArrayObject>();
+ uint32_t index;
+ if (IdIsIndex(id, &index))
+ MOZ_ASSERT(index < arr->length() || arr->lengthIsWritable());
+ }
+#endif
+
+ AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+ /*
+ * Search for id in order to claim its entry if table has been allocated.
+ *
+ * Note that we can only try to claim an entry in a table that is thread
+ * local. An object may be thread local *without* its shape being thread
+ * local. The only thread local objects that *also* have thread local
+ * shapes are dictionaries that were allocated/converted thread
+ * locally. Only for those objects we can try to claim an entry in its
+ * shape table.
+ */
+ AutoKeepShapeTables keep(cx);
+ ShapeTable::Entry* entry;
+ RootedShape shape(cx);
+ if (!Shape::search<MaybeAdding::Adding>(cx, obj->lastProperty(), id, keep,
+ shape.address(), &entry))
+ {
+ return nullptr;
+ }
+
+ if (!shape) {
+ /*
+ * You can't add properties to a non-extensible object, but you can change
+ * attributes of properties in such objects.
+ */
+ bool extensible;
+
+ if (!IsExtensible(cx, obj, &extensible))
+ return nullptr;
+
+ if (!extensible) {
+ if (cx->isJSContext())
+ obj->reportNotExtensible(cx->asJSContext());
+ return nullptr;
+ }
+
+ return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags,
+ entry, true, keep);
+ }
+
+ /* Property exists: search must have returned a valid entry. */
+ MOZ_ASSERT_IF(entry, !entry->isRemoved());
+
+ if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
+ return nullptr;
+
+ /*
+ * If the caller wants to allocate a slot, but doesn't care which slot,
+ * copy the existing shape's slot into slot so we can match shape, if all
+ * other members match.
+ */
+ bool hadSlot = shape->hasSlot();
+ uint32_t oldSlot = shape->maybeSlot();
+ if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
+ slot = oldSlot;
+
+ Rooted<UnownedBaseShape*> nbase(cx);
+ {
+ uint32_t index;
+ bool indexed = IdIsIndex(id, &index);
+ StackBaseShape base(obj->lastProperty()->base());
+ if (indexed)
+ base.flags |= BaseShape::INDEXED;
+ nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return nullptr;
+ }
+
+ /*
+ * Now that we've possibly preserved slot, check whether all members match.
+ * If so, this is a redundant "put" and we can return without more work.
+ */
+ if (shape->matchesParamsAfterId(nbase, slot, attrs, flags, getter, setter))
+ return shape;
+
+ /*
+ * Overwriting a non-last property requires switching to dictionary mode.
+ * The shape tree is shared immutable, and we can't removeProperty and then
+ * addPropertyInternal because a failure under add would lose data.
+ */
+ if (shape != obj->lastProperty() && !obj->inDictionaryMode()) {
+ if (!obj->toDictionaryMode(cx))
+ return nullptr;
+ ShapeTable* table = obj->lastProperty()->maybeTable(keep);
+ MOZ_ASSERT(table);
+ entry = &table->search<MaybeAdding::NotAdding>(shape->propid(), keep);
+ shape = entry->shape();
+ }
+
+ MOZ_ASSERT_IF(shape->hasSlot() && !(attrs & JSPROP_SHARED), shape->slot() == slot);
+
+ if (obj->inDictionaryMode()) {
+ /*
+ * Updating some property in a dictionary-mode object. Create a new
+ * shape for the existing property, and also generate a new shape for
+ * the last property of the dictionary (unless the modified property
+ * is also the last property).
+ */
+ bool updateLast = (shape == obj->lastProperty());
+ bool accessorShape = getter || setter || (attrs & (JSPROP_GETTER | JSPROP_SETTER));
+ shape = obj->replaceWithNewEquivalentShape(cx, shape, nullptr, accessorShape);
+ if (!shape)
+ return nullptr;
+ if (!updateLast && !obj->generateOwnShape(cx))
+ return nullptr;
+
+ /*
+ * FIXME bug 593129 -- slot allocation and NativeObject *this must move
+ * out of here!
+ */
+ if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) {
+ if (!allocSlot(cx, obj, &slot))
+ return nullptr;
+ }
+
+ if (updateLast)
+ shape->base()->adoptUnowned(nbase);
+ else
+ shape->base_ = nbase;
+
+ MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
+
+ shape->setSlot(slot);
+ shape->attrs = uint8_t(attrs);
+ shape->flags = flags | Shape::IN_DICTIONARY | (accessorShape ? Shape::ACCESSOR_SHAPE : 0);
+ if (shape->isAccessorShape()) {
+ AccessorShape& accShape = shape->asAccessorShape();
+ accShape.rawGetter = getter;
+ accShape.rawSetter = setter;
+ GetterSetterWriteBarrierPost(&accShape);
+ } else {
+ MOZ_ASSERT(!getter);
+ MOZ_ASSERT(!setter);
+ }
+ } else {
+ /*
+ * Updating the last property in a non-dictionary-mode object. Find an
+ * alternate shared child of the last property's previous shape.
+ */
+ StackBaseShape base(obj->lastProperty()->base());
+
+ UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return nullptr;
+
+ MOZ_ASSERT(shape == obj->lastProperty());
+
+ /* Find or create a property tree node labeled by our arguments. */
+ Rooted<StackShape> child(cx, StackShape(nbase, id, slot, attrs, flags));
+ child.updateGetterSetter(getter, setter);
+ RootedShape parent(cx, shape->parent);
+ Shape* newShape = getChildProperty(cx, obj, parent, &child);
+
+ if (!newShape) {
+ obj->checkShapeConsistency();
+ return nullptr;
+ }
+
+ shape = newShape;
+ }
+
+ /*
+ * Can't fail now, so free the previous incarnation's slot if the new shape
+ * has no slot. But we do not need to free oldSlot (and must not, as trying
+ * to will botch an assertion in JSObject::freeSlot) if the new last
+ * property (shape here) has a slotSpan that does not cover it.
+ */
+ if (hadSlot && !shape->hasSlot()) {
+ if (oldSlot < obj->slotSpan())
+ obj->freeSlot(cx, oldSlot);
+ /* Note: The optimization based on propertyRemovals is only relevant to the main thread. */
+ if (cx->isJSContext())
+ ++cx->asJSContext()->runtime()->propertyRemovals;
+ }
+
+ obj->checkShapeConsistency();
+
+ return shape;
+}
+
+/* static */ Shape*
+NativeObject::changeProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleShape shape,
+ unsigned attrs, GetterOp getter, SetterOp setter)
+{
+ MOZ_ASSERT(obj->containsPure(shape));
+ MOZ_ASSERT(getter != JS_PropertyStub);
+ MOZ_ASSERT(setter != JS_StrictPropertyStub);
+ MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
+
+ /* Allow only shared (slotless) => unshared (slotful) transition. */
+ MOZ_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
+ !(attrs & JSPROP_SHARED));
+
+ MarkTypePropertyNonData(cx, obj, shape->propid());
+
+ if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
+ return nullptr;
+
+ if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
+ return shape;
+
+ /*
+ * Let JSObject::putProperty handle this |overwriting| case, including
+ * the conservation of shape->slot (if it's valid). We must not call
+ * removeProperty because it will free an allocated shape->slot, and
+ * putProperty won't re-allocate it.
+ */
+ RootedId propid(cx, shape->propid());
+ Shape* newShape = putProperty(cx, obj, propid, getter, setter,
+ shape->maybeSlot(), attrs, shape->flags);
+
+ obj->checkShapeConsistency();
+ return newShape;
+}
+
+bool
+NativeObject::removeProperty(ExclusiveContext* cx, jsid id_)
+{
+ RootedId id(cx, id_);
+ RootedNativeObject self(cx, this);
+
+ AutoKeepShapeTables keep(cx);
+ ShapeTable::Entry* entry;
+ RootedShape shape(cx);
+ if (!Shape::search(cx, lastProperty(), id, keep, shape.address(), &entry))
+ return false;
+
+ if (!shape)
+ return true;
+
+ /*
+ * If shape is not the last property added, or the last property cannot
+ * be removed, switch to dictionary mode.
+ */
+ if (!self->inDictionaryMode() && (shape != self->lastProperty() || !self->canRemoveLastProperty())) {
+ if (!self->toDictionaryMode(cx))
+ return false;
+ ShapeTable* table = self->lastProperty()->maybeTable(keep);
+ MOZ_ASSERT(table);
+ entry = &table->search<MaybeAdding::NotAdding>(shape->propid(), keep);
+ shape = entry->shape();
+ }
+
+ /*
+ * If in dictionary mode, get a new shape for the last property after the
+ * removal. We need a fresh shape for all dictionary deletions, even of
+ * the last property. Otherwise, a shape could replay and caches might
+ * return deleted DictionaryShapes! See bug 595365. Do this before changing
+ * the object or table, so the remaining removal is infallible.
+ */
+ RootedShape spare(cx);
+ if (self->inDictionaryMode()) {
+ /* For simplicity, always allocate an accessor shape for now. */
+ spare = Allocate<AccessorShape>(cx);
+ if (!spare)
+ return false;
+ new (spare) Shape(shape->base()->unowned(), 0);
+ if (shape == self->lastProperty()) {
+ /*
+ * Get an up to date unowned base shape for the new last property
+ * when removing the dictionary's last property. Information in
+ * base shapes for non-last properties may be out of sync with the
+ * object's state.
+ */
+ RootedShape previous(cx, self->lastProperty()->parent);
+ StackBaseShape base(self->lastProperty()->base());
+ BaseShape* nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return false;
+ previous->base_ = nbase;
+ }
+ }
+
+ /* If shape has a slot, free its slot number. */
+ if (shape->hasSlot()) {
+ self->freeSlot(cx, shape->slot());
+ if (cx->isJSContext())
+ ++cx->asJSContext()->runtime()->propertyRemovals;
+ }
+
+ /*
+ * A dictionary-mode object owns mutable, unique shapes on a non-circular
+ * doubly linked list, hashed by lastProperty()->table. So we can edit the
+ * list and hash in place.
+ */
+ if (self->inDictionaryMode()) {
+ ShapeTable* table = self->lastProperty()->maybeTable(keep);
+ MOZ_ASSERT(table);
+
+ if (entry->hadCollision()) {
+ entry->setRemoved();
+ table->decEntryCount();
+ table->incRemovedCount();
+ } else {
+ entry->setFree();
+ table->decEntryCount();
+
+#ifdef DEBUG
+ /*
+ * Check the consistency of the table but limit the number of
+ * checks not to alter significantly the complexity of the
+ * delete in debug builds, see bug 534493.
+ */
+ Shape* aprop = self->lastProperty();
+ for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent)
+ MOZ_ASSERT_IF(aprop != shape, self->contains(cx, aprop));
+#endif
+ }
+
+ {
+ /* Remove shape from its non-circular doubly linked list. */
+ Shape* oldLastProp = self->lastProperty();
+ shape->removeFromDictionary(self);
+
+ /* Hand off table from the old to new last property. */
+ oldLastProp->handoffTableTo(self->lastProperty());
+ }
+
+ /* Generate a new shape for the object, infallibly. */
+ JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
+
+ /* Consider shrinking table if its load factor is <= .25. */
+ uint32_t size = table->capacity();
+ if (size > ShapeTable::MIN_SIZE && table->entryCount() <= size >> 2)
+ (void) table->change(cx, -1);
+ } else {
+ /*
+ * Non-dictionary-mode shape tables are shared immutables, so all we
+ * need do is retract the last property and we'll either get or else
+ * lazily make via a later hashify the exact table for the new property
+ * lineage.
+ */
+ MOZ_ASSERT(shape == self->lastProperty());
+ self->removeLastProperty(cx);
+ }
+
+ self->checkShapeConsistency();
+ return true;
+}
+
+/* static */ void
+NativeObject::clear(ExclusiveContext* cx, HandleNativeObject obj)
+{
+ Shape* shape = obj->lastProperty();
+ MOZ_ASSERT(obj->inDictionaryMode() == shape->inDictionary());
+
+ while (shape->parent) {
+ shape = shape->parent;
+ MOZ_ASSERT(obj->inDictionaryMode() == shape->inDictionary());
+ }
+ MOZ_ASSERT(shape->isEmptyShape());
+
+ if (obj->inDictionaryMode())
+ shape->listp = &obj->shape_;
+
+ JS_ALWAYS_TRUE(obj->setLastProperty(cx, shape));
+
+ if (cx->isJSContext())
+ ++cx->asJSContext()->runtime()->propertyRemovals;
+ obj->checkShapeConsistency();
+}
+
+/* static */ bool
+NativeObject::rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj, uint32_t slotSpan)
+{
+ /*
+ * Remove properties from this object until it has a matching slot span.
+ * The object cannot have escaped in a way which would prevent safe
+ * removal of the last properties.
+ */
+ MOZ_ASSERT(!obj->inDictionaryMode() && slotSpan <= obj->slotSpan());
+ while (true) {
+ if (obj->lastProperty()->isEmptyShape()) {
+ MOZ_ASSERT(slotSpan == 0);
+ break;
+ } else {
+ uint32_t slot = obj->lastProperty()->slot();
+ if (slot < slotSpan)
+ break;
+ }
+ if (!obj->removeProperty(cx, obj->lastProperty()->propid()))
+ return false;
+ }
+
+ return true;
+}
+
+Shape*
+NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShape, Shape* newShape,
+ bool accessorShape)
+{
+ MOZ_ASSERT(cx->isInsideCurrentZone(oldShape));
+ MOZ_ASSERT_IF(oldShape != lastProperty(),
+ inDictionaryMode() && lookup(cx, oldShape->propidRef()) == oldShape);
+
+ NativeObject* self = this;
+
+ if (!inDictionaryMode()) {
+ RootedNativeObject selfRoot(cx, self);
+ RootedShape newRoot(cx, newShape);
+ if (!toDictionaryMode(cx))
+ return nullptr;
+ oldShape = selfRoot->lastProperty();
+ self = selfRoot;
+ newShape = newRoot;
+ }
+
+ if (!newShape) {
+ RootedNativeObject selfRoot(cx, self);
+ RootedShape oldRoot(cx, oldShape);
+ newShape = (oldShape->isAccessorShape() || accessorShape)
+ ? Allocate<AccessorShape>(cx)
+ : Allocate<Shape>(cx);
+ if (!newShape)
+ return nullptr;
+ new (newShape) Shape(oldRoot->base()->unowned(), 0);
+ self = selfRoot;
+ oldShape = oldRoot;
+ }
+
+ AutoCheckCannotGC nogc;
+ ShapeTable* table = self->lastProperty()->ensureTableForDictionary(cx, nogc);
+ if (!table)
+ return nullptr;
+
+ ShapeTable::Entry* entry = oldShape->isEmptyShape()
+ ? nullptr
+ : &table->search<MaybeAdding::NotAdding>(oldShape->propidRef(), nogc);
+
+ /*
+ * Splice the new shape into the same position as the old shape, preserving
+ * enumeration order (see bug 601399).
+ */
+ StackShape nshape(oldShape);
+ newShape->initDictionaryShape(nshape, self->numFixedSlots(), oldShape->listp);
+
+ MOZ_ASSERT(newShape->parent == oldShape);
+ oldShape->removeFromDictionary(self);
+
+ if (newShape == self->lastProperty())
+ oldShape->handoffTableTo(newShape);
+
+ if (entry)
+ entry->setPreservingCollision(newShape);
+ return newShape;
+}
+
+bool
+NativeObject::shadowingShapeChange(ExclusiveContext* cx, const Shape& shape)
+{
+ return generateOwnShape(cx);
+}
+
+bool
+JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape generateShape)
+{
+ if (hasAllFlags(flags))
+ return true;
+
+ RootedObject self(cx, this);
+
+ if (isNative() && as<NativeObject>().inDictionaryMode()) {
+ if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx))
+ return false;
+ StackBaseShape base(self->as<NativeObject>().lastProperty());
+ base.flags |= flags;
+ UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return false;
+
+ self->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
+ return true;
+ }
+
+ Shape* existingShape = self->ensureShape(cx);
+ if (!existingShape)
+ return false;
+
+ Shape* newShape = Shape::setObjectFlags(cx, flags, self->taggedProto(), existingShape);
+ if (!newShape)
+ return false;
+
+ // The success of the |JSObject::ensureShape| call above means that |self|
+ // can be assumed to have a shape.
+ self->as<ShapedObject>().setShape(newShape);
+
+ return true;
+}
+
+bool
+NativeObject::clearFlag(ExclusiveContext* cx, BaseShape::Flag flag)
+{
+ MOZ_ASSERT(inDictionaryMode());
+
+ RootedNativeObject self(cx, &as<NativeObject>());
+ MOZ_ASSERT(self->lastProperty()->getObjectFlags() & flag);
+
+ StackBaseShape base(self->lastProperty());
+ base.flags &= ~flag;
+ UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base);
+ if (!nbase)
+ return false;
+
+ self->lastProperty()->base()->adoptUnowned(nbase);
+ return true;
+}
+
+/* static */ Shape*
+Shape::setObjectFlags(ExclusiveContext* cx, BaseShape::Flag flags, TaggedProto proto, Shape* last)
+{
+ if ((last->getObjectFlags() & flags) == flags)
+ return last;
+
+ StackBaseShape base(last);
+ base.flags |= flags;
+
+ RootedShape lastRoot(cx, last);
+ return replaceLastProperty(cx, base, proto, lastRoot);
+}
+
+/* static */ inline HashNumber
+StackBaseShape::hash(const Lookup& lookup)
+{
+ HashNumber hash = lookup.flags;
+ hash = RotateLeft(hash, 4) ^ (uintptr_t(lookup.clasp) >> 3);
+ return hash;
+}
+
+/* static */ inline bool
+StackBaseShape::match(ReadBarriered<UnownedBaseShape*> key, const Lookup& lookup)
+{
+ return key.unbarrieredGet()->flags == lookup.flags &&
+ key.unbarrieredGet()->clasp_ == lookup.clasp;
+}
+
+inline
+BaseShape::BaseShape(const StackBaseShape& base)
+ : clasp_(base.clasp),
+ flags(base.flags),
+ slotSpan_(0),
+ unowned_(nullptr),
+ table_(nullptr)
+{
+}
+
+/* static */ void
+BaseShape::copyFromUnowned(BaseShape& dest, UnownedBaseShape& src)
+{
+ dest.clasp_ = src.clasp_;
+ dest.slotSpan_ = src.slotSpan_;
+ dest.unowned_ = &src;
+ dest.flags = src.flags | OWNED_SHAPE;
+}
+
+inline void
+BaseShape::adoptUnowned(UnownedBaseShape* other)
+{
+ // This is a base shape owned by a dictionary object, update it to reflect the
+ // unowned base shape of a new last property.
+ MOZ_ASSERT(isOwned());
+
+ uint32_t span = slotSpan();
+
+ BaseShape::copyFromUnowned(*this, *other);
+ setSlotSpan(span);
+
+ assertConsistency();
+}
+
+/* static */ UnownedBaseShape*
+BaseShape::getUnowned(ExclusiveContext* cx, StackBaseShape& base)
+{
+ auto& table = cx->zone()->baseShapes;
+
+ if (!table.initialized() && !table.init()) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ auto p = MakeDependentAddPtr(cx, table, base);
+ if (p)
+ return *p;
+
+ BaseShape* nbase_ = Allocate<BaseShape>(cx);
+ if (!nbase_)
+ return nullptr;
+
+ new (nbase_) BaseShape(base);
+
+ UnownedBaseShape* nbase = static_cast<UnownedBaseShape*>(nbase_);
+
+ if (!p.add(cx, table, base, nbase))
+ return nullptr;
+
+ return nbase;
+}
+
+void
+BaseShape::assertConsistency()
+{
+#ifdef DEBUG
+ if (isOwned()) {
+ UnownedBaseShape* unowned = baseUnowned();
+ MOZ_ASSERT(getObjectFlags() == unowned->getObjectFlags());
+ }
+#endif
+}
+
+void
+BaseShape::traceChildren(JSTracer* trc)
+{
+ traceChildrenSkipShapeTable(trc);
+ traceShapeTable(trc);
+}
+
+void
+BaseShape::traceChildrenSkipShapeTable(JSTracer* trc)
+{
+ if (isOwned())
+ TraceEdge(trc, &unowned_, "base");
+
+ assertConsistency();
+}
+
+void
+BaseShape::traceShapeTable(JSTracer* trc)
+{
+ AutoCheckCannotGC nogc;
+ if (ShapeTable* table = maybeTable(nogc))
+ table->trace(trc);
+}
+
+#ifdef DEBUG
+bool
+BaseShape::canSkipMarkingShapeTable(Shape* lastShape)
+{
+ // Check that every shape in the shape table will be marked by marking
+ // |lastShape|.
+
+ AutoCheckCannotGC nogc;
+ ShapeTable* table = maybeTable(nogc);
+ if (!table)
+ return true;
+
+ uint32_t count = 0;
+ for (Shape::Range<NoGC> r(lastShape); !r.empty(); r.popFront()) {
+ Shape* shape = &r.front();
+ ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(shape->propid(), nogc);
+ if (entry.isLive())
+ count++;
+ }
+
+ return count == table->entryCount();
+}
+#endif
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+
+void
+Zone::checkBaseShapeTableAfterMovingGC()
+{
+ if (!baseShapes.initialized())
+ return;
+
+ for (decltype(baseShapes)::Enum e(baseShapes); !e.empty(); e.popFront()) {
+ UnownedBaseShape* base = e.front().unbarrieredGet();
+ CheckGCThingAfterMovingGC(base);
+
+ BaseShapeSet::Ptr ptr = baseShapes.lookup(base);
+ MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
+ }
+}
+
+#endif // JSGC_HASH_TABLE_CHECKS
+
+void
+BaseShape::finalize(FreeOp* fop)
+{
+ if (table_) {
+ fop->delete_(table_);
+ table_ = nullptr;
+ }
+}
+
+inline
+InitialShapeEntry::InitialShapeEntry() : shape(nullptr), proto()
+{
+}
+
+inline
+InitialShapeEntry::InitialShapeEntry(Shape* shape, const Lookup::ShapeProto& proto)
+ : shape(shape), proto(proto)
+{
+}
+
+/* static */ inline HashNumber
+InitialShapeEntry::hash(const Lookup& lookup)
+{
+ return (RotateLeft(uintptr_t(lookup.clasp) >> 3, 4) ^ lookup.proto.hashCode()) +
+ lookup.nfixed;
+}
+
+/* static */ inline bool
+InitialShapeEntry::match(const InitialShapeEntry& key, const Lookup& lookup)
+{
+ const Shape* shape = key.shape.unbarrieredGet();
+ return lookup.clasp == shape->getObjectClass()
+ && lookup.nfixed == shape->numFixedSlots()
+ && lookup.baseFlags == shape->getObjectFlags()
+ && lookup.proto.match(key.proto);
+}
+
+#ifdef JSGC_HASH_TABLE_CHECKS
+
+void
+Zone::checkInitialShapesTableAfterMovingGC()
+{
+ if (!initialShapes.initialized())
+ return;
+
+ /*
+ * Assert that the postbarriers have worked and that nothing is left in
+ * initialShapes that points into the nursery, and that the hash table
+ * entries are discoverable.
+ */
+ for (decltype(initialShapes)::Enum e(initialShapes); !e.empty(); e.popFront()) {
+ InitialShapeEntry entry = e.front();
+ JSProtoKey protoKey = entry.proto.key();
+ TaggedProto proto = entry.proto.proto().unbarrieredGet();
+ Shape* shape = entry.shape.unbarrieredGet();
+
+ CheckGCThingAfterMovingGC(shape);
+ if (proto.isObject())
+ CheckGCThingAfterMovingGC(proto.toObject());
+
+ using Lookup = InitialShapeEntry::Lookup;
+ Lookup lookup(shape->getObjectClass(),
+ Lookup::ShapeProto(protoKey, proto),
+ shape->numFixedSlots(),
+ shape->getObjectFlags());
+ InitialShapeSet::Ptr ptr = initialShapes.lookup(lookup);
+ MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front());
+ }
+}
+
+#endif // JSGC_HASH_TABLE_CHECKS
+
+Shape*
+EmptyShape::new_(ExclusiveContext* cx, Handle<UnownedBaseShape*> base, uint32_t nfixed)
+{
+ Shape* shape = Allocate<Shape>(cx);
+ if (!shape) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ new (shape) EmptyShape(base, nfixed);
+ return shape;
+}
+
+static bool
+IsOriginalProto(GlobalObject* global, JSProtoKey key, JSObject& proto)
+{
+ if (global->getPrototype(key) != ObjectValue(proto))
+ return false;
+
+ if (key == JSProto_Object) {
+ MOZ_ASSERT(proto.staticPrototypeIsImmutable(),
+ "proto should be Object.prototype, whose prototype is "
+ "immutable");
+ MOZ_ASSERT(proto.staticPrototype() == nullptr,
+ "Object.prototype must have null prototype");
+ return true;
+ }
+
+ // Check that other prototypes still have Object.prototype as proto.
+ JSObject* protoProto = proto.staticPrototype();
+ if (!protoProto || global->getPrototype(JSProto_Object) != ObjectValue(*protoProto))
+ return false;
+
+ MOZ_ASSERT(protoProto->staticPrototypeIsImmutable(),
+ "protoProto should be Object.prototype, whose prototype is "
+ "immutable");
+ MOZ_ASSERT(protoProto->staticPrototype() == nullptr,
+ "Object.prototype must have null prototype");
+ return true;
+}
+
+static JSProtoKey
+GetInitialShapeProtoKey(TaggedProto proto, ExclusiveContext* cx)
+{
+ if (proto.isObject() && proto.toObject()->hasStaticPrototype()) {
+ GlobalObject* global = cx->global();
+ JSObject& obj = *proto.toObject();
+ MOZ_ASSERT(global == &obj.global());
+
+ if (IsOriginalProto(global, JSProto_Object, obj))
+ return JSProto_Object;
+ if (IsOriginalProto(global, JSProto_Function, obj))
+ return JSProto_Function;
+ if (IsOriginalProto(global, JSProto_Array, obj))
+ return JSProto_Array;
+ if (IsOriginalProto(global, JSProto_RegExp, obj))
+ return JSProto_RegExp;
+ }
+ return JSProto_LIMIT;
+}
+
+/* static */ Shape*
+EmptyShape::getInitialShape(ExclusiveContext* cx, const Class* clasp, TaggedProto proto,
+ size_t nfixed, uint32_t objectFlags)
+{
+ MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
+
+ auto& table = cx->zone()->initialShapes;
+
+ if (!table.initialized() && !table.init()) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ using Lookup = InitialShapeEntry::Lookup;
+ auto protoPointer = MakeDependentAddPtr(cx, table,
+ Lookup(clasp, Lookup::ShapeProto(proto),
+ nfixed, objectFlags));
+ if (protoPointer)
+ return protoPointer->shape;
+
+ // No entry for this proto. If the proto is one of a few common builtin
+ // prototypes, try to do a lookup based on the JSProtoKey, so we can share
+ // shapes across globals.
+ Rooted<TaggedProto> protoRoot(cx, proto);
+ Shape* shape = nullptr;
+ bool insertKey = false;
+ mozilla::Maybe<DependentAddPtr<decltype(cx->zone()->initialShapes)>> keyPointer;
+
+ JSProtoKey key = GetInitialShapeProtoKey(protoRoot, cx);
+ if (key != JSProto_LIMIT) {
+ keyPointer.emplace(MakeDependentAddPtr(cx, table,
+ Lookup(clasp, Lookup::ShapeProto(key),
+ nfixed, objectFlags)));
+ if (keyPointer.ref()) {
+ shape = keyPointer.ref()->shape;
+ MOZ_ASSERT(shape);
+ } else {
+ insertKey = true;
+ }
+ }
+
+ if (!shape) {
+ StackBaseShape base(cx, clasp, objectFlags);
+ Rooted<UnownedBaseShape*> nbase(cx, BaseShape::getUnowned(cx, base));
+ if (!nbase)
+ return nullptr;
+
+ shape = EmptyShape::new_(cx, nbase, nfixed);
+ if (!shape)
+ return nullptr;
+ }
+
+ Lookup::ShapeProto shapeProto(protoRoot);
+ Lookup lookup(clasp, shapeProto, nfixed, objectFlags);
+ if (!protoPointer.add(cx, table, lookup, InitialShapeEntry(shape, shapeProto)))
+ return nullptr;
+
+ // Also add an entry based on the JSProtoKey, if needed.
+ if (insertKey) {
+ Lookup::ShapeProto shapeProto(key);
+ Lookup lookup(clasp, shapeProto, nfixed, objectFlags);
+ if (!keyPointer->add(cx, table, lookup, InitialShapeEntry(shape, shapeProto)))
+ return nullptr;
+ }
+
+ return shape;
+}
+
+/* static */ Shape*
+EmptyShape::getInitialShape(ExclusiveContext* cx, const Class* clasp, TaggedProto proto,
+ AllocKind kind, uint32_t objectFlags)
+{
+ return getInitialShape(cx, clasp, proto, GetGCKindSlots(kind, clasp), objectFlags);
+}
+
+void
+NewObjectCache::invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto)
+{
+ const Class* clasp = shape->getObjectClass();
+
+ gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
+ if (CanBeFinalizedInBackground(kind, clasp))
+ kind = GetBackgroundAllocKind(kind);
+
+ RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto)));
+ if (!group) {
+ purge();
+ cx->recoverFromOutOfMemory();
+ return;
+ }
+
+ EntryIndex entry;
+ for (CompartmentsInZoneIter comp(shape->zone()); !comp.done(); comp.next()) {
+ if (GlobalObject* global = comp->unsafeUnbarrieredMaybeGlobal()) {
+ if (lookupGlobal(clasp, global, kind, &entry))
+ PodZero(&entries[entry]);
+ }
+ }
+ if (!proto->is<GlobalObject>() && lookupProto(clasp, proto, kind, &entry))
+ PodZero(&entries[entry]);
+ if (lookupGroup(group, kind, &entry))
+ PodZero(&entries[entry]);
+}
+
+/* static */ void
+EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleObject proto)
+{
+ using Lookup = InitialShapeEntry::Lookup;
+ Lookup lookup(shape->getObjectClass(), Lookup::ShapeProto(TaggedProto(proto)),
+ shape->numFixedSlots(), shape->getObjectFlags());
+
+ InitialShapeSet::Ptr p = cx->zone()->initialShapes.lookup(lookup);
+ MOZ_ASSERT(p);
+
+ InitialShapeEntry& entry = const_cast<InitialShapeEntry&>(*p);
+
+ // The metadata callback can end up causing redundant changes of the initial shape.
+ if (entry.shape == shape)
+ return;
+
+ // The new shape had better be rooted at the old one.
+#ifdef DEBUG
+ Shape* nshape = shape;
+ while (!nshape->isEmptyShape())
+ nshape = nshape->previous();
+ MOZ_ASSERT(nshape == entry.shape);
+#endif
+
+ entry.shape = ReadBarrieredShape(shape);
+
+ // For certain prototypes -- namely, those of various builtin classes,
+ // keyed by JSProtoKey |key| -- there are two entries: one for a lookup
+ // via |proto|, and one for a lookup via |key|. If this is such a
+ // prototype, also update the alternate |key|-keyed shape.
+ JSProtoKey key = GetInitialShapeProtoKey(TaggedProto(proto), cx);
+ if (key != JSProto_LIMIT) {
+ Lookup lookup(shape->getObjectClass(), Lookup::ShapeProto(key),
+ shape->numFixedSlots(), shape->getObjectFlags());
+ if (InitialShapeSet::Ptr p = cx->zone()->initialShapes.lookup(lookup)) {
+ InitialShapeEntry& entry = const_cast<InitialShapeEntry&>(*p);
+ if (entry.shape != shape)
+ entry.shape = ReadBarrieredShape(shape);
+ }
+ }
+
+ /*
+ * This affects the shape that will be produced by the various NewObject
+ * methods, so clear any cache entry referring to the old shape. This is
+ * not required for correctness: the NewObject must always check for a
+ * nativeEmpty() result and generate the appropriate properties if found.
+ * Clearing the cache entry avoids this duplicate regeneration.
+ *
+ * Clearing is not necessary when this context is running off the main
+ * thread, as it will not use the new object cache for allocations.
+ */
+ if (cx->isJSContext()) {
+ JSContext* ncx = cx->asJSContext();
+ ncx->caches.newObjectCache.invalidateEntriesForShape(ncx, shape, proto);
+ }
+}
+
+void
+Zone::fixupInitialShapeTable()
+{
+ if (!initialShapes.initialized())
+ return;
+
+ for (decltype(initialShapes)::Enum e(initialShapes); !e.empty(); e.popFront()) {
+ // The shape may have been moved, but we can update that in place.
+ Shape* shape = e.front().shape.unbarrieredGet();
+ if (IsForwarded(shape)) {
+ shape = Forwarded(shape);
+ e.mutableFront().shape.set(shape);
+ }
+ shape->updateBaseShapeAfterMovingGC();
+
+ // If the prototype has moved we have to rekey the entry.
+ InitialShapeEntry entry = e.front();
+ if (entry.proto.proto().isObject() && IsForwarded(entry.proto.proto().toObject())) {
+ entry.proto.setProto(TaggedProto(Forwarded(entry.proto.proto().toObject())));
+ using Lookup = InitialShapeEntry::Lookup;
+ Lookup relookup(shape->getObjectClass(),
+ Lookup::ShapeProto(entry.proto),
+ shape->numFixedSlots(),
+ shape->getObjectFlags());
+ e.rekeyFront(relookup, entry);
+ }
+ }
+}
+
+void
+AutoRooterGetterSetter::Inner::trace(JSTracer* trc)
+{
+ if ((attrs & JSPROP_GETTER) && *pgetter)
+ TraceRoot(trc, (JSObject**) pgetter, "AutoRooterGetterSetter getter");
+ if ((attrs & JSPROP_SETTER) && *psetter)
+ TraceRoot(trc, (JSObject**) psetter, "AutoRooterGetterSetter setter");
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<js::Shape>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+
+ AutoCheckCannotGC nogc;
+ if (ShapeTable* table = get().maybeTable(nogc))
+ size += table->sizeOfIncludingThis(mallocSizeOf);
+
+ if (!get().inDictionary() && get().kids.isHash())
+ size += get().kids.toHash()->sizeOfIncludingThis(mallocSizeOf);
+
+ return size;
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<js::BaseShape>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+}
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
new file mode 100644
index 000000000..978798aaa
--- /dev/null
+++ b/js/src/vm/Shape.h
@@ -0,0 +1,1636 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Shape_h
+#define vm_Shape_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/GuardObjects.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/TemplateLib.h"
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "jspropertytree.h"
+#include "jstypes.h"
+#include "NamespaceImports.h"
+
+#include "gc/Barrier.h"
+#include "gc/Heap.h"
+#include "gc/Marking.h"
+#include "gc/Rooting.h"
+#include "js/HashTable.h"
+#include "js/MemoryMetrics.h"
+#include "js/RootingAPI.h"
+#include "js/UbiNode.h"
+#include "vm/ObjectGroup.h"
+#include "vm/String.h"
+#include "vm/Symbol.h"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4800)
+#pragma warning(push)
+#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
+#endif
+
+/*
+ * In isolation, a Shape represents a property that exists in one or more
+ * objects; it has an id, flags, etc. (But it doesn't represent the property's
+ * value.) However, Shapes are always stored in linked linear sequence of
+ * Shapes, called "shape lineages". Each shape lineage represents the layout of
+ * an entire object.
+ *
+ * Every JSObject has a pointer, |shape_|, accessible via lastProperty(), to
+ * the last Shape in a shape lineage, which identifies the property most
+ * recently added to the object. This pointer permits fast object layout
+ * tests. The shape lineage order also dictates the enumeration order for the
+ * object; ECMA requires no particular order but this implementation has
+ * promised and delivered property definition order.
+ *
+ * Shape lineages occur in two kinds of data structure.
+ *
+ * 1. N-ary property trees. Each path from a non-root node to the root node in
+ * a property tree is a shape lineage. Property trees permit full (or
+ * partial) sharing of Shapes between objects that have fully (or partly)
+ * identical layouts. The root is an EmptyShape whose identity is determined
+ * by the object's class, compartment and prototype. These Shapes are shared
+ * and immutable.
+ *
+ * 2. Dictionary mode lists. Shapes in such lists are said to be "in
+ * dictionary mode", as are objects that point to such Shapes. These Shapes
+ * are unshared, private to a single object, and immutable except for their
+ * links in the dictionary list.
+ *
+ * All shape lineages are bi-directionally linked, via the |parent| and
+ * |kids|/|listp| members.
+ *
+ * Shape lineages start out life in the property tree. They can be converted
+ * (by copying) to dictionary mode lists in the following circumstances.
+ *
+ * 1. The shape lineage's size reaches MAX_HEIGHT. This reasonable limit avoids
+ * potential worst cases involving shape lineage mutations.
+ *
+ * 2. A property represented by a non-last Shape in a shape lineage is removed
+ * from an object. (In the last Shape case, obj->shape_ can be easily
+ * adjusted to point to obj->shape_->parent.) We originally tried lazy
+ * forking of the property tree, but this blows up for delete/add
+ * repetitions.
+ *
+ * 3. A property represented by a non-last Shape in a shape lineage has its
+ * attributes modified.
+ *
+ * To find the Shape for a particular property of an object initially requires
+ * a linear search. But if the number of searches starting at any particular
+ * Shape in the property tree exceeds LINEAR_SEARCHES_MAX and the Shape's
+ * lineage has (excluding the EmptyShape) at least MIN_ENTRIES, we create an
+ * auxiliary hash table -- the ShapeTable -- that allows faster lookup.
+ * Furthermore, a ShapeTable is always created for dictionary mode lists,
+ * and it is attached to the last Shape in the lineage. Shape tables for
+ * property tree Shapes never change, but shape tables for dictionary mode
+ * Shapes can grow and shrink.
+ *
+ * To save memory, shape tables can be discarded on GC and recreated when
+ * needed. AutoKeepShapeTables can be used to avoid discarding shape tables
+ * for a particular zone. Methods operating on ShapeTables take either an
+ * AutoCheckCannotGC or AutoKeepShapeTables argument, to help ensure tables
+ * are not purged while we're using them.
+ *
+ * There used to be a long, math-heavy comment here explaining why property
+ * trees are more space-efficient than alternatives. This was removed in bug
+ * 631138; see that bug for the full details.
+ *
+ * For getters/setters, an AccessorShape is allocated. This is a slightly fatter
+ * type with extra fields for the getter/setter data.
+ *
+ * Because many Shapes have similar data, there is actually a secondary type
+ * called a BaseShape that holds some of a Shape's data. Many shapes can share
+ * a single BaseShape.
+ */
+
+#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
+
+namespace js {
+
+class TenuringTracer;
+
+typedef JSGetterOp GetterOp;
+typedef JSSetterOp SetterOp;
+
+/* Limit on the number of slotful properties in an object. */
+static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
+static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
+
+enum class MaybeAdding { Adding = true, NotAdding = false };
+
+class AutoKeepShapeTables;
+
+/*
+ * Shapes use multiplicative hashing, but specialized to
+ * minimize footprint.
+ */
+class ShapeTable {
+ public:
+ friend class NativeObject;
+ friend class BaseShape;
+ static const uint32_t MIN_ENTRIES = 11;
+
+ class Entry {
+ // js::Shape pointer tag bit indicating a collision.
+ static const uintptr_t SHAPE_COLLISION = 1;
+ static Shape* const SHAPE_REMOVED; // = SHAPE_COLLISION
+
+ Shape* shape_;
+
+ Entry() = delete;
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
+
+ public:
+ bool isFree() const { return shape_ == nullptr; }
+ bool isRemoved() const { return shape_ == SHAPE_REMOVED; }
+ bool isLive() const { return !isFree() && !isRemoved(); }
+ bool hadCollision() const { return uintptr_t(shape_) & SHAPE_COLLISION; }
+
+ void setFree() { shape_ = nullptr; }
+ void setRemoved() { shape_ = SHAPE_REMOVED; }
+
+ Shape* shape() const {
+ return reinterpret_cast<Shape*>(uintptr_t(shape_) & ~SHAPE_COLLISION);
+ }
+
+ void setShape(Shape* shape) {
+ MOZ_ASSERT(isFree());
+ MOZ_ASSERT(shape);
+ MOZ_ASSERT(shape != SHAPE_REMOVED);
+ shape_ = shape;
+ MOZ_ASSERT(!hadCollision());
+ }
+
+ void flagCollision() {
+ shape_ = reinterpret_cast<Shape*>(uintptr_t(shape_) | SHAPE_COLLISION);
+ }
+ void setPreservingCollision(Shape* shape) {
+ shape_ = reinterpret_cast<Shape*>(uintptr_t(shape) | uintptr_t(hadCollision()));
+ }
+ };
+
+ private:
+ static const uint32_t HASH_BITS = mozilla::tl::BitSize<HashNumber>::value;
+
+ // This value is low because it's common for a ShapeTable to be created
+ // with an entryCount of zero.
+ static const uint32_t MIN_SIZE_LOG2 = 2;
+ static const uint32_t MIN_SIZE = JS_BIT(MIN_SIZE_LOG2);
+
+ uint32_t hashShift_; /* multiplicative hash shift */
+
+ uint32_t entryCount_; /* number of entries in table */
+ uint32_t removedCount_; /* removed entry sentinels in table */
+
+ uint32_t freeList_; /* SHAPE_INVALID_SLOT or head of slot
+ freelist in owning dictionary-mode
+ object */
+
+ Entry* entries_; /* table of ptrs to shared tree nodes */
+
+ template<MaybeAdding Adding>
+ Entry& searchUnchecked(jsid id);
+
+ public:
+ explicit ShapeTable(uint32_t nentries)
+ : hashShift_(HASH_BITS - MIN_SIZE_LOG2),
+ entryCount_(nentries),
+ removedCount_(0),
+ freeList_(SHAPE_INVALID_SLOT),
+ entries_(nullptr)
+ {
+ /* NB: entries is set by init, which must be called. */
+ }
+
+ ~ShapeTable() {
+ js_free(entries_);
+ }
+
+ uint32_t entryCount() const { return entryCount_; }
+
+ uint32_t freeList() const { return freeList_; }
+ void setFreeList(uint32_t slot) { freeList_ = slot; }
+
+ /*
+ * This counts the ShapeTable object itself (which must be
+ * heap-allocated) and its |entries| array.
+ */
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(this) + mallocSizeOf(entries_);
+ }
+
+ // init() is fallible and reports OOM to the context.
+ bool init(ExclusiveContext* cx, Shape* lastProp);
+
+ // change() is fallible but does not report OOM.
+ bool change(ExclusiveContext* cx, int log2Delta);
+
+ template<MaybeAdding Adding>
+ MOZ_ALWAYS_INLINE Entry& search(jsid id, const AutoKeepShapeTables&) {
+ return searchUnchecked<Adding>(id);
+ }
+
+ template<MaybeAdding Adding>
+ MOZ_ALWAYS_INLINE Entry& search(jsid id, const JS::AutoCheckCannotGC&) {
+ return searchUnchecked<Adding>(id);
+ }
+
+ void trace(JSTracer* trc);
+#ifdef JSGC_HASH_TABLE_CHECKS
+ void checkAfterMovingGC();
+#endif
+
+ private:
+ Entry& getEntry(uint32_t i) const {
+ MOZ_ASSERT(i < capacity());
+ return entries_[i];
+ }
+ void decEntryCount() {
+ MOZ_ASSERT(entryCount_ > 0);
+ entryCount_--;
+ }
+ void incEntryCount() {
+ entryCount_++;
+ MOZ_ASSERT(entryCount_ + removedCount_ <= capacity());
+ }
+ void incRemovedCount() {
+ removedCount_++;
+ MOZ_ASSERT(entryCount_ + removedCount_ <= capacity());
+ }
+
+ /* By definition, hashShift = HASH_BITS - log2(capacity). */
+ uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift_); }
+
+ /* Whether we need to grow. We want to do this if the load factor is >= 0.75 */
+ bool needsToGrow() const {
+ uint32_t size = capacity();
+ return entryCount_ + removedCount_ >= size - (size >> 2);
+ }
+
+ /*
+ * Try to grow the table. On failure, reports out of memory on cx
+ * and returns false. This will make any extant pointers into the
+ * table invalid. Don't call this unless needsToGrow() is true.
+ */
+ bool grow(ExclusiveContext* cx);
+};
+
+// Ensures no shape tables are purged in the current zone.
+class MOZ_RAII AutoKeepShapeTables
+{
+ ExclusiveContext* cx_;
+ bool prev_;
+
+ AutoKeepShapeTables(const AutoKeepShapeTables&) = delete;
+ void operator=(const AutoKeepShapeTables&) = delete;
+
+ public:
+ explicit inline AutoKeepShapeTables(ExclusiveContext* cx);
+ inline ~AutoKeepShapeTables();
+};
+
+/*
+ * Use the reserved attribute bit to mean shadowability.
+ */
+#define JSPROP_SHADOWABLE JSPROP_INTERNAL_USE_BIT
+
+/*
+ * Shapes encode information about both a property lineage *and* a particular
+ * property. This information is split across the Shape and the BaseShape
+ * at shape->base(). Both Shape and BaseShape can be either owned or unowned
+ * by, respectively, the Object or Shape referring to them.
+ *
+ * Owned Shapes are used in dictionary objects, and form a doubly linked list
+ * whose entries are all owned by that dictionary. Unowned Shapes are all in
+ * the property tree.
+ *
+ * Owned BaseShapes are used for shapes which have shape tables, including the
+ * last properties in all dictionaries. Unowned BaseShapes compactly store
+ * information common to many shapes. In a given zone there is a single
+ * BaseShape for each combination of BaseShape information. This information is
+ * cloned in owned BaseShapes so that information can be quickly looked up for a
+ * given object or shape without regard to whether the base shape is owned or
+ * not.
+ *
+ * All combinations of owned/unowned Shapes/BaseShapes are possible:
+ *
+ * Owned Shape, Owned BaseShape:
+ *
+ * Last property in a dictionary object. The BaseShape is transferred from
+ * property to property as the object's last property changes.
+ *
+ * Owned Shape, Unowned BaseShape:
+ *
+ * Property in a dictionary object other than the last one.
+ *
+ * Unowned Shape, Owned BaseShape:
+ *
+ * Property in the property tree which has a shape table.
+ *
+ * Unowned Shape, Unowned BaseShape:
+ *
+ * Property in the property tree which does not have a shape table.
+ *
+ * BaseShapes additionally encode some information about the referring object
+ * itself. This includes the object's class and various flags that may be set
+ * for the object. Except for the class, this information is mutable and may
+ * change when the object has an established property lineage. On such changes
+ * the entire property lineage is not updated, but rather only the last property
+ * (and its base shape). This works because only the object's last property is
+ * used to query information about the object. Care must be taken to call
+ * JSObject::canRemoveLastProperty when unwinding an object to an earlier
+ * property, however.
+ */
+
+class AccessorShape;
+class Shape;
+class UnownedBaseShape;
+struct StackBaseShape;
+
+class BaseShape : public gc::TenuredCell
+{
+ public:
+ friend class Shape;
+ friend struct StackBaseShape;
+ friend struct StackShape;
+ friend void gc::MergeCompartments(JSCompartment* source, JSCompartment* target);
+
+ enum Flag {
+ /* Owned by the referring shape. */
+ OWNED_SHAPE = 0x1,
+
+ /* (0x2 and 0x4 are unused) */
+
+ /*
+ * Flags set which describe the referring object. Once set these cannot
+ * be unset (except during object densification of sparse indexes), and
+ * are transferred from shape to shape as the object's last property
+ * changes.
+ *
+ * If you add a new flag here, please add appropriate code to
+ * JSObject::dump to dump it as part of object representation.
+ */
+
+ DELEGATE = 0x8,
+ NOT_EXTENSIBLE = 0x10,
+ INDEXED = 0x20,
+ /* (0x40 is unused) */
+ HAD_ELEMENTS_ACCESS = 0x80,
+ WATCHED = 0x100,
+ ITERATED_SINGLETON = 0x200,
+ NEW_GROUP_UNKNOWN = 0x400,
+ UNCACHEABLE_PROTO = 0x800,
+ IMMUTABLE_PROTOTYPE = 0x1000,
+
+ // See JSObject::isQualifiedVarObj().
+ QUALIFIED_VAROBJ = 0x2000,
+
+ // 0x4000 is unused.
+
+ // For a function used as an interpreted constructor, whether a 'new'
+ // type had constructor information cleared.
+ NEW_SCRIPT_CLEARED = 0x8000,
+
+ OBJECT_FLAG_MASK = 0xfff8
+ };
+
+ private:
+ const Class* clasp_; /* Class of referring object. */
+ uint32_t flags; /* Vector of above flags. */
+ uint32_t slotSpan_; /* Object slot span for BaseShapes at
+ * dictionary last properties. */
+
+ /* For owned BaseShapes, the canonical unowned BaseShape. */
+ GCPtrUnownedBaseShape unowned_;
+
+ /* For owned BaseShapes, the shape's shape table. */
+ ShapeTable* table_;
+
+#if JS_BITS_PER_WORD == 32
+ // Ensure sizeof(BaseShape) is a multiple of gc::CellSize.
+ uint32_t padding_;
+#endif
+
+ BaseShape(const BaseShape& base) = delete;
+ BaseShape& operator=(const BaseShape& other) = delete;
+
+ public:
+ void finalize(FreeOp* fop);
+
+ explicit inline BaseShape(const StackBaseShape& base);
+
+ /* Not defined: BaseShapes must not be stack allocated. */
+ ~BaseShape();
+
+ const Class* clasp() const { return clasp_; }
+
+ bool isOwned() const { return !!(flags & OWNED_SHAPE); }
+
+ static void copyFromUnowned(BaseShape& dest, UnownedBaseShape& src);
+ inline void adoptUnowned(UnownedBaseShape* other);
+
+ void setOwned(UnownedBaseShape* unowned) {
+ flags |= OWNED_SHAPE;
+ unowned_ = unowned;
+ }
+
+ uint32_t getObjectFlags() const { return flags & OBJECT_FLAG_MASK; }
+
+ bool hasTable() const { MOZ_ASSERT_IF(table_, isOwned()); return table_ != nullptr; }
+ void setTable(ShapeTable* table) { MOZ_ASSERT(isOwned()); table_ = table; }
+
+ ShapeTable* maybeTable(const AutoKeepShapeTables&) const {
+ MOZ_ASSERT_IF(table_, isOwned());
+ return table_;
+ }
+ ShapeTable* maybeTable(const JS::AutoCheckCannotGC&) const {
+ MOZ_ASSERT_IF(table_, isOwned());
+ return table_;
+ }
+ void maybePurgeTable() {
+ if (table_ && table_->freeList() == SHAPE_INVALID_SLOT) {
+ js_delete(table_);
+ table_ = nullptr;
+ }
+ }
+
+ uint32_t slotSpan() const { MOZ_ASSERT(isOwned()); return slotSpan_; }
+ void setSlotSpan(uint32_t slotSpan) { MOZ_ASSERT(isOwned()); slotSpan_ = slotSpan; }
+
+ /*
+ * Lookup base shapes from the zone's baseShapes table, adding if not
+ * already found.
+ */
+ static UnownedBaseShape* getUnowned(ExclusiveContext* cx, StackBaseShape& base);
+
+ /* Get the canonical base shape. */
+ inline UnownedBaseShape* unowned();
+
+ /* Get the canonical base shape for an owned one. */
+ inline UnownedBaseShape* baseUnowned();
+
+ /* Get the canonical base shape for an unowned one (i.e. identity). */
+ inline UnownedBaseShape* toUnowned();
+
+ /* Check that an owned base shape is consistent with its unowned base. */
+ void assertConsistency();
+
+ /* For JIT usage */
+ static inline size_t offsetOfFlags() { return offsetof(BaseShape, flags); }
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::BaseShape;
+
+ void traceChildren(JSTracer* trc);
+ void traceChildrenSkipShapeTable(JSTracer* trc);
+
+#ifdef DEBUG
+ bool canSkipMarkingShapeTable(Shape* lastShape);
+#endif
+
+ private:
+ static void staticAsserts() {
+ JS_STATIC_ASSERT(offsetof(BaseShape, clasp_) == offsetof(js::shadow::BaseShape, clasp_));
+ static_assert(sizeof(BaseShape) % gc::CellSize == 0,
+ "Things inheriting from gc::Cell must have a size that's "
+ "a multiple of gc::CellSize");
+ }
+
+ void traceShapeTable(JSTracer* trc);
+};
+
+class UnownedBaseShape : public BaseShape {};
+
+UnownedBaseShape*
+BaseShape::unowned()
+{
+ return isOwned() ? baseUnowned() : toUnowned();
+}
+
+UnownedBaseShape*
+BaseShape::toUnowned()
+{
+ MOZ_ASSERT(!isOwned() && !unowned_);
+ return static_cast<UnownedBaseShape*>(this);
+}
+
+UnownedBaseShape*
+BaseShape::baseUnowned()
+{
+ MOZ_ASSERT(isOwned() && unowned_);
+ return unowned_;
+}
+
+/* Entries for the per-zone baseShapes set of unowned base shapes. */
+struct StackBaseShape : public DefaultHasher<ReadBarriered<UnownedBaseShape*>>
+{
+ uint32_t flags;
+ const Class* clasp;
+
+ explicit StackBaseShape(BaseShape* base)
+ : flags(base->flags & BaseShape::OBJECT_FLAG_MASK),
+ clasp(base->clasp_)
+ {}
+
+ inline StackBaseShape(ExclusiveContext* cx, const Class* clasp, uint32_t objectFlags);
+ explicit inline StackBaseShape(Shape* shape);
+
+ struct Lookup
+ {
+ uint32_t flags;
+ const Class* clasp;
+
+ MOZ_IMPLICIT Lookup(const StackBaseShape& base)
+ : flags(base.flags), clasp(base.clasp)
+ {}
+
+ MOZ_IMPLICIT Lookup(UnownedBaseShape* base)
+ : flags(base->getObjectFlags()), clasp(base->clasp())
+ {
+ MOZ_ASSERT(!base->isOwned());
+ }
+ };
+
+ static inline HashNumber hash(const Lookup& lookup);
+ static inline bool match(ReadBarriered<UnownedBaseShape*> key, const Lookup& lookup);
+};
+
+static MOZ_ALWAYS_INLINE js::HashNumber
+HashId(jsid id)
+{
+ // HashGeneric alone would work, but bits of atom and symbol addresses
+ // could then be recovered from the hash code. See bug 1330769.
+ if (MOZ_LIKELY(JSID_IS_ATOM(id)))
+ return JSID_TO_ATOM(id)->hash();
+ if (JSID_IS_SYMBOL(id))
+ return JSID_TO_SYMBOL(id)->hash();
+ return mozilla::HashGeneric(JSID_BITS(id));
+}
+
+template <>
+struct DefaultHasher<jsid>
+{
+ typedef jsid Lookup;
+ static HashNumber hash(jsid id) {
+ return HashId(id);
+ }
+ static bool match(jsid id1, jsid id2) {
+ return id1 == id2;
+ }
+};
+
+using BaseShapeSet = JS::GCHashSet<ReadBarriered<UnownedBaseShape*>,
+ StackBaseShape,
+ SystemAllocPolicy>;
+
+class Shape : public gc::TenuredCell
+{
+ friend class ::JSObject;
+ friend class ::JSFunction;
+ friend class NativeObject;
+ friend class PropertyTree;
+ friend class TenuringTracer;
+ friend struct StackBaseShape;
+ friend struct StackShape;
+ friend class JS::ubi::Concrete<Shape>;
+ friend class js::gc::RelocationOverlay;
+
+ protected:
+ GCPtrBaseShape base_;
+ PreBarrieredId propid_;
+
+ enum SlotInfo : uint32_t
+ {
+ /* Number of fixed slots in objects with this shape. */
+ // FIXED_SLOTS_MAX is the biggest count of fixed slots a Shape can store
+ FIXED_SLOTS_MAX = 0x1f,
+ FIXED_SLOTS_SHIFT = 27,
+ FIXED_SLOTS_MASK = uint32_t(FIXED_SLOTS_MAX << FIXED_SLOTS_SHIFT),
+
+ /*
+ * numLinearSearches starts at zero and is incremented initially on
+ * search() calls. Once numLinearSearches reaches LINEAR_SEARCHES_MAX,
+ * the table is created on the next search() call. The table can also
+ * be created when hashifying for dictionary mode.
+ */
+ LINEAR_SEARCHES_MAX = 0x7,
+ LINEAR_SEARCHES_SHIFT = 24,
+ LINEAR_SEARCHES_MASK = LINEAR_SEARCHES_MAX << LINEAR_SEARCHES_SHIFT,
+
+ /*
+ * Mask to get the index in object slots for shapes which hasSlot().
+ * For !hasSlot() shapes in the property tree with a parent, stores the
+ * parent's slot index (which may be invalid), and invalid for all
+ * other shapes.
+ */
+ SLOT_MASK = JS_BIT(24) - 1
+ };
+
+ uint32_t slotInfo; /* mask of above info */
+ uint8_t attrs; /* attributes, see jsapi.h JSPROP_* */
+ uint8_t flags; /* flags, see below for defines */
+
+ GCPtrShape parent; /* parent node, reverse for..in order */
+ /* kids is valid when !inDictionary(), listp is valid when inDictionary(). */
+ union {
+ KidsPointer kids; /* null, single child, or a tagged ptr
+ to many-kids data structure */
+ GCPtrShape* listp; /* dictionary list starting at shape_
+ has a double-indirect back pointer,
+ either to the next shape's parent if not
+ last, else to obj->shape_ */
+ };
+
+ template<MaybeAdding Adding = MaybeAdding::NotAdding>
+ static inline Shape* search(ExclusiveContext* cx, Shape* start, jsid id);
+
+ template<MaybeAdding Adding = MaybeAdding::NotAdding>
+ static inline MOZ_MUST_USE bool search(ExclusiveContext* cx, Shape* start, jsid id,
+ const AutoKeepShapeTables&,
+ Shape** pshape, ShapeTable::Entry** pentry);
+
+ static inline Shape* searchNoHashify(Shape* start, jsid id);
+
+ void removeFromDictionary(NativeObject* obj);
+ void insertIntoDictionary(GCPtrShape* dictp);
+
+ inline void initDictionaryShape(const StackShape& child, uint32_t nfixed,
+ GCPtrShape* dictp);
+
+ /* Replace the base shape of the last shape in a non-dictionary lineage with base. */
+ static Shape* replaceLastProperty(ExclusiveContext* cx, StackBaseShape& base,
+ TaggedProto proto, HandleShape shape);
+
+ /*
+ * This function is thread safe if every shape in the lineage of |shape|
+ * is thread local, which is the case when we clone the entire shape
+ * lineage in preparation for converting an object to dictionary mode.
+ */
+ static bool hashify(ExclusiveContext* cx, Shape* shape);
+ void handoffTableTo(Shape* newShape);
+
+ void setParent(Shape* p) {
+ MOZ_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
+ p->maybeSlot() <= maybeSlot());
+ MOZ_ASSERT_IF(p && !inDictionary(),
+ hasSlot() == (p->maybeSlot() != maybeSlot()));
+ parent = p;
+ }
+
+ bool ensureOwnBaseShape(ExclusiveContext* cx) {
+ if (base()->isOwned())
+ return true;
+ return makeOwnBaseShape(cx);
+ }
+
+ bool makeOwnBaseShape(ExclusiveContext* cx);
+
+ MOZ_ALWAYS_INLINE MOZ_MUST_USE bool maybeCreateTableForLookup(ExclusiveContext* cx);
+
+ public:
+ bool hasTable() const { return base()->hasTable(); }
+
+ ShapeTable* maybeTable(const AutoKeepShapeTables& keep) const {
+ return base()->maybeTable(keep);
+ }
+ ShapeTable* maybeTable(const JS::AutoCheckCannotGC& check) const {
+ return base()->maybeTable(check);
+ }
+
+ template <typename T>
+ MOZ_MUST_USE ShapeTable* ensureTableForDictionary(ExclusiveContext* cx, const T& nogc) {
+ MOZ_ASSERT(inDictionary());
+ if (ShapeTable* table = maybeTable(nogc))
+ return table;
+ if (!hashify(cx, this))
+ return nullptr;
+ ShapeTable* table = maybeTable(nogc);
+ MOZ_ASSERT(table);
+ return table;
+ }
+
+ void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ JS::ShapeInfo* info) const
+ {
+ JS::AutoCheckCannotGC nogc;
+ if (ShapeTable* table = maybeTable(nogc)) {
+ if (inDictionary())
+ info->shapesMallocHeapDictTables += table->sizeOfIncludingThis(mallocSizeOf);
+ else
+ info->shapesMallocHeapTreeTables += table->sizeOfIncludingThis(mallocSizeOf);
+ }
+
+ if (!inDictionary() && kids.isHash())
+ info->shapesMallocHeapTreeKids += kids.toHash()->sizeOfIncludingThis(mallocSizeOf);
+ }
+
+ bool isAccessorShape() const {
+ MOZ_ASSERT_IF(flags & ACCESSOR_SHAPE, getAllocKind() == gc::AllocKind::ACCESSOR_SHAPE);
+ return flags & ACCESSOR_SHAPE;
+ }
+ AccessorShape& asAccessorShape() const {
+ MOZ_ASSERT(isAccessorShape());
+ return *(AccessorShape*)this;
+ }
+
+ const GCPtrShape& previous() const { return parent; }
+
+ template <AllowGC allowGC>
+ class Range {
+ protected:
+ friend class Shape;
+
+ typename MaybeRooted<Shape*, allowGC>::RootType cursor;
+
+ public:
+ Range(ExclusiveContext* cx, Shape* shape) : cursor(cx, shape) {
+ JS_STATIC_ASSERT(allowGC == CanGC);
+ }
+
+ explicit Range(Shape* shape) : cursor((ExclusiveContext*) nullptr, shape) {
+ JS_STATIC_ASSERT(allowGC == NoGC);
+ }
+
+ bool empty() const {
+ return !cursor || cursor->isEmptyShape();
+ }
+
+ Shape& front() const {
+ MOZ_ASSERT(!empty());
+ return *cursor;
+ }
+
+ void popFront() {
+ MOZ_ASSERT(!empty());
+ cursor = cursor->parent;
+ }
+ };
+
+ const Class* getObjectClass() const {
+ return base()->clasp_;
+ }
+
+ static Shape* setObjectFlags(ExclusiveContext* cx,
+ BaseShape::Flag flag, TaggedProto proto, Shape* last);
+
+ uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
+ bool hasAllObjectFlags(BaseShape::Flag flags) const {
+ MOZ_ASSERT(flags);
+ MOZ_ASSERT(!(flags & ~BaseShape::OBJECT_FLAG_MASK));
+ return (base()->flags & flags) == flags;
+ }
+
+ protected:
+ /*
+ * Implementation-private bits stored in shape->flags. See public: enum {}
+ * flags further below, which were allocated FCFS over time, so interleave
+ * with these bits.
+ */
+ enum {
+ /* Property stored in per-object dictionary, not shared property tree. */
+ IN_DICTIONARY = 0x01,
+
+ /*
+ * Slotful property was stored to more than once. This is used as a
+ * hint for type inference.
+ */
+ OVERWRITTEN = 0x02,
+
+ /*
+ * This shape is an AccessorShape, a fat Shape that can store
+ * getter/setter information.
+ */
+ ACCESSOR_SHAPE = 0x04,
+
+ /* Flags used to speed up isBigEnoughForAShapeTable(). */
+ HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x08,
+ CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x10,
+ };
+
+ /* Get a shape identical to this one, without parent/kids information. */
+ inline Shape(const StackShape& other, uint32_t nfixed);
+
+ /* Used by EmptyShape (see jsscopeinlines.h). */
+ inline Shape(UnownedBaseShape* base, uint32_t nfixed);
+
+ /* Copy constructor disabled, to avoid misuse of the above form. */
+ Shape(const Shape& other) = delete;
+
+ /* Allocate a new shape based on the given StackShape. */
+ static inline Shape* new_(ExclusiveContext* cx, Handle<StackShape> other, uint32_t nfixed);
+
+ /*
+ * Whether this shape has a valid slot value. This may be true even if
+ * !hasSlot() (see SlotInfo comment above), and may be false even if
+ * hasSlot() if the shape is being constructed and has not had a slot
+ * assigned yet. After construction, hasSlot() implies !hasMissingSlot().
+ */
+ bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
+
+ public:
+ bool inDictionary() const {
+ return (flags & IN_DICTIONARY) != 0;
+ }
+
+ inline GetterOp getter() const;
+ bool hasDefaultGetter() const { return !getter(); }
+ GetterOp getterOp() const { MOZ_ASSERT(!hasGetterValue()); return getter(); }
+ inline JSObject* getterObject() const;
+ bool hasGetterObject() const { return hasGetterValue() && getterObject(); }
+
+ // Per ES5, decode null getterObj as the undefined value, which encodes as null.
+ Value getterValue() const {
+ MOZ_ASSERT(hasGetterValue());
+ if (JSObject* getterObj = getterObject())
+ return ObjectValue(*getterObj);
+ return UndefinedValue();
+ }
+
+ Value getterOrUndefined() const {
+ return hasGetterValue() ? getterValue() : UndefinedValue();
+ }
+
+ inline SetterOp setter() const;
+ bool hasDefaultSetter() const { return !setter(); }
+ SetterOp setterOp() const { MOZ_ASSERT(!hasSetterValue()); return setter(); }
+ inline JSObject* setterObject() const;
+ bool hasSetterObject() const { return hasSetterValue() && setterObject(); }
+
+ // Per ES5, decode null setterObj as the undefined value, which encodes as null.
+ Value setterValue() const {
+ MOZ_ASSERT(hasSetterValue());
+ if (JSObject* setterObj = setterObject())
+ return ObjectValue(*setterObj);
+ return UndefinedValue();
+ }
+
+ Value setterOrUndefined() const {
+ return hasSetterValue() ? setterValue() : UndefinedValue();
+ }
+
+ void setOverwritten() {
+ flags |= OVERWRITTEN;
+ }
+ bool hadOverwrite() const {
+ return flags & OVERWRITTEN;
+ }
+
+ void update(GetterOp getter, SetterOp setter, uint8_t attrs);
+
+ bool matches(const Shape* other) const {
+ return propid_.get() == other->propid_.get() &&
+ matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs, other->flags,
+ other->getter(), other->setter());
+ }
+
+ inline bool matches(const StackShape& other) const;
+
+ bool matchesParamsAfterId(BaseShape* base, uint32_t aslot, unsigned aattrs, unsigned aflags,
+ GetterOp rawGetter, SetterOp rawSetter) const
+ {
+ return base->unowned() == this->base()->unowned() &&
+ maybeSlot() == aslot &&
+ attrs == aattrs &&
+ getter() == rawGetter &&
+ setter() == rawSetter;
+ }
+
+ bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp,
+ ObjectOpResult& result);
+
+ BaseShape* base() const { return base_.get(); }
+
+ bool hasSlot() const {
+ return (attrs & JSPROP_SHARED) == 0;
+ }
+ uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
+ uint32_t maybeSlot() const {
+ return slotInfo & SLOT_MASK;
+ }
+
+ bool isEmptyShape() const {
+ MOZ_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
+ return JSID_IS_EMPTY(propid_);
+ }
+
+ uint32_t slotSpan(const Class* clasp) const {
+ MOZ_ASSERT(!inDictionary());
+ uint32_t free = JSSLOT_FREE(clasp);
+ return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
+ }
+
+ uint32_t slotSpan() const {
+ return slotSpan(getObjectClass());
+ }
+
+ void setSlot(uint32_t slot) {
+ MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
+ slotInfo = slotInfo & ~Shape::SLOT_MASK;
+ slotInfo = slotInfo | slot;
+ }
+
+ uint32_t numFixedSlots() const {
+ return slotInfo >> FIXED_SLOTS_SHIFT;
+ }
+
+ void setNumFixedSlots(uint32_t nfixed) {
+ MOZ_ASSERT(nfixed < FIXED_SLOTS_MAX);
+ slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
+ slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
+ }
+
+ uint32_t numLinearSearches() const {
+ return (slotInfo & LINEAR_SEARCHES_MASK) >> LINEAR_SEARCHES_SHIFT;
+ }
+
+ void incrementNumLinearSearches() {
+ uint32_t count = numLinearSearches();
+ MOZ_ASSERT(count < LINEAR_SEARCHES_MAX);
+ slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
+ slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
+ }
+
+ const PreBarrieredId& propid() const {
+ MOZ_ASSERT(!isEmptyShape());
+ MOZ_ASSERT(!JSID_IS_VOID(propid_));
+ return propid_;
+ }
+ PreBarrieredId& propidRef() { MOZ_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
+ jsid propidRaw() const {
+ // Return the actual jsid, not an internal reference.
+ return propid();
+ }
+
+ uint8_t attributes() const { return attrs; }
+ bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; }
+ bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
+ bool writable() const {
+ return (attrs & JSPROP_READONLY) == 0;
+ }
+ bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
+ bool hasSetterValue() const { return attrs & JSPROP_SETTER; }
+
+ bool isDataDescriptor() const {
+ return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
+ }
+ bool isAccessorDescriptor() const {
+ return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
+ }
+
+ bool hasShadowable() const { return attrs & JSPROP_SHADOWABLE; }
+
+ uint32_t entryCount() {
+ JS::AutoCheckCannotGC nogc;
+ if (ShapeTable* table = maybeTable(nogc))
+ return table->entryCount();
+ uint32_t count = 0;
+ for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
+ ++count;
+ return count;
+ }
+
+ private:
+ bool isBigEnoughForAShapeTableSlow() {
+ uint32_t count = 0;
+ for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront()) {
+ ++count;
+ if (count >= ShapeTable::MIN_ENTRIES)
+ return true;
+ }
+ return false;
+ }
+ void clearCachedBigEnoughForShapeTable() {
+ flags &= ~(HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE | CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE);
+ }
+
+ public:
+ bool isBigEnoughForAShapeTable() {
+ MOZ_ASSERT(!hasTable());
+
+ // isBigEnoughForAShapeTableSlow is pretty inefficient so we only call
+ // it once and cache the result.
+
+ if (flags & HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE) {
+ bool res = flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+ MOZ_ASSERT(res == isBigEnoughForAShapeTableSlow());
+ return res;
+ }
+
+ MOZ_ASSERT(!(flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE));
+
+ bool res = isBigEnoughForAShapeTableSlow();
+ if (res)
+ flags |= CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+ flags |= HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
+ return res;
+ }
+
+#ifdef DEBUG
+ void dump(FILE* fp) const;
+ void dumpSubtree(int level, FILE* fp) const;
+#endif
+
+ void sweep();
+ void finalize(FreeOp* fop);
+ void removeChild(Shape* child);
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::Shape;
+
+ void traceChildren(JSTracer* trc);
+
+ inline Shape* search(ExclusiveContext* cx, jsid id);
+ MOZ_ALWAYS_INLINE Shape* searchLinear(jsid id);
+
+ void fixupAfterMovingGC();
+ void fixupGetterSetterForBarrier(JSTracer* trc);
+ void updateBaseShapeAfterMovingGC();
+
+ /* For JIT usage */
+ static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
+ static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); }
+ static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
+
+ private:
+ void fixupDictionaryShapeAfterMovingGC();
+ void fixupShapeTreeAfterMovingGC();
+
+ static void staticAsserts() {
+ JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
+ JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
+ JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
+ }
+};
+
+/* Fat Shape used for accessor properties. */
+class AccessorShape : public Shape
+{
+ friend class Shape;
+ friend class NativeObject;
+
+ union {
+ GetterOp rawGetter; /* getter hook for shape */
+ JSObject* getterObj; /* user-defined callable "get" object or
+ null if shape->hasGetterValue() */
+ };
+ union {
+ SetterOp rawSetter; /* setter hook for shape */
+ JSObject* setterObj; /* user-defined callable "set" object or
+ null if shape->hasSetterValue() */
+ };
+
+ public:
+ /* Get a shape identical to this one, without parent/kids information. */
+ inline AccessorShape(const StackShape& other, uint32_t nfixed);
+};
+
+inline
+StackBaseShape::StackBaseShape(Shape* shape)
+ : flags(shape->getObjectFlags()),
+ clasp(shape->getObjectClass())
+{}
+
+class MOZ_RAII AutoRooterGetterSetter
+{
+ class Inner final : private JS::CustomAutoRooter
+ {
+ public:
+ inline Inner(ExclusiveContext* cx, uint8_t attrs, GetterOp* pgetter_, SetterOp* psetter_);
+
+ private:
+ virtual void trace(JSTracer* trc);
+
+ uint8_t attrs;
+ GetterOp* pgetter;
+ SetterOp* psetter;
+ };
+
+ public:
+ inline AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs,
+ GetterOp* pgetter, SetterOp* psetter
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ inline AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t attrs,
+ JSNative* pgetter, JSNative* psetter
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+
+ private:
+ mozilla::Maybe<Inner> inner;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+struct EmptyShape : public js::Shape
+{
+ EmptyShape(UnownedBaseShape* base, uint32_t nfixed)
+ : js::Shape(base, nfixed)
+ { }
+
+ static Shape* new_(ExclusiveContext* cx, Handle<UnownedBaseShape*> base, uint32_t nfixed);
+
+ /*
+ * Lookup an initial shape matching the given parameters, creating an empty
+ * shape if none was found.
+ */
+ static Shape* getInitialShape(ExclusiveContext* cx, const Class* clasp,
+ TaggedProto proto, size_t nfixed, uint32_t objectFlags = 0);
+ static Shape* getInitialShape(ExclusiveContext* cx, const Class* clasp,
+ TaggedProto proto, gc::AllocKind kind, uint32_t objectFlags = 0);
+
+ /*
+ * Reinsert an alternate initial shape, to be returned by future
+ * getInitialShape calls, until the new shape becomes unreachable in a GC
+ * and the table entry is purged.
+ */
+ static void insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleObject proto);
+
+ /*
+ * Some object subclasses are allocated with a built-in set of properties.
+ * The first time such an object is created, these built-in properties must
+ * be set manually, to compute an initial shape. Afterward, that initial
+ * shape can be reused for newly-created objects that use the subclass's
+ * standard prototype. This method should be used in a post-allocation
+ * init method, to ensure that objects of such subclasses compute and cache
+ * the initial shape, if it hasn't already been computed.
+ */
+ template<class ObjectSubclass>
+ static inline bool
+ ensureInitialCustomShape(ExclusiveContext* cx, Handle<ObjectSubclass*> obj);
+};
+
+// InitialShapeProto stores either:
+//
+// * A TaggedProto (or ReadBarriered<TaggedProto>).
+//
+// * A JSProtoKey. This is used instead of the TaggedProto if the proto is one
+// of the global's builtin prototypes. For instance, if the proto is the
+// initial Object.prototype, we use key_ = JSProto_Object, proto_ = nullptr.
+//
+// Using the JSProtoKey here is an optimization that lets us share more shapes
+// across compartments within a zone.
+template <typename PtrType>
+class InitialShapeProto
+{
+ template <typename T> friend class InitialShapeProto;
+
+ JSProtoKey key_;
+ PtrType proto_;
+
+ public:
+ InitialShapeProto()
+ : key_(JSProto_LIMIT), proto_()
+ {}
+
+ InitialShapeProto(JSProtoKey key, TaggedProto proto)
+ : key_(key), proto_(proto)
+ {}
+
+ template <typename T>
+ explicit InitialShapeProto(const InitialShapeProto<T>& other)
+ : key_(other.key()), proto_(other.proto_)
+ {}
+
+ explicit InitialShapeProto(TaggedProto proto)
+ : key_(JSProto_LIMIT), proto_(proto)
+ {}
+ explicit InitialShapeProto(JSProtoKey key)
+ : key_(key), proto_(nullptr)
+ {
+ MOZ_ASSERT(key < JSProto_LIMIT);
+ }
+
+ HashNumber hashCode() const {
+ return proto_.hashCode() ^ HashNumber(key_);
+ }
+ template <typename T>
+ bool match(const InitialShapeProto<T>& other) const {
+ return key_ == other.key_ &&
+ proto_.uniqueId() == other.proto_.unbarrieredGet().uniqueId();
+ }
+
+ JSProtoKey key() const {
+ return key_;
+ }
+ const PtrType& proto() const {
+ return proto_;
+ }
+ void setProto(TaggedProto proto) {
+ proto_ = proto;
+ }
+};
+
+/*
+ * Entries for the per-zone initialShapes set indexing initial shapes for
+ * objects in the zone and the associated types.
+ */
+struct InitialShapeEntry
+{
+ /*
+ * Initial shape to give to the object. This is an empty shape, except for
+ * certain classes (e.g. String, RegExp) which may add certain baked-in
+ * properties.
+ */
+ ReadBarriered<Shape*> shape;
+
+ /*
+ * Matching prototype for the entry. The shape of an object determines its
+ * prototype, but the prototype cannot be determined from the shape itself.
+ */
+ using ShapeProto = InitialShapeProto<ReadBarriered<TaggedProto>>;
+ ShapeProto proto;
+
+ /* State used to determine a match on an initial shape. */
+ struct Lookup {
+ using ShapeProto = InitialShapeProto<TaggedProto>;
+ const Class* clasp;
+ ShapeProto proto;
+ uint32_t nfixed;
+ uint32_t baseFlags;
+
+ Lookup(const Class* clasp, ShapeProto proto, uint32_t nfixed, uint32_t baseFlags)
+ : clasp(clasp), proto(proto), nfixed(nfixed), baseFlags(baseFlags)
+ {}
+ };
+
+ inline InitialShapeEntry();
+ inline InitialShapeEntry(Shape* shape, const Lookup::ShapeProto& proto);
+
+ static inline HashNumber hash(const Lookup& lookup);
+ static inline bool match(const InitialShapeEntry& key, const Lookup& lookup);
+ static void rekey(InitialShapeEntry& k, const InitialShapeEntry& newKey) { k = newKey; }
+
+ bool needsSweep() {
+ Shape* ushape = shape.unbarrieredGet();
+ JSObject* protoObj = proto.proto().raw();
+ return (gc::IsAboutToBeFinalizedUnbarriered(&ushape) ||
+ (proto.proto().isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj)));
+ }
+};
+
+using InitialShapeSet = JS::GCHashSet<InitialShapeEntry, InitialShapeEntry, SystemAllocPolicy>;
+
+struct StackShape
+{
+ /* For performance, StackShape only roots when absolutely necessary. */
+ UnownedBaseShape* base;
+ jsid propid;
+ GetterOp rawGetter;
+ SetterOp rawSetter;
+ uint32_t slot_;
+ uint8_t attrs;
+ uint8_t flags;
+
+ explicit StackShape(UnownedBaseShape* base, jsid propid, uint32_t slot,
+ unsigned attrs, unsigned flags)
+ : base(base),
+ propid(propid),
+ rawGetter(nullptr),
+ rawSetter(nullptr),
+ slot_(slot),
+ attrs(uint8_t(attrs)),
+ flags(uint8_t(flags))
+ {
+ MOZ_ASSERT(base);
+ MOZ_ASSERT(!JSID_IS_VOID(propid));
+ MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
+ MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
+ }
+
+ explicit StackShape(Shape* shape)
+ : base(shape->base()->unowned()),
+ propid(shape->propidRef()),
+ rawGetter(shape->getter()),
+ rawSetter(shape->setter()),
+ slot_(shape->maybeSlot()),
+ attrs(shape->attrs),
+ flags(shape->flags)
+ {}
+
+ void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) {
+ if (rawGetter || rawSetter || (attrs & (JSPROP_GETTER|JSPROP_SETTER)))
+ flags |= Shape::ACCESSOR_SHAPE;
+ else
+ flags &= ~Shape::ACCESSOR_SHAPE;
+
+ this->rawGetter = rawGetter;
+ this->rawSetter = rawSetter;
+ }
+
+ bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
+ bool hasMissingSlot() const { return maybeSlot() == SHAPE_INVALID_SLOT; }
+
+ uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
+ uint32_t maybeSlot() const { return slot_; }
+
+ uint32_t slotSpan() const {
+ uint32_t free = JSSLOT_FREE(base->clasp_);
+ return hasMissingSlot() ? free : (maybeSlot() + 1);
+ }
+
+ void setSlot(uint32_t slot) {
+ MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
+ slot_ = slot;
+ }
+
+ bool isAccessorShape() const {
+ return flags & Shape::ACCESSOR_SHAPE;
+ }
+
+ HashNumber hash() const {
+ HashNumber hash = uintptr_t(base);
+
+ /* Accumulate from least to most random so the low bits are most random. */
+ hash = mozilla::RotateLeft(hash, 4) ^ attrs;
+ hash = mozilla::RotateLeft(hash, 4) ^ slot_;
+ hash = mozilla::RotateLeft(hash, 4) ^ HashId(propid);
+ hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawGetter);
+ hash = mozilla::RotateLeft(hash, 4) ^ uintptr_t(rawSetter);
+ return hash;
+ }
+
+ // Traceable implementation.
+ static void trace(StackShape* stackShape, JSTracer* trc) { stackShape->trace(trc); }
+ void trace(JSTracer* trc);
+};
+
+template <typename Outer>
+class StackShapeOperations {
+ const StackShape& ss() const { return static_cast<const Outer*>(this)->get(); }
+
+ public:
+ bool hasSlot() const { return ss().hasSlot(); }
+ bool hasMissingSlot() const { return ss().hasMissingSlot(); }
+ uint32_t slot() const { return ss().slot(); }
+ uint32_t maybeSlot() const { return ss().maybeSlot(); }
+ uint32_t slotSpan() const { return ss().slotSpan(); }
+ bool isAccessorShape() const { return ss().isAccessorShape(); }
+ uint8_t attrs() const { return ss().attrs; }
+};
+
+template <typename Outer>
+class MutableStackShapeOperations : public StackShapeOperations<Outer> {
+ StackShape& ss() { return static_cast<Outer*>(this)->get(); }
+
+ public:
+ void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) {
+ ss().updateGetterSetter(rawGetter, rawSetter);
+ }
+ void setSlot(uint32_t slot) { ss().setSlot(slot); }
+ void setBase(UnownedBaseShape* base) { ss().base = base; }
+ void setAttrs(uint8_t attrs) { ss().attrs = attrs; }
+};
+
+template <>
+class RootedBase<StackShape> : public MutableStackShapeOperations<JS::Rooted<StackShape>>
+{};
+
+template <>
+class HandleBase<StackShape> : public StackShapeOperations<JS::Handle<StackShape>>
+{};
+
+template <>
+class MutableHandleBase<StackShape>
+ : public MutableStackShapeOperations<JS::MutableHandle<StackShape>>
+{};
+
+inline
+Shape::Shape(const StackShape& other, uint32_t nfixed)
+ : base_(other.base),
+ propid_(other.propid),
+ slotInfo(other.maybeSlot() | (nfixed << FIXED_SLOTS_SHIFT)),
+ attrs(other.attrs),
+ flags(other.flags),
+ parent(nullptr)
+{
+#ifdef DEBUG
+ gc::AllocKind allocKind = getAllocKind();
+ MOZ_ASSERT_IF(other.isAccessorShape(), allocKind == gc::AllocKind::ACCESSOR_SHAPE);
+ MOZ_ASSERT_IF(allocKind == gc::AllocKind::SHAPE, !other.isAccessorShape());
+#endif
+
+ MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
+ kids.setNull();
+}
+
+// This class is used to add a post barrier on the AccessorShape's getter/setter
+// objects. It updates the pointers and the shape's entry in the parent's
+// KidsHash table.
+class ShapeGetterSetterRef : public gc::BufferableRef
+{
+ AccessorShape* shape_;
+
+ public:
+ explicit ShapeGetterSetterRef(AccessorShape* shape) : shape_(shape) {}
+ void trace(JSTracer* trc) override { shape_->fixupGetterSetterForBarrier(trc); }
+};
+
+static inline void
+GetterSetterWriteBarrierPost(AccessorShape* shape)
+{
+ MOZ_ASSERT(shape);
+ if (shape->hasGetterObject()) {
+ gc::StoreBuffer* sb = reinterpret_cast<gc::Cell*>(shape->getterObject())->storeBuffer();
+ if (sb) {
+ sb->putGeneric(ShapeGetterSetterRef(shape));
+ return;
+ }
+ }
+ if (shape->hasSetterObject()) {
+ gc::StoreBuffer* sb = reinterpret_cast<gc::Cell*>(shape->setterObject())->storeBuffer();
+ if (sb) {
+ sb->putGeneric(ShapeGetterSetterRef(shape));
+ return;
+ }
+ }
+}
+
+inline
+AccessorShape::AccessorShape(const StackShape& other, uint32_t nfixed)
+ : Shape(other, nfixed),
+ rawGetter(other.rawGetter),
+ rawSetter(other.rawSetter)
+{
+ MOZ_ASSERT(getAllocKind() == gc::AllocKind::ACCESSOR_SHAPE);
+ GetterSetterWriteBarrierPost(this);
+}
+
+inline
+Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
+ : base_(base),
+ propid_(JSID_EMPTY),
+ slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
+ attrs(JSPROP_SHARED),
+ flags(0),
+ parent(nullptr)
+{
+ MOZ_ASSERT(base);
+ kids.setNull();
+}
+
+inline GetterOp
+Shape::getter() const
+{
+ return isAccessorShape() ? asAccessorShape().rawGetter : nullptr;
+}
+
+inline SetterOp
+Shape::setter() const
+{
+ return isAccessorShape() ? asAccessorShape().rawSetter : nullptr;
+}
+
+inline JSObject*
+Shape::getterObject() const
+{
+ MOZ_ASSERT(hasGetterValue());
+ return asAccessorShape().getterObj;
+}
+
+inline JSObject*
+Shape::setterObject() const
+{
+ MOZ_ASSERT(hasSetterValue());
+ return asAccessorShape().setterObj;
+}
+
+inline void
+Shape::initDictionaryShape(const StackShape& child, uint32_t nfixed, GCPtrShape* dictp)
+{
+ if (child.isAccessorShape())
+ new (this) AccessorShape(child, nfixed);
+ else
+ new (this) Shape(child, nfixed);
+ this->flags |= IN_DICTIONARY;
+
+ this->listp = nullptr;
+ if (dictp)
+ insertIntoDictionary(dictp);
+}
+
+inline Shape*
+Shape::searchLinear(jsid id)
+{
+ for (Shape* shape = this; shape; ) {
+ if (shape->propidRef() == id)
+ return shape;
+ shape = shape->parent;
+ }
+
+ return nullptr;
+}
+
+/*
+ * Keep this function in sync with search. It neither hashifies the start
+ * shape nor increments linear search count.
+ */
+inline Shape*
+Shape::searchNoHashify(Shape* start, jsid id)
+{
+ /*
+ * If we have a table, search in the shape table, else do a linear
+ * search. We never hashify into a table in parallel.
+ */
+ JS::AutoCheckCannotGC nogc;
+ if (ShapeTable* table = start->maybeTable(nogc)) {
+ ShapeTable::Entry& entry = table->search<MaybeAdding::NotAdding>(id, nogc);
+ return entry.shape();
+ }
+
+ return start->searchLinear(id);
+}
+
+inline bool
+Shape::matches(const StackShape& other) const
+{
+ return propid_.get() == other.propid &&
+ matchesParamsAfterId(other.base, other.slot_, other.attrs, other.flags,
+ other.rawGetter, other.rawSetter);
+}
+
+// Property lookup hooks on objects are required to return a non-nullptr shape
+// to signify that the property has been found. For cases where the property is
+// not actually represented by a Shape, use a dummy value. This includes all
+// properties of non-native objects, and dense elements for native objects.
+// Use separate APIs for these two cases.
+
+template <AllowGC allowGC>
+static inline void
+MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+{
+ propp.set(reinterpret_cast<Shape*>(1));
+}
+
+template <AllowGC allowGC>
+static inline void
+MarkDenseOrTypedArrayElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+{
+ propp.set(reinterpret_cast<Shape*>(1));
+}
+
+static inline bool
+IsImplicitDenseOrTypedArrayElement(Shape* prop)
+{
+ return prop == reinterpret_cast<Shape*>(1);
+}
+
+static inline bool
+IsImplicitNonNativeProperty(Shape* prop)
+{
+ return prop == reinterpret_cast<Shape*>(1);
+}
+
+Shape*
+ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
+ gc::AllocKind allocKind);
+
+} // namespace js
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#pragma warning(pop)
+#endif
+
+// JS::ubi::Nodes can point to Shapes and BaseShapes; they're js::gc::Cell
+// instances that occupy a compartment.
+namespace JS {
+namespace ubi {
+
+template<>
+class Concrete<js::Shape> : TracerConcrete<js::Shape> {
+ protected:
+ explicit Concrete(js::Shape *ptr) : TracerConcrete<js::Shape>(ptr) { }
+
+ public:
+ static void construct(void *storage, js::Shape *ptr) { new (storage) Concrete(ptr); }
+
+ Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+ const char16_t* typeName() const override { return concreteTypeName; }
+ static const char16_t concreteTypeName[];
+};
+
+template<>
+class Concrete<js::BaseShape> : TracerConcrete<js::BaseShape> {
+ protected:
+ explicit Concrete(js::BaseShape *ptr) : TracerConcrete<js::BaseShape>(ptr) { }
+
+ public:
+ static void construct(void *storage, js::BaseShape *ptr) { new (storage) Concrete(ptr); }
+
+ Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+ const char16_t* typeName() const override { return concreteTypeName; }
+ static const char16_t concreteTypeName[];
+};
+
+} // namespace ubi
+} // namespace JS
+
+#endif /* vm_Shape_h */
diff --git a/js/src/vm/ShapedObject-inl.h b/js/src/vm/ShapedObject-inl.h
new file mode 100644
index 000000000..5f6a4b4f0
--- /dev/null
+++ b/js/src/vm/ShapedObject-inl.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ShapedObject_inl_h
+#define vm_ShapedObject_inl_h
+
+#include "vm/ShapedObject.h"
+
+#include "jsfriendapi.h"
+
+#include "js/Proxy.h"
+
+template<>
+inline bool
+JSObject::is<js::ShapedObject>() const
+{
+ return isNative() || is<js::ProxyObject>() || is<js::TypedObject>();
+}
+
+#endif /* vm_ShapedObject_inl_h */
diff --git a/js/src/vm/ShapedObject.h b/js/src/vm/ShapedObject.h
new file mode 100644
index 000000000..408649bd8
--- /dev/null
+++ b/js/src/vm/ShapedObject.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ShapedObject_h
+#define vm_ShapedObject_h
+
+#include "jsobj.h"
+
+namespace js {
+
+/*
+ * Shaped objects extend the base implementation of an object with a shape
+ * field. Subclasses of ShapedObject ascribe meaning to this field.
+ *
+ * ShapedObject is only created as the base class of some other class. It's
+ * never created as a most-derived class.
+ */
+class ShapedObject : public JSObject
+{
+ protected:
+ // Property layout description and other state.
+ GCPtrShape shape_;
+
+ public:
+ // Set the shape of an object. This pointer is valid for native objects and
+ // some non-native objects. After creating an object, the objects for which
+ // the shape pointer is invalid need to overwrite this pointer before a GC
+ // can occur.
+ void initShape(Shape* shape) {
+ this->shape_.init(shape);
+ }
+
+ void setShape(Shape* shape) {
+ this->shape_ = shape;
+ }
+
+ Shape* shape() const { return this->shape_; }
+
+ void traceShape(JSTracer* trc) {
+ TraceEdge(trc, &shape_, "shape");
+ }
+
+ static size_t offsetOfShape() { return offsetof(ShapedObject, shape_); }
+
+ private:
+ static void staticAsserts() {
+ static_assert(offsetof(ShapedObject, shape_) == offsetof(shadow::Object, shape),
+ "shadow shape must match actual shape");
+ }
+};
+
+} // namespace js
+
+#endif /* vm_ShapedObject_h */
diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp
new file mode 100644
index 000000000..730578cd4
--- /dev/null
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -0,0 +1,488 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SharedArrayObject.h"
+
+#include "mozilla/Atomics.h"
+
+#include "jsfriendapi.h"
+#include "jsprf.h"
+
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+#include "jswrapper.h"
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+#ifdef MOZ_VALGRIND
+# include <valgrind/memcheck.h>
+#endif
+
+#include "vm/SharedMem.h"
+#include "vm/TypedArrayCommon.h"
+#include "wasm/AsmJS.h"
+#include "wasm/WasmTypes.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+static inline void*
+MapMemory(size_t length, bool commit)
+{
+#ifdef XP_WIN
+ int prot = (commit ? MEM_COMMIT : MEM_RESERVE);
+ int flags = (commit ? PAGE_READWRITE : PAGE_NOACCESS);
+ return VirtualAlloc(nullptr, length, prot, flags);
+#else
+ int prot = (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE);
+ void* p = mmap(nullptr, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return nullptr;
+ return p;
+#endif
+}
+
+static inline void
+UnmapMemory(void* addr, size_t len)
+{
+#ifdef XP_WIN
+ VirtualFree(addr, 0, MEM_RELEASE);
+#else
+ munmap(addr, len);
+#endif
+}
+
+static inline bool
+MarkValidRegion(void* addr, size_t len)
+{
+#ifdef XP_WIN
+ if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_READWRITE))
+ return false;
+ return true;
+#else
+ if (mprotect(addr, len, PROT_READ | PROT_WRITE))
+ return false;
+ return true;
+#endif
+}
+
+// Since this SharedArrayBuffer will likely be used for asm.js code, prepare it
+// for asm.js by mapping the 4gb protected zone described in WasmTypes.h.
+// Since we want to put the SharedArrayBuffer header immediately before the
+// heap but keep the heap page-aligned, allocate an extra page before the heap.
+static uint64_t
+SharedArrayMappedSize(uint32_t allocSize)
+{
+ MOZ_RELEASE_ASSERT(sizeof(SharedArrayRawBuffer) < gc::SystemPageSize());
+#ifdef WASM_HUGE_MEMORY
+ return wasm::HugeMappedSize + gc::SystemPageSize();
+#else
+ return allocSize + wasm::GuardSize;
+#endif
+}
+
+// If there are too many 4GB buffers live we run up against system resource
+// exhaustion (address space or number of memory map descriptors), see
+// bug 1068684, bug 1073934 for details. The limiting case seems to be
+// Windows Vista Home 64-bit, where the per-process address space is limited
+// to 8TB. Thus we track the number of live objects, and set a limit of
+// 1000 live objects per process; we run synchronous GC if necessary; and
+// we throw an OOM error if the per-process limit is exceeded.
+static mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numLive;
+static const uint32_t maxLive = 1000;
+
+static uint32_t
+SharedArrayAllocSize(uint32_t length)
+{
+ return AlignBytes(length + gc::SystemPageSize(), gc::SystemPageSize());
+}
+
+SharedArrayRawBuffer*
+SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
+{
+ // The value (uint32_t)-1 is used as a signal in various places,
+ // so guard against it on principle.
+ MOZ_ASSERT(length != (uint32_t)-1);
+
+ // Add a page for the header and round to a page boundary.
+ uint32_t allocSize = SharedArrayAllocSize(length);
+ if (allocSize <= length)
+ return nullptr;
+
+ bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
+
+ void* p = nullptr;
+ if (preparedForAsmJS) {
+ // Test >= to guard against the case where multiple extant runtimes
+ // race to allocate.
+ if (++numLive >= maxLive) {
+ JSRuntime* rt = cx->runtime();
+ if (rt->largeAllocationFailureCallback)
+ rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
+ if (numLive >= maxLive) {
+ numLive--;
+ return nullptr;
+ }
+ }
+
+ uint32_t mappedSize = SharedArrayMappedSize(allocSize);
+
+ // Get the entire reserved region (with all pages inaccessible)
+ p = MapMemory(mappedSize, false);
+ if (!p) {
+ numLive--;
+ return nullptr;
+ }
+
+ if (!MarkValidRegion(p, allocSize)) {
+ UnmapMemory(p, mappedSize);
+ numLive--;
+ return nullptr;
+ }
+
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+ // Tell Valgrind/Memcheck to not report accesses in the inaccessible region.
+ VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)p + allocSize,
+ mappedSize - allocSize);
+# endif
+ } else {
+ p = MapMemory(allocSize, true);
+ if (!p)
+ return nullptr;
+ }
+
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
+ uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
+ SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS);
+ MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this
+ return rawbuf;
+}
+
+void
+SharedArrayRawBuffer::addReference()
+{
+ MOZ_ASSERT(this->refcount_ > 0);
+ ++this->refcount_; // Atomic.
+}
+
+void
+SharedArrayRawBuffer::dropReference()
+{
+ // Drop the reference to the buffer.
+ uint32_t refcount = --this->refcount_; // Atomic.
+ if (refcount)
+ return;
+
+ // If this was the final reference, release the buffer.
+
+ SharedMem<uint8_t*> p = this->dataPointerShared() - gc::SystemPageSize();
+ MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0);
+
+ uint8_t* address = p.unwrap(/*safe - only reference*/);
+ uint32_t allocSize = SharedArrayAllocSize(this->length);
+
+ if (this->preparedForAsmJS) {
+ numLive--;
+
+ uint32_t mappedSize = SharedArrayMappedSize(allocSize);
+ UnmapMemory(address, mappedSize);
+
+# if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+ // Tell Valgrind/Memcheck to recommence reporting accesses in the
+ // previously-inaccessible region.
+ VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(address, mappedSize);
+# endif
+ } else {
+ UnmapMemory(address, allocSize);
+ }
+}
+
+
+MOZ_ALWAYS_INLINE bool
+SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(IsSharedArrayBuffer(args.thisv()));
+ args.rval().setInt32(args.thisv().toObject().as<SharedArrayBufferObject>().byteLength());
+ return true;
+}
+
+bool
+SharedArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
+}
+
+bool
+SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "SharedArrayBuffer"))
+ return false;
+
+ // Bugs 1068458, 1161298: Limit length to 2^31-1.
+ uint32_t length;
+ bool overflow_unused;
+ if (!ToLengthClamped(cx, args.get(0), &length, &overflow_unused) || length > INT32_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH);
+ return false;
+ }
+
+ RootedObject proto(cx);
+ RootedObject newTarget(cx, &args.newTarget().toObject());
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ JSObject* bufobj = New(cx, length, proto);
+ if (!bufobj)
+ return false;
+ args.rval().setObject(*bufobj);
+ return true;
+}
+
+SharedArrayBufferObject*
+SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto)
+{
+ SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length);
+ if (!buffer)
+ return nullptr;
+
+ return New(cx, buffer, proto);
+}
+
+SharedArrayBufferObject*
+SharedArrayBufferObject::New(JSContext* cx, SharedArrayRawBuffer* buffer, HandleObject proto)
+{
+ MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
+
+ AutoSetNewObjectMetadata metadata(cx);
+ Rooted<SharedArrayBufferObject*> obj(cx,
+ NewObjectWithClassProto<SharedArrayBufferObject>(cx, proto));
+ if (!obj)
+ return nullptr;
+
+ MOZ_ASSERT(obj->getClass() == &class_);
+
+ obj->acceptRawBuffer(buffer);
+
+ return obj;
+}
+
+void
+SharedArrayBufferObject::acceptRawBuffer(SharedArrayRawBuffer* buffer)
+{
+ setReservedSlot(RAWBUF_SLOT, PrivateValue(buffer));
+}
+
+void
+SharedArrayBufferObject::dropRawBuffer()
+{
+ setReservedSlot(RAWBUF_SLOT, UndefinedValue());
+}
+
+SharedArrayRawBuffer*
+SharedArrayBufferObject::rawBufferObject() const
+{
+ Value v = getReservedSlot(RAWBUF_SLOT);
+ MOZ_ASSERT(!v.isUndefined());
+ return reinterpret_cast<SharedArrayRawBuffer*>(v.toPrivate());
+}
+
+void
+SharedArrayBufferObject::Finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(fop->maybeOffMainThread());
+
+ SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
+
+ // Detect the case of failure during SharedArrayBufferObject creation,
+ // which causes a SharedArrayRawBuffer to never be attached.
+ Value v = buf.getReservedSlot(RAWBUF_SLOT);
+ if (!v.isUndefined()) {
+ buf.rawBufferObject()->dropReference();
+ buf.dropRawBuffer();
+ }
+}
+
+/* static */ void
+SharedArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
+ JS::ClassInfo* info)
+{
+ // Divide the buffer size by the refcount to get the fraction of the buffer
+ // owned by this thread. It's conceivable that the refcount might change in
+ // the middle of memory reporting, in which case the amount reported for
+ // some threads might be to high (if the refcount goes up) or too low (if
+ // the refcount goes down). But that's unlikely and hard to avoid, so we
+ // just live with the risk.
+ const SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
+ info->objectsNonHeapElementsShared +=
+ buf.byteLength() / buf.rawBufferObject()->refcount();
+}
+
+/* static */ void
+SharedArrayBufferObject::copyData(Handle<SharedArrayBufferObject*> toBuffer,
+ Handle<SharedArrayBufferObject*> fromBuffer,
+ uint32_t fromIndex, uint32_t count)
+{
+ MOZ_ASSERT(toBuffer->byteLength() >= count);
+ MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
+ MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex + count);
+
+ jit::AtomicOperations::memcpySafeWhenRacy(toBuffer->dataPointerShared(),
+ fromBuffer->dataPointerShared() + fromIndex,
+ count);
+}
+
+static const ClassSpec SharedArrayBufferObjectProtoClassSpec = {
+ DELEGATED_CLASSSPEC(SharedArrayBufferObject::class_.spec),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ ClassSpec::IsDelegated
+};
+
+static const Class SharedArrayBufferObjectProtoClass = {
+ "SharedArrayBufferPrototype",
+ JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
+ JS_NULL_CLASS_OPS,
+ &SharedArrayBufferObjectProtoClassSpec
+};
+
+static JSObject*
+CreateSharedArrayBufferPrototype(JSContext* cx, JSProtoKey key)
+{
+ return cx->global()->createBlankPrototype(cx, &SharedArrayBufferObjectProtoClass);
+}
+
+static const ClassOps SharedArrayBufferObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ SharedArrayBufferObject::Finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ nullptr, /* trace */
+};
+
+static const JSFunctionSpec static_functions[] = {
+ JS_FS_END
+};
+
+static const JSPropertySpec static_properties[] = {
+ JS_SELF_HOSTED_SYM_GET(species, "SharedArrayBufferSpecies", 0),
+ JS_PS_END
+};
+
+static const JSFunctionSpec prototype_functions[] = {
+ JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0),
+ JS_FS_END
+};
+
+static const JSPropertySpec prototype_properties[] = {
+ JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
+ JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
+ JS_PS_END
+};
+
+static const ClassSpec ArrayBufferObjectClassSpec = {
+ GenericCreateConstructor<SharedArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
+ CreateSharedArrayBufferPrototype,
+ static_functions,
+ static_properties,
+ prototype_functions,
+ prototype_properties
+};
+
+const Class SharedArrayBufferObject::class_ = {
+ "SharedArrayBuffer",
+ JSCLASS_DELAY_METADATA_BUILDER |
+ JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &SharedArrayBufferObjectClassOps,
+ &ArrayBufferObjectClassSpec,
+ JS_NULL_CLASS_EXT
+};
+
+bool
+js::IsSharedArrayBuffer(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<SharedArrayBufferObject>();
+}
+
+bool
+js::IsSharedArrayBuffer(HandleObject o)
+{
+ return o->is<SharedArrayBufferObject>();
+}
+
+bool
+js::IsSharedArrayBuffer(JSObject* o)
+{
+ return o->is<SharedArrayBufferObject>();
+}
+
+SharedArrayBufferObject&
+js::AsSharedArrayBuffer(HandleObject obj)
+{
+ MOZ_ASSERT(IsSharedArrayBuffer(obj));
+ return obj->as<SharedArrayBufferObject>();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetSharedArrayBufferByteLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->as<SharedArrayBufferObject>().byteLength() : 0;
+}
+
+JS_FRIEND_API(void)
+js::GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data)
+{
+ MOZ_ASSERT(obj->is<SharedArrayBufferObject>());
+ *length = obj->as<SharedArrayBufferObject>().byteLength();
+ *data = obj->as<SharedArrayBufferObject>().dataPointerShared().unwrap(/*safe - caller knows*/);
+ *isSharedMemory = true;
+}
+
+JS_FRIEND_API(JSObject*)
+JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes)
+{
+ MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
+
+ MOZ_ASSERT(nbytes <= INT32_MAX);
+ return SharedArrayBufferObject::New(cx, nbytes, /* proto = */ nullptr);
+}
+
+JS_FRIEND_API(bool)
+JS_IsSharedArrayBufferObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->is<SharedArrayBufferObject>() : false;
+}
+
+JS_FRIEND_API(uint8_t*)
+JS_GetSharedArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ *isSharedMemory = true;
+ return obj->as<SharedArrayBufferObject>().dataPointerShared().unwrap(/*safe - caller knows*/);
+}
diff --git a/js/src/vm/SharedArrayObject.h b/js/src/vm/SharedArrayObject.h
new file mode 100644
index 000000000..9aef6d74e
--- /dev/null
+++ b/js/src/vm/SharedArrayObject.h
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SharedArrayObject_h
+#define vm_SharedArrayObject_h
+
+#include "mozilla/Atomics.h"
+
+#include "jsapi.h"
+#include "jsobj.h"
+#include "jstypes.h"
+
+#include "gc/Barrier.h"
+#include "vm/ArrayBufferObject.h"
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+class FutexWaiter;
+
+/*
+ * SharedArrayRawBuffer
+ *
+ * A bookkeeping object always stored immediately before the raw buffer.
+ * The buffer itself is mmap()'d and refcounted.
+ * SharedArrayBufferObjects and AsmJS code may hold references.
+ *
+ * |<------ sizeof ------>|<- length ->|
+ *
+ * | waste | SharedArrayRawBuffer | data array | waste |
+ *
+ * Observe that if we want to map the data array on a specific address, such
+ * as absolute zero (bug 1056027), then the SharedArrayRawBuffer cannot be
+ * prefixed to the data array, it has to be a separate object, also in
+ * shared memory. (That would get rid of ~4KB of waste, as well.) Very little
+ * else would have to change throughout the engine, the SARB would point to
+ * the data array using a constant pointer, instead of computing its
+ * address.
+ */
+class SharedArrayRawBuffer
+{
+ private:
+ mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
+ uint32_t length;
+ bool preparedForAsmJS;
+
+ // A list of structures representing tasks waiting on some
+ // location within this buffer.
+ FutexWaiter* waiters_;
+
+ protected:
+ SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS)
+ : refcount_(1),
+ length(length),
+ preparedForAsmJS(preparedForAsmJS),
+ waiters_(nullptr)
+ {
+ MOZ_ASSERT(buffer == dataPointerShared());
+ }
+
+ public:
+ static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length);
+
+ // This may be called from multiple threads. The caller must take
+ // care of mutual exclusion.
+ FutexWaiter* waiters() const {
+ return waiters_;
+ }
+
+ // This may be called from multiple threads. The caller must take
+ // care of mutual exclusion.
+ void setWaiters(FutexWaiter* waiters) {
+ waiters_ = waiters;
+ }
+
+ SharedMem<uint8_t*> dataPointerShared() const {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(const_cast<SharedArrayRawBuffer*>(this));
+ return SharedMem<uint8_t*>::shared(ptr + sizeof(SharedArrayRawBuffer));
+ }
+
+ uint32_t byteLength() const {
+ return length;
+ }
+
+ bool isPreparedForAsmJS() const {
+ return preparedForAsmJS;
+ }
+
+ uint32_t refcount() const { return refcount_; }
+
+ void addReference();
+ void dropReference();
+};
+
+/*
+ * SharedArrayBufferObject
+ *
+ * When transferred to a WebWorker, the buffer is not detached on the
+ * parent side, and both child and parent reference the same buffer.
+ *
+ * The underlying memory is memory-mapped and reference counted
+ * (across workers and/or processes). The SharedArrayBuffer object
+ * has a finalizer that decrements the refcount, the last one to leave
+ * (globally) unmaps the memory. The sender ups the refcount before
+ * transmitting the memory to another worker.
+ *
+ * SharedArrayBufferObject (or really the underlying memory) /is
+ * racy/: more than one worker can access the memory at the same time.
+ *
+ * A TypedArrayObject (a view) references a SharedArrayBuffer
+ * and keeps it alive. The SharedArrayBuffer does /not/ reference its
+ * views.
+ */
+class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
+{
+ static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
+
+ public:
+ // RAWBUF_SLOT holds a pointer (as "private" data) to the
+ // SharedArrayRawBuffer object, which is manually managed storage.
+ static const uint8_t RAWBUF_SLOT = 0;
+
+ static const uint8_t RESERVED_SLOTS = 1;
+
+ static const Class class_;
+
+ static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
+
+ // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
+ static SharedArrayBufferObject* New(JSContext* cx,
+ uint32_t length,
+ HandleObject proto = nullptr);
+
+ // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
+ static SharedArrayBufferObject* New(JSContext* cx,
+ SharedArrayRawBuffer* buffer,
+ HandleObject proto = nullptr);
+
+ static void Finalize(FreeOp* fop, JSObject* obj);
+
+ static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
+ JS::ClassInfo* info);
+
+ static void copyData(Handle<SharedArrayBufferObject*> toBuffer,
+ Handle<SharedArrayBufferObject*> fromBuffer,
+ uint32_t fromIndex, uint32_t count);
+
+ SharedArrayRawBuffer* rawBufferObject() const;
+
+ // Invariant: This method does not cause GC and can be called
+ // without anchoring the object it is called on.
+ uintptr_t globalID() const {
+ // The buffer address is good enough as an ID provided the memory is not shared
+ // between processes or, if it is, it is mapped to the same address in every
+ // process. (At the moment, shared memory cannot be shared between processes.)
+ return dataPointerShared().asValue();
+ }
+
+ uint32_t byteLength() const {
+ return rawBufferObject()->byteLength();
+ }
+ bool isPreparedForAsmJS() const {
+ return rawBufferObject()->isPreparedForAsmJS();
+ }
+
+ SharedMem<uint8_t*> dataPointerShared() const {
+ return rawBufferObject()->dataPointerShared();
+ }
+
+private:
+ void acceptRawBuffer(SharedArrayRawBuffer* buffer);
+ void dropRawBuffer();
+};
+
+bool IsSharedArrayBuffer(HandleValue v);
+bool IsSharedArrayBuffer(HandleObject o);
+bool IsSharedArrayBuffer(JSObject* o);
+
+SharedArrayBufferObject& AsSharedArrayBuffer(HandleObject o);
+
+} // namespace js
+
+#endif // vm_SharedArrayObject_h
diff --git a/js/src/vm/SharedImmutableStringsCache-inl.h b/js/src/vm/SharedImmutableStringsCache-inl.h
new file mode 100644
index 000000000..6a6373c0a
--- /dev/null
+++ b/js/src/vm/SharedImmutableStringsCache-inl.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SharedImmutableStringsCache_inl_h
+#define vm_SharedImmutableStringsCache_inl_h
+
+#include "vm/SharedImmutableStringsCache.h"
+
+namespace js {
+
+template <typename IntoOwnedChars>
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+SharedImmutableStringsCache::getOrCreate(const char* chars, size_t length,
+ IntoOwnedChars intoOwnedChars)
+{
+ MOZ_ASSERT(inner_);
+ MOZ_ASSERT(chars);
+ Hasher::Lookup lookup(Hasher::hashLongString(chars, length), chars, length);
+
+ auto locked = inner_->lock();
+ if (!locked->set.initialized() && !locked->set.init())
+ return mozilla::Nothing();
+
+ auto entry = locked->set.lookupForAdd(lookup);
+ if (!entry) {
+ OwnedChars ownedChars(intoOwnedChars());
+ if (!ownedChars)
+ return mozilla::Nothing();
+ MOZ_ASSERT(ownedChars.get() == chars ||
+ memcmp(ownedChars.get(), chars, length) == 0);
+ auto box = StringBox::Create(mozilla::Move(ownedChars), length);
+ if (!box || !locked->set.add(entry, mozilla::Move(box)))
+ return mozilla::Nothing();
+ }
+
+ MOZ_ASSERT(entry && *entry);
+ return mozilla::Some(SharedImmutableString(locked, entry->get()));
+}
+
+template <typename IntoOwnedTwoByteChars>
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+SharedImmutableStringsCache::getOrCreate(const char16_t* chars, size_t length,
+ IntoOwnedTwoByteChars intoOwnedTwoByteChars) {
+ MOZ_ASSERT(inner_);
+ MOZ_ASSERT(chars);
+ auto hash = Hasher::hashLongString(reinterpret_cast<const char*>(chars),
+ length * sizeof(char16_t));
+ Hasher::Lookup lookup(hash, chars, length);
+
+ auto locked = inner_->lock();
+ if (!locked->set.initialized() && !locked->set.init())
+ return mozilla::Nothing();
+
+ auto entry = locked->set.lookupForAdd(lookup);
+ if (!entry) {
+ OwnedTwoByteChars ownedTwoByteChars(intoOwnedTwoByteChars());
+ if (!ownedTwoByteChars)
+ return mozilla::Nothing();
+ MOZ_ASSERT(ownedTwoByteChars.get() == chars ||
+ memcmp(ownedTwoByteChars.get(), chars, length * sizeof(char16_t)) == 0);
+ OwnedChars ownedChars(reinterpret_cast<char*>(ownedTwoByteChars.release()));
+ auto box = StringBox::Create(mozilla::Move(ownedChars), length * sizeof(char16_t));
+ if (!box || !locked->set.add(entry, mozilla::Move(box)))
+ return mozilla::Nothing();
+ }
+
+ MOZ_ASSERT(entry && *entry);
+ return mozilla::Some(SharedImmutableTwoByteString(locked, entry->get()));
+}
+
+} // namespace js
+
+#endif // vm_SharedImmutableStringsCache_inl_h
diff --git a/js/src/vm/SharedImmutableStringsCache.cpp b/js/src/vm/SharedImmutableStringsCache.cpp
new file mode 100644
index 000000000..84422810f
--- /dev/null
+++ b/js/src/vm/SharedImmutableStringsCache.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SharedImmutableStringsCache-inl.h"
+
+#include "jsstr.h"
+
+namespace js {
+
+SharedImmutableString::SharedImmutableString(
+ ExclusiveData<SharedImmutableStringsCache::Inner>::Guard& locked,
+ SharedImmutableStringsCache::StringBox* box)
+ : cache_(locked)
+ , box_(box)
+{
+ MOZ_ASSERT(box);
+ box->refcount++;
+}
+
+SharedImmutableString::SharedImmutableString(SharedImmutableString&& rhs)
+ : cache_(mozilla::Move(rhs.cache_))
+ , box_(rhs.box_)
+{
+ MOZ_ASSERT(this != &rhs, "self move not allowed");
+ MOZ_ASSERT(rhs.box_);
+ MOZ_ASSERT(rhs.box_->refcount > 0);
+
+ rhs.box_ = nullptr;
+}
+
+SharedImmutableString&
+SharedImmutableString::operator=(SharedImmutableString&& rhs) {
+ this->~SharedImmutableString();
+ new (this) SharedImmutableString(mozilla::Move(rhs));
+ return *this;
+}
+
+SharedImmutableTwoByteString::SharedImmutableTwoByteString(SharedImmutableString&& string)
+ : string_(mozilla::Move(string))
+{ }
+
+SharedImmutableTwoByteString::SharedImmutableTwoByteString(
+ ExclusiveData<SharedImmutableStringsCache::Inner>::Guard& locked,
+ SharedImmutableStringsCache::StringBox* box)
+ : string_(locked, box)
+{
+ MOZ_ASSERT(box->length() % sizeof(char16_t) == 0);
+}
+
+SharedImmutableTwoByteString::SharedImmutableTwoByteString(SharedImmutableTwoByteString&& rhs)
+ : string_(mozilla::Move(rhs.string_))
+{
+ MOZ_ASSERT(this != &rhs, "self move not allowed");
+}
+
+SharedImmutableTwoByteString&
+SharedImmutableTwoByteString::operator=(SharedImmutableTwoByteString&& rhs)
+{
+ this->~SharedImmutableTwoByteString();
+ new (this) SharedImmutableTwoByteString(mozilla::Move(rhs));
+ return *this;
+}
+
+SharedImmutableString::~SharedImmutableString() {
+ if (!box_)
+ return;
+
+ auto locked = cache_.inner_->lock();
+
+ MOZ_ASSERT(box_->refcount > 0);
+
+ box_->refcount--;
+ if (box_->refcount == 0)
+ box_->chars_.reset(nullptr);
+}
+
+SharedImmutableString
+SharedImmutableString::clone() const
+{
+ auto locked = cache_.inner_->lock();
+ MOZ_ASSERT(box_);
+ MOZ_ASSERT(box_->refcount > 0);
+ return SharedImmutableString(locked, box_);
+}
+
+SharedImmutableTwoByteString
+SharedImmutableTwoByteString::clone() const
+{
+ return SharedImmutableTwoByteString(string_.clone());
+}
+
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+SharedImmutableStringsCache::getOrCreate(OwnedChars&& chars, size_t length)
+{
+ OwnedChars owned(mozilla::Move(chars));
+ MOZ_ASSERT(owned);
+ return getOrCreate(owned.get(), length, [&]() { return mozilla::Move(owned); });
+}
+
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+SharedImmutableStringsCache::getOrCreate(const char* chars, size_t length)
+{
+ return getOrCreate(chars, length, [&]() { return DuplicateString(chars, length); });
+}
+
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+SharedImmutableStringsCache::getOrCreate(OwnedTwoByteChars&& chars, size_t length)
+{
+ OwnedTwoByteChars owned(mozilla::Move(chars));
+ MOZ_ASSERT(owned);
+ return getOrCreate(owned.get(), length, [&]() { return mozilla::Move(owned); });
+}
+
+MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+SharedImmutableStringsCache::getOrCreate(const char16_t* chars, size_t length)
+{
+ return getOrCreate(chars, length, [&]() { return DuplicateString(chars, length); });
+}
+
+} // namespace js
diff --git a/js/src/vm/SharedImmutableStringsCache.h b/js/src/vm/SharedImmutableStringsCache.h
new file mode 100644
index 000000000..ddb6ff87f
--- /dev/null
+++ b/js/src/vm/SharedImmutableStringsCache.h
@@ -0,0 +1,468 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SharedImmutableStringsCache_h
+#define vm_SharedImmutableStringsCache_h
+
+#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+
+#include <cstring>
+#include <new> // for placement new
+
+#include "jsstr.h"
+
+#include "js/HashTable.h"
+#include "js/Utility.h"
+
+#include "threading/ExclusiveData.h"
+
+#include "vm/MutexIDs.h"
+
+namespace js {
+
+class SharedImmutableString;
+class SharedImmutableTwoByteString;
+
+/**
+ * The `SharedImmutableStringsCache` allows for safely sharing and deduplicating
+ * immutable strings (either `const char*` or `const char16_t*`) between
+ * threads.
+ *
+ * The locking mechanism is dead-simple and coarse grained: a single lock guards
+ * all of the internal table itself, the table's entries, and the entries'
+ * reference counts. It is only safe to perform any mutation on the cache or any
+ * data stored within the cache when this lock is acquired.
+ */
+class SharedImmutableStringsCache
+{
+ friend class SharedImmutableString;
+ friend class SharedImmutableTwoByteString;
+ struct Hasher;
+
+ public:
+ using OwnedChars = mozilla::UniquePtr<char[], JS::FreePolicy>;
+ using OwnedTwoByteChars = mozilla::UniquePtr<char16_t[], JS::FreePolicy>;
+
+ /**
+ * Get the canonical, shared, and de-duplicated version of the given `const
+ * char*` string. If such a string does not exist, call `intoOwnedChars` and
+ * add the string it returns to the cache.
+ *
+ * `intoOwnedChars` must create an owned version of the given string, and
+ * must have one of the following types:
+ *
+ * mozilla::UniquePtr<char[], JS::FreePolicy> intoOwnedChars();
+ * mozilla::UniquePtr<char[], JS::FreePolicy>&& intoOwnedChars();
+ *
+ * It can be used by callers to elide a copy of the string when it is safe
+ * to give up ownership of the lookup string to the cache. It must return a
+ * `nullptr` on failure.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ template <typename IntoOwnedChars>
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+ getOrCreate(const char* chars, size_t length, IntoOwnedChars intoOwnedChars);
+
+ /**
+ * Take ownership of the given `chars` and return the canonical, shared and
+ * de-duplicated version.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+ getOrCreate(OwnedChars&& chars, size_t length);
+
+ /**
+ * Do not take ownership of the given `chars`. Return the canonical, shared
+ * and de-duplicated version. If there is no extant shared version of
+ * `chars`, make a copy and insert it into the cache.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableString>
+ getOrCreate(const char* chars, size_t length);
+
+ /**
+ * Get the canonical, shared, and de-duplicated version of the given `const
+ * char16_t*` string. If such a string does not exist, call `intoOwnedChars`
+ * and add the string it returns to the cache.
+ *
+ * `intoOwnedTwoByteChars` must create an owned version of the given string,
+ * and must have one of the following types:
+ *
+ * mozilla::UniquePtr<char16_t[], JS::FreePolicy> intoOwnedTwoByteChars();
+ * mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& intoOwnedTwoByteChars();
+ *
+ * It can be used by callers to elide a copy of the string when it is safe
+ * to give up ownership of the lookup string to the cache. It must return a
+ * `nullptr` on failure.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ template <typename IntoOwnedTwoByteChars>
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+ getOrCreate(const char16_t* chars, size_t length, IntoOwnedTwoByteChars intoOwnedTwoByteChars);
+
+ /**
+ * Take ownership of the given `chars` and return the canonical, shared and
+ * de-duplicated version.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+ getOrCreate(OwnedTwoByteChars&& chars, size_t length);
+
+ /**
+ * Do not take ownership of the given `chars`. Return the canonical, shared
+ * and de-duplicated version. If there is no extant shared version of
+ * `chars`, then make a copy and insert it into the cache.
+ *
+ * On success, `Some` is returned. In the case of OOM failure, `Nothing` is
+ * returned.
+ */
+ MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString>
+ getOrCreate(const char16_t* chars, size_t length);
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ MOZ_ASSERT(inner_);
+ size_t n = mallocSizeOf(inner_);
+
+ auto locked = inner_->lock();
+ if (!locked->set.initialized())
+ return n;
+
+ // Size of the table.
+ n += locked->set.sizeOfExcludingThis(mallocSizeOf);
+
+ // Sizes of the strings and their boxes.
+ for (auto r = locked->set.all(); !r.empty(); r.popFront()) {
+ n += mallocSizeOf(r.front().get());
+ if (const char* chars = r.front()->chars())
+ n += mallocSizeOf(chars);
+ }
+
+ return n;
+ }
+
+ /**
+ * Construct a new cache of shared, immutable strings. Returns
+ * `mozilla::Nothing` on out of memory failure.
+ */
+ static mozilla::Maybe<SharedImmutableStringsCache> Create() {
+ auto inner = js_new<ExclusiveData<Inner>>(mutexid::SharedImmutableStringsCache);
+ if (!inner)
+ return mozilla::Nothing();
+
+ auto locked = inner->lock();
+ return mozilla::Some(SharedImmutableStringsCache(locked));
+ }
+
+ SharedImmutableStringsCache(SharedImmutableStringsCache&& rhs)
+ : inner_(rhs.inner_)
+ {
+ MOZ_ASSERT(inner_);
+ rhs.inner_ = nullptr;
+ }
+
+ SharedImmutableStringsCache& operator=(SharedImmutableStringsCache&& rhs) {
+ MOZ_ASSERT(this != &rhs, "self move not allowed");
+ new (this) SharedImmutableStringsCache(mozilla::Move(rhs));
+ return *this;
+ }
+
+ SharedImmutableStringsCache& operator=(const SharedImmutableStringsCache&) = delete;
+
+ SharedImmutableStringsCache clone() {
+ MOZ_ASSERT(inner_);
+ auto locked = inner_->lock();
+ return SharedImmutableStringsCache(locked);
+ }
+
+ ~SharedImmutableStringsCache() {
+ if (!inner_)
+ return;
+
+ bool shouldDestroy = false;
+ {
+ // ~ExclusiveData takes the lock, so be sure to drop the lock before
+ // attempting to destroy the inner.
+ auto locked = inner_->lock();
+ MOZ_ASSERT(locked->refcount > 0);
+ locked->refcount--;
+ if (locked->refcount == 0)
+ shouldDestroy = true;
+ }
+ if (shouldDestroy)
+ js_delete(inner_);
+ }
+
+ /**
+ * Purge the cache of all refcount == 0 entries.
+ */
+ void purge() {
+ auto locked = inner_->lock();
+ MOZ_ASSERT(locked->refcount > 0);
+
+ if (!locked->set.initialized())
+ return;
+
+ for (Inner::Set::Enum e(locked->set); !e.empty(); e.popFront()) {
+ if (e.front()->refcount == 0) {
+ // The chars should be eagerly freed when refcount reaches zero.
+ MOZ_ASSERT(!e.front()->chars());
+ e.removeFront();
+ } else {
+ // The chars should exist as long as the refcount is non-zero.
+ MOZ_ASSERT(e.front()->chars());
+ }
+ }
+ }
+
+ private:
+ class StringBox
+ {
+ friend class SharedImmutableString;
+
+ OwnedChars chars_;
+ size_t length_;
+
+ public:
+ mutable size_t refcount;
+
+ using Ptr = mozilla::UniquePtr<StringBox, JS::DeletePolicy<StringBox>>;
+
+ StringBox(OwnedChars&& chars, size_t length)
+ : chars_(mozilla::Move(chars))
+ , length_(length)
+ , refcount(0)
+ {
+ MOZ_ASSERT(chars_);
+ }
+
+ static Ptr Create(OwnedChars&& chars, size_t length) {
+ return Ptr(js_new<StringBox>(mozilla::Move(chars), length));
+ }
+
+ StringBox(const StringBox&) = delete;
+ StringBox& operator=(const StringBox&) = delete;
+
+ ~StringBox() {
+ MOZ_RELEASE_ASSERT(refcount == 0,
+ "There are `SharedImmutable[TwoByte]String`s outliving their "
+ "associated cache! This always leads to use-after-free in the "
+ "`~SharedImmutableString` destructor!");
+ }
+
+ const char* chars() const { return chars_.get(); }
+ size_t length() const { return length_; }
+ };
+
+ struct Hasher
+ {
+ /**
+ * A structure used when querying for a `const char*` string in the cache.
+ */
+ class Lookup
+ {
+ friend struct Hasher;
+
+ HashNumber hash_;
+ const char* chars_;
+ size_t length_;
+
+ public:
+ Lookup(HashNumber hash, const char* chars, size_t length)
+ : hash_(hash)
+ , chars_(chars)
+ , length_(length)
+ {
+ MOZ_ASSERT(chars_);
+ MOZ_ASSERT(hash == Hasher::hashLongString(chars, length));
+ }
+
+ Lookup(HashNumber hash, const char16_t* chars, size_t length)
+ : Lookup(hash, reinterpret_cast<const char*>(chars), length * sizeof(char16_t))
+ { }
+ };
+
+ static const size_t SHORT_STRING_MAX_LENGTH = 8192;
+ static const size_t HASH_CHUNK_LENGTH = SHORT_STRING_MAX_LENGTH / 2;
+
+ // For strings longer than SHORT_STRING_MAX_LENGTH, we only hash the
+ // first HASH_CHUNK_LENGTH and last HASH_CHUNK_LENGTH characters in the
+ // string. This increases the risk of collisions, but in practice it
+ // should be rare, and it yields a large speedup for hashing long
+ // strings.
+ static HashNumber hashLongString(const char* chars, size_t length) {
+ MOZ_ASSERT(chars);
+ return length <= SHORT_STRING_MAX_LENGTH
+ ? mozilla::HashString(chars, length)
+ : mozilla::AddToHash(mozilla::HashString(chars, HASH_CHUNK_LENGTH),
+ mozilla::HashString(chars + length - HASH_CHUNK_LENGTH,
+ HASH_CHUNK_LENGTH));
+ }
+
+ static HashNumber hash(const Lookup& lookup) {
+ return lookup.hash_;
+ }
+
+ static bool match(const StringBox::Ptr& key, const Lookup& lookup) {
+ MOZ_ASSERT(lookup.chars_);
+
+ if (!key->chars() || key->length() != lookup.length_)
+ return false;
+
+ if (key->chars() == lookup.chars_)
+ return true;
+
+ return memcmp(key->chars(), lookup.chars_, key->length()) == 0;
+ }
+ };
+
+ // The `Inner` struct contains the actual cached contents, and is reference
+ // counted and shared between all `SharedImmutableStringsCache` and
+ // `SharedImmutable[TwoByte]String` holders.
+ struct Inner
+ {
+ using Set = HashSet<StringBox::Ptr, Hasher, SystemAllocPolicy>;
+
+ size_t refcount;
+ Set set;
+
+ Inner()
+ : refcount(0)
+ , set()
+ { }
+
+ Inner(const Inner&) = delete;
+ Inner& operator=(const Inner&) = delete;
+
+ ~Inner()
+ {
+ MOZ_ASSERT(refcount == 0);
+ }
+ };
+
+ const ExclusiveData<Inner>* inner_;
+
+ explicit SharedImmutableStringsCache(ExclusiveData<Inner>::Guard& locked)
+ : inner_(locked.parent())
+ {
+ locked->refcount++;
+ }
+};
+
+/**
+ * The `SharedImmutableString` class holds a reference to a `const char*` string
+ * from the `SharedImmutableStringsCache` and releases the reference upon
+ * destruction.
+ */
+class SharedImmutableString
+{
+ friend class SharedImmutableStringsCache;
+ friend class SharedImmutableTwoByteString;
+
+ mutable SharedImmutableStringsCache cache_;
+ mutable SharedImmutableStringsCache::StringBox* box_;
+
+ SharedImmutableString(ExclusiveData<SharedImmutableStringsCache::Inner>::Guard& locked,
+ SharedImmutableStringsCache::StringBox* box);
+
+ public:
+ /**
+ * `SharedImmutableString`s are move-able. It is an error to use a
+ * `SharedImmutableString` after it has been moved.
+ */
+ SharedImmutableString(SharedImmutableString&& rhs);
+ SharedImmutableString& operator=(SharedImmutableString&& rhs);
+
+ /**
+ * Create another shared reference to the underlying string.
+ */
+ SharedImmutableString clone() const;
+
+ // If you want a copy, take one explicitly with `clone`!
+ SharedImmutableString& operator=(const SharedImmutableString&) = delete;
+
+ ~SharedImmutableString();
+
+ /**
+ * Get a raw pointer to the underlying string. It is only safe to use the
+ * resulting pointer while this `SharedImmutableString` exists.
+ */
+ const char* chars() const {
+ MOZ_ASSERT(box_);
+ MOZ_ASSERT(box_->refcount > 0);
+ MOZ_ASSERT(box_->chars());
+ return box_->chars();
+ }
+
+ /**
+ * Get the length of the underlying string.
+ */
+ size_t length() const {
+ MOZ_ASSERT(box_);
+ MOZ_ASSERT(box_->refcount > 0);
+ MOZ_ASSERT(box_->chars());
+ return box_->length();
+ }
+};
+
+/**
+ * The `SharedImmutableTwoByteString` class holds a reference to a `const
+ * char16_t*` string from the `SharedImmutableStringsCache` and releases the
+ * reference upon destruction.
+ */
+class SharedImmutableTwoByteString
+{
+ friend class SharedImmutableStringsCache;
+
+ // If a `char*` string and `char16_t*` string happen to have the same bytes,
+ // the bytes will be shared but handed out as different types.
+ SharedImmutableString string_;
+
+ explicit SharedImmutableTwoByteString(SharedImmutableString&& string);
+ SharedImmutableTwoByteString(ExclusiveData<SharedImmutableStringsCache::Inner>::Guard& locked,
+ SharedImmutableStringsCache::StringBox* box);
+
+ public:
+ /**
+ * `SharedImmutableTwoByteString`s are move-able. It is an error to use a
+ * `SharedImmutableTwoByteString` after it has been moved.
+ */
+ SharedImmutableTwoByteString(SharedImmutableTwoByteString&& rhs);
+ SharedImmutableTwoByteString& operator=(SharedImmutableTwoByteString&& rhs);
+
+ /**
+ * Create another shared reference to the underlying string.
+ */
+ SharedImmutableTwoByteString clone() const;
+
+ // If you want a copy, take one explicitly with `clone`!
+ SharedImmutableTwoByteString& operator=(const SharedImmutableTwoByteString&) = delete;
+
+ /**
+ * Get a raw pointer to the underlying string. It is only safe to use the
+ * resulting pointer while this `SharedImmutableTwoByteString` exists.
+ */
+ const char16_t* chars() const { return reinterpret_cast<const char16_t*>(string_.chars()); }
+
+ /**
+ * Get the length of the underlying string.
+ */
+ size_t length() const { return string_.length() / sizeof(char16_t); }
+};
+
+} // namespace js
+
+#endif // vm_SharedImmutableStringsCache_h
diff --git a/js/src/vm/SharedMem.h b/js/src/vm/SharedMem.h
new file mode 100644
index 000000000..f30bf99e8
--- /dev/null
+++ b/js/src/vm/SharedMem.h
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SharedMem_h
+#define vm_SharedMem_h
+
+#include "mozilla/TypeTraits.h"
+
+template<typename T>
+class SharedMem
+{
+ static_assert(mozilla::IsPointer<T>::value,
+ "SharedMem encapsulates pointer types");
+
+ enum Sharedness {
+ IsUnshared,
+ IsShared
+ };
+
+ T ptr_;
+#ifdef DEBUG
+ Sharedness sharedness_;
+#endif
+
+ SharedMem(T ptr, Sharedness sharedness)
+ : ptr_(ptr)
+#ifdef DEBUG
+ , sharedness_(sharedness)
+#endif
+ {}
+
+ public:
+ // Create a SharedMem<T> that is an unshared nullptr.
+ SharedMem()
+ : ptr_(nullptr)
+#ifdef DEBUG
+ , sharedness_(IsUnshared)
+#endif
+ {}
+
+ // Create a SharedMem<T> that's shared/unshared in the same way as
+ // "forSharedness".
+ SharedMem(T ptr, const SharedMem& forSharedness)
+ : ptr_(ptr)
+#ifdef DEBUG
+ , sharedness_(forSharedness.sharedness_)
+#endif
+ {}
+
+ // Create a SharedMem<T> that's marked as shared.
+ static SharedMem shared(void* p) {
+ return SharedMem(static_cast<T>(p), IsShared);
+ }
+
+ // Create a SharedMem<T> that's marked as unshared.
+ static SharedMem unshared(void* p) {
+ return SharedMem(static_cast<T>(p), IsUnshared);
+ }
+
+ SharedMem& operator =(const SharedMem& that) {
+ ptr_ = that.ptr_;
+#ifdef DEBUG
+ sharedness_ = that.sharedness_;
+#endif
+ return *this;
+ }
+
+ // Reinterpret-cast the pointer to type U, preserving sharedness.
+ template<typename U>
+ inline SharedMem<U> cast() const {
+#ifdef DEBUG
+ MOZ_ASSERT(asValue() % sizeof(mozilla::Conditional<mozilla::IsVoid<typename mozilla::RemovePointer<U>::Type>::value,
+ char,
+ typename mozilla::RemovePointer<U>::Type>) == 0);
+ if (sharedness_ == IsUnshared)
+ return SharedMem<U>::unshared(unwrap());
+#endif
+ return SharedMem<U>::shared(unwrap());
+ }
+
+ explicit operator bool() { return ptr_ != nullptr; }
+
+ SharedMem operator +(size_t offset) {
+ return SharedMem(ptr_ + offset, *this);
+ }
+
+ SharedMem operator -(size_t offset) {
+ return SharedMem(ptr_ - offset, *this);
+ }
+
+ SharedMem operator ++() {
+ ptr_++;
+ return *this;
+ }
+
+ SharedMem operator ++(int) {
+ SharedMem<T> result(*this);
+ ptr_++;
+ return result;
+ }
+
+ SharedMem operator --() {
+ ptr_--;
+ return *this;
+ }
+
+ SharedMem operator --(int) {
+ SharedMem<T> result(*this);
+ ptr_--;
+ return result;
+ }
+
+ uintptr_t asValue() const {
+ return reinterpret_cast<uintptr_t>(ptr_);
+ }
+
+ // Cast to char*, add nbytes, and cast back to T. Simplifies code in a few places.
+ SharedMem addBytes(size_t nbytes) {
+ MOZ_ASSERT(nbytes % sizeof(mozilla::Conditional<mozilla::IsVoid<typename mozilla::RemovePointer<T>::Type>::value,
+ char,
+ typename mozilla::RemovePointer<T>::Type>) == 0);
+ return SharedMem(reinterpret_cast<T>(reinterpret_cast<char*>(ptr_) + nbytes), *this);
+ }
+
+ T unwrap() const {
+ return ptr_;
+ }
+
+ T unwrapUnshared() const {
+ MOZ_ASSERT(sharedness_ == IsUnshared);
+ return ptr_;
+ }
+
+ uintptr_t unwrapValue() const {
+ return reinterpret_cast<uintptr_t>(ptr_);
+ }
+};
+
+template<typename T>
+inline bool
+operator >=(const SharedMem<T>& a, const SharedMem<T>& b)
+{
+ return a.unwrap() >= b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator >=(const void* a, const SharedMem<T>& b)
+{
+ return a >= b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator ==(const void* a, const SharedMem<T>& b)
+{
+ return a == b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator ==(const SharedMem<T>& a, decltype(nullptr) b)
+{
+ return a.unwrap() == b;
+}
+
+template<typename T>
+inline bool
+operator ==(const SharedMem<T>& a, const SharedMem<T>& b)
+{
+ return a.unwrap() == b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator !=(const SharedMem<T>& a, decltype(nullptr) b)
+{
+ return a.unwrap() != b;
+}
+
+template<typename T>
+inline bool
+operator !=(const SharedMem<T>& a, const SharedMem<T>& b)
+{
+ return a.unwrap() != b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator >(const SharedMem<T>& a, const SharedMem<T>& b)
+{
+ return a.unwrap() > b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator >(const void* a, const SharedMem<T>& b)
+{
+ return a > b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator <=(const SharedMem<T>& a, const SharedMem<T>& b)
+{
+ return a.unwrap() <= b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator <=(const void* a, const SharedMem<T>& b)
+{
+ return a <= b.unwrap();
+}
+
+template<typename T>
+inline bool
+operator <(const void* a, const SharedMem<T>& b)
+{
+ return a < b.unwrap();
+}
+
+#endif // vm_SharedMem_h
diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h
new file mode 100644
index 000000000..a51c0aa14
--- /dev/null
+++ b/js/src/vm/Stack-inl.h
@@ -0,0 +1,998 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Stack_inl_h
+#define vm_Stack_inl_h
+
+#include "vm/Stack.h"
+
+#include "mozilla/PodOperations.h"
+
+#include "jscntxt.h"
+#include "jsscript.h"
+
+#include "jit/BaselineFrame.h"
+#include "jit/RematerializedFrame.h"
+#include "js/Debug.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/GeneratorObject.h"
+
+#include "jsobjinlines.h"
+#include "jsscriptinlines.h"
+
+#include "jit/BaselineFrame-inl.h"
+
+namespace js {
+
+/*
+ * We cache name lookup results only for the global object or for native
+ * non-global objects without prototype or with prototype that never mutates,
+ * see bug 462734 and bug 487039.
+ */
+static inline bool
+IsCacheableEnvironment(JSObject* obj)
+{
+ bool cacheable = obj->is<CallObject>() || obj->is<LexicalEnvironmentObject>();
+
+ MOZ_ASSERT_IF(cacheable, !obj->getOpsLookupProperty());
+ return cacheable;
+}
+
+inline HandleObject
+InterpreterFrame::environmentChain() const
+{
+ return HandleObject::fromMarkedLocation(&envChain_);
+}
+
+inline GlobalObject&
+InterpreterFrame::global() const
+{
+ return environmentChain()->global();
+}
+
+inline JSObject&
+InterpreterFrame::varObj() const
+{
+ JSObject* obj = environmentChain();
+ while (!obj->isQualifiedVarObj())
+ obj = obj->enclosingEnvironment();
+ return *obj;
+}
+
+inline LexicalEnvironmentObject&
+InterpreterFrame::extensibleLexicalEnvironment() const
+{
+ return NearestEnclosingExtensibleLexicalEnvironment(environmentChain());
+}
+
+inline void
+InterpreterFrame::initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc,
+ Value* prevsp, JSFunction& callee, JSScript* script, Value* argv,
+ uint32_t nactual, MaybeConstruct constructing)
+{
+ MOZ_ASSERT(callee.nonLazyScript() == script);
+
+ /* Initialize stack frame members. */
+ flags_ = 0;
+ if (constructing)
+ flags_ |= CONSTRUCTING;
+ argv_ = argv;
+ script_ = script;
+ nactual_ = nactual;
+ envChain_ = callee.environment();
+ prev_ = prev;
+ prevpc_ = prevpc;
+ prevsp_ = prevsp;
+
+ if (script->isDebuggee())
+ setIsDebuggee();
+
+ initLocals();
+}
+
+inline void
+InterpreterFrame::initLocals()
+{
+ SetValueRangeToUndefined(slots(), script()->nfixed());
+}
+
+inline Value&
+InterpreterFrame::unaliasedLocal(uint32_t i)
+{
+ MOZ_ASSERT(i < script()->nfixed());
+ return slots()[i];
+}
+
+inline Value&
+InterpreterFrame::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
+{
+ MOZ_ASSERT(i < numFormalArgs());
+ MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
+ MOZ_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i));
+ return argv()[i];
+}
+
+inline Value&
+InterpreterFrame::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing)
+{
+ MOZ_ASSERT(i < numActualArgs());
+ MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
+ MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
+ return argv()[i];
+}
+
+template <class Op>
+inline void
+InterpreterFrame::unaliasedForEachActual(Op op)
+{
+ // Don't assert !script()->funHasAnyAliasedFormal() since this function is
+ // called from ArgumentsObject::createUnexpected() which can access aliased
+ // slots.
+
+ const Value* argsEnd = argv() + numActualArgs();
+ for (const Value* p = argv(); p < argsEnd; ++p)
+ op(*p);
+}
+
+struct CopyTo
+{
+ Value* dst;
+ explicit CopyTo(Value* dst) : dst(dst) {}
+ void operator()(const Value& src) { *dst++ = src; }
+};
+
+struct CopyToHeap
+{
+ GCPtrValue* dst;
+ explicit CopyToHeap(GCPtrValue* dst) : dst(dst) {}
+ void operator()(const Value& src) { dst->init(src); ++dst; }
+};
+
+inline ArgumentsObject&
+InterpreterFrame::argsObj() const
+{
+ MOZ_ASSERT(script()->needsArgsObj());
+ MOZ_ASSERT(flags_ & HAS_ARGS_OBJ);
+ return *argsObj_;
+}
+
+inline void
+InterpreterFrame::initArgsObj(ArgumentsObject& argsobj)
+{
+ MOZ_ASSERT(script()->needsArgsObj());
+ flags_ |= HAS_ARGS_OBJ;
+ argsObj_ = &argsobj;
+}
+
+inline EnvironmentObject&
+InterpreterFrame::aliasedEnvironment(EnvironmentCoordinate ec) const
+{
+ JSObject* env = &environmentChain()->as<EnvironmentObject>();
+ for (unsigned i = ec.hops(); i; i--)
+ env = &env->as<EnvironmentObject>().enclosingEnvironment();
+ return env->as<EnvironmentObject>();
+}
+
+template <typename SpecificEnvironment>
+inline void
+InterpreterFrame::pushOnEnvironmentChain(SpecificEnvironment& env)
+{
+ MOZ_ASSERT(*environmentChain() == env.enclosingEnvironment());
+ envChain_ = &env;
+ if (IsFrameInitialEnvironment(this, env))
+ flags_ |= HAS_INITIAL_ENV;
+}
+
+template <typename SpecificEnvironment>
+inline void
+InterpreterFrame::popOffEnvironmentChain()
+{
+ MOZ_ASSERT(envChain_->is<SpecificEnvironment>());
+ envChain_ = &envChain_->as<SpecificEnvironment>().enclosingEnvironment();
+}
+
+inline void
+InterpreterFrame::replaceInnermostEnvironment(EnvironmentObject& env)
+{
+ MOZ_ASSERT(env.enclosingEnvironment() ==
+ envChain_->as<EnvironmentObject>().enclosingEnvironment());
+ envChain_ = &env;
+}
+
+bool
+InterpreterFrame::hasInitialEnvironment() const
+{
+ MOZ_ASSERT(script()->initialEnvironmentShape());
+ return flags_ & HAS_INITIAL_ENV;
+}
+
+inline CallObject&
+InterpreterFrame::callObj() const
+{
+ MOZ_ASSERT(callee().needsCallObject());
+
+ JSObject* pobj = environmentChain();
+ while (MOZ_UNLIKELY(!pobj->is<CallObject>()))
+ pobj = pobj->enclosingEnvironment();
+ return pobj->as<CallObject>();
+}
+
+inline void
+InterpreterFrame::unsetIsDebuggee()
+{
+ MOZ_ASSERT(!script()->isDebuggee());
+ flags_ &= ~DEBUGGEE;
+}
+
+/*****************************************************************************/
+
+inline void
+InterpreterStack::purge(JSRuntime* rt)
+{
+ rt->gc.freeUnusedLifoBlocksAfterSweeping(&allocator_);
+}
+
+uint8_t*
+InterpreterStack::allocateFrame(JSContext* cx, size_t size)
+{
+ size_t maxFrames;
+ if (cx->compartment()->principals() == cx->runtime()->trustedPrincipals())
+ maxFrames = MAX_FRAMES_TRUSTED;
+ else
+ maxFrames = MAX_FRAMES;
+
+ if (MOZ_UNLIKELY(frameCount_ >= maxFrames)) {
+ ReportOverRecursed(cx);
+ return nullptr;
+ }
+
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(allocator_.alloc(size));
+ if (!buffer) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ frameCount_++;
+ return buffer;
+}
+
+MOZ_ALWAYS_INLINE InterpreterFrame*
+InterpreterStack::getCallFrame(JSContext* cx, const CallArgs& args, HandleScript script,
+ MaybeConstruct constructing, Value** pargv)
+{
+ JSFunction* fun = &args.callee().as<JSFunction>();
+
+ MOZ_ASSERT(fun->nonLazyScript() == script);
+ unsigned nformal = fun->nargs();
+ unsigned nvals = script->nslots();
+
+ if (args.length() >= nformal) {
+ *pargv = args.array();
+ uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
+ return reinterpret_cast<InterpreterFrame*>(buffer);
+ }
+
+ // Pad any missing arguments with |undefined|.
+ MOZ_ASSERT(args.length() < nformal);
+
+ unsigned nfunctionState = 2 + constructing; // callee, |this|, |new.target|
+
+ nvals += nformal + nfunctionState;
+ uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
+ if (!buffer)
+ return nullptr;
+
+ Value* argv = reinterpret_cast<Value*>(buffer);
+ unsigned nmissing = nformal - args.length();
+
+ mozilla::PodCopy(argv, args.base(), 2 + args.length());
+ SetValueRangeToUndefined(argv + 2 + args.length(), nmissing);
+
+ if (constructing)
+ argv[2 + nformal] = args.newTarget();
+
+ *pargv = argv + 2;
+ return reinterpret_cast<InterpreterFrame*>(argv + nfunctionState + nformal);
+}
+
+MOZ_ALWAYS_INLINE bool
+InterpreterStack::pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
+ HandleScript script, MaybeConstruct constructing)
+{
+ RootedFunction callee(cx, &args.callee().as<JSFunction>());
+ MOZ_ASSERT(regs.sp == args.end());
+ MOZ_ASSERT(callee->nonLazyScript() == script);
+
+ script->ensureNonLazyCanonicalFunction(cx);
+
+ InterpreterFrame* prev = regs.fp();
+ jsbytecode* prevpc = regs.pc;
+ Value* prevsp = regs.sp;
+ MOZ_ASSERT(prev);
+
+ LifoAlloc::Mark mark = allocator_.mark();
+
+ Value* argv;
+ InterpreterFrame* fp = getCallFrame(cx, args, script, constructing, &argv);
+ if (!fp)
+ return false;
+
+ fp->mark_ = mark;
+
+ /* Initialize frame, locals, regs. */
+ fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, args.length(),
+ constructing);
+
+ regs.prepareToRun(*fp, script);
+ return true;
+}
+
+MOZ_ALWAYS_INLINE bool
+InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
+ HandleFunction callee, HandleValue newTarget,
+ HandleObject envChain)
+{
+ MOZ_ASSERT(callee->isGenerator());
+ RootedScript script(cx, callee->getOrCreateScript(cx));
+ InterpreterFrame* prev = regs.fp();
+ jsbytecode* prevpc = regs.pc;
+ Value* prevsp = regs.sp;
+ MOZ_ASSERT(prev);
+
+ script->ensureNonLazyCanonicalFunction(cx);
+
+ LifoAlloc::Mark mark = allocator_.mark();
+
+ MaybeConstruct constructing = MaybeConstruct(newTarget.isObject());
+
+ // Include callee, |this|, and maybe |new.target|
+ unsigned nformal = callee->nargs();
+ unsigned nvals = 2 + constructing + nformal + script->nslots();
+
+ uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
+ if (!buffer)
+ return false;
+
+ Value* argv = reinterpret_cast<Value*>(buffer) + 2;
+ argv[-2] = ObjectValue(*callee);
+ argv[-1] = UndefinedValue();
+ SetValueRangeToUndefined(argv, nformal);
+ if (constructing)
+ argv[nformal] = newTarget;
+
+ InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(argv + nformal + constructing);
+ fp->mark_ = mark;
+ fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, 0, constructing);
+ fp->resumeGeneratorFrame(envChain);
+
+ regs.prepareToRun(*fp, script);
+ return true;
+}
+
+MOZ_ALWAYS_INLINE void
+InterpreterStack::popInlineFrame(InterpreterRegs& regs)
+{
+ InterpreterFrame* fp = regs.fp();
+ regs.popInlineFrame();
+ regs.sp[-1] = fp->returnValue();
+ releaseFrame(fp);
+ MOZ_ASSERT(regs.fp());
+}
+
+template <class Op>
+inline void
+FrameIter::unaliasedForEachActual(JSContext* cx, Op op)
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ interpFrame()->unaliasedForEachActual(op);
+ return;
+ case JIT:
+ if (data_.jitFrames_.isIonJS()) {
+ jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
+ ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover);
+ } else if (data_.jitFrames_.isBailoutJS()) {
+ // :TODO: (Bug 1070962) If we are introspecting the frame which is
+ // being bailed, then we might be in the middle of recovering
+ // instructions. Stacking computeInstructionResults implies that we
+ // might be recovering result twice. In the mean time, to avoid
+ // that, we just return Undefined values for instruction results
+ // which are not yet recovered.
+ jit::MaybeReadFallback fallback;
+ ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback);
+ } else {
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);
+ }
+ return;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+inline HandleValue
+AbstractFramePtr::returnValue() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->returnValue();
+ return asBaselineFrame()->returnValue();
+}
+
+inline void
+AbstractFramePtr::setReturnValue(const Value& rval) const
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->setReturnValue(rval);
+ return;
+ }
+ if (isBaselineFrame()) {
+ asBaselineFrame()->setReturnValue(rval);
+ return;
+ }
+ asRematerializedFrame()->setReturnValue(rval);
+}
+
+inline JSObject*
+AbstractFramePtr::environmentChain() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->environmentChain();
+ if (isBaselineFrame())
+ return asBaselineFrame()->environmentChain();
+ return asRematerializedFrame()->environmentChain();
+}
+
+template <typename SpecificEnvironment>
+inline void
+AbstractFramePtr::pushOnEnvironmentChain(SpecificEnvironment& env)
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->pushOnEnvironmentChain(env);
+ return;
+ }
+ if (isBaselineFrame()) {
+ asBaselineFrame()->pushOnEnvironmentChain(env);
+ return;
+ }
+ asRematerializedFrame()->pushOnEnvironmentChain(env);
+}
+
+template <typename SpecificEnvironment>
+inline void
+AbstractFramePtr::popOffEnvironmentChain()
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->popOffEnvironmentChain<SpecificEnvironment>();
+ return;
+ }
+ if (isBaselineFrame()) {
+ asBaselineFrame()->popOffEnvironmentChain<SpecificEnvironment>();
+ return;
+ }
+ asRematerializedFrame()->popOffEnvironmentChain<SpecificEnvironment>();
+}
+
+inline CallObject&
+AbstractFramePtr::callObj() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->callObj();
+ if (isBaselineFrame())
+ return asBaselineFrame()->callObj();
+ return asRematerializedFrame()->callObj();
+}
+
+inline bool
+AbstractFramePtr::initFunctionEnvironmentObjects(JSContext* cx)
+{
+ return js::InitFunctionEnvironmentObjects(cx, *this);
+}
+
+inline bool
+AbstractFramePtr::pushVarEnvironment(JSContext* cx, HandleScope scope)
+{
+ return js::PushVarEnvironmentObject(cx, scope, *this);
+}
+
+inline JSCompartment*
+AbstractFramePtr::compartment() const
+{
+ return environmentChain()->compartment();
+}
+
+inline unsigned
+AbstractFramePtr::numActualArgs() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->numActualArgs();
+ if (isBaselineFrame())
+ return asBaselineFrame()->numActualArgs();
+ return asRematerializedFrame()->numActualArgs();
+}
+
+inline unsigned
+AbstractFramePtr::numFormalArgs() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->numFormalArgs();
+ if (isBaselineFrame())
+ return asBaselineFrame()->numFormalArgs();
+ return asRematerializedFrame()->numFormalArgs();
+}
+
+inline Value&
+AbstractFramePtr::unaliasedLocal(uint32_t i)
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->unaliasedLocal(i);
+ if (isBaselineFrame())
+ return asBaselineFrame()->unaliasedLocal(i);
+ return asRematerializedFrame()->unaliasedLocal(i);
+}
+
+inline Value&
+AbstractFramePtr::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->unaliasedFormal(i, checkAliasing);
+ if (isBaselineFrame())
+ return asBaselineFrame()->unaliasedFormal(i, checkAliasing);
+ return asRematerializedFrame()->unaliasedFormal(i, checkAliasing);
+}
+
+inline Value&
+AbstractFramePtr::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing)
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->unaliasedActual(i, checkAliasing);
+ if (isBaselineFrame())
+ return asBaselineFrame()->unaliasedActual(i, checkAliasing);
+ return asRematerializedFrame()->unaliasedActual(i, checkAliasing);
+}
+
+inline bool
+AbstractFramePtr::hasInitialEnvironment() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->hasInitialEnvironment();
+ if (isBaselineFrame())
+ return asBaselineFrame()->hasInitialEnvironment();
+ return asRematerializedFrame()->hasInitialEnvironment();
+}
+
+inline bool
+AbstractFramePtr::createSingleton() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->createSingleton();
+ return false;
+}
+
+inline bool
+AbstractFramePtr::isGlobalFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isGlobalFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isGlobalFrame();
+ return asRematerializedFrame()->isGlobalFrame();
+}
+
+inline bool
+AbstractFramePtr::isModuleFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isModuleFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isModuleFrame();
+ return asRematerializedFrame()->isModuleFrame();
+}
+
+inline bool
+AbstractFramePtr::isEvalFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isEvalFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isEvalFrame();
+ MOZ_ASSERT(isRematerializedFrame());
+ return false;
+}
+
+inline bool
+AbstractFramePtr::isDebuggerEvalFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isDebuggerEvalFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isDebuggerEvalFrame();
+ MOZ_ASSERT(isRematerializedFrame());
+ return false;
+}
+
+inline bool
+AbstractFramePtr::hasCachedSavedFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->hasCachedSavedFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->hasCachedSavedFrame();
+ return asRematerializedFrame()->hasCachedSavedFrame();
+}
+
+inline void
+AbstractFramePtr::setHasCachedSavedFrame()
+{
+ if (isInterpreterFrame())
+ asInterpreterFrame()->setHasCachedSavedFrame();
+ else if (isBaselineFrame())
+ asBaselineFrame()->setHasCachedSavedFrame();
+ else
+ asRematerializedFrame()->setHasCachedSavedFrame();
+}
+
+inline bool
+AbstractFramePtr::isDebuggee() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isDebuggee();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isDebuggee();
+ return asRematerializedFrame()->isDebuggee();
+}
+
+inline void
+AbstractFramePtr::setIsDebuggee()
+{
+ if (isInterpreterFrame())
+ asInterpreterFrame()->setIsDebuggee();
+ else if (isBaselineFrame())
+ asBaselineFrame()->setIsDebuggee();
+ else
+ asRematerializedFrame()->setIsDebuggee();
+}
+
+inline void
+AbstractFramePtr::unsetIsDebuggee()
+{
+ if (isInterpreterFrame())
+ asInterpreterFrame()->unsetIsDebuggee();
+ else if (isBaselineFrame())
+ asBaselineFrame()->unsetIsDebuggee();
+ else
+ asRematerializedFrame()->unsetIsDebuggee();
+}
+
+inline bool
+AbstractFramePtr::hasArgs() const {
+ return isFunctionFrame();
+}
+
+inline JSScript*
+AbstractFramePtr::script() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->script();
+ if (isBaselineFrame())
+ return asBaselineFrame()->script();
+ return asRematerializedFrame()->script();
+}
+
+inline JSFunction*
+AbstractFramePtr::callee() const
+{
+ if (isInterpreterFrame())
+ return &asInterpreterFrame()->callee();
+ if (isBaselineFrame())
+ return asBaselineFrame()->callee();
+ return asRematerializedFrame()->callee();
+}
+
+inline Value
+AbstractFramePtr::calleev() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->calleev();
+ if (isBaselineFrame())
+ return asBaselineFrame()->calleev();
+ return asRematerializedFrame()->calleev();
+}
+
+inline bool
+AbstractFramePtr::isFunctionFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isFunctionFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isFunctionFrame();
+ return asRematerializedFrame()->isFunctionFrame();
+}
+
+inline bool
+AbstractFramePtr::isNonStrictDirectEvalFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isNonStrictDirectEvalFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isNonStrictDirectEvalFrame();
+ MOZ_ASSERT(isRematerializedFrame());
+ return false;
+}
+
+inline bool
+AbstractFramePtr::isStrictEvalFrame() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->isStrictEvalFrame();
+ if (isBaselineFrame())
+ return asBaselineFrame()->isStrictEvalFrame();
+ MOZ_ASSERT(isRematerializedFrame());
+ return false;
+}
+
+inline Value*
+AbstractFramePtr::argv() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->argv();
+ if (isBaselineFrame())
+ return asBaselineFrame()->argv();
+ return asRematerializedFrame()->argv();
+}
+
+inline bool
+AbstractFramePtr::hasArgsObj() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->hasArgsObj();
+ if (isBaselineFrame())
+ return asBaselineFrame()->hasArgsObj();
+ return asRematerializedFrame()->hasArgsObj();
+}
+
+inline ArgumentsObject&
+AbstractFramePtr::argsObj() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->argsObj();
+ if (isBaselineFrame())
+ return asBaselineFrame()->argsObj();
+ return asRematerializedFrame()->argsObj();
+}
+
+inline void
+AbstractFramePtr::initArgsObj(ArgumentsObject& argsobj) const
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->initArgsObj(argsobj);
+ return;
+ }
+ asBaselineFrame()->initArgsObj(argsobj);
+}
+
+inline bool
+AbstractFramePtr::prevUpToDate() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->prevUpToDate();
+ if (isBaselineFrame())
+ return asBaselineFrame()->prevUpToDate();
+ return asRematerializedFrame()->prevUpToDate();
+}
+
+inline void
+AbstractFramePtr::setPrevUpToDate() const
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->setPrevUpToDate();
+ return;
+ }
+ if (isBaselineFrame()) {
+ asBaselineFrame()->setPrevUpToDate();
+ return;
+ }
+ asRematerializedFrame()->setPrevUpToDate();
+}
+
+inline void
+AbstractFramePtr::unsetPrevUpToDate() const
+{
+ if (isInterpreterFrame()) {
+ asInterpreterFrame()->unsetPrevUpToDate();
+ return;
+ }
+ if (isBaselineFrame()) {
+ asBaselineFrame()->unsetPrevUpToDate();
+ return;
+ }
+ asRematerializedFrame()->unsetPrevUpToDate();
+}
+
+inline Value&
+AbstractFramePtr::thisArgument() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->thisArgument();
+ if (isBaselineFrame())
+ return asBaselineFrame()->thisArgument();
+ return asRematerializedFrame()->thisArgument();
+}
+
+inline Value
+AbstractFramePtr::newTarget() const
+{
+ if (isInterpreterFrame())
+ return asInterpreterFrame()->newTarget();
+ if (isBaselineFrame())
+ return asBaselineFrame()->newTarget();
+ return asRematerializedFrame()->newTarget();
+}
+
+inline bool
+AbstractFramePtr::debuggerNeedsCheckPrimitiveReturn() const
+{
+ return script()->isDerivedClassConstructor();
+}
+
+ActivationEntryMonitor::~ActivationEntryMonitor()
+{
+ if (entryMonitor_)
+ entryMonitor_->Exit(cx_);
+
+ cx_->runtime()->entryMonitor = entryMonitor_;
+}
+
+Activation::Activation(JSContext* cx, Kind kind)
+ : cx_(cx),
+ compartment_(cx->compartment()),
+ prev_(cx->activation_),
+ prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr),
+ hideScriptedCallerCount_(0),
+ frameCache_(cx),
+ asyncStack_(cx, cx->asyncStackForNewActivations),
+ asyncCause_(cx->asyncCauseForNewActivations),
+ asyncCallIsExplicit_(cx->asyncCallIsExplicit),
+ kind_(kind)
+{
+ cx->asyncStackForNewActivations = nullptr;
+ cx->asyncCauseForNewActivations = nullptr;
+ cx->asyncCallIsExplicit = false;
+ cx->activation_ = this;
+}
+
+Activation::~Activation()
+{
+ MOZ_ASSERT_IF(isProfiling(), this != cx_->profilingActivation_);
+ MOZ_ASSERT(cx_->activation_ == this);
+ MOZ_ASSERT(hideScriptedCallerCount_ == 0);
+ cx_->activation_ = prev_;
+ cx_->asyncCauseForNewActivations = asyncCause_;
+ cx_->asyncStackForNewActivations = asyncStack_;
+ cx_->asyncCallIsExplicit = asyncCallIsExplicit_;
+}
+
+bool
+Activation::isProfiling() const
+{
+ if (isInterpreter())
+ return asInterpreter()->isProfiling();
+
+ if (isJit())
+ return asJit()->isProfiling();
+
+ MOZ_ASSERT(isWasm());
+ return asWasm()->isProfiling();
+}
+
+Activation*
+Activation::mostRecentProfiling()
+{
+ if (isProfiling())
+ return this;
+ return prevProfiling_;
+}
+
+inline LiveSavedFrameCache*
+Activation::getLiveSavedFrameCache(JSContext* cx) {
+ if (!frameCache_.get().initialized() && !frameCache_.get().init(cx))
+ return nullptr;
+ return frameCache_.address();
+}
+
+InterpreterActivation::InterpreterActivation(RunState& state, JSContext* cx,
+ InterpreterFrame* entryFrame)
+ : Activation(cx, Interpreter),
+ entryFrame_(entryFrame),
+ opMask_(0)
+#ifdef DEBUG
+ , oldFrameCount_(cx->runtime()->interpreterStack().frameCount_)
+#endif
+{
+ regs_.prepareToRun(*entryFrame, state.script());
+ MOZ_ASSERT(regs_.pc == state.script()->code());
+ MOZ_ASSERT_IF(entryFrame_->isEvalFrame(), state.script()->isActiveEval());
+}
+
+InterpreterActivation::~InterpreterActivation()
+{
+ // Pop all inline frames.
+ while (regs_.fp() != entryFrame_)
+ popInlineFrame(regs_.fp());
+
+ MOZ_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_);
+ MOZ_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0);
+
+ if (entryFrame_)
+ cx_->runtime()->interpreterStack().releaseFrame(entryFrame_);
+}
+
+inline bool
+InterpreterActivation::pushInlineFrame(const CallArgs& args, HandleScript script,
+ MaybeConstruct constructing)
+{
+ if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, constructing))
+ return false;
+ MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment());
+ return true;
+}
+
+inline void
+InterpreterActivation::popInlineFrame(InterpreterFrame* frame)
+{
+ (void)frame; // Quell compiler warning.
+ MOZ_ASSERT(regs_.fp() == frame);
+ MOZ_ASSERT(regs_.fp() != entryFrame_);
+
+ cx_->runtime()->interpreterStack().popInlineFrame(regs_);
+}
+
+inline bool
+InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
+ HandleObject envChain)
+{
+ InterpreterStack& stack = cx_->runtime()->interpreterStack();
+ if (!stack.resumeGeneratorCallFrame(cx_, regs_, callee, newTarget, envChain))
+ return false;
+
+ MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_);
+ return true;
+}
+
+inline bool
+FrameIter::hasCachedSavedFrame() const
+{
+ if (isWasm())
+ return false;
+
+ if (hasUsableAbstractFramePtr())
+ return abstractFramePtr().hasCachedSavedFrame();
+
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+ // SavedFrame caching is done at the physical frame granularity (rather than
+ // for each inlined frame) for ion. Therefore, it is impossible to have a
+ // cached SavedFrame if this frame is not a physical frame.
+ return isPhysicalIonFrame() && data_.jitFrames_.current()->hasCachedSavedFrame();
+}
+
+inline void
+FrameIter::setHasCachedSavedFrame()
+{
+ MOZ_ASSERT(!isWasm());
+
+ if (hasUsableAbstractFramePtr()) {
+ abstractFramePtr().setHasCachedSavedFrame();
+ return;
+ }
+
+ MOZ_ASSERT(isPhysicalIonFrame());
+ data_.jitFrames_.current()->setHasCachedSavedFrame();
+}
+
+} /* namespace js */
+
+#endif /* vm_Stack_inl_h */
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
new file mode 100644
index 000000000..7978d8dbc
--- /dev/null
+++ b/js/src/vm/Stack.cpp
@@ -0,0 +1,1959 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Stack-inl.h"
+
+#include "mozilla/PodOperations.h"
+
+#include "jscntxt.h"
+
+#include "gc/Marking.h"
+#include "jit/BaselineFrame.h"
+#include "jit/JitcodeMap.h"
+#include "jit/JitCompartment.h"
+#include "js/GCAPI.h"
+#include "vm/Debugger.h"
+#include "vm/Opcodes.h"
+
+#include "jit/JitFrameIterator-inl.h"
+#include "vm/EnvironmentObject-inl.h"
+#include "vm/Interpreter-inl.h"
+#include "vm/Probes-inl.h"
+
+using namespace js;
+
+using mozilla::Maybe;
+using mozilla::PodCopy;
+
+/*****************************************************************************/
+
+void
+InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script,
+ AbstractFramePtr evalInFramePrev,
+ const Value& newTargetValue, HandleObject envChain)
+{
+ flags_ = 0;
+ script_ = script;
+
+ // newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
+ // It should never be passed from Ion code.
+ RootedValue newTarget(cx, newTargetValue);
+ if (script->isDirectEvalInFunction()) {
+ FrameIter iter(cx);
+ MOZ_ASSERT(!iter.isWasm());
+ if (newTarget.isNull() &&
+ iter.script()->bodyScope()->hasOnChain(ScopeKind::Function))
+ {
+ newTarget = iter.newTarget();
+ }
+ } else if (evalInFramePrev) {
+ if (newTarget.isNull() &&
+ evalInFramePrev.script()->bodyScope()->hasOnChain(ScopeKind::Function))
+ {
+ newTarget = evalInFramePrev.newTarget();
+ }
+ }
+
+ Value* dstvp = (Value*)this - 1;
+ dstvp[0] = newTarget;
+
+ envChain_ = envChain.get();
+ prev_ = nullptr;
+ prevpc_ = nullptr;
+ prevsp_ = nullptr;
+
+ evalInFramePrev_ = evalInFramePrev;
+ MOZ_ASSERT_IF(evalInFramePrev, isDebuggerEvalFrame());
+
+ if (script->isDebuggee())
+ setIsDebuggee();
+
+#ifdef DEBUG
+ Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
+#endif
+}
+
+bool
+InterpreterFrame::isNonGlobalEvalFrame() const
+{
+ return isEvalFrame() && script()->bodyScope()->as<EvalScope>().isNonGlobal();
+}
+
+JSObject*
+InterpreterFrame::createRestParameter(JSContext* cx)
+{
+ MOZ_ASSERT(callee().hasRest());
+ unsigned nformal = callee().nargs() - 1, nactual = numActualArgs();
+ unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
+ Value* restvp = argv() + nformal;
+ return ObjectGroup::newArrayObject(cx, restvp, nrest, GenericObject,
+ ObjectGroup::NewArrayKind::UnknownIndex);
+}
+
+static inline void
+AssertScopeMatchesEnvironment(Scope* scope, JSObject* originalEnv)
+{
+#ifdef DEBUG
+ JSObject* env = originalEnv;
+ for (ScopeIter si(scope); si; si++) {
+ if (si.kind() == ScopeKind::NonSyntactic) {
+ while (env->is<WithEnvironmentObject>() ||
+ env->is<NonSyntacticVariablesObject>() ||
+ (env->is<LexicalEnvironmentObject>() &&
+ !env->as<LexicalEnvironmentObject>().isSyntactic()))
+ {
+ MOZ_ASSERT(!IsSyntacticEnvironment(env));
+ env = &env->as<EnvironmentObject>().enclosingEnvironment();
+ }
+ } else if (si.hasSyntacticEnvironment()) {
+ switch (si.kind()) {
+ case ScopeKind::Function:
+ MOZ_ASSERT(env->as<CallObject>().callee().existingScriptNonDelazifying() ==
+ si.scope()->as<FunctionScope>().script());
+ env = &env->as<CallObject>().enclosingEnvironment();
+ break;
+
+ case ScopeKind::FunctionBodyVar:
+ case ScopeKind::ParameterExpressionVar:
+ MOZ_ASSERT(&env->as<VarEnvironmentObject>().scope() == si.scope());
+ env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
+ break;
+
+ case ScopeKind::Lexical:
+ case ScopeKind::SimpleCatch:
+ case ScopeKind::Catch:
+ case ScopeKind::NamedLambda:
+ case ScopeKind::StrictNamedLambda:
+ MOZ_ASSERT(&env->as<LexicalEnvironmentObject>().scope() == si.scope());
+ env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment();
+ break;
+
+ case ScopeKind::With:
+ MOZ_ASSERT(&env->as<WithEnvironmentObject>().scope() == si.scope());
+ env = &env->as<WithEnvironmentObject>().enclosingEnvironment();
+ break;
+
+ case ScopeKind::Eval:
+ case ScopeKind::StrictEval:
+ env = &env->as<VarEnvironmentObject>().enclosingEnvironment();
+ break;
+
+ case ScopeKind::Global:
+ MOZ_ASSERT(env->as<LexicalEnvironmentObject>().isGlobal());
+ env = &env->as<LexicalEnvironmentObject>().enclosingEnvironment();
+ MOZ_ASSERT(env->is<GlobalObject>());
+ break;
+
+ case ScopeKind::NonSyntactic:
+ MOZ_CRASH("NonSyntactic should not have a syntactic environment");
+ break;
+
+ case ScopeKind::Module:
+ MOZ_ASSERT(env->as<ModuleEnvironmentObject>().module().script() ==
+ si.scope()->as<ModuleScope>().script());
+ env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
+ break;
+ }
+ }
+ }
+
+ // In the case of a non-syntactic env chain, the immediate parent of the
+ // outermost non-syntactic env may be the global lexical env, or, if
+ // called from Debugger, a DebugEnvironmentProxy.
+ //
+ // In the case of a syntactic env chain, the outermost env is always a
+ // GlobalObject.
+ MOZ_ASSERT(env->is<GlobalObject>() || IsGlobalLexicalEnvironment(env) ||
+ env->is<DebugEnvironmentProxy>());
+#endif
+}
+
+static inline void
+AssertScopeMatchesEnvironment(InterpreterFrame* fp, jsbytecode* pc)
+{
+#ifdef DEBUG
+ // If we OOMed before fully initializing the environment chain, the scope
+ // and environment will definitely mismatch.
+ if (fp->script()->initialEnvironmentShape() && fp->hasInitialEnvironment())
+ AssertScopeMatchesEnvironment(fp->script()->innermostScope(pc), fp->environmentChain());
+#endif
+}
+
+bool
+InterpreterFrame::initFunctionEnvironmentObjects(JSContext* cx)
+{
+ return js::InitFunctionEnvironmentObjects(cx, this);
+}
+
+bool
+InterpreterFrame::prologue(JSContext* cx)
+{
+ RootedScript script(cx, this->script());
+
+ MOZ_ASSERT(cx->interpreterRegs().pc == script->code());
+
+ if (isEvalFrame()) {
+ if (!script->bodyScope()->hasEnvironment()) {
+ MOZ_ASSERT(!script->strict());
+ // Non-strict eval may introduce var bindings that conflict with
+ // lexical bindings in an enclosing lexical scope.
+ RootedObject varObjRoot(cx, &varObj());
+ if (!CheckEvalDeclarationConflicts(cx, script, environmentChain(), varObjRoot))
+ return false;
+ }
+ return probes::EnterScript(cx, script, nullptr, this);
+ }
+
+ if (isGlobalFrame()) {
+ Rooted<LexicalEnvironmentObject*> lexicalEnv(cx);
+ RootedObject varObjRoot(cx);
+ if (script->hasNonSyntacticScope()) {
+ lexicalEnv = &extensibleLexicalEnvironment();
+ varObjRoot = &varObj();
+ } else {
+ lexicalEnv = &cx->global()->lexicalEnvironment();
+ varObjRoot = cx->global();
+ }
+ if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, varObjRoot))
+ return false;
+ return probes::EnterScript(cx, script, nullptr, this);
+ }
+
+ if (isModuleFrame())
+ return probes::EnterScript(cx, script, nullptr, this);
+
+ // At this point, we've yet to push any environments. Check that they
+ // match the enclosing scope.
+ AssertScopeMatchesEnvironment(script->enclosingScope(), environmentChain());
+
+ MOZ_ASSERT(isFunctionFrame());
+ if (callee().needsFunctionEnvironmentObjects() && !initFunctionEnvironmentObjects(cx))
+ return false;
+
+ if (isConstructing()) {
+ if (callee().isBoundFunction()) {
+ thisArgument() = MagicValue(JS_UNINITIALIZED_LEXICAL);
+ } else if (script->isDerivedClassConstructor()) {
+ MOZ_ASSERT(callee().isClassConstructor());
+ thisArgument() = MagicValue(JS_UNINITIALIZED_LEXICAL);
+ } else if (thisArgument().isObject()) {
+ // Nothing to do. Correctly set.
+ } else {
+ MOZ_ASSERT(thisArgument().isMagic(JS_IS_CONSTRUCTING));
+ RootedObject callee(cx, &this->callee());
+ RootedObject newTarget(cx, &this->newTarget().toObject());
+ JSObject* obj = CreateThisForFunction(cx, callee, newTarget,
+ createSingleton() ? SingletonObject : GenericObject);
+ if (!obj)
+ return false;
+ thisArgument() = ObjectValue(*obj);
+ }
+ }
+
+ return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
+}
+
+void
+InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc)
+{
+ RootedScript script(cx, this->script());
+ probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
+
+ // Check that the scope matches the environment at the point of leaving
+ // the frame.
+ AssertScopeMatchesEnvironment(this, pc);
+
+ EnvironmentIter ei(cx, this, pc);
+ UnwindAllEnvironmentsInFrame(cx, ei);
+
+ if (isFunctionFrame()) {
+ if (!callee().isGenerator() &&
+ isConstructing() &&
+ thisArgument().isObject() &&
+ returnValue().isPrimitive())
+ {
+ setReturnValue(thisArgument());
+ }
+
+ return;
+ }
+
+ MOZ_ASSERT(isEvalFrame() || isGlobalFrame() || isModuleFrame());
+}
+
+bool
+InterpreterFrame::checkReturn(JSContext* cx, HandleValue thisv)
+{
+ MOZ_ASSERT(script()->isDerivedClassConstructor());
+ MOZ_ASSERT(isFunctionFrame());
+ MOZ_ASSERT(callee().isClassConstructor());
+
+ HandleValue retVal = returnValue();
+ if (retVal.isObject())
+ return true;
+
+ if (!retVal.isUndefined()) {
+ ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, retVal, nullptr);
+ return false;
+ }
+
+ if (thisv.isMagic(JS_UNINITIALIZED_LEXICAL))
+ return ThrowUninitializedThis(cx, this);
+
+ setReturnValue(thisv);
+ return true;
+}
+
+bool
+InterpreterFrame::pushVarEnvironment(JSContext* cx, HandleScope scope)
+{
+ return js::PushVarEnvironmentObject(cx, scope, this);
+}
+
+bool
+InterpreterFrame::pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope)
+{
+ LexicalEnvironmentObject* env = LexicalEnvironmentObject::create(cx, scope, this);
+ if (!env)
+ return false;
+
+ pushOnEnvironmentChain(*env);
+ return true;
+}
+
+bool
+InterpreterFrame::freshenLexicalEnvironment(JSContext* cx)
+{
+ Rooted<LexicalEnvironmentObject*> env(cx, &envChain_->as<LexicalEnvironmentObject>());
+ LexicalEnvironmentObject* fresh = LexicalEnvironmentObject::clone(cx, env);
+ if (!fresh)
+ return false;
+
+ replaceInnermostEnvironment(*fresh);
+ return true;
+}
+
+bool
+InterpreterFrame::recreateLexicalEnvironment(JSContext* cx)
+{
+ Rooted<LexicalEnvironmentObject*> env(cx, &envChain_->as<LexicalEnvironmentObject>());
+ LexicalEnvironmentObject* fresh = LexicalEnvironmentObject::recreate(cx, env);
+ if (!fresh)
+ return false;
+
+ replaceInnermostEnvironment(*fresh);
+ return true;
+}
+
+void
+InterpreterFrame::trace(JSTracer* trc, Value* sp, jsbytecode* pc)
+{
+ TraceRoot(trc, &envChain_, "env chain");
+ TraceRoot(trc, &script_, "script");
+
+ if (flags_ & HAS_ARGS_OBJ)
+ TraceRoot(trc, &argsObj_, "arguments");
+
+ if (hasReturnValue())
+ TraceRoot(trc, &rval_, "rval");
+
+ MOZ_ASSERT(sp >= slots());
+
+ if (hasArgs()) {
+ // Trace the callee and |this|. When we're doing a moving GC, we
+ // need to fix up the callee pointer before we use it below, under
+ // numFormalArgs() and script().
+ TraceRootRange(trc, 2, argv_ - 2, "fp callee and this");
+
+ // Trace arguments.
+ unsigned argc = Max(numActualArgs(), numFormalArgs());
+ TraceRootRange(trc, argc + isConstructing(), argv_, "fp argv");
+ } else {
+ // Mark newTarget.
+ TraceRoot(trc, ((Value*)this) - 1, "stack newTarget");
+ }
+
+ JSScript* script = this->script();
+ size_t nfixed = script->nfixed();
+ size_t nlivefixed = script->calculateLiveFixed(pc);
+
+ if (nfixed == nlivefixed) {
+ // All locals are live.
+ traceValues(trc, 0, sp - slots());
+ } else {
+ // Mark operand stack.
+ traceValues(trc, nfixed, sp - slots());
+
+ // Clear dead block-scoped locals.
+ while (nfixed > nlivefixed)
+ unaliasedLocal(--nfixed).setUndefined();
+
+ // Mark live locals.
+ traceValues(trc, 0, nlivefixed);
+ }
+
+ if (script->compartment()->debugEnvs)
+ script->compartment()->debugEnvs->markLiveFrame(trc, this);
+
+ if (trc->isMarkingTracer())
+ script->compartment()->zone()->active = true;
+}
+
+void
+InterpreterFrame::traceValues(JSTracer* trc, unsigned start, unsigned end)
+{
+ if (start < end)
+ TraceRootRange(trc, end - start, slots() + start, "vm_stack");
+}
+
+static void
+MarkInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
+{
+ for (InterpreterFrameIterator frames(act); !frames.done(); ++frames) {
+ InterpreterFrame* fp = frames.frame();
+ fp->trace(trc, frames.sp(), frames.pc());
+ }
+}
+
+void
+js::MarkInterpreterActivations(JSRuntime* rt, JSTracer* trc)
+{
+ for (ActivationIterator iter(rt); !iter.done(); ++iter) {
+ Activation* act = iter.activation();
+ if (act->isInterpreter())
+ MarkInterpreterActivation(trc, act->asInterpreter());
+ }
+}
+
+/*****************************************************************************/
+
+// Unlike the other methods of this class, this method is defined here so that
+// we don't have to #include jsautooplen.h in vm/Stack.h.
+void
+InterpreterRegs::setToEndOfScript()
+{
+ sp = fp()->base();
+}
+
+/*****************************************************************************/
+
+InterpreterFrame*
+InterpreterStack::pushInvokeFrame(JSContext* cx, const CallArgs& args, MaybeConstruct constructing)
+{
+ LifoAlloc::Mark mark = allocator_.mark();
+
+ RootedFunction fun(cx, &args.callee().as<JSFunction>());
+ RootedScript script(cx, fun->nonLazyScript());
+
+ Value* argv;
+ InterpreterFrame* fp = getCallFrame(cx, args, script, constructing, &argv);
+ if (!fp)
+ return nullptr;
+
+ fp->mark_ = mark;
+ fp->initCallFrame(cx, nullptr, nullptr, nullptr, *fun, script, argv, args.length(),
+ constructing);
+ return fp;
+}
+
+InterpreterFrame*
+InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Value& newTargetValue,
+ HandleObject envChain, AbstractFramePtr evalInFrame)
+{
+ LifoAlloc::Mark mark = allocator_.mark();
+
+ unsigned nvars = 1 /* newTarget */ + script->nslots();
+ uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvars * sizeof(Value));
+ if (!buffer)
+ return nullptr;
+
+ InterpreterFrame* fp = reinterpret_cast<InterpreterFrame*>(buffer + 1 * sizeof(Value));
+ fp->mark_ = mark;
+ fp->initExecuteFrame(cx, script, evalInFrame, newTargetValue, envChain);
+ fp->initLocals();
+
+ return fp;
+}
+
+/*****************************************************************************/
+
+void
+FrameIter::popActivation()
+{
+ ++data_.activations_;
+ settleOnActivation();
+}
+
+void
+FrameIter::popInterpreterFrame()
+{
+ MOZ_ASSERT(data_.state_ == INTERP);
+
+ ++data_.interpFrames_;
+
+ if (data_.interpFrames_.done())
+ popActivation();
+ else
+ data_.pc_ = data_.interpFrames_.pc();
+}
+
+void
+FrameIter::settleOnActivation()
+{
+ while (true) {
+ if (data_.activations_.done()) {
+ data_.state_ = DONE;
+ return;
+ }
+
+ Activation* activation = data_.activations_.activation();
+
+ // If the caller supplied principals, only show activations which are subsumed (of the same
+ // origin or of an origin accessible) by these principals.
+ if (data_.principals_) {
+ JSContext* cx = data_.cx_;
+ if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) {
+ if (!subsumes(data_.principals_, activation->compartment()->principals())) {
+ ++data_.activations_;
+ continue;
+ }
+ }
+ }
+
+ if (activation->isJit()) {
+ data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
+
+ // Stop at the first scripted frame.
+ while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
+ ++data_.jitFrames_;
+
+ // It's possible to have an JitActivation with no scripted frames,
+ // for instance if we hit an over-recursion during bailout.
+ if (data_.jitFrames_.done()) {
+ ++data_.activations_;
+ continue;
+ }
+
+ nextJitFrame();
+ data_.state_ = JIT;
+ return;
+ }
+
+ if (activation->isWasm()) {
+ data_.wasmFrames_ = wasm::FrameIterator(*data_.activations_->asWasm());
+
+ if (data_.wasmFrames_.done()) {
+ ++data_.activations_;
+ continue;
+ }
+
+ data_.pc_ = (jsbytecode*)data_.wasmFrames_.pc();
+ data_.state_ = WASM;
+ return;
+ }
+
+ MOZ_ASSERT(activation->isInterpreter());
+
+ InterpreterActivation* interpAct = activation->asInterpreter();
+ data_.interpFrames_ = InterpreterFrameIterator(interpAct);
+
+ // If we OSR'ed into JIT code, skip the interpreter frame so that
+ // the same frame is not reported twice.
+ if (data_.interpFrames_.frame()->runningInJit()) {
+ ++data_.interpFrames_;
+ if (data_.interpFrames_.done()) {
+ ++data_.activations_;
+ continue;
+ }
+ }
+
+ MOZ_ASSERT(!data_.interpFrames_.frame()->runningInJit());
+ data_.pc_ = data_.interpFrames_.pc();
+ data_.state_ = INTERP;
+ return;
+ }
+}
+
+FrameIter::Data::Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
+ JSPrincipals* principals)
+ : cx_(cx),
+ debuggerEvalOption_(debuggerEvalOption),
+ principals_(principals),
+ state_(DONE),
+ pc_(nullptr),
+ interpFrames_(nullptr),
+ activations_(cx->runtime()),
+ jitFrames_(),
+ ionInlineFrameNo_(0),
+ wasmFrames_()
+{
+}
+
+FrameIter::Data::Data(const FrameIter::Data& other)
+ : cx_(other.cx_),
+ debuggerEvalOption_(other.debuggerEvalOption_),
+ principals_(other.principals_),
+ state_(other.state_),
+ pc_(other.pc_),
+ interpFrames_(other.interpFrames_),
+ activations_(other.activations_),
+ jitFrames_(other.jitFrames_),
+ ionInlineFrameNo_(other.ionInlineFrameNo_),
+ wasmFrames_(other.wasmFrames_)
+{
+}
+
+FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption)
+ : data_(cx, debuggerEvalOption, nullptr),
+ ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
+{
+ // settleOnActivation can only GC if principals are given.
+ JS::AutoSuppressGCAnalysis nogc;
+ settleOnActivation();
+}
+
+FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
+ JSPrincipals* principals)
+ : data_(cx, debuggerEvalOption, principals),
+ ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
+{
+ settleOnActivation();
+}
+
+FrameIter::FrameIter(const FrameIter& other)
+ : data_(other.data_),
+ ionInlineFrames_(other.data_.cx_,
+ data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
+{
+}
+
+FrameIter::FrameIter(const Data& data)
+ : data_(data),
+ ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
+{
+ MOZ_ASSERT(data.cx_);
+
+ if (data_.jitFrames_.isIonScripted()) {
+ while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
+ ++ionInlineFrames_;
+ }
+}
+
+void
+FrameIter::nextJitFrame()
+{
+ if (data_.jitFrames_.isIonScripted()) {
+ ionInlineFrames_.resetOn(&data_.jitFrames_);
+ data_.pc_ = ionInlineFrames_.pc();
+ } else {
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
+ }
+}
+
+void
+FrameIter::popJitFrame()
+{
+ MOZ_ASSERT(data_.state_ == JIT);
+
+ if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
+ ++ionInlineFrames_;
+ data_.pc_ = ionInlineFrames_.pc();
+ return;
+ }
+
+ ++data_.jitFrames_;
+ while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
+ ++data_.jitFrames_;
+
+ if (!data_.jitFrames_.done()) {
+ nextJitFrame();
+ return;
+ }
+
+ popActivation();
+}
+
+void
+FrameIter::popWasmFrame()
+{
+ MOZ_ASSERT(data_.state_ == WASM);
+
+ ++data_.wasmFrames_;
+ data_.pc_ = (jsbytecode*)data_.wasmFrames_.pc();
+ if (data_.wasmFrames_.done())
+ popActivation();
+}
+
+FrameIter&
+FrameIter::operator++()
+{
+ switch (data_.state_) {
+ case DONE:
+ MOZ_CRASH("Unexpected state");
+ case INTERP:
+ if (interpFrame()->isDebuggerEvalFrame() &&
+ interpFrame()->evalInFramePrev() &&
+ data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK)
+ {
+ AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
+
+ popInterpreterFrame();
+
+ while (!hasUsableAbstractFramePtr() || abstractFramePtr() != eifPrev) {
+ if (data_.state_ == JIT)
+ popJitFrame();
+ else
+ popInterpreterFrame();
+ }
+
+ break;
+ }
+ popInterpreterFrame();
+ break;
+ case JIT:
+ popJitFrame();
+ break;
+ case WASM:
+ popWasmFrame();
+ break;
+ }
+ return *this;
+}
+
+FrameIter::Data*
+FrameIter::copyData() const
+{
+ Data* data = data_.cx_->new_<Data>(data_);
+ if (!data)
+ return nullptr;
+
+ MOZ_ASSERT(data_.state_ != WASM);
+ if (data && data_.jitFrames_.isIonScripted())
+ data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
+ return data;
+}
+
+AbstractFramePtr
+FrameIter::copyDataAsAbstractFramePtr() const
+{
+ AbstractFramePtr frame;
+ if (Data* data = copyData())
+ frame.ptr_ = uintptr_t(data);
+ return frame;
+}
+
+void*
+FrameIter::rawFramePtr() const
+{
+ switch (data_.state_) {
+ case DONE:
+ return nullptr;
+ case JIT:
+ return data_.jitFrames_.fp();
+ case INTERP:
+ return interpFrame();
+ case WASM:
+ return data_.wasmFrames_.fp();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+JSCompartment*
+FrameIter::compartment() const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT:
+ case WASM:
+ return data_.activations_->compartment();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::isEvalFrame() const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ return interpFrame()->isEvalFrame();
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS())
+ return data_.jitFrames_.baselineFrame()->isEvalFrame();
+ MOZ_ASSERT(!script()->isForEval());
+ return false;
+ case WASM:
+ return false;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::isFunctionFrame() const
+{
+ MOZ_ASSERT(!done());
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ return interpFrame()->isFunctionFrame();
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS())
+ return data_.jitFrames_.baselineFrame()->isFunctionFrame();
+ return script()->functionNonDelazifying();
+ case WASM:
+ return true;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+JSAtom*
+FrameIter::functionDisplayAtom() const
+{
+ MOZ_ASSERT(isFunctionFrame());
+
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT:
+ return calleeTemplate()->displayAtom();
+ case WASM:
+ return data_.wasmFrames_.functionDisplayAtom();
+ }
+
+ MOZ_CRASH("Unexpected state");
+}
+
+ScriptSource*
+FrameIter::scriptSource() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ case JIT:
+ return script()->scriptSource();
+ }
+
+ MOZ_CRASH("Unexpected state");
+}
+
+const char*
+FrameIter::filename() const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT:
+ return script()->filename();
+ case WASM:
+ return data_.wasmFrames_.filename();
+ }
+
+ MOZ_CRASH("Unexpected state");
+}
+
+const char16_t*
+FrameIter::displayURL() const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT: {
+ ScriptSource* ss = script()->scriptSource();
+ return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
+ }
+ case WASM:
+ return data_.wasmFrames_.displayURL();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+unsigned
+FrameIter::computeLine(uint32_t* column) const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT:
+ return PCToLineNumber(script(), pc(), column);
+ case WASM:
+ if (column)
+ *column = 0;
+ return data_.wasmFrames_.lineOrBytecode();
+ }
+
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::mutedErrors() const
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP:
+ case JIT:
+ return script()->mutedErrors();
+ case WASM:
+ return data_.wasmFrames_.mutedErrors();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::isConstructing() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isIonScripted())
+ return ionInlineFrames_.isConstructing();
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ return data_.jitFrames_.isConstructing();
+ case INTERP:
+ return interpFrame()->isConstructing();
+ }
+
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::ensureHasRematerializedFrame(JSContext* cx)
+{
+ MOZ_ASSERT(isIon());
+ return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_);
+}
+
+bool
+FrameIter::hasUsableAbstractFramePtr() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ return false;
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS())
+ return true;
+
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+ return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
+ ionInlineFrames_.frameNo());
+ break;
+ case INTERP:
+ return true;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+AbstractFramePtr
+FrameIter::abstractFramePtr() const
+{
+ MOZ_ASSERT(hasUsableAbstractFramePtr());
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT: {
+ if (data_.jitFrames_.isBaselineJS())
+ return data_.jitFrames_.baselineFrame();
+
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+ return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
+ ionInlineFrames_.frameNo());
+ break;
+ }
+ case INTERP:
+ MOZ_ASSERT(interpFrame());
+ return AbstractFramePtr(interpFrame());
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+void
+FrameIter::updatePcQuadratic()
+{
+ switch (data_.state_) {
+ case DONE:
+ break;
+ case INTERP: {
+ InterpreterFrame* frame = interpFrame();
+ InterpreterActivation* activation = data_.activations_->asInterpreter();
+
+ // Look for the current frame.
+ data_.interpFrames_ = InterpreterFrameIterator(activation);
+ while (data_.interpFrames_.frame() != frame)
+ ++data_.interpFrames_;
+
+ // Update the pc.
+ MOZ_ASSERT(data_.interpFrames_.frame() == frame);
+ data_.pc_ = data_.interpFrames_.pc();
+ return;
+ }
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS()) {
+ jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
+ jit::JitActivation* activation = data_.activations_->asJit();
+
+ // ActivationIterator::jitTop_ may be invalid, so create a new
+ // activation iterator.
+ data_.activations_ = ActivationIterator(data_.cx_->runtime());
+ while (data_.activations_.activation() != activation)
+ ++data_.activations_;
+
+ // Look for the current frame.
+ data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
+ while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
+ ++data_.jitFrames_;
+
+ // Update the pc.
+ MOZ_ASSERT(data_.jitFrames_.baselineFrame() == frame);
+ data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
+ return;
+ }
+ break;
+ case WASM:
+ // Update the pc.
+ data_.pc_ = (jsbytecode*)data_.wasmFrames_.pc();
+ break;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+JSFunction*
+FrameIter::calleeTemplate() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ MOZ_ASSERT(isFunctionFrame());
+ return &interpFrame()->callee();
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS())
+ return data_.jitFrames_.callee();
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+ return ionInlineFrames_.calleeTemplate();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+JSFunction*
+FrameIter::callee(JSContext* cx) const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ return calleeTemplate();
+ case JIT:
+ if (data_.jitFrames_.isIonScripted()) {
+ jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
+ return ionInlineFrames_.callee(recover);
+ }
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ return calleeTemplate();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+bool
+FrameIter::matchCallee(JSContext* cx, HandleFunction fun) const
+{
+ RootedFunction currentCallee(cx, calleeTemplate());
+
+ // As we do not know if the calleeTemplate is the real function, or the
+ // template from which it would be cloned, we compare properties which are
+ // stable across the cloning of JSFunctions.
+ if (((currentCallee->flags() ^ fun->flags()) & JSFunction::STABLE_ACROSS_CLONES) != 0 ||
+ currentCallee->nargs() != fun->nargs())
+ {
+ return false;
+ }
+
+ // Use the same condition as |js::CloneFunctionObject|, to know if we should
+ // expect both functions to have the same JSScript. If so, and if they are
+ // different, then they cannot be equal.
+ RootedObject global(cx, &fun->global());
+ bool useSameScript = CanReuseScriptForClone(fun->compartment(), currentCallee, global);
+ if (useSameScript &&
+ (currentCallee->hasScript() != fun->hasScript() ||
+ currentCallee->nonLazyScript() != fun->nonLazyScript()))
+ {
+ return false;
+ }
+
+ // If none of the previous filters worked, then take the risk of
+ // invalidating the frame to identify the JSFunction.
+ return callee(cx) == fun;
+}
+
+unsigned
+FrameIter::numActualArgs() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ MOZ_ASSERT(isFunctionFrame());
+ return interpFrame()->numActualArgs();
+ case JIT:
+ if (data_.jitFrames_.isIonScripted())
+ return ionInlineFrames_.numActualArgs();
+
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ return data_.jitFrames_.numActualArgs();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+unsigned
+FrameIter::numFormalArgs() const
+{
+ return script()->functionNonDelazifying()->nargs();
+}
+
+Value
+FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const
+{
+ return abstractFramePtr().unaliasedActual(i, checkAliasing);
+}
+
+JSObject*
+FrameIter::environmentChain(JSContext* cx) const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isIonScripted()) {
+ jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
+ return ionInlineFrames_.environmentChain(recover);
+ }
+ return data_.jitFrames_.baselineFrame()->environmentChain();
+ case INTERP:
+ return interpFrame()->environmentChain();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+CallObject&
+FrameIter::callObj(JSContext* cx) const
+{
+ MOZ_ASSERT(calleeTemplate()->needsCallObject());
+
+ JSObject* pobj = environmentChain(cx);
+ while (!pobj->is<CallObject>())
+ pobj = pobj->enclosingEnvironment();
+ return pobj->as<CallObject>();
+}
+
+bool
+FrameIter::hasArgsObj() const
+{
+ return abstractFramePtr().hasArgsObj();
+}
+
+ArgumentsObject&
+FrameIter::argsObj() const
+{
+ MOZ_ASSERT(hasArgsObj());
+ return abstractFramePtr().argsObj();
+}
+
+Value
+FrameIter::thisArgument(JSContext* cx) const
+{
+ MOZ_ASSERT(isFunctionFrame());
+
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isIonScripted()) {
+ jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
+ return ionInlineFrames_.thisArgument(recover);
+ }
+ return data_.jitFrames_.baselineFrame()->thisArgument();
+ case INTERP:
+ return interpFrame()->thisArgument();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+Value
+FrameIter::newTarget() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case INTERP:
+ return interpFrame()->newTarget();
+ case JIT:
+ MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
+ return data_.jitFrames_.baselineFrame()->newTarget();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+Value
+FrameIter::returnValue() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS())
+ return data_.jitFrames_.baselineFrame()->returnValue();
+ break;
+ case INTERP:
+ return interpFrame()->returnValue();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+void
+FrameIter::setReturnValue(const Value& v)
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isBaselineJS()) {
+ data_.jitFrames_.baselineFrame()->setReturnValue(v);
+ return;
+ }
+ break;
+ case INTERP:
+ interpFrame()->setReturnValue(v);
+ return;
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+size_t
+FrameIter::numFrameSlots() const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT: {
+ if (data_.jitFrames_.isIonScripted()) {
+ return ionInlineFrames_.snapshotIterator().numAllocations() -
+ ionInlineFrames_.script()->nfixed();
+ }
+ jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
+ return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
+ }
+ case INTERP:
+ MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
+ return data_.interpFrames_.sp() - interpFrame()->base();
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+Value
+FrameIter::frameSlotValue(size_t index) const
+{
+ switch (data_.state_) {
+ case DONE:
+ case WASM:
+ break;
+ case JIT:
+ if (data_.jitFrames_.isIonScripted()) {
+ jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
+ index += ionInlineFrames_.script()->nfixed();
+ return si.maybeReadAllocByIndex(index);
+ }
+
+ index += data_.jitFrames_.script()->nfixed();
+ return *data_.jitFrames_.baselineFrame()->valueSlot(index);
+ case INTERP:
+ return interpFrame()->base()[index];
+ }
+ MOZ_CRASH("Unexpected state");
+}
+
+#ifdef DEBUG
+bool
+js::SelfHostedFramesVisible()
+{
+ static bool checked = false;
+ static bool visible = false;
+ if (!checked) {
+ checked = true;
+ char* env = getenv("MOZ_SHOW_ALL_JS_FRAMES");
+ visible = !!env;
+ }
+ return visible;
+}
+#endif
+
+void
+NonBuiltinFrameIter::settle()
+{
+ if (!SelfHostedFramesVisible()) {
+ while (!done() && hasScript() && script()->selfHosted())
+ FrameIter::operator++();
+ }
+}
+
+void
+NonBuiltinScriptFrameIter::settle()
+{
+ if (!SelfHostedFramesVisible()) {
+ while (!done() && script()->selfHosted())
+ ScriptFrameIter::operator++();
+ }
+}
+
+ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx)
+ : cx_(cx), entryMonitor_(cx->runtime()->entryMonitor)
+{
+ cx->runtime()->entryMonitor = nullptr;
+}
+
+Value
+ActivationEntryMonitor::asyncStack(JSContext* cx)
+{
+ RootedValue stack(cx, ObjectOrNullValue(cx->asyncStackForNewActivations));
+ if (!cx->compartment()->wrap(cx, &stack)) {
+ cx->clearPendingException();
+ return UndefinedValue();
+ }
+ return stack;
+}
+
+ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame)
+ : ActivationEntryMonitor(cx)
+{
+ if (entryMonitor_) {
+ // The InterpreterFrame is not yet part of an Activation, so it won't
+ // be traced if we trigger GC here. Suppress GC to avoid this.
+ gc::AutoSuppressGC suppressGC(cx);
+ RootedValue stack(cx, asyncStack(cx));
+ const char* asyncCause = cx->asyncCauseForNewActivations;
+ if (entryFrame->isFunctionFrame())
+ entryMonitor_->Entry(cx, &entryFrame->callee(), stack, asyncCause);
+ else
+ entryMonitor_->Entry(cx, entryFrame->script(), stack, asyncCause);
+ }
+}
+
+ActivationEntryMonitor::ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken)
+ : ActivationEntryMonitor(cx)
+{
+ if (entryMonitor_) {
+ // The CalleeToken is not traced at this point and we also don't want
+ // a GC to discard the code we're about to enter, so we suppress GC.
+ gc::AutoSuppressGC suppressGC(cx);
+ RootedValue stack(cx, asyncStack(cx));
+ const char* asyncCause = cx->asyncCauseForNewActivations;
+ if (jit::CalleeTokenIsFunction(entryToken))
+ entryMonitor_->Entry(cx_, jit::CalleeTokenToFunction(entryToken), stack, asyncCause);
+ else
+ entryMonitor_->Entry(cx_, jit::CalleeTokenToScript(entryToken), stack, asyncCause);
+ }
+}
+
+/*****************************************************************************/
+
+jit::JitActivation::JitActivation(JSContext* cx, bool active)
+ : Activation(cx, Jit),
+ prevJitTop_(cx->runtime()->jitTop),
+ prevJitActivation_(cx->runtime()->jitActivation),
+ active_(active),
+ rematerializedFrames_(nullptr),
+ ionRecovery_(cx),
+ bailoutData_(nullptr),
+ lastProfilingFrame_(nullptr),
+ lastProfilingCallSite_(nullptr)
+{
+ if (active) {
+ cx->runtime()->jitActivation = this;
+ registerProfiling();
+ }
+}
+
+jit::JitActivation::~JitActivation()
+{
+ if (active_) {
+ if (isProfiling())
+ unregisterProfiling();
+
+ cx_->runtime()->jitTop = prevJitTop_;
+ cx_->runtime()->jitActivation = prevJitActivation_;
+ } else {
+ MOZ_ASSERT(cx_->runtime()->jitTop == prevJitTop_);
+ MOZ_ASSERT(cx_->runtime()->jitActivation == prevJitActivation_);
+ }
+
+ // All reocvered value are taken from activation during the bailout.
+ MOZ_ASSERT(ionRecovery_.empty());
+
+ // The BailoutFrameInfo should have unregistered itself from the
+ // JitActivations.
+ MOZ_ASSERT(!bailoutData_);
+
+ clearRematerializedFrames();
+ js_delete(rematerializedFrames_);
+}
+
+bool
+jit::JitActivation::isProfiling() const
+{
+ // All JitActivations can be profiled.
+ return true;
+}
+
+void
+jit::JitActivation::setBailoutData(jit::BailoutFrameInfo* bailoutData)
+{
+ MOZ_ASSERT(!bailoutData_);
+ bailoutData_ = bailoutData;
+}
+
+void
+jit::JitActivation::cleanBailoutData()
+{
+ MOZ_ASSERT(bailoutData_);
+ bailoutData_ = nullptr;
+}
+
+// setActive() is inlined in GenerateJitExit() with explicit masm instructions so
+// changes to the logic here need to be reflected in GenerateJitExit() in the enable
+// and disable activation instruction sequences.
+void
+jit::JitActivation::setActive(JSContext* cx, bool active)
+{
+ // Only allowed to deactivate/activate if activation is top.
+ // (Not tested and will probably fail in other situations.)
+ MOZ_ASSERT(cx->runtime()->activation_ == this);
+ MOZ_ASSERT(active != active_);
+
+ if (active) {
+ *((volatile bool*) active_) = true;
+ MOZ_ASSERT(prevJitTop_ == cx->runtime()->jitTop);
+ MOZ_ASSERT(prevJitActivation_ == cx->runtime()->jitActivation);
+ cx->runtime()->jitActivation = this;
+
+ registerProfiling();
+
+ } else {
+ unregisterProfiling();
+
+ cx->runtime()->jitTop = prevJitTop_;
+ cx->runtime()->jitActivation = prevJitActivation_;
+
+ *((volatile bool*) active_) = false;
+ }
+}
+
+void
+jit::JitActivation::removeRematerializedFrame(uint8_t* top)
+{
+ if (!rematerializedFrames_)
+ return;
+
+ if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
+ RematerializedFrame::FreeInVector(p->value());
+ rematerializedFrames_->remove(p);
+ }
+}
+
+void
+jit::JitActivation::clearRematerializedFrames()
+{
+ if (!rematerializedFrames_)
+ return;
+
+ for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
+ RematerializedFrame::FreeInVector(e.front().value());
+ e.removeFront();
+ }
+}
+
+jit::RematerializedFrame*
+jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator& iter,
+ size_t inlineDepth)
+{
+ MOZ_ASSERT(iter.activation() == this);
+ MOZ_ASSERT(iter.isIonScripted());
+
+ if (!rematerializedFrames_) {
+ rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
+ if (!rematerializedFrames_)
+ return nullptr;
+ if (!rematerializedFrames_->init()) {
+ rematerializedFrames_ = nullptr;
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ }
+
+ uint8_t* top = iter.fp();
+ RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
+ if (!p) {
+ RematerializedFrameVector empty(cx);
+ if (!rematerializedFrames_->add(p, top, Move(empty))) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ // The unit of rematerialization is an uninlined frame and its inlined
+ // frames. Since inlined frames do not exist outside of snapshots, it
+ // is impossible to synchronize their rematerialized copies to
+ // preserve identity. Therefore, we always rematerialize an uninlined
+ // frame and all its inlined frames at once.
+ InlineFrameIterator inlineIter(cx, &iter);
+ MaybeReadFallback recover(cx, this, &iter);
+
+ // Frames are often rematerialized with the cx inside a Debugger's
+ // compartment. To recover slots and to create CallObjects, we need to
+ // be in the activation's compartment.
+ AutoCompartment ac(cx, compartment_);
+
+ if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
+ p->value()))
+ {
+ return nullptr;
+ }
+
+ // See comment in unsetPrevUpToDateUntil.
+ DebugEnvironments::unsetPrevUpToDateUntil(cx, p->value()[inlineDepth]);
+ }
+
+ return p->value()[inlineDepth];
+}
+
+jit::RematerializedFrame*
+jit::JitActivation::lookupRematerializedFrame(uint8_t* top, size_t inlineDepth)
+{
+ if (!rematerializedFrames_)
+ return nullptr;
+ if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
+ return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
+ return nullptr;
+}
+
+void
+jit::JitActivation::removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top)
+{
+ // Ion bailout can fail due to overrecursion and OOM. In such cases we
+ // cannot honor any further Debugger hooks on the frame, and need to
+ // ensure that its Debugger.Frame entry is cleaned up.
+ if (!cx->compartment()->isDebuggee() || !rematerializedFrames_)
+ return;
+ if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) {
+ for (uint32_t i = 0; i < p->value().length(); i++)
+ Debugger::handleUnrecoverableIonBailoutError(cx, p->value()[i]);
+ }
+}
+
+void
+jit::JitActivation::markRematerializedFrames(JSTracer* trc)
+{
+ if (!rematerializedFrames_)
+ return;
+ for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront())
+ e.front().value().trace(trc);
+}
+
+bool
+jit::JitActivation::registerIonFrameRecovery(RInstructionResults&& results)
+{
+ // Check that there is no entry in the vector yet.
+ MOZ_ASSERT(!maybeIonFrameRecovery(results.frame()));
+ if (!ionRecovery_.append(mozilla::Move(results)))
+ return false;
+
+ return true;
+}
+
+jit::RInstructionResults*
+jit::JitActivation::maybeIonFrameRecovery(JitFrameLayout* fp)
+{
+ for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); ) {
+ if (it->frame() == fp)
+ return it;
+ }
+
+ return nullptr;
+}
+
+void
+jit::JitActivation::removeIonFrameRecovery(JitFrameLayout* fp)
+{
+ RInstructionResults* elem = maybeIonFrameRecovery(fp);
+ if (!elem)
+ return;
+
+ ionRecovery_.erase(elem);
+}
+
+void
+jit::JitActivation::markIonRecovery(JSTracer* trc)
+{
+ for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++)
+ it->trace(trc);
+}
+
+WasmActivation::WasmActivation(JSContext* cx)
+ : Activation(cx, Wasm),
+ entrySP_(nullptr),
+ resumePC_(nullptr),
+ fp_(nullptr),
+ exitReason_(wasm::ExitReason::None)
+{
+ (void) entrySP_; // silence "unused private member" warning
+
+ prevWasm_ = cx->runtime()->wasmActivationStack_;
+ cx->runtime()->wasmActivationStack_ = this;
+
+ cx->compartment()->wasm.activationCount_++;
+
+ // Now that the WasmActivation is fully initialized, make it visible to
+ // asynchronous profiling.
+ registerProfiling();
+}
+
+WasmActivation::~WasmActivation()
+{
+ // Hide this activation from the profiler before is is destroyed.
+ unregisterProfiling();
+
+ MOZ_ASSERT(fp_ == nullptr);
+
+ MOZ_ASSERT(cx_->runtime()->wasmActivationStack_ == this);
+ cx_->runtime()->wasmActivationStack_ = prevWasm_;
+
+ MOZ_ASSERT(cx_->compartment()->wasm.activationCount_ > 0);
+ cx_->compartment()->wasm.activationCount_--;
+}
+
+InterpreterFrameIterator&
+InterpreterFrameIterator::operator++()
+{
+ MOZ_ASSERT(!done());
+ if (fp_ != activation_->entryFrame_) {
+ pc_ = fp_->prevpc();
+ sp_ = fp_->prevsp();
+ fp_ = fp_->prev();
+ } else {
+ pc_ = nullptr;
+ sp_ = nullptr;
+ fp_ = nullptr;
+ }
+ return *this;
+}
+
+void
+Activation::registerProfiling()
+{
+ MOZ_ASSERT(isProfiling());
+ cx_->runtime()->profilingActivation_ = this;
+}
+
+void
+Activation::unregisterProfiling()
+{
+ MOZ_ASSERT(isProfiling());
+ MOZ_ASSERT(cx_->runtime()->profilingActivation_ == this);
+
+ // There may be a non-active jit activation in the linked list. Skip past it.
+ Activation* prevProfiling = prevProfiling_;
+ while (prevProfiling && prevProfiling->isJit() && !prevProfiling->asJit()->isActive())
+ prevProfiling = prevProfiling->prevProfiling_;
+
+ cx_->runtime()->profilingActivation_ = prevProfiling;
+}
+
+ActivationIterator::ActivationIterator(JSRuntime* rt)
+ : jitTop_(rt->jitTop),
+ activation_(rt->activation_)
+{
+ settle();
+}
+
+ActivationIterator&
+ActivationIterator::operator++()
+{
+ MOZ_ASSERT(activation_);
+ if (activation_->isJit() && activation_->asJit()->isActive())
+ jitTop_ = activation_->asJit()->prevJitTop();
+ activation_ = activation_->prev();
+ settle();
+ return *this;
+}
+
+void
+ActivationIterator::settle()
+{
+ // Stop at the next active activation. No need to update jitTop_, since
+ // we don't iterate over an active jit activation.
+ while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
+ activation_ = activation_->prev();
+}
+
+JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const RegisterState& state,
+ uint32_t sampleBufferGen)
+ : rt_(cx),
+ sampleBufferGen_(sampleBufferGen),
+ activation_(nullptr),
+ savedPrevJitTop_(nullptr),
+ nogc_(cx)
+{
+ if (!cx->spsProfiler.enabled())
+ MOZ_CRASH("ProfilingFrameIterator called when spsProfiler not enabled for runtime.");
+
+ if (!cx->profilingActivation())
+ return;
+
+ // If profiler sampling is not enabled, skip.
+ if (!cx->isProfilerSamplingEnabled())
+ return;
+
+ activation_ = cx->profilingActivation();
+
+ MOZ_ASSERT(activation_->isProfiling());
+
+ static_assert(sizeof(wasm::ProfilingFrameIterator) <= StorageSpace &&
+ sizeof(jit::JitProfilingFrameIterator) <= StorageSpace,
+ "Need to increase storage");
+
+ iteratorConstruct(state);
+ settle();
+}
+
+JS::ProfilingFrameIterator::~ProfilingFrameIterator()
+{
+ if (!done()) {
+ MOZ_ASSERT(activation_->isProfiling());
+ iteratorDestroy();
+ }
+}
+
+void
+JS::ProfilingFrameIterator::operator++()
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm()) {
+ ++wasmIter();
+ settle();
+ return;
+ }
+
+ ++jitIter();
+ settle();
+}
+
+void
+JS::ProfilingFrameIterator::settle()
+{
+ while (iteratorDone()) {
+ iteratorDestroy();
+ activation_ = activation_->prevProfiling();
+
+ // Skip past any non-active jit activations in the list.
+ while (activation_ && activation_->isJit() && !activation_->asJit()->isActive())
+ activation_ = activation_->prevProfiling();
+
+ if (!activation_)
+ return;
+ iteratorConstruct();
+ }
+}
+
+void
+JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm()) {
+ new (storage_.addr()) wasm::ProfilingFrameIterator(*activation_->asWasm(), state);
+ // Set savedPrevJitTop_ to the actual jitTop_ from the runtime.
+ savedPrevJitTop_ = activation_->cx()->runtime()->jitTop;
+ return;
+ }
+
+ MOZ_ASSERT(activation_->asJit()->isActive());
+ new (storage_.addr()) jit::JitProfilingFrameIterator(rt_, state);
+}
+
+void
+JS::ProfilingFrameIterator::iteratorConstruct()
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm()) {
+ new (storage_.addr()) wasm::ProfilingFrameIterator(*activation_->asWasm());
+ return;
+ }
+
+ MOZ_ASSERT(activation_->asJit()->isActive());
+ MOZ_ASSERT(savedPrevJitTop_ != nullptr);
+ new (storage_.addr()) jit::JitProfilingFrameIterator(savedPrevJitTop_);
+}
+
+void
+JS::ProfilingFrameIterator::iteratorDestroy()
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm()) {
+ wasmIter().~ProfilingFrameIterator();
+ return;
+ }
+
+ // Save prevjitTop for later use
+ savedPrevJitTop_ = activation_->asJit()->prevJitTop();
+ jitIter().~JitProfilingFrameIterator();
+}
+
+bool
+JS::ProfilingFrameIterator::iteratorDone()
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm())
+ return wasmIter().done();
+
+ return jitIter().done();
+}
+
+void*
+JS::ProfilingFrameIterator::stackAddress() const
+{
+ MOZ_ASSERT(!done());
+ MOZ_ASSERT(activation_->isWasm() || activation_->isJit());
+
+ if (activation_->isWasm())
+ return wasmIter().stackAddress();
+
+ return jitIter().stackAddress();
+}
+
+Maybe<JS::ProfilingFrameIterator::Frame>
+JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry* entry) const
+{
+ void* stackAddr = stackAddress();
+
+ if (isWasm()) {
+ Frame frame;
+ frame.kind = Frame_Wasm;
+ frame.stackAddress = stackAddr;
+ frame.returnAddress = nullptr;
+ frame.activation = activation_;
+ return mozilla::Some(mozilla::Move(frame));
+ }
+
+ MOZ_ASSERT(isJit());
+
+ // Look up an entry for the return address.
+ void* returnAddr = jitIter().returnAddressToFp();
+ jit::JitcodeGlobalTable* table = rt_->jitRuntime()->getJitcodeGlobalTable();
+ if (hasSampleBufferGen())
+ *entry = table->lookupForSamplerInfallible(returnAddr, rt_, sampleBufferGen_);
+ else
+ *entry = table->lookupInfallible(returnAddr);
+
+ MOZ_ASSERT(entry->isIon() || entry->isIonCache() || entry->isBaseline() || entry->isDummy());
+
+ // Dummy frames produce no stack frames.
+ if (entry->isDummy())
+ return mozilla::Nothing();
+
+ Frame frame;
+ frame.kind = entry->isBaseline() ? Frame_Baseline : Frame_Ion;
+ frame.stackAddress = stackAddr;
+ frame.returnAddress = returnAddr;
+ frame.activation = activation_;
+ return mozilla::Some(mozilla::Move(frame));
+}
+
+uint32_t
+JS::ProfilingFrameIterator::extractStack(Frame* frames, uint32_t offset, uint32_t end) const
+{
+ if (offset >= end)
+ return 0;
+
+ jit::JitcodeGlobalEntry entry;
+ Maybe<Frame> physicalFrame = getPhysicalFrameAndEntry(&entry);
+
+ // Dummy frames produce no stack frames.
+ if (physicalFrame.isNothing())
+ return 0;
+
+ if (isWasm()) {
+ frames[offset] = mozilla::Move(physicalFrame.ref());
+ frames[offset].label = DuplicateString(wasmIter().label());
+ if (!frames[offset].label)
+ return 0; // Drop stack frames silently on OOM.
+ return 1;
+ }
+
+ // Extract the stack for the entry. Assume maximum inlining depth is <64
+ const char* labels[64];
+ uint32_t depth = entry.callStackAtAddr(rt_, jitIter().returnAddressToFp(), labels, 64);
+ MOZ_ASSERT(depth < 64);
+ for (uint32_t i = 0; i < depth; i++) {
+ if (offset + i >= end)
+ return i;
+ Frame& frame = frames[offset + i];
+ frame = mozilla::Move(physicalFrame.ref());
+ frame.label = DuplicateString(labels[i]);
+ if (!frame.label)
+ return i; // Drop stack frames silently on OOM.
+ }
+
+ return depth;
+}
+
+Maybe<JS::ProfilingFrameIterator::Frame>
+JS::ProfilingFrameIterator::getPhysicalFrameWithoutLabel() const
+{
+ jit::JitcodeGlobalEntry unused;
+ return getPhysicalFrameAndEntry(&unused);
+}
+
+bool
+JS::ProfilingFrameIterator::isWasm() const
+{
+ MOZ_ASSERT(!done());
+ return activation_->isWasm();
+}
+
+bool
+JS::ProfilingFrameIterator::isJit() const
+{
+ return activation_->isJit();
+}
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
new file mode 100644
index 000000000..552738d89
--- /dev/null
+++ b/js/src/vm/Stack.h
@@ -0,0 +1,2077 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Stack_h
+#define vm_Stack_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Variant.h"
+
+#include "jsfun.h"
+#include "jsscript.h"
+#include "jsutil.h"
+
+#include "gc/Rooting.h"
+#include "jit/JitFrameIterator.h"
+#ifdef CHECK_OSIPOINT_REGISTERS
+#include "jit/Registers.h" // for RegisterDump
+#endif
+#include "js/RootingAPI.h"
+#include "vm/ArgumentsObject.h"
+#include "vm/SavedFrame.h"
+#include "wasm/WasmFrameIterator.h"
+
+struct JSCompartment;
+
+namespace JS {
+namespace dbg {
+#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes"
+#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
+
+class JS_PUBLIC_API(AutoEntryMonitor);
+
+#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
+#pragma GCC diagnostic pop
+#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
+} // namespace dbg
+} // namespace JS
+
+namespace js {
+
+class InterpreterRegs;
+class CallObject;
+class FrameIter;
+class EnvironmentObject;
+class ScriptFrameIter;
+class SPSProfiler;
+class InterpreterFrame;
+class LexicalEnvironmentObject;
+class EnvironmentIter;
+class EnvironmentCoordinate;
+
+class SavedFrame;
+
+namespace jit {
+class CommonFrameLayout;
+}
+namespace wasm {
+class Instance;
+}
+
+// VM stack layout
+//
+// A JSRuntime's stack consists of a linked list of activations. Every activation
+// contains a number of scripted frames that are either running in the interpreter
+// (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
+// activation are contiguous: whenever C++ calls back into JS, a new activation is
+// pushed.
+//
+// Every activation is tied to a single JSContext and JSCompartment. This means we
+// can reconstruct a given context's stack by skipping activations belonging to other
+// contexts. This happens whenever an embedding enters the JS engine on cx1 and
+// then, from a native called by the JS engine, reenters the VM on cx2.
+
+// Interpreter frames (InterpreterFrame)
+//
+// Each interpreter script activation (global or function code) is given a
+// fixed-size header (js::InterpreterFrame). The frame contains bookkeeping
+// information about the activation and links to the previous frame.
+//
+// The values after an InterpreterFrame in memory are its locals followed by its
+// expression stack. InterpreterFrame::argv_ points to the frame's arguments.
+// Missing formal arguments are padded with |undefined|, so the number of
+// arguments is always >= the number of formals.
+//
+// The top of an activation's current frame's expression stack is pointed to by
+// the activation's "current regs", which contains the stack pointer 'sp'. In
+// the interpreter, sp is adjusted as individual values are pushed and popped
+// from the stack and the InterpreterRegs struct (pointed to by the
+// InterpreterActivation) is a local var of js::Interpret.
+
+enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
+enum MaybeCheckTDZ { CheckTDZ = true, DontCheckTDZ = false };
+
+/*****************************************************************************/
+
+namespace jit {
+ class BaselineFrame;
+ class RematerializedFrame;
+} // namespace jit
+
+/*
+ * Pointer to either a ScriptFrameIter::Data, an InterpreterFrame, or a Baseline
+ * JIT frame.
+ *
+ * The Debugger may cache ScriptFrameIter::Data as a bookmark to reconstruct a
+ * ScriptFrameIter without doing a full stack walk.
+ *
+ * There is no way to directly create such an AbstractFramePtr. To do so, the
+ * user must call ScriptFrameIter::copyDataAsAbstractFramePtr().
+ *
+ * ScriptFrameIter::abstractFramePtr() will never return an AbstractFramePtr
+ * that is in fact a ScriptFrameIter::Data.
+ *
+ * To recover a ScriptFrameIter settled at the location pointed to by an
+ * AbstractFramePtr, use the THIS_FRAME_ITER macro in Debugger.cpp. As an
+ * aside, no asScriptFrameIterData() is provided because C++ is stupid and
+ * cannot forward declare inner classes.
+ */
+
+class AbstractFramePtr
+{
+ friend class FrameIter;
+
+ uintptr_t ptr_;
+
+ enum {
+ Tag_ScriptFrameIterData = 0x0,
+ Tag_InterpreterFrame = 0x1,
+ Tag_BaselineFrame = 0x2,
+ Tag_RematerializedFrame = 0x3,
+ TagMask = 0x3
+ };
+
+ public:
+ AbstractFramePtr()
+ : ptr_(0)
+ {}
+
+ MOZ_IMPLICIT AbstractFramePtr(InterpreterFrame* fp)
+ : ptr_(fp ? uintptr_t(fp) | Tag_InterpreterFrame : 0)
+ {
+ MOZ_ASSERT_IF(fp, asInterpreterFrame() == fp);
+ }
+
+ MOZ_IMPLICIT AbstractFramePtr(jit::BaselineFrame* fp)
+ : ptr_(fp ? uintptr_t(fp) | Tag_BaselineFrame : 0)
+ {
+ MOZ_ASSERT_IF(fp, asBaselineFrame() == fp);
+ }
+
+ MOZ_IMPLICIT AbstractFramePtr(jit::RematerializedFrame* fp)
+ : ptr_(fp ? uintptr_t(fp) | Tag_RematerializedFrame : 0)
+ {
+ MOZ_ASSERT_IF(fp, asRematerializedFrame() == fp);
+ }
+
+ static AbstractFramePtr FromRaw(void* raw) {
+ AbstractFramePtr frame;
+ frame.ptr_ = uintptr_t(raw);
+ return frame;
+ }
+
+ bool isScriptFrameIterData() const {
+ return !!ptr_ && (ptr_ & TagMask) == Tag_ScriptFrameIterData;
+ }
+ bool isInterpreterFrame() const {
+ return (ptr_ & TagMask) == Tag_InterpreterFrame;
+ }
+ InterpreterFrame* asInterpreterFrame() const {
+ MOZ_ASSERT(isInterpreterFrame());
+ InterpreterFrame* res = (InterpreterFrame*)(ptr_ & ~TagMask);
+ MOZ_ASSERT(res);
+ return res;
+ }
+ bool isBaselineFrame() const {
+ return (ptr_ & TagMask) == Tag_BaselineFrame;
+ }
+ jit::BaselineFrame* asBaselineFrame() const {
+ MOZ_ASSERT(isBaselineFrame());
+ jit::BaselineFrame* res = (jit::BaselineFrame*)(ptr_ & ~TagMask);
+ MOZ_ASSERT(res);
+ return res;
+ }
+ bool isRematerializedFrame() const {
+ return (ptr_ & TagMask) == Tag_RematerializedFrame;
+ }
+ jit::RematerializedFrame* asRematerializedFrame() const {
+ MOZ_ASSERT(isRematerializedFrame());
+ jit::RematerializedFrame* res = (jit::RematerializedFrame*)(ptr_ & ~TagMask);
+ MOZ_ASSERT(res);
+ return res;
+ }
+
+ void* raw() const { return reinterpret_cast<void*>(ptr_); }
+
+ bool operator ==(const AbstractFramePtr& other) const { return ptr_ == other.ptr_; }
+ bool operator !=(const AbstractFramePtr& other) const { return ptr_ != other.ptr_; }
+
+ explicit operator bool() const { return !!ptr_; }
+
+ inline JSObject* environmentChain() const;
+ inline CallObject& callObj() const;
+ inline bool initFunctionEnvironmentObjects(JSContext* cx);
+ inline bool pushVarEnvironment(JSContext* cx, HandleScope scope);
+ template <typename SpecificEnvironment>
+ inline void pushOnEnvironmentChain(SpecificEnvironment& env);
+ template <typename SpecificEnvironment>
+ inline void popOffEnvironmentChain();
+
+ inline JSCompartment* compartment() const;
+
+ inline bool hasInitialEnvironment() const;
+ inline bool isGlobalFrame() const;
+ inline bool isModuleFrame() const;
+ inline bool isEvalFrame() const;
+ inline bool isDebuggerEvalFrame() const;
+ inline bool hasCachedSavedFrame() const;
+ inline void setHasCachedSavedFrame();
+
+ inline JSScript* script() const;
+ inline JSFunction* callee() const;
+ inline Value calleev() const;
+ inline Value& thisArgument() const;
+
+ inline Value newTarget() const;
+
+ inline bool debuggerNeedsCheckPrimitiveReturn() const;
+
+ inline bool isFunctionFrame() const;
+ inline bool isNonStrictDirectEvalFrame() const;
+ inline bool isStrictEvalFrame() const;
+
+ inline unsigned numActualArgs() const;
+ inline unsigned numFormalArgs() const;
+
+ inline Value* argv() const;
+
+ inline bool hasArgs() const;
+ inline bool hasArgsObj() const;
+ inline ArgumentsObject& argsObj() const;
+ inline void initArgsObj(ArgumentsObject& argsobj) const;
+ inline bool createSingleton() const;
+
+ inline Value& unaliasedLocal(uint32_t i);
+ inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
+ inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
+ template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
+
+ inline bool prevUpToDate() const;
+ inline void setPrevUpToDate() const;
+ inline void unsetPrevUpToDate() const;
+
+ inline bool isDebuggee() const;
+ inline void setIsDebuggee();
+ inline void unsetIsDebuggee();
+
+ inline HandleValue returnValue() const;
+ inline void setReturnValue(const Value& rval) const;
+
+ friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, void*);
+ friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, InterpreterFrame*);
+ friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::BaselineFrame*);
+ friend void GDBTestInitAbstractFramePtr(AbstractFramePtr&, jit::RematerializedFrame*);
+};
+
+class NullFramePtr : public AbstractFramePtr
+{
+ public:
+ NullFramePtr()
+ : AbstractFramePtr()
+ { }
+};
+
+enum MaybeConstruct { NO_CONSTRUCT = false, CONSTRUCT = true };
+
+/*****************************************************************************/
+
+class InterpreterFrame
+{
+ enum Flags : uint32_t {
+ CONSTRUCTING = 0x1, /* frame is for a constructor invocation */
+
+ RESUMED_GENERATOR = 0x2, /* frame is for a resumed generator invocation */
+
+ /* Function prologue state */
+ HAS_INITIAL_ENV = 0x4, /* callobj created for function or var env for eval */
+ HAS_ARGS_OBJ = 0x8, /* ArgumentsObject created for needsArgsObj script */
+
+ /* Lazy frame initialization */
+ HAS_RVAL = 0x10, /* frame has rval_ set */
+
+ /* Debugger state */
+ PREV_UP_TO_DATE = 0x20, /* see DebugScopes::updateLiveScopes */
+
+ /*
+ * See comment above 'isDebuggee' in jscompartment.h for explanation of
+ * invariants of debuggee compartments, scripts, and frames.
+ */
+ DEBUGGEE = 0x40, /* Execution is being observed by Debugger */
+
+ /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
+ HAS_PUSHED_SPS_FRAME = 0x80, /* SPS was notified of entry */
+
+ /*
+ * If set, we entered one of the JITs and ScriptFrameIter should skip
+ * this frame.
+ */
+ RUNNING_IN_JIT = 0x100,
+
+ /* Miscellaneous state. */
+ CREATE_SINGLETON = 0x200, /* Constructed |this| object should be singleton. */
+
+ /*
+ * If set, this frame has been on the stack when
+ * |js::SavedStacks::saveCurrentStack| was called, and so there is a
+ * |js::SavedFrame| object cached for this frame.
+ */
+ HAS_CACHED_SAVED_FRAME = 0x400,
+ };
+
+ mutable uint32_t flags_; /* bits described by Flags */
+ uint32_t nactual_; /* number of actual arguments, for function frames */
+ JSScript* script_; /* the script we're executing */
+ JSObject* envChain_; /* current environment chain */
+ Value rval_; /* if HAS_RVAL, return value of the frame */
+ ArgumentsObject* argsObj_; /* if HAS_ARGS_OBJ, the call's arguments object */
+
+ /*
+ * Previous frame and its pc and sp. Always nullptr for
+ * InterpreterActivation's entry frame, always non-nullptr for inline
+ * frames.
+ */
+ InterpreterFrame* prev_;
+ jsbytecode* prevpc_;
+ Value* prevsp_;
+
+ void* unused;
+
+ /*
+ * For an eval-in-frame DEBUGGER_EVAL frame, the frame in whose scope
+ * we're evaluating code. Iteration treats this as our previous frame.
+ */
+ AbstractFramePtr evalInFramePrev_;
+
+ Value* argv_; /* If hasArgs(), points to frame's arguments. */
+ LifoAlloc::Mark mark_; /* Used to release memory for this frame. */
+
+ static void staticAsserts() {
+ JS_STATIC_ASSERT(offsetof(InterpreterFrame, rval_) % sizeof(Value) == 0);
+ JS_STATIC_ASSERT(sizeof(InterpreterFrame) % sizeof(Value) == 0);
+ }
+
+ /*
+ * The utilities are private since they are not able to assert that only
+ * unaliased vars/formals are accessed. Normal code should prefer the
+ * InterpreterFrame::unaliased* members (or InterpreterRegs::stackDepth for
+ * the usual "depth is at least" assertions).
+ */
+ Value* slots() const { return (Value*)(this + 1); }
+ Value* base() const { return slots() + script()->nfixed(); }
+
+ friend class FrameIter;
+ friend class InterpreterRegs;
+ friend class InterpreterStack;
+ friend class jit::BaselineFrame;
+
+ /*
+ * Frame initialization, called by InterpreterStack operations after acquiring
+ * the raw memory for the frame:
+ */
+
+ /* Used for Invoke and Interpret. */
+ void initCallFrame(JSContext* cx, InterpreterFrame* prev, jsbytecode* prevpc, Value* prevsp,
+ JSFunction& callee, JSScript* script, Value* argv, uint32_t nactual,
+ MaybeConstruct constructing);
+
+ /* Used for global and eval frames. */
+ void initExecuteFrame(JSContext* cx, HandleScript script, AbstractFramePtr prev,
+ const Value& newTargetValue, HandleObject envChain);
+
+ public:
+ /*
+ * Frame prologue/epilogue
+ *
+ * Every stack frame must have 'prologue' called before executing the
+ * first op and 'epilogue' called after executing the last op and before
+ * popping the frame (whether the exit is exceptional or not).
+ *
+ * For inline JS calls/returns, it is easy to call the prologue/epilogue
+ * exactly once. When calling JS from C++, Invoke/Execute push the stack
+ * frame but do *not* call the prologue/epilogue. That means Interpret
+ * must call the prologue/epilogue for the entry frame. This scheme
+ * simplifies jit compilation.
+ *
+ * An important corner case is what happens when an error occurs (OOM,
+ * over-recursed) after pushing the stack frame but before 'prologue' is
+ * called or completes fully. To simplify usage, 'epilogue' does not assume
+ * 'prologue' has completed and handles all the intermediate state details.
+ */
+
+ bool prologue(JSContext* cx);
+ void epilogue(JSContext* cx, jsbytecode* pc);
+
+ bool checkReturn(JSContext* cx, HandleValue thisv);
+
+ bool initFunctionEnvironmentObjects(JSContext* cx);
+
+ /*
+ * Initialize locals of newly-pushed frame to undefined.
+ */
+ void initLocals();
+
+ /*
+ * Stack frame type
+ *
+ * A stack frame may have one of four types, which determines which
+ * members of the frame may be accessed and other invariants:
+ *
+ * global frame: execution of global code
+ * function frame: execution of function code
+ * module frame: execution of a module
+ * eval frame: execution of eval code
+ */
+
+ bool isGlobalFrame() const {
+ return script_->isGlobalCode();
+ }
+
+ bool isModuleFrame() const {
+ return script_->module();
+ }
+
+ bool isEvalFrame() const {
+ return script_->isForEval();
+ }
+
+ bool isFunctionFrame() const {
+ return script_->functionNonDelazifying();
+ }
+
+ inline bool isStrictEvalFrame() const {
+ return isEvalFrame() && script()->strict();
+ }
+
+ bool isNonStrictEvalFrame() const {
+ return isEvalFrame() && !script()->strict();
+ }
+
+ bool isNonGlobalEvalFrame() const;
+
+ bool isNonStrictDirectEvalFrame() const {
+ return isNonStrictEvalFrame() && isNonGlobalEvalFrame();
+ }
+
+ /*
+ * Previous frame
+ *
+ * A frame's 'prev' frame is either null or the previous frame pointed to
+ * by cx->regs->fp when this frame was pushed. Often, given two prev-linked
+ * frames, the next-frame is a function or eval that was called by the
+ * prev-frame, but not always: the prev-frame may have called a native that
+ * reentered the VM through JS_CallFunctionValue on the same context
+ * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
+ * 'prev' has little semantic meaning and basically just tells the VM what
+ * to set cx->regs->fp to when this frame is popped.
+ */
+
+ InterpreterFrame* prev() const {
+ return prev_;
+ }
+
+ AbstractFramePtr evalInFramePrev() const {
+ MOZ_ASSERT(isEvalFrame());
+ return evalInFramePrev_;
+ }
+
+ /*
+ * (Unaliased) locals and arguments
+ *
+ * Only non-eval function frames have arguments. The arguments pushed by
+ * the caller are the 'actual' arguments. The declared arguments of the
+ * callee are the 'formal' arguments. When the caller passes less actual
+ * arguments, missing formal arguments are padded with |undefined|.
+ *
+ * When a local/formal variable is aliased (accessed by nested closures,
+ * environment operations, or 'arguments'), the canonical location for
+ * that value is the slot of an environment object. Aliased locals don't
+ * have stack slots assigned to them. These functions assert that
+ * accesses to stack values are unaliased.
+ */
+
+ inline Value& unaliasedLocal(uint32_t i);
+
+ bool hasArgs() const { return isFunctionFrame(); }
+ inline Value& unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
+ inline Value& unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
+ template <class Op> inline void unaliasedForEachActual(Op op);
+
+ unsigned numFormalArgs() const { MOZ_ASSERT(hasArgs()); return callee().nargs(); }
+ unsigned numActualArgs() const { MOZ_ASSERT(hasArgs()); return nactual_; }
+
+ /* Watch out, this exposes a pointer to the unaliased formal arg array. */
+ Value* argv() const { MOZ_ASSERT(hasArgs()); return argv_; }
+
+ /*
+ * Arguments object
+ *
+ * If a non-eval function has script->needsArgsObj, an arguments object is
+ * created in the prologue and stored in the local variable for the
+ * 'arguments' binding (script->argumentsLocal). Since this local is
+ * mutable, the arguments object can be overwritten and we can "lose" the
+ * arguments object. Thus, InterpreterFrame keeps an explicit argsObj_ field so
+ * that the original arguments object is always available.
+ */
+
+ ArgumentsObject& argsObj() const;
+ void initArgsObj(ArgumentsObject& argsobj);
+
+ JSObject* createRestParameter(JSContext* cx);
+
+ /*
+ * Environment chain
+ *
+ * In theory, the environment chain would contain an object for every
+ * lexical scope. However, only objects that are required for dynamic
+ * lookup are actually created.
+ *
+ * Given that an InterpreterFrame corresponds roughly to a ES Execution
+ * Context (ES 10.3), InterpreterFrame::varObj corresponds to the
+ * VariableEnvironment component of a Exection Context. Intuitively, the
+ * variables object is where new bindings (variables and functions) are
+ * stored. One might expect that this is either the Call object or
+ * envChain.globalObj for function or global code, respectively, however
+ * the JSAPI allows calls of Execute to specify a variables object on the
+ * environment chain other than the call/global object. This allows
+ * embeddings to run multiple scripts under the same global, each time
+ * using a new variables object to collect and discard the script's global
+ * variables.
+ */
+
+ inline HandleObject environmentChain() const;
+
+ inline EnvironmentObject& aliasedEnvironment(EnvironmentCoordinate ec) const;
+ inline GlobalObject& global() const;
+ inline CallObject& callObj() const;
+ inline JSObject& varObj() const;
+ inline LexicalEnvironmentObject& extensibleLexicalEnvironment() const;
+
+ template <typename SpecificEnvironment>
+ inline void pushOnEnvironmentChain(SpecificEnvironment& env);
+ template <typename SpecificEnvironment>
+ inline void popOffEnvironmentChain();
+ inline void replaceInnermostEnvironment(EnvironmentObject& env);
+
+ // Push a VarEnvironmentObject for function frames of functions that have
+ // parameter expressions with closed over var bindings.
+ bool pushVarEnvironment(JSContext* cx, HandleScope scope);
+
+ /*
+ * For lexical envs with aliased locals, these interfaces push and pop
+ * entries on the environment chain. The "freshen" operation replaces the
+ * current lexical env with a fresh copy of it, to implement semantics
+ * providing distinct bindings per iteration of a for(;;) loop whose head
+ * has a lexical declaration. The "recreate" operation replaces the
+ * current lexical env with a copy of it containing uninitialized
+ * bindings, to implement semantics providing distinct bindings per
+ * iteration of a for-in/of loop.
+ */
+
+ bool pushLexicalEnvironment(JSContext* cx, Handle<LexicalScope*> scope);
+ bool freshenLexicalEnvironment(JSContext* cx);
+ bool recreateLexicalEnvironment(JSContext* cx);
+
+ /*
+ * Script
+ *
+ * All frames have an associated JSScript which holds the bytecode being
+ * executed for the frame.
+ */
+
+ JSScript* script() const {
+ return script_;
+ }
+
+ /* Return the previous frame's pc. */
+ jsbytecode* prevpc() {
+ MOZ_ASSERT(prev_);
+ return prevpc_;
+ }
+
+ /* Return the previous frame's sp. */
+ Value* prevsp() {
+ MOZ_ASSERT(prev_);
+ return prevsp_;
+ }
+
+ /*
+ * Return the 'this' argument passed to a non-eval function frame. This is
+ * not necessarily the frame's this-binding, for instance non-strict
+ * functions will box primitive 'this' values and thisArgument() will
+ * return the original, unboxed Value.
+ */
+ Value& thisArgument() const {
+ MOZ_ASSERT(isFunctionFrame());
+ return argv()[-1];
+ }
+
+ /*
+ * Callee
+ *
+ * Only function frames have a callee. An eval frame in a function has the
+ * same callee as its containing function frame.
+ */
+
+ JSFunction& callee() const {
+ MOZ_ASSERT(isFunctionFrame());
+ return calleev().toObject().as<JSFunction>();
+ }
+
+ const Value& calleev() const {
+ MOZ_ASSERT(isFunctionFrame());
+ return argv()[-2];
+ }
+
+ /*
+ * New Target
+ *
+ * Only function frames have a meaningful newTarget. An eval frame in a
+ * function will have a copy of the newTarget of the enclosing function
+ * frame.
+ */
+ Value newTarget() const {
+ if (isEvalFrame())
+ return ((Value*)this)[-1];
+
+ MOZ_ASSERT(isFunctionFrame());
+
+ if (callee().isArrow())
+ return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
+
+ if (isConstructing()) {
+ unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
+ return argv()[pushedArgs];
+ }
+ return UndefinedValue();
+ }
+
+ /* Profiler flags */
+
+ bool hasPushedSPSFrame() {
+ return !!(flags_ & HAS_PUSHED_SPS_FRAME);
+ }
+
+ void setPushedSPSFrame() {
+ flags_ |= HAS_PUSHED_SPS_FRAME;
+ }
+
+ void unsetPushedSPSFrame() {
+ flags_ &= ~HAS_PUSHED_SPS_FRAME;
+ }
+
+ /* Return value */
+
+ bool hasReturnValue() const {
+ return flags_ & HAS_RVAL;
+ }
+
+ MutableHandleValue returnValue() {
+ if (!hasReturnValue())
+ rval_.setUndefined();
+ return MutableHandleValue::fromMarkedLocation(&rval_);
+ }
+
+ void markReturnValue() {
+ flags_ |= HAS_RVAL;
+ }
+
+ void setReturnValue(const Value& v) {
+ rval_ = v;
+ markReturnValue();
+ }
+
+ void clearReturnValue() {
+ rval_.setUndefined();
+ markReturnValue();
+ }
+
+ void resumeGeneratorFrame(JSObject* envChain) {
+ MOZ_ASSERT(script()->isGenerator());
+ MOZ_ASSERT(isFunctionFrame());
+ flags_ |= HAS_INITIAL_ENV;
+ envChain_ = envChain;
+ }
+
+ /*
+ * Other flags
+ */
+
+ bool isConstructing() const {
+ return !!(flags_ & CONSTRUCTING);
+ }
+
+ void setResumedGenerator() {
+ flags_ |= RESUMED_GENERATOR;
+ }
+ bool isResumedGenerator() const {
+ return !!(flags_ & RESUMED_GENERATOR);
+ }
+
+ /*
+ * These two queries should not be used in general: the presence/absence of
+ * the call/args object is determined by the static(ish) properties of the
+ * JSFunction/JSScript. These queries should only be performed when probing
+ * a stack frame that may be in the middle of the prologue (during which
+ * time the call/args object are created).
+ */
+
+ inline bool hasInitialEnvironment() const;
+
+ bool hasInitialEnvironmentUnchecked() const {
+ return flags_ & HAS_INITIAL_ENV;
+ }
+
+ bool hasArgsObj() const {
+ MOZ_ASSERT(script()->needsArgsObj());
+ return flags_ & HAS_ARGS_OBJ;
+ }
+
+ void setCreateSingleton() {
+ MOZ_ASSERT(isConstructing());
+ flags_ |= CREATE_SINGLETON;
+ }
+ bool createSingleton() const {
+ MOZ_ASSERT(isConstructing());
+ return flags_ & CREATE_SINGLETON;
+ }
+
+ /*
+ * Debugger eval frames.
+ *
+ * - If evalInFramePrev_ is non-null, frame was created for an "eval in
+ * frame" call, which can push a successor to any live frame; so its
+ * logical "prev" frame is not necessarily the previous frame in memory.
+ * Iteration should treat evalInFramePrev_ as this frame's previous frame.
+ *
+ * - Don't bother to JIT it, because it's probably short-lived.
+ *
+ * - It is required to have a environment chain object outside the
+ * js::EnvironmentObject hierarchy: either a global object, or a
+ * DebugEnvironmentProxy.
+ */
+ bool isDebuggerEvalFrame() const {
+ return isEvalFrame() && !!evalInFramePrev_;
+ }
+
+ bool prevUpToDate() const {
+ return !!(flags_ & PREV_UP_TO_DATE);
+ }
+
+ void setPrevUpToDate() {
+ flags_ |= PREV_UP_TO_DATE;
+ }
+
+ void unsetPrevUpToDate() {
+ flags_ &= ~PREV_UP_TO_DATE;
+ }
+
+ bool isDebuggee() const {
+ return !!(flags_ & DEBUGGEE);
+ }
+
+ void setIsDebuggee() {
+ flags_ |= DEBUGGEE;
+ }
+
+ inline void unsetIsDebuggee();
+
+ bool hasCachedSavedFrame() const {
+ return flags_ & HAS_CACHED_SAVED_FRAME;
+ }
+ void setHasCachedSavedFrame() {
+ flags_ |= HAS_CACHED_SAVED_FRAME;
+ }
+
+ public:
+ void trace(JSTracer* trc, Value* sp, jsbytecode* pc);
+ void traceValues(JSTracer* trc, unsigned start, unsigned end);
+
+ // Entered Baseline/Ion from the interpreter.
+ bool runningInJit() const {
+ return !!(flags_ & RUNNING_IN_JIT);
+ }
+ void setRunningInJit() {
+ flags_ |= RUNNING_IN_JIT;
+ }
+ void clearRunningInJit() {
+ flags_ &= ~RUNNING_IN_JIT;
+ }
+};
+
+/*****************************************************************************/
+
+class InterpreterRegs
+{
+ public:
+ Value* sp;
+ jsbytecode* pc;
+ private:
+ InterpreterFrame* fp_;
+ public:
+ InterpreterFrame* fp() const { return fp_; }
+
+ unsigned stackDepth() const {
+ MOZ_ASSERT(sp >= fp_->base());
+ return sp - fp_->base();
+ }
+
+ Value* spForStackDepth(unsigned depth) const {
+ MOZ_ASSERT(fp_->script()->nfixed() + depth <= fp_->script()->nslots());
+ return fp_->base() + depth;
+ }
+
+ /* For generators. */
+ void rebaseFromTo(const InterpreterRegs& from, InterpreterFrame& to) {
+ fp_ = &to;
+ sp = to.slots() + (from.sp - from.fp_->slots());
+ pc = from.pc;
+ MOZ_ASSERT(fp_);
+ }
+
+ void popInlineFrame() {
+ pc = fp_->prevpc();
+ unsigned spForNewTarget = fp_->isResumedGenerator() ? 0 : fp_->isConstructing();
+ sp = fp_->prevsp() - fp_->numActualArgs() - 1 - spForNewTarget;
+ fp_ = fp_->prev();
+ MOZ_ASSERT(fp_);
+ }
+ void prepareToRun(InterpreterFrame& fp, JSScript* script) {
+ pc = script->code();
+ sp = fp.slots() + script->nfixed();
+ fp_ = &fp;
+ }
+
+ void setToEndOfScript();
+
+ MutableHandleValue stackHandleAt(int i) {
+ return MutableHandleValue::fromMarkedLocation(&sp[i]);
+ }
+
+ HandleValue stackHandleAt(int i) const {
+ return HandleValue::fromMarkedLocation(&sp[i]);
+ }
+
+ friend void GDBTestInitInterpreterRegs(InterpreterRegs&, js::InterpreterFrame*,
+ JS::Value*, uint8_t*);
+};
+
+/*****************************************************************************/
+
+class InterpreterStack
+{
+ friend class InterpreterActivation;
+
+ static const size_t DEFAULT_CHUNK_SIZE = 4 * 1024;
+ LifoAlloc allocator_;
+
+ // Number of interpreter frames on the stack, for over-recursion checks.
+ static const size_t MAX_FRAMES = 50 * 1000;
+ static const size_t MAX_FRAMES_TRUSTED = MAX_FRAMES + 1000;
+ size_t frameCount_;
+
+ inline uint8_t* allocateFrame(JSContext* cx, size_t size);
+
+ inline InterpreterFrame*
+ getCallFrame(JSContext* cx, const CallArgs& args, HandleScript script,
+ MaybeConstruct constructing, Value** pargv);
+
+ void releaseFrame(InterpreterFrame* fp) {
+ frameCount_--;
+ allocator_.release(fp->mark_);
+ }
+
+ public:
+ InterpreterStack()
+ : allocator_(DEFAULT_CHUNK_SIZE),
+ frameCount_(0)
+ { }
+
+ ~InterpreterStack() {
+ MOZ_ASSERT(frameCount_ == 0);
+ }
+
+ // For execution of eval or global code.
+ InterpreterFrame* pushExecuteFrame(JSContext* cx, HandleScript script,
+ const Value& newTargetValue, HandleObject envChain,
+ AbstractFramePtr evalInFrame);
+
+ // Called to invoke a function.
+ InterpreterFrame* pushInvokeFrame(JSContext* cx, const CallArgs& args,
+ MaybeConstruct constructing);
+
+ // The interpreter can push light-weight, "inline" frames without entering a
+ // new InterpreterActivation or recursively calling Interpret.
+ bool pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
+ HandleScript script, MaybeConstruct constructing);
+
+ void popInlineFrame(InterpreterRegs& regs);
+
+ bool resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
+ HandleFunction callee, HandleValue newTarget,
+ HandleObject envChain);
+
+ inline void purge(JSRuntime* rt);
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return allocator_.sizeOfExcludingThis(mallocSizeOf);
+ }
+};
+
+void MarkInterpreterActivations(JSRuntime* rt, JSTracer* trc);
+
+/*****************************************************************************/
+
+/** Base class for all function call args. */
+class AnyInvokeArgs : public JS::CallArgs
+{
+};
+
+/** Base class for all function construction args. */
+class AnyConstructArgs : public JS::CallArgs
+{
+ // Only js::Construct (or internal methods that call the qualified CallArgs
+ // versions) should do these things!
+ void setCallee(const Value& v) = delete;
+ void setThis(const Value& v) = delete;
+ MutableHandleValue newTarget() const = delete;
+ MutableHandleValue rval() const = delete;
+};
+
+namespace detail {
+
+/** Function call/construct args of statically-unknown count. */
+template <MaybeConstruct Construct>
+class GenericArgsBase
+ : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
+{
+ protected:
+ AutoValueVector v_;
+
+ explicit GenericArgsBase(JSContext* cx) : v_(cx) {}
+
+ public:
+ bool init(JSContext* cx, unsigned argc) {
+ if (argc > ARGS_LENGTH_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_ARGUMENTS);
+ return false;
+ }
+
+ // callee, this, arguments[, new.target iff constructing]
+ size_t len = 2 + argc + uint32_t(Construct);
+ MOZ_ASSERT(len > argc); // no overflow
+ if (!v_.resize(len))
+ return false;
+
+ *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(argc, v_.begin());
+ this->constructing_ = Construct;
+ if (Construct)
+ this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
+ return true;
+ }
+};
+
+/** Function call/construct args of statically-known count. */
+template <MaybeConstruct Construct, size_t N>
+class FixedArgsBase
+ : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
+{
+ static_assert(N <= ARGS_LENGTH_MAX, "o/~ too many args o/~");
+
+ protected:
+ JS::AutoValueArray<2 + N + uint32_t(Construct)> v_;
+
+ explicit FixedArgsBase(JSContext* cx) : v_(cx) {
+ *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
+ this->constructing_ = Construct;
+ if (Construct)
+ this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
+ }
+};
+
+} // namespace detail
+
+/** Function call args of statically-unknown count. */
+class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT>
+{
+ using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
+
+ public:
+ explicit InvokeArgs(JSContext* cx) : Base(cx) {}
+};
+
+/** Function call args of statically-known count. */
+template <size_t N>
+class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
+{
+ using Base = detail::FixedArgsBase<NO_CONSTRUCT, N>;
+
+ public:
+ explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
+};
+
+/** Function construct args of statically-unknown count. */
+class ConstructArgs : public detail::GenericArgsBase<CONSTRUCT>
+{
+ using Base = detail::GenericArgsBase<CONSTRUCT>;
+
+ public:
+ explicit ConstructArgs(JSContext* cx) : Base(cx) {}
+};
+
+/** Function call args of statically-known count. */
+template <size_t N>
+class FixedConstructArgs : public detail::FixedArgsBase<CONSTRUCT, N>
+{
+ using Base = detail::FixedArgsBase<CONSTRUCT, N>;
+
+ public:
+ explicit FixedConstructArgs(JSContext* cx) : Base(cx) {}
+};
+
+template <class Args, class Arraylike>
+inline bool
+FillArgumentsFromArraylike(JSContext* cx, Args& args, const Arraylike& arraylike)
+{
+ uint32_t len = arraylike.length();
+ if (!args.init(cx, len))
+ return false;
+
+ for (uint32_t i = 0; i < len; i++)
+ args[i].set(arraylike[i]);
+
+ return true;
+}
+
+template <>
+struct DefaultHasher<AbstractFramePtr> {
+ typedef AbstractFramePtr Lookup;
+
+ static js::HashNumber hash(const Lookup& key) {
+ return size_t(key.raw());
+ }
+
+ static bool match(const AbstractFramePtr& k, const Lookup& l) {
+ return k == l;
+ }
+};
+
+/*****************************************************************************/
+
+// SavedFrame caching to minimize stack walking.
+//
+// SavedFrames are hash consed to minimize expensive (with regards to both space
+// and time) allocations in the face of many stack frames that tend to share the
+// same older tail frames. Despite that, in scenarios where we are frequently
+// saving the same or similar stacks, such as when the Debugger's allocation
+// site tracking is enabled, these older stack frames still get walked
+// repeatedly just to create the lookup structs to find their corresponding
+// SavedFrames in the hash table. This stack walking is slow, and we would like
+// to minimize it.
+//
+// We have reserved a bit on most of SpiderMonkey's various frame
+// representations (the exceptions being asm and inlined ion frames). As we
+// create SavedFrame objects for live stack frames in SavedStacks::insertFrames,
+// we set this bit and append the SavedFrame object to the cache. As we walk the
+// stack, if we encounter a frame that has this bit set, that indicates that we
+// have already captured a SavedFrame object for the given stack frame (but not
+// necessarily the current pc) during a previous call to insertFrames. We know
+// that the frame's parent was also captured and has its bit set as well, but
+// additionally we know the parent was captured at its current pc. For the
+// parent, rather than continuing the expensive stack walk, we do a quick and
+// cache-friendly linear search through the frame cache. Upon finishing search
+// through the frame cache, stale entries are removed.
+//
+// The frame cache maintains the invariant that its first E[0] .. E[j-1]
+// entries are live and sorted from oldest to younger frames, where 0 < j < n
+// and n = the length of the cache. When searching the cache, we require
+// that we are considering the youngest live frame whose bit is set. Every
+// cache entry E[i] where i >= j is a stale entry. Consider the following
+// scenario:
+//
+// P > Q > R > S Initial stack, bits not set.
+// P* > Q* > R* > S* Capture a SavedFrame stack, set bits.
+// P* > Q* > R* Return from S.
+// P* > Q* Return from R.
+// P* > Q* > T Call T, its bit is not set.
+//
+// The frame cache was populated with [P, Q, R, S] when we captured a
+// SavedFrame stack, but because we returned from frames R and S, their
+// entries in the frame cache are now stale. This fact is unbeknownst to us
+// because we do not observe frame pops. Upon capturing a second stack, we
+// start stack walking at the youngest frame T, which does not have its bit
+// set and must take the hash table lookup slow path rather than the frame
+// cache short circuit. Next we proceed to Q and find that it has its bit
+// set, and it is therefore the youngest live frame with its bit set. We
+// search through the frame cache from oldest to youngest and find the cache
+// entry matching Q. We know that T is the next younger live frame from Q
+// and that T does not have an entry in the frame cache because its bit was
+// not set. Therefore, we have found entry E[j-1] and the subsequent entries
+// are stale and should be purged from the frame cache.
+//
+// We have a LiveSavedFrameCache for each activation to minimize the number of
+// entries that must be scanned through, and to avoid the headaches of
+// maintaining a cache for each compartment and invalidating stale cache entries
+// in the presence of cross-compartment calls.
+class LiveSavedFrameCache
+{
+ public:
+ using FramePtr = mozilla::Variant<AbstractFramePtr, jit::CommonFrameLayout*>;
+
+ private:
+ struct Entry
+ {
+ FramePtr framePtr;
+ jsbytecode* pc;
+ HeapPtr<SavedFrame*> savedFrame;
+
+ Entry(FramePtr& framePtr, jsbytecode* pc, SavedFrame* savedFrame)
+ : framePtr(framePtr)
+ , pc(pc)
+ , savedFrame(savedFrame)
+ { }
+ };
+
+ using EntryVector = Vector<Entry, 0, SystemAllocPolicy>;
+ EntryVector* frames;
+
+ LiveSavedFrameCache(const LiveSavedFrameCache&) = delete;
+ LiveSavedFrameCache& operator=(const LiveSavedFrameCache&) = delete;
+
+ public:
+ explicit LiveSavedFrameCache() : frames(nullptr) { }
+
+ LiveSavedFrameCache(LiveSavedFrameCache&& rhs)
+ : frames(rhs.frames)
+ {
+ MOZ_ASSERT(this != &rhs, "self-move disallowed");
+ rhs.frames = nullptr;
+ }
+
+ ~LiveSavedFrameCache() {
+ if (frames) {
+ js_delete(frames);
+ frames = nullptr;
+ }
+ }
+
+ bool initialized() const { return !!frames; }
+ bool init(JSContext* cx) {
+ frames = js_new<EntryVector>();
+ if (!frames) {
+ JS_ReportOutOfMemory(cx);
+ return false;
+ }
+ return true;
+ }
+
+ static mozilla::Maybe<FramePtr> getFramePtr(FrameIter& iter);
+ void trace(JSTracer* trc);
+
+ void find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const;
+ bool insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc, HandleSavedFrame savedFrame);
+};
+
+static_assert(sizeof(LiveSavedFrameCache) == sizeof(uintptr_t),
+ "Every js::Activation has a LiveSavedFrameCache, so we need to be pretty careful "
+ "about avoiding bloat. If you're adding members to LiveSavedFrameCache, maybe you "
+ "should consider figuring out a way to make js::Activation have a "
+ "LiveSavedFrameCache* instead of a Rooted<LiveSavedFrameCache>.");
+
+/*****************************************************************************/
+
+class InterpreterActivation;
+class WasmActivation;
+
+namespace jit {
+ class JitActivation;
+} // namespace jit
+
+// This class is separate from Activation, because it calls JSCompartment::wrap()
+// which can GC and walk the stack. It's not safe to do that within the
+// JitActivation constructor.
+class MOZ_RAII ActivationEntryMonitor
+{
+ JSContext* cx_;
+
+ // The entry point monitor that was set on cx_->runtime() when this
+ // ActivationEntryMonitor was created.
+ JS::dbg::AutoEntryMonitor* entryMonitor_;
+
+ explicit ActivationEntryMonitor(JSContext* cx);
+
+ ActivationEntryMonitor(const ActivationEntryMonitor& other) = delete;
+ void operator=(const ActivationEntryMonitor& other) = delete;
+
+ Value asyncStack(JSContext* cx);
+
+ public:
+ ActivationEntryMonitor(JSContext* cx, InterpreterFrame* entryFrame);
+ ActivationEntryMonitor(JSContext* cx, jit::CalleeToken entryToken);
+ inline ~ActivationEntryMonitor();
+};
+
+class Activation
+{
+ protected:
+ JSContext* cx_;
+ JSCompartment* compartment_;
+ Activation* prev_;
+ Activation* prevProfiling_;
+
+ // Counter incremented by JS::HideScriptedCaller and decremented by
+ // JS::UnhideScriptedCaller. If > 0 for the top activation,
+ // DescribeScriptedCaller will return null instead of querying that
+ // activation, which should prompt the caller to consult embedding-specific
+ // data structures instead.
+ size_t hideScriptedCallerCount_;
+
+ // The cache of SavedFrame objects we have already captured when walking
+ // this activation's stack.
+ Rooted<LiveSavedFrameCache> frameCache_;
+
+ // Youngest saved frame of an async stack that will be iterated during stack
+ // capture in place of the actual stack of previous activations. Note that
+ // the stack of this activation is captured entirely before this is used.
+ //
+ // Usually this is nullptr, meaning that normal stack capture will occur.
+ // When this is set, the stack of any previous activation is ignored.
+ Rooted<SavedFrame*> asyncStack_;
+
+ // Value of asyncCause to be attached to asyncStack_.
+ const char* asyncCause_;
+
+ // True if the async call was explicitly requested, e.g. via
+ // callFunctionWithAsyncStack.
+ bool asyncCallIsExplicit_;
+
+ enum Kind { Interpreter, Jit, Wasm };
+ Kind kind_;
+
+ inline Activation(JSContext* cx, Kind kind);
+ inline ~Activation();
+
+ public:
+ JSContext* cx() const {
+ return cx_;
+ }
+ JSCompartment* compartment() const {
+ return compartment_;
+ }
+ Activation* prev() const {
+ return prev_;
+ }
+ Activation* prevProfiling() const { return prevProfiling_; }
+ inline Activation* mostRecentProfiling();
+
+ bool isInterpreter() const {
+ return kind_ == Interpreter;
+ }
+ bool isJit() const {
+ return kind_ == Jit;
+ }
+ bool isWasm() const {
+ return kind_ == Wasm;
+ }
+
+ inline bool isProfiling() const;
+ void registerProfiling();
+ void unregisterProfiling();
+
+ InterpreterActivation* asInterpreter() const {
+ MOZ_ASSERT(isInterpreter());
+ return (InterpreterActivation*)this;
+ }
+ jit::JitActivation* asJit() const {
+ MOZ_ASSERT(isJit());
+ return (jit::JitActivation*)this;
+ }
+ WasmActivation* asWasm() const {
+ MOZ_ASSERT(isWasm());
+ return (WasmActivation*)this;
+ }
+
+ void hideScriptedCaller() {
+ hideScriptedCallerCount_++;
+ }
+ void unhideScriptedCaller() {
+ MOZ_ASSERT(hideScriptedCallerCount_ > 0);
+ hideScriptedCallerCount_--;
+ }
+ bool scriptedCallerIsHidden() const {
+ return hideScriptedCallerCount_ > 0;
+ }
+
+ static size_t offsetOfPrevProfiling() {
+ return offsetof(Activation, prevProfiling_);
+ }
+
+ SavedFrame* asyncStack() {
+ return asyncStack_;
+ }
+
+ const char* asyncCause() const {
+ return asyncCause_;
+ }
+
+ bool asyncCallIsExplicit() const {
+ return asyncCallIsExplicit_;
+ }
+
+ inline LiveSavedFrameCache* getLiveSavedFrameCache(JSContext* cx);
+
+ private:
+ Activation(const Activation& other) = delete;
+ void operator=(const Activation& other) = delete;
+};
+
+// This variable holds a special opcode value which is greater than all normal
+// opcodes, and is chosen such that the bitwise or of this value with any
+// opcode is this value.
+static const jsbytecode EnableInterruptsPseudoOpcode = -1;
+
+static_assert(EnableInterruptsPseudoOpcode >= JSOP_LIMIT,
+ "EnableInterruptsPseudoOpcode must be greater than any opcode");
+static_assert(EnableInterruptsPseudoOpcode == jsbytecode(-1),
+ "EnableInterruptsPseudoOpcode must be the maximum jsbytecode value");
+
+class InterpreterFrameIterator;
+class RunState;
+
+class InterpreterActivation : public Activation
+{
+ friend class js::InterpreterFrameIterator;
+
+ InterpreterRegs regs_;
+ InterpreterFrame* entryFrame_;
+ size_t opMask_; // For debugger interrupts, see js::Interpret.
+
+#ifdef DEBUG
+ size_t oldFrameCount_;
+#endif
+
+ public:
+ inline InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame);
+ inline ~InterpreterActivation();
+
+ inline bool pushInlineFrame(const CallArgs& args, HandleScript script,
+ MaybeConstruct constructing);
+ inline void popInlineFrame(InterpreterFrame* frame);
+
+ inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue newTarget,
+ HandleObject envChain);
+
+ InterpreterFrame* current() const {
+ return regs_.fp();
+ }
+ InterpreterRegs& regs() {
+ return regs_;
+ }
+ InterpreterFrame* entryFrame() const {
+ return entryFrame_;
+ }
+ size_t opMask() const {
+ return opMask_;
+ }
+
+ bool isProfiling() const {
+ return false;
+ }
+
+ // If this js::Interpret frame is running |script|, enable interrupts.
+ void enableInterruptsIfRunning(JSScript* script) {
+ if (regs_.fp()->script() == script)
+ enableInterruptsUnconditionally();
+ }
+ void enableInterruptsUnconditionally() {
+ opMask_ = EnableInterruptsPseudoOpcode;
+ }
+ void clearInterruptsMask() {
+ opMask_ = 0;
+ }
+};
+
+// Iterates over a thread's activation list. If given a runtime, iterate over
+// the runtime's main thread's activation list.
+class ActivationIterator
+{
+ uint8_t* jitTop_;
+
+ protected:
+ Activation* activation_;
+
+ private:
+ void settle();
+
+ public:
+ explicit ActivationIterator(JSRuntime* rt);
+
+ ActivationIterator& operator++();
+
+ Activation* operator->() const {
+ return activation_;
+ }
+ Activation* activation() const {
+ return activation_;
+ }
+ uint8_t* jitTop() const {
+ MOZ_ASSERT(activation_->isJit());
+ return jitTop_;
+ }
+ bool done() const {
+ return activation_ == nullptr;
+ }
+};
+
+namespace jit {
+
+class BailoutFrameInfo;
+
+// A JitActivation is used for frames running in Baseline or Ion.
+class JitActivation : public Activation
+{
+ uint8_t* prevJitTop_;
+ JitActivation* prevJitActivation_;
+ bool active_;
+
+ // Rematerialized Ion frames which has info copied out of snapshots. Maps
+ // frame pointers (i.e. jitTop) to a vector of rematerializations of all
+ // inline frames associated with that frame.
+ //
+ // This table is lazily initialized by calling getRematerializedFrame.
+ typedef GCVector<RematerializedFrame*> RematerializedFrameVector;
+ typedef HashMap<uint8_t*, RematerializedFrameVector> RematerializedFrameTable;
+ RematerializedFrameTable* rematerializedFrames_;
+
+ // This vector is used to remember the outcome of the evaluation of recover
+ // instructions.
+ //
+ // RInstructionResults are appended into this vector when Snapshot values
+ // have to be read, or when the evaluation has to run before some mutating
+ // code. Each RInstructionResults belongs to one frame which has to bailout
+ // as soon as we get back to it.
+ typedef Vector<RInstructionResults, 1> IonRecoveryMap;
+ IonRecoveryMap ionRecovery_;
+
+ // If we are bailing out from Ion, then this field should be a non-null
+ // pointer which references the BailoutFrameInfo used to walk the inner
+ // frames. This field is used for all newly constructed JitFrameIterators to
+ // read the innermost frame information from this bailout data instead of
+ // reading it from the stack.
+ BailoutFrameInfo* bailoutData_;
+
+ // When profiling is enabled, these fields will be updated to reflect the
+ // last pushed frame for this activation, and if that frame has been
+ // left for a call, the native code site of the call.
+ mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingFrame_;
+ mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingCallSite_;
+ static_assert(sizeof(mozilla::Atomic<void*, mozilla::Relaxed>) == sizeof(void*),
+ "Atomic should have same memory format as underlying type.");
+
+ void clearRematerializedFrames();
+
+#ifdef CHECK_OSIPOINT_REGISTERS
+ protected:
+ // Used to verify that live registers don't change between a VM call and
+ // the OsiPoint that follows it. Protected to silence Clang warning.
+ uint32_t checkRegs_;
+ RegisterDump regs_;
+#endif
+
+ public:
+ explicit JitActivation(JSContext* cx, bool active = true);
+ ~JitActivation();
+
+ bool isActive() const {
+ return active_;
+ }
+ void setActive(JSContext* cx, bool active = true);
+
+ bool isProfiling() const;
+
+ uint8_t* prevJitTop() const {
+ return prevJitTop_;
+ }
+ JitActivation* prevJitActivation() const {
+ return prevJitActivation_;
+ }
+ static size_t offsetOfPrevJitTop() {
+ return offsetof(JitActivation, prevJitTop_);
+ }
+ static size_t offsetOfPrevJitActivation() {
+ return offsetof(JitActivation, prevJitActivation_);
+ }
+ static size_t offsetOfActiveUint8() {
+ MOZ_ASSERT(sizeof(bool) == 1);
+ return offsetof(JitActivation, active_);
+ }
+
+#ifdef CHECK_OSIPOINT_REGISTERS
+ void setCheckRegs(bool check) {
+ checkRegs_ = check;
+ }
+ static size_t offsetOfCheckRegs() {
+ return offsetof(JitActivation, checkRegs_);
+ }
+ static size_t offsetOfRegs() {
+ return offsetof(JitActivation, regs_);
+ }
+#endif
+
+ // Look up a rematerialized frame keyed by the fp, rematerializing the
+ // frame if one doesn't already exist. A frame can only be rematerialized
+ // if an IonFrameIterator pointing to the nearest uninlined frame can be
+ // provided, as values need to be read out of snapshots.
+ //
+ // The inlineDepth must be within bounds of the frame pointed to by iter.
+ RematerializedFrame* getRematerializedFrame(JSContext* cx, const JitFrameIterator& iter,
+ size_t inlineDepth = 0);
+
+ // Look up a rematerialized frame by the fp. If inlineDepth is out of
+ // bounds of what has been rematerialized, nullptr is returned.
+ RematerializedFrame* lookupRematerializedFrame(uint8_t* top, size_t inlineDepth = 0);
+
+ // Remove all rematerialized frames associated with the fp top from the
+ // Debugger.
+ void removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top);
+
+ bool hasRematerializedFrame(uint8_t* top, size_t inlineDepth = 0) {
+ return !!lookupRematerializedFrame(top, inlineDepth);
+ }
+
+ // Remove a previous rematerialization by fp.
+ void removeRematerializedFrame(uint8_t* top);
+
+ void markRematerializedFrames(JSTracer* trc);
+
+
+ // Register the results of on Ion frame recovery.
+ bool registerIonFrameRecovery(RInstructionResults&& results);
+
+ // Return the pointer to the Ion frame recovery, if it is already registered.
+ RInstructionResults* maybeIonFrameRecovery(JitFrameLayout* fp);
+
+ // If an Ion frame recovery exists for the |fp| frame exists, then remove it
+ // from the activation.
+ void removeIonFrameRecovery(JitFrameLayout* fp);
+
+ void markIonRecovery(JSTracer* trc);
+
+ // Return the bailout information if it is registered.
+ const BailoutFrameInfo* bailoutData() const { return bailoutData_; }
+
+ // Register the bailout data when it is constructed.
+ void setBailoutData(BailoutFrameInfo* bailoutData);
+
+ // Unregister the bailout data when the frame is reconstructed.
+ void cleanBailoutData();
+
+ static size_t offsetOfLastProfilingFrame() {
+ return offsetof(JitActivation, lastProfilingFrame_);
+ }
+ void* lastProfilingFrame() {
+ return lastProfilingFrame_;
+ }
+ void setLastProfilingFrame(void* ptr) {
+ lastProfilingFrame_ = ptr;
+ }
+
+ static size_t offsetOfLastProfilingCallSite() {
+ return offsetof(JitActivation, lastProfilingCallSite_);
+ }
+ void* lastProfilingCallSite() {
+ return lastProfilingCallSite_;
+ }
+ void setLastProfilingCallSite(void* ptr) {
+ lastProfilingCallSite_ = ptr;
+ }
+};
+
+// A filtering of the ActivationIterator to only stop at JitActivations.
+class JitActivationIterator : public ActivationIterator
+{
+ void settle() {
+ while (!done() && !activation_->isJit())
+ ActivationIterator::operator++();
+ }
+
+ public:
+ explicit JitActivationIterator(JSRuntime* rt)
+ : ActivationIterator(rt)
+ {
+ settle();
+ }
+
+ JitActivationIterator& operator++() {
+ ActivationIterator::operator++();
+ settle();
+ return *this;
+ }
+};
+
+} // namespace jit
+
+// Iterates over the frames of a single InterpreterActivation.
+class InterpreterFrameIterator
+{
+ InterpreterActivation* activation_;
+ InterpreterFrame* fp_;
+ jsbytecode* pc_;
+ Value* sp_;
+
+ public:
+ explicit InterpreterFrameIterator(InterpreterActivation* activation)
+ : activation_(activation),
+ fp_(nullptr),
+ pc_(nullptr),
+ sp_(nullptr)
+ {
+ if (activation) {
+ fp_ = activation->current();
+ pc_ = activation->regs().pc;
+ sp_ = activation->regs().sp;
+ }
+ }
+
+ InterpreterFrame* frame() const {
+ MOZ_ASSERT(!done());
+ return fp_;
+ }
+ jsbytecode* pc() const {
+ MOZ_ASSERT(!done());
+ return pc_;
+ }
+ Value* sp() const {
+ MOZ_ASSERT(!done());
+ return sp_;
+ }
+
+ InterpreterFrameIterator& operator++();
+
+ bool done() const {
+ return fp_ == nullptr;
+ }
+};
+
+// A WasmActivation is part of two activation linked lists:
+// - the normal Activation list used by FrameIter
+// - a list of only WasmActivations that is signal-safe since it is accessed
+// from the profiler at arbitrary points
+//
+// An eventual goal is to remove WasmActivation and to run asm code in a
+// JitActivation interleaved with Ion/Baseline jit code. This would allow
+// efficient calls back and forth but requires that we can walk the stack for
+// all kinds of jit code.
+class WasmActivation : public Activation
+{
+ WasmActivation* prevWasm_;
+ void* entrySP_;
+ void* resumePC_;
+ uint8_t* fp_;
+ wasm::ExitReason exitReason_;
+
+ public:
+ explicit WasmActivation(JSContext* cx);
+ ~WasmActivation();
+
+ WasmActivation* prevWasm() const { return prevWasm_; }
+
+ bool isProfiling() const {
+ return true;
+ }
+
+ // Returns a pointer to the base of the innermost stack frame of wasm code
+ // in this activation.
+ uint8_t* fp() const { return fp_; }
+
+ // Returns the reason why wasm code called out of wasm code.
+ wasm::ExitReason exitReason() const { return exitReason_; }
+
+ // Read by JIT code:
+ static unsigned offsetOfContext() { return offsetof(WasmActivation, cx_); }
+ static unsigned offsetOfResumePC() { return offsetof(WasmActivation, resumePC_); }
+
+ // Written by JIT code:
+ static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); }
+ static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); }
+ static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); }
+
+ // Read/written from SIGSEGV handler:
+ void setResumePC(void* pc) { resumePC_ = pc; }
+ void* resumePC() const { return resumePC_; }
+};
+
+// A FrameIter walks over the runtime's stack of JS script activations,
+// abstracting over whether the JS scripts were running in the interpreter or
+// different modes of compiled code.
+//
+// FrameIter is parameterized by what it includes in the stack iteration:
+// - When provided, the optional JSPrincipal argument will cause FrameIter to
+// only show frames in globals whose JSPrincipals are subsumed (via
+// JSSecurityCallbacks::subsume) by the given JSPrincipal.
+//
+// Additionally, there are derived FrameIter types that automatically skip
+// certain frames:
+// - ScriptFrameIter only shows frames that have an associated JSScript
+// (currently everything other than wasm stack frames). When !hasScript(),
+// clients must stick to the portion of the
+// interface marked below.
+// - NonBuiltinScriptFrameIter additionally filters out builtin (self-hosted)
+// scripts.
+class FrameIter
+{
+ public:
+ enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
+ IGNORE_DEBUGGER_EVAL_PREV_LINK };
+ enum State { DONE, INTERP, JIT, WASM };
+
+ // Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
+ // the heap, so this structure should not contain any GC things.
+ struct Data
+ {
+ JSContext * cx_;
+ DebuggerEvalOption debuggerEvalOption_;
+ JSPrincipals * principals_;
+
+ State state_;
+
+ jsbytecode * pc_;
+
+ InterpreterFrameIterator interpFrames_;
+ ActivationIterator activations_;
+
+ jit::JitFrameIterator jitFrames_;
+ unsigned ionInlineFrameNo_;
+ wasm::FrameIterator wasmFrames_;
+
+ Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
+ Data(const Data& other);
+ };
+
+ explicit FrameIter(JSContext* cx,
+ DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
+ FrameIter(JSContext* cx, DebuggerEvalOption, JSPrincipals*);
+ FrameIter(const FrameIter& iter);
+ MOZ_IMPLICIT FrameIter(const Data& data);
+ MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
+
+ bool done() const { return data_.state_ == DONE; }
+
+ // -------------------------------------------------------
+ // The following functions can only be called when !done()
+ // -------------------------------------------------------
+
+ FrameIter& operator++();
+
+ JSCompartment* compartment() const;
+ Activation* activation() const { return data_.activations_.activation(); }
+
+ bool isInterp() const { MOZ_ASSERT(!done()); return data_.state_ == INTERP; }
+ bool isJit() const { MOZ_ASSERT(!done()); return data_.state_ == JIT; }
+ bool isWasm() const { MOZ_ASSERT(!done()); return data_.state_ == WASM; }
+ inline bool isIon() const;
+ inline bool isBaseline() const;
+ inline bool isPhysicalIonFrame() const;
+
+ bool isEvalFrame() const;
+ bool isFunctionFrame() const;
+ bool hasArgs() const { return isFunctionFrame(); }
+
+ // These two methods may not be called with asm frames.
+ inline bool hasCachedSavedFrame() const;
+ inline void setHasCachedSavedFrame();
+
+ ScriptSource* scriptSource() const;
+ const char* filename() const;
+ const char16_t* displayURL() const;
+ unsigned computeLine(uint32_t* column = nullptr) const;
+ JSAtom* functionDisplayAtom() const;
+ bool mutedErrors() const;
+
+ bool hasScript() const { return !isWasm(); }
+
+ // -----------------------------------------------------------
+ // The following functions can only be called when hasScript()
+ // -----------------------------------------------------------
+
+ inline JSScript* script() const;
+
+ bool isConstructing() const;
+ jsbytecode* pc() const { MOZ_ASSERT(!done()); return data_.pc_; }
+ void updatePcQuadratic();
+
+ // The function |calleeTemplate()| returns either the function from which
+ // the current |callee| was cloned or the |callee| if it can be read. As
+ // long as we do not have to investigate the environment chain or build a
+ // new frame, we should prefer to use |calleeTemplate| instead of
+ // |callee|, as requesting the |callee| might cause the invalidation of
+ // the frame. (see js::Lambda)
+ JSFunction* calleeTemplate() const;
+ JSFunction* callee(JSContext* cx) const;
+
+ JSFunction* maybeCallee(JSContext* cx) const {
+ return isFunctionFrame() ? callee(cx) : nullptr;
+ }
+
+ bool matchCallee(JSContext* cx, HandleFunction fun) const;
+
+ unsigned numActualArgs() const;
+ unsigned numFormalArgs() const;
+ Value unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
+ template <class Op> inline void unaliasedForEachActual(JSContext* cx, Op op);
+
+ JSObject* environmentChain(JSContext* cx) const;
+ CallObject& callObj(JSContext* cx) const;
+
+ bool hasArgsObj() const;
+ ArgumentsObject& argsObj() const;
+
+ // Get the original |this| value passed to this function. May not be the
+ // actual this-binding (for instance, derived class constructors will
+ // change their this-value later and non-strict functions will box
+ // primitives).
+ Value thisArgument(JSContext* cx) const;
+
+ Value newTarget() const;
+
+ Value returnValue() const;
+ void setReturnValue(const Value& v);
+
+ // These are only valid for the top frame.
+ size_t numFrameSlots() const;
+ Value frameSlotValue(size_t index) const;
+
+ // Ensures that we have rematerialized the top frame and its associated
+ // inline frames. Can only be called when isIon().
+ bool ensureHasRematerializedFrame(JSContext* cx);
+
+ // True when isInterp() or isBaseline(). True when isIon() if it
+ // has a rematerialized frame. False otherwise false otherwise.
+ bool hasUsableAbstractFramePtr() const;
+
+ // -----------------------------------------------------------
+ // The following functions can only be called when isInterp(),
+ // isBaseline(), or isIon(). Further, abstractFramePtr() can
+ // only be called when hasUsableAbstractFramePtr().
+ // -----------------------------------------------------------
+
+ AbstractFramePtr abstractFramePtr() const;
+ AbstractFramePtr copyDataAsAbstractFramePtr() const;
+ Data* copyData() const;
+
+ // This can only be called when isInterp():
+ inline InterpreterFrame* interpFrame() const;
+
+ // This can only be called when isPhysicalIonFrame():
+ inline jit::CommonFrameLayout* physicalIonFrame() const;
+
+ // This is used to provide a raw interface for debugging.
+ void* rawFramePtr() const;
+
+ private:
+ Data data_;
+ jit::InlineFrameIterator ionInlineFrames_;
+
+ void popActivation();
+ void popInterpreterFrame();
+ void nextJitFrame();
+ void popJitFrame();
+ void popWasmFrame();
+ void settleOnActivation();
+};
+
+class ScriptFrameIter : public FrameIter
+{
+ void settle() {
+ while (!done() && !hasScript())
+ FrameIter::operator++();
+ }
+
+ public:
+ explicit ScriptFrameIter(JSContext* cx,
+ DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
+ : FrameIter(cx, debuggerEvalOption)
+ {
+ settle();
+ }
+
+ ScriptFrameIter(JSContext* cx,
+ DebuggerEvalOption debuggerEvalOption,
+ JSPrincipals* prin)
+ : FrameIter(cx, debuggerEvalOption, prin)
+ {
+ settle();
+ }
+
+ ScriptFrameIter(const ScriptFrameIter& iter) : FrameIter(iter) { settle(); }
+ explicit ScriptFrameIter(const FrameIter::Data& data) : FrameIter(data) { settle(); }
+ explicit ScriptFrameIter(AbstractFramePtr frame) : FrameIter(frame) { settle(); }
+
+ ScriptFrameIter& operator++() {
+ FrameIter::operator++();
+ settle();
+ return *this;
+ }
+};
+
+#ifdef DEBUG
+bool SelfHostedFramesVisible();
+#else
+static inline bool
+SelfHostedFramesVisible()
+{
+ return false;
+}
+#endif
+
+/* A filtering of the FrameIter to only stop at non-self-hosted scripts. */
+class NonBuiltinFrameIter : public FrameIter
+{
+ void settle();
+
+ public:
+ explicit NonBuiltinFrameIter(JSContext* cx,
+ FrameIter::DebuggerEvalOption debuggerEvalOption =
+ FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
+ : FrameIter(cx, debuggerEvalOption)
+ {
+ settle();
+ }
+
+ NonBuiltinFrameIter(JSContext* cx,
+ FrameIter::DebuggerEvalOption debuggerEvalOption,
+ JSPrincipals* principals)
+ : FrameIter(cx, debuggerEvalOption, principals)
+ {
+ settle();
+ }
+
+ NonBuiltinFrameIter(JSContext* cx, JSPrincipals* principals)
+ : FrameIter(cx, FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK, principals)
+ {
+ settle();
+ }
+
+ explicit NonBuiltinFrameIter(const FrameIter::Data& data)
+ : FrameIter(data)
+ {}
+
+ NonBuiltinFrameIter& operator++() {
+ FrameIter::operator++();
+ settle();
+ return *this;
+ }
+};
+
+/* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */
+class NonBuiltinScriptFrameIter : public ScriptFrameIter
+{
+ void settle();
+
+ public:
+ explicit NonBuiltinScriptFrameIter(JSContext* cx,
+ ScriptFrameIter::DebuggerEvalOption debuggerEvalOption =
+ ScriptFrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
+ : ScriptFrameIter(cx, debuggerEvalOption)
+ {
+ settle();
+ }
+
+ NonBuiltinScriptFrameIter(JSContext* cx,
+ ScriptFrameIter::DebuggerEvalOption debuggerEvalOption,
+ JSPrincipals* principals)
+ : ScriptFrameIter(cx, debuggerEvalOption, principals)
+ {
+ settle();
+ }
+
+ explicit NonBuiltinScriptFrameIter(const ScriptFrameIter::Data& data)
+ : ScriptFrameIter(data)
+ {}
+
+ NonBuiltinScriptFrameIter& operator++() {
+ ScriptFrameIter::operator++();
+ settle();
+ return *this;
+ }
+};
+
+/*
+ * Blindly iterate over all frames in the current thread's stack. These frames
+ * can be from different contexts and compartments, so beware.
+ */
+class AllFramesIter : public FrameIter
+{
+ public:
+ explicit AllFramesIter(JSContext* cx)
+ : FrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
+ {}
+};
+
+/* Iterates over all script frame in the current thread's stack.
+ * See also AllFramesIter and ScriptFrameIter.
+ */
+class AllScriptFramesIter : public ScriptFrameIter
+{
+ public:
+ explicit AllScriptFramesIter(JSContext* cx)
+ : ScriptFrameIter(cx, ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
+ {}
+};
+
+/* Popular inline definitions. */
+
+inline JSScript*
+FrameIter::script() const
+{
+ MOZ_ASSERT(!done());
+ if (data_.state_ == INTERP)
+ return interpFrame()->script();
+ MOZ_ASSERT(data_.state_ == JIT);
+ if (data_.jitFrames_.isIonJS())
+ return ionInlineFrames_.script();
+ return data_.jitFrames_.script();
+}
+
+inline bool
+FrameIter::isIon() const
+{
+ return isJit() && data_.jitFrames_.isIonJS();
+}
+
+inline bool
+FrameIter::isBaseline() const
+{
+ return isJit() && data_.jitFrames_.isBaselineJS();
+}
+
+inline InterpreterFrame*
+FrameIter::interpFrame() const
+{
+ MOZ_ASSERT(data_.state_ == INTERP);
+ return data_.interpFrames_.frame();
+}
+
+inline bool
+FrameIter::isPhysicalIonFrame() const
+{
+ return isJit() &&
+ data_.jitFrames_.isIonScripted() &&
+ ionInlineFrames_.frameNo() == 0;
+}
+
+inline jit::CommonFrameLayout*
+FrameIter::physicalIonFrame() const
+{
+ MOZ_ASSERT(isPhysicalIonFrame());
+ return data_.jitFrames_.current();
+}
+
+} /* namespace js */
+#endif /* vm_Stack_h */
diff --git a/js/src/vm/StopIterationObject.h b/js/src/vm/StopIterationObject.h
new file mode 100644
index 000000000..fe366f096
--- /dev/null
+++ b/js/src/vm/StopIterationObject.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_StopIterationObject_h
+#define vm_StopIterationObject_h
+
+#include "jsobj.h"
+
+namespace js {
+
+class StopIterationObject : public JSObject
+{
+ public:
+ static const Class class_;
+};
+
+} // namespace js
+
+#endif /* vm_StopIterationObject_h */
diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp
new file mode 100644
index 000000000..28632c2a1
--- /dev/null
+++ b/js/src/vm/Stopwatch.cpp
@@ -0,0 +1,655 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Stopwatch.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/Unused.h"
+
+#if defined(XP_WIN)
+#include <processthreadsapi.h>
+#include <windows.h>
+#endif // defined(XP_WIN)
+
+#include "jscompartment.h"
+
+#include "gc/Zone.h"
+#include "vm/Runtime.h"
+
+namespace js {
+
+bool
+PerformanceMonitoring::addRecentGroup(PerformanceGroup* group)
+{
+ if (group->isUsedInThisIteration())
+ return true;
+
+ group->setIsUsedInThisIteration(true);
+ return recentGroups_.append(group);
+}
+
+void
+PerformanceMonitoring::reset()
+{
+ // All ongoing measures are dependent on the current iteration#.
+ // By incrementing it, we mark all data as stale. Stale data will
+ // be overwritten progressively during the execution.
+ ++iteration_;
+ recentGroups_.clear();
+
+ // Every so often, we will be rescheduled to another CPU. If this
+ // happens, we may end up with an entirely unsynchronized
+ // timestamp counter. If we do not reset
+ // `highestTimestampCounter_`, we could end up ignoring entirely
+ // valid sets of measures just because we are on a CPU that has a
+ // lower RDTSC.
+ highestTimestampCounter_ = 0;
+}
+
+void
+PerformanceMonitoring::start()
+{
+ if (!isMonitoringJank_)
+ return;
+
+ if (iteration_ == startedAtIteration_) {
+ // The stopwatch is already started for this iteration.
+ return;
+ }
+
+ startedAtIteration_ = iteration_;
+ if (stopwatchStartCallback)
+ stopwatchStartCallback(iteration_, stopwatchStartClosure);
+}
+
+// Commit the data that has been collected during the iteration
+// into the actual `PerformanceData`.
+//
+// We use the proportion of cycles-spent-in-group over
+// cycles-spent-in-toplevel-group as an approximation to allocate
+// system (kernel) time and user (CPU) time to each group. Note
+// that cycles are not an exact measure:
+//
+// 1. if the computer has gone to sleep, the clock may be reset to 0;
+// 2. if the process is moved between CPUs/cores, it may end up on a CPU
+// or core with an unsynchronized clock;
+// 3. the mapping between clock cycles and walltime varies with the current
+// frequency of the CPU;
+// 4. other threads/processes using the same CPU will also increment
+// the counter.
+//
+// ** Effect of 1. (computer going to sleep)
+//
+// We assume that this will happen very seldom. Since the final numbers
+// are bounded by the CPU time and Kernel time reported by `getresources`,
+// the effect will be contained to a single iteration of the event loop.
+//
+// ** Effect of 2. (moving between CPUs/cores)
+//
+// On platforms that support it, we only measure the number of cycles
+// if we start and end execution of a group on the same
+// CPU/core. While there is a small window (a few cycles) during which
+// the thread can be migrated without us noticing, we expect that this
+// will happen rarely enough that this won't affect the statistics
+// meaningfully.
+//
+// On other platforms, assuming that the probability of jumping
+// between CPUs/cores during a given (real) cycle is constant, and
+// that the distribution of differences between clocks is even, the
+// probability that the number of cycles reported by a measure is
+// modified by X cycles should be a gaussian distribution, with groups
+// with longer execution having a larger amplitude than groups with
+// shorter execution. Since we discard measures that result in a
+// negative number of cycles, this distribution is actually skewed
+// towards over-estimating the number of cycles of groups that already
+// have many cycles and under-estimating the number of cycles that
+// already have fewer cycles.
+//
+// Since the final numbers are bounded by the CPU time and Kernel time
+// reported by `getresources`, we accept this bias.
+//
+// ** Effect of 3. (mapping between clock cycles and walltime)
+//
+// Assuming that this is evenly distributed, we expect that this will
+// eventually balance out.
+//
+// ** Effect of 4. (cycles increase with system activity)
+//
+// Assuming that, within an iteration of the event loop, this happens
+// unformly over time, this will skew towards over-estimating the number
+// of cycles of groups that already have many cycles and under-estimating
+// the number of cycles that already have fewer cycles.
+//
+// Since the final numbers are bounded by the CPU time and Kernel time
+// reported by `getresources`, we accept this bias.
+//
+// ** Big picture
+//
+// Computing the number of cycles is fast and should be accurate
+// enough in practice. Alternatives (such as calling `getresources`
+// all the time or sampling from another thread) are very expensive
+// in system calls and/or battery and not necessarily more accurate.
+bool
+PerformanceMonitoring::commit()
+{
+#if !defined(MOZ_HAVE_RDTSC)
+ // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`.
+ return false;
+#endif // !defined(MOZ_HAVE_RDTSC)
+
+ if (!isMonitoringJank_) {
+ // Either we have not started monitoring or monitoring has
+ // been cancelled during the iteration.
+ return true;
+ }
+
+ if (startedAtIteration_ != iteration_) {
+ // No JS code has been monitored during this iteration.
+ return true;
+ }
+
+ PerformanceGroupVector recentGroups;
+ recentGroups_.swap(recentGroups);
+
+ bool success = true;
+ if (stopwatchCommitCallback)
+ success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure);
+
+ // Reset immediately, to make sure that we're not hit by the end
+ // of a nested event loop (which would cause `commit` to be called
+ // twice in succession).
+ reset();
+ return success;
+}
+
+uint64_t
+PerformanceMonitoring::monotonicReadTimestampCounter()
+{
+#if defined(MOZ_HAVE_RDTSC)
+ const uint64_t hardware = ReadTimestampCounter();
+ if (highestTimestampCounter_ < hardware)
+ highestTimestampCounter_ = hardware;
+ return highestTimestampCounter_;
+#else
+ return 0;
+#endif // defined(MOZ_HAVE_RDTSC)
+}
+
+void
+PerformanceMonitoring::dispose(JSRuntime* rt)
+{
+ reset();
+ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
+ c->performanceMonitoring.unlink();
+ }
+}
+
+PerformanceGroupHolder::~PerformanceGroupHolder()
+{
+ unlink();
+}
+
+void
+PerformanceGroupHolder::unlink()
+{
+ initialized_ = false;
+ groups_.clear();
+}
+
+const PerformanceGroupVector*
+PerformanceGroupHolder::getGroups(JSContext* cx)
+{
+ if (initialized_)
+ return &groups_;
+
+ if (!runtime_->performanceMonitoring.getGroupsCallback)
+ return nullptr;
+
+ if (!runtime_->performanceMonitoring.getGroupsCallback(cx, groups_, runtime_->performanceMonitoring.getGroupsClosure))
+ return nullptr;
+
+ initialized_ = true;
+ return &groups_;
+}
+
+AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+ : cx_(cx)
+ , iteration_(0)
+ , isMonitoringJank_(false)
+ , isMonitoringCPOW_(false)
+ , cyclesStart_(0)
+ , CPOWTimeStart_(0)
+{
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+
+ JSCompartment* compartment = cx_->compartment();
+ if (compartment->scheduledForDestruction)
+ return;
+
+ JSRuntime* runtime = cx_->runtime();
+ iteration_ = runtime->performanceMonitoring.iteration();
+
+ const PerformanceGroupVector* groups = compartment->performanceMonitoring.getGroups(cx);
+ if (!groups) {
+ // Either the embedding has not provided any performance
+ // monitoring logistics or there was an error that prevents
+ // performance monitoring.
+ return;
+ }
+ for (auto group = groups->begin(); group < groups->end(); group++) {
+ auto acquired = acquireGroup(*group);
+ if (acquired) {
+ if (!groups_.append(acquired))
+ MOZ_CRASH();
+ }
+ }
+ if (groups_.length() == 0) {
+ // We are not in charge of monitoring anything.
+ return;
+ }
+
+ // Now that we are sure that JS code is being executed,
+ // initialize the stopwatch for this iteration, lazily.
+ runtime->performanceMonitoring.start();
+ enter();
+}
+
+AutoStopwatch::~AutoStopwatch()
+{
+ if (groups_.length() == 0) {
+ // We are not in charge of monitoring anything.
+ return;
+ }
+
+ JSCompartment* compartment = cx_->compartment();
+ if (compartment->scheduledForDestruction)
+ return;
+
+ JSRuntime* runtime = cx_->runtime();
+ if (iteration_ != runtime->performanceMonitoring.iteration()) {
+ // We have entered a nested event loop at some point.
+ // Any information we may have is obsolete.
+ return;
+ }
+
+ mozilla::Unused << exit(); // Sadly, there is nothing we can do about an error at this point.
+
+ for (auto group = groups_.begin(); group < groups_.end(); group++)
+ releaseGroup(*group);
+}
+
+void
+AutoStopwatch::enter()
+{
+ JSRuntime* runtime = cx_->runtime();
+
+ if (runtime->performanceMonitoring.isMonitoringCPOW()) {
+ CPOWTimeStart_ = runtime->performanceMonitoring.totalCPOWTime;
+ isMonitoringCPOW_ = true;
+ }
+
+ if (runtime->performanceMonitoring.isMonitoringJank()) {
+ cyclesStart_ = this->getCycles(runtime);
+ cpuStart_ = this->getCPU();
+ isMonitoringJank_ = true;
+ }
+}
+
+bool
+AutoStopwatch::exit()
+{
+ JSRuntime* runtime = cx_->runtime();
+
+ uint64_t cyclesDelta = 0;
+ if (isMonitoringJank_ && runtime->performanceMonitoring.isMonitoringJank()) {
+ // We were monitoring jank when we entered and we still are.
+
+ // If possible, discard results when we don't end on the
+ // same CPU as we started. Note that we can be
+ // rescheduled to another CPU beween `getCycles()` and
+ // `getCPU()`. We hope that this will happen rarely
+ // enough that the impact on our statistics will remain
+ // limited.
+ const cpuid_t cpuEnd = this->getCPU();
+ if (isSameCPU(cpuStart_, cpuEnd)) {
+ const uint64_t cyclesEnd = getCycles(runtime);
+ cyclesDelta = cyclesEnd - cyclesStart_; // Always >= 0 by definition of `getCycles`.
+ }
+#if WINVER >= 0x600
+ updateTelemetry(cpuStart_, cpuEnd);
+#elif defined(__linux__)
+ updateTelemetry(cpuStart_, cpuEnd);
+#endif // WINVER >= 0x600 || _linux__
+ }
+
+ uint64_t CPOWTimeDelta = 0;
+ if (isMonitoringCPOW_ && runtime->performanceMonitoring.isMonitoringCPOW()) {
+ // We were monitoring CPOW when we entered and we still are.
+ const uint64_t CPOWTimeEnd = runtime->performanceMonitoring.totalCPOWTime;
+ CPOWTimeDelta = getDelta(CPOWTimeEnd, CPOWTimeStart_);
+ }
+ return addToGroups(cyclesDelta, CPOWTimeDelta);
+}
+
+void
+AutoStopwatch::updateTelemetry(const cpuid_t& cpuStart_, const cpuid_t& cpuEnd)
+{
+ JSRuntime* runtime = cx_->runtime();
+
+ if (isSameCPU(cpuStart_, cpuEnd))
+ runtime->performanceMonitoring.testCpuRescheduling.stayed += 1;
+ else
+ runtime->performanceMonitoring.testCpuRescheduling.moved += 1;
+}
+
+PerformanceGroup*
+AutoStopwatch::acquireGroup(PerformanceGroup* group)
+{
+ MOZ_ASSERT(group);
+
+ if (group->isAcquired(iteration_))
+ return nullptr;
+
+ if (!group->isActive())
+ return nullptr;
+
+ group->acquire(iteration_, this);
+ return group;
+}
+
+void
+AutoStopwatch::releaseGroup(PerformanceGroup* group)
+{
+ MOZ_ASSERT(group);
+ group->release(iteration_, this);
+}
+
+bool
+AutoStopwatch::addToGroups(uint64_t cyclesDelta, uint64_t CPOWTimeDelta)
+{
+ JSRuntime* runtime = cx_->runtime();
+
+ for (auto group = groups_.begin(); group < groups_.end(); ++group) {
+ if (!addToGroup(runtime, cyclesDelta, CPOWTimeDelta, *group))
+ return false;
+ }
+ return true;
+}
+
+bool
+AutoStopwatch::addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPOWTimeDelta, PerformanceGroup* group)
+{
+ MOZ_ASSERT(group);
+ MOZ_ASSERT(group->isAcquired(iteration_, this));
+
+ if (!runtime->performanceMonitoring.addRecentGroup(group))
+ return false;
+ group->addRecentTicks(iteration_, 1);
+ group->addRecentCycles(iteration_, cyclesDelta);
+ group->addRecentCPOW(iteration_, CPOWTimeDelta);
+ return true;
+}
+
+uint64_t
+AutoStopwatch::getDelta(const uint64_t end, const uint64_t start) const
+{
+ if (start >= end)
+ return 0;
+ return end - start;
+}
+
+uint64_t
+AutoStopwatch::getCycles(JSRuntime* runtime) const
+{
+ return runtime->performanceMonitoring.monotonicReadTimestampCounter();
+}
+
+cpuid_t inline
+AutoStopwatch::getCPU() const
+{
+#if defined(XP_WIN) && WINVER >= _WIN32_WINNT_VISTA
+ PROCESSOR_NUMBER proc;
+ GetCurrentProcessorNumberEx(&proc);
+
+ cpuid_t result(proc.Group, proc.Number);
+ return result;
+#else
+ return {};
+#endif // defined(XP_WIN)
+}
+
+bool inline
+AutoStopwatch::isSameCPU(const cpuid_t& a, const cpuid_t& b) const
+{
+#if defined(XP_WIN) && WINVER >= _WIN32_WINNT_VISTA
+ return a.group_ == b.group_ && a.number_ == b.number_;
+#else
+ return true;
+#endif
+}
+
+PerformanceGroup::PerformanceGroup()
+ : recentCycles_(0)
+ , recentTicks_(0)
+ , recentCPOW_(0)
+ , iteration_(0)
+ , isActive_(false)
+ , isUsedInThisIteration_(false)
+ , owner_(nullptr)
+ , refCount_(0)
+{ }
+
+uint64_t
+PerformanceGroup::iteration() const
+{
+ return iteration_;
+}
+
+
+bool
+PerformanceGroup::isAcquired(uint64_t it) const
+{
+ return owner_ != nullptr && iteration_ == it;
+}
+
+bool
+PerformanceGroup::isAcquired(uint64_t it, const AutoStopwatch* owner) const
+{
+ return owner_ == owner && iteration_ == it;
+}
+
+void
+PerformanceGroup::acquire(uint64_t it, const AutoStopwatch* owner)
+{
+ if (iteration_ != it) {
+ // Any data that pretends to be recent is actually bound
+ // to an older iteration and therefore stale.
+ resetRecentData();
+ }
+ iteration_ = it;
+ owner_ = owner;
+}
+
+void
+PerformanceGroup::release(uint64_t it, const AutoStopwatch* owner)
+{
+ if (iteration_ != it)
+ return;
+
+ MOZ_ASSERT(owner == owner_ || owner_ == nullptr);
+ owner_ = nullptr;
+}
+
+void
+PerformanceGroup::resetRecentData()
+{
+ recentCycles_ = 0;
+ recentTicks_ = 0;
+ recentCPOW_ = 0;
+ isUsedInThisIteration_ = false;
+}
+
+
+uint64_t
+PerformanceGroup::recentCycles(uint64_t iteration) const
+{
+ MOZ_ASSERT(iteration == iteration_);
+ return recentCycles_;
+}
+
+void
+PerformanceGroup::addRecentCycles(uint64_t iteration, uint64_t cycles)
+{
+ MOZ_ASSERT(iteration == iteration_);
+ recentCycles_ += cycles;
+}
+
+uint64_t
+PerformanceGroup::recentTicks(uint64_t iteration) const
+{
+ MOZ_ASSERT(iteration == iteration_);
+ return recentTicks_;
+}
+
+void
+PerformanceGroup::addRecentTicks(uint64_t iteration, uint64_t ticks)
+{
+ MOZ_ASSERT(iteration == iteration_);
+ recentTicks_ += ticks;
+}
+
+
+uint64_t
+PerformanceGroup::recentCPOW(uint64_t iteration) const
+{
+ MOZ_ASSERT(iteration == iteration_);
+ return recentCPOW_;
+}
+
+void
+PerformanceGroup::addRecentCPOW(uint64_t iteration, uint64_t CPOW)
+{
+ MOZ_ASSERT(iteration == iteration_);
+ recentCPOW_ += CPOW;
+}
+
+
+bool
+PerformanceGroup::isActive() const
+{
+ return isActive_;
+}
+
+void
+PerformanceGroup::setIsActive(bool value)
+{
+ isActive_ = value;
+}
+
+void
+PerformanceGroup::setIsUsedInThisIteration(bool value)
+{
+ isUsedInThisIteration_ = value;
+}
+bool
+PerformanceGroup::isUsedInThisIteration() const
+{
+ return isUsedInThisIteration_;
+}
+
+void
+PerformanceGroup::AddRef()
+{
+ ++refCount_;
+}
+
+void
+PerformanceGroup::Release()
+{
+ MOZ_ASSERT(refCount_ > 0);
+ --refCount_;
+ if (refCount_ > 0)
+ return;
+
+ this->Delete();
+}
+
+JS_PUBLIC_API(bool)
+SetStopwatchStartCallback(JSContext* cx, StopwatchStartCallback cb, void* closure)
+{
+ cx->performanceMonitoring.setStopwatchStartCallback(cb, closure);
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+SetStopwatchCommitCallback(JSContext* cx, StopwatchCommitCallback cb, void* closure)
+{
+ cx->performanceMonitoring.setStopwatchCommitCallback(cb, closure);
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+SetGetPerformanceGroupsCallback(JSContext* cx, GetGroupsCallback cb, void* closure)
+{
+ cx->performanceMonitoring.setGetGroupsCallback(cb, closure);
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+FlushPerformanceMonitoring(JSContext* cx)
+{
+ return cx->performanceMonitoring.commit();
+}
+JS_PUBLIC_API(void)
+ResetPerformanceMonitoring(JSContext* cx)
+{
+ return cx->performanceMonitoring.reset();
+}
+JS_PUBLIC_API(void)
+DisposePerformanceMonitoring(JSContext* cx)
+{
+ return cx->performanceMonitoring.dispose(cx);
+}
+
+JS_PUBLIC_API(bool)
+SetStopwatchIsMonitoringJank(JSContext* cx, bool value)
+{
+ return cx->performanceMonitoring.setIsMonitoringJank(value);
+}
+JS_PUBLIC_API(bool)
+GetStopwatchIsMonitoringJank(JSContext* cx)
+{
+ return cx->performanceMonitoring.isMonitoringJank();
+}
+
+JS_PUBLIC_API(bool)
+SetStopwatchIsMonitoringCPOW(JSContext* cx, bool value)
+{
+ return cx->performanceMonitoring.setIsMonitoringCPOW(value);
+}
+JS_PUBLIC_API(bool)
+GetStopwatchIsMonitoringCPOW(JSContext* cx)
+{
+ return cx->performanceMonitoring.isMonitoringCPOW();
+}
+
+JS_PUBLIC_API(void)
+GetPerfMonitoringTestCpuRescheduling(JSContext* cx, uint64_t* stayed, uint64_t* moved)
+{
+ *stayed = cx->performanceMonitoring.testCpuRescheduling.stayed;
+ *moved = cx->performanceMonitoring.testCpuRescheduling.moved;
+}
+
+JS_PUBLIC_API(void)
+AddCPOWPerformanceDelta(JSContext* cx, uint64_t delta)
+{
+ cx->performanceMonitoring.totalCPOWTime += delta;
+}
+
+
+} // namespace js
+
diff --git a/js/src/vm/Stopwatch.h b/js/src/vm/Stopwatch.h
new file mode 100644
index 000000000..a1b8bbbcb
--- /dev/null
+++ b/js/src/vm/Stopwatch.h
@@ -0,0 +1,406 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Stopwatch_h
+#define vm_Stopwatch_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/Vector.h"
+
+#include "jsapi.h"
+
+/*
+ An API for following in real-time the amount of CPU spent executing
+ webpages, add-ons, etc.
+*/
+
+namespace js {
+
+/**
+ * A container for performance groups.
+ *
+ * Performance monitoring deals with the execution duration of code
+ * that belongs to components, for a notion of components defined by
+ * the embedding. Typically, in a web browser, a component may be a
+ * webpage and/or a frame and/or a module and/or an add-on and/or a
+ * sandbox and/or a process etc.
+ *
+ * A PerformanceGroupHolder is owned y a JSCompartment and maps that
+ * compartment to all the components to which it belongs.
+ */
+struct PerformanceGroupHolder {
+
+ /**
+ * Get the groups to which this compartment belongs.
+ *
+ * Pre-condition: Execution must have entered the compartment.
+ *
+ * May return `nullptr` if the embedding has not initialized
+ * support for performance groups.
+ */
+ const PerformanceGroupVector* getGroups(JSContext*);
+
+ explicit PerformanceGroupHolder(JSRuntime* runtime)
+ : runtime_(runtime)
+ , initialized_(false)
+ { }
+ ~PerformanceGroupHolder();
+ void unlink();
+ private:
+ JSRuntime* runtime_;
+
+ // `true` once a call to `getGroups` has succeeded.
+ bool initialized_;
+
+ // The groups to which this compartment belongs. Filled if and only
+ // if `initialized_` is `true`.
+ PerformanceGroupVector groups_;
+};
+
+/**
+ * Container class for everything related to performance monitoring.
+ */
+struct PerformanceMonitoring {
+ /**
+ * The number of the current iteration of the event loop.
+ */
+ uint64_t iteration() {
+ return iteration_;
+ }
+
+ explicit PerformanceMonitoring(JSRuntime* runtime)
+ : totalCPOWTime(0)
+ , stopwatchStartCallback(nullptr)
+ , stopwatchStartClosure(nullptr)
+ , stopwatchCommitCallback(nullptr)
+ , stopwatchCommitClosure(nullptr)
+ , getGroupsCallback(nullptr)
+ , getGroupsClosure(nullptr)
+ , isMonitoringJank_(false)
+ , isMonitoringCPOW_(false)
+ , iteration_(0)
+ , startedAtIteration_(0)
+ , highestTimestampCounter_(0)
+ { }
+
+ /**
+ * Reset the stopwatch.
+ *
+ * This method is meant to be called whenever we start
+ * processing an event, to ensure that we stop any ongoing
+ * measurement that would otherwise provide irrelevant
+ * results.
+ */
+ void reset();
+
+ /**
+ * Start the stopwatch.
+ *
+ * This method is meant to be called once we know that the
+ * current event contains JavaScript code to execute. Calling
+ * this several times during the same iteration is idempotent.
+ */
+ void start();
+
+ /**
+ * Commit the performance data collected since the last call
+ * to `start()`, unless `reset()` has been called since then.
+ */
+ bool commit();
+
+ /**
+ * Liberate memory and references.
+ */
+ void dispose(JSRuntime* rtx);
+
+ /**
+ * Activate/deactivate stopwatch measurement of jank.
+ *
+ * Noop if `value` is `true` and the stopwatch is already
+ * measuring jank, or if `value` is `false` and the stopwatch
+ * is not measuring jank.
+ *
+ * Otherwise, any pending measurements are dropped, but previous
+ * measurements remain stored.
+ *
+ * May return `false` if the underlying hashtable cannot be allocated.
+ */
+ bool setIsMonitoringJank(bool value) {
+ if (isMonitoringJank_ != value)
+ reset();
+
+ isMonitoringJank_ = value;
+ return true;
+ }
+ bool isMonitoringJank() const {
+ return isMonitoringJank_;
+ }
+
+ /**
+ * Mark that a group has been used in this iteration.
+ */
+ bool addRecentGroup(PerformanceGroup* group);
+
+ /**
+ * Activate/deactivate stopwatch measurement of CPOW.
+ *
+ * Noop if `value` is `true` and the stopwatch is already
+ * measuring CPOW, or if `value` is `false` and the stopwatch
+ * is not measuring CPOW.
+ *
+ * Otherwise, any pending measurements are dropped, but previous
+ * measurements remain stored.
+ *
+ * May return `false` if the underlying hashtable cannot be allocated.
+ */
+ bool setIsMonitoringCPOW(bool value) {
+ if (isMonitoringCPOW_ != value)
+ reset();
+
+ isMonitoringCPOW_ = value;
+ return true;
+ }
+
+ bool isMonitoringCPOW() const {
+ return isMonitoringCPOW_;
+ }
+
+ /**
+ * Callbacks called when we start executing an event/when we have
+ * run to completion (including enqueued microtasks).
+ *
+ * If there are no nested event loops, each call to
+ * `stopwatchStartCallback` is followed by a call to
+ * `stopwatchCommitCallback`. However, embedders should not assume
+ * that this will always be the case, unless they take measures to
+ * prevent nested event loops.
+ *
+ * In presence of nested event loops, several calls to
+ * `stopwatchStartCallback` may occur before a call to
+ * `stopwatchCommitCallback`. Embedders should assume that a
+ * second call to `stopwatchStartCallback` cancels any measure
+ * started by the previous calls to `stopwatchStartCallback` and
+ * which have not been committed by `stopwatchCommitCallback`.
+ */
+ void setStopwatchStartCallback(js::StopwatchStartCallback cb, void* closure) {
+ stopwatchStartCallback = cb;
+ stopwatchStartClosure = closure;
+ }
+ void setStopwatchCommitCallback(js::StopwatchCommitCallback cb, void* closure) {
+ stopwatchCommitCallback = cb;
+ stopwatchCommitClosure = closure;
+ }
+
+ /**
+ * Callback called to associate a JSCompartment to the set of
+ * `PerformanceGroup`s that represent the components to which
+ * it belongs.
+ */
+ void setGetGroupsCallback(js::GetGroupsCallback cb, void* closure) {
+ getGroupsCallback = cb;
+ getGroupsClosure = closure;
+ }
+
+ /**
+ * The total amount of time spent waiting on CPOWs since the
+ * start of the process, in microseconds.
+ */
+ uint64_t totalCPOWTime;
+
+ /**
+ * A variant of RDTSC artificially made monotonic.
+ *
+ * Always return 0 on platforms that do not support RDTSC.
+ */
+ uint64_t monotonicReadTimestampCounter();
+
+ /**
+ * Data extracted by the AutoStopwatch to determine how often
+ * we reschedule the process to a different CPU during the
+ * execution of JS.
+ *
+ * Warning: These values are incremented *only* on platforms
+ * that offer a syscall/libcall to check on which CPU a
+ * process is currently executed.
+ */
+ struct TestCpuRescheduling
+ {
+ // Incremented once we have finished executing code
+ // in a group, if the CPU on which we started
+ // execution is the same as the CPU on which
+ // we finished.
+ uint64_t stayed;
+ // Incremented once we have finished executing code
+ // in a group, if the CPU on which we started
+ // execution is different from the CPU on which
+ // we finished.
+ uint64_t moved;
+ TestCpuRescheduling()
+ : stayed(0),
+ moved(0)
+ { }
+ };
+ TestCpuRescheduling testCpuRescheduling;
+ private:
+ PerformanceMonitoring(const PerformanceMonitoring&) = delete;
+ PerformanceMonitoring& operator=(const PerformanceMonitoring&) = delete;
+
+ private:
+ friend struct PerformanceGroupHolder;
+ js::StopwatchStartCallback stopwatchStartCallback;
+ void* stopwatchStartClosure;
+ js::StopwatchCommitCallback stopwatchCommitCallback;
+ void* stopwatchCommitClosure;
+
+ js::GetGroupsCallback getGroupsCallback;
+ void* getGroupsClosure;
+
+ /**
+ * `true` if stopwatch monitoring is active for Jank, `false` otherwise.
+ */
+ bool isMonitoringJank_;
+ /**
+ * `true` if stopwatch monitoring is active for CPOW, `false` otherwise.
+ */
+ bool isMonitoringCPOW_;
+
+ /**
+ * The number of times we have entered the event loop.
+ * Used to reset counters whenever we enter the loop,
+ * which may be caused either by having completed the
+ * previous run of the event loop, or by entering a
+ * nested loop.
+ *
+ * Always incremented by 1, may safely overflow.
+ */
+ uint64_t iteration_;
+
+ /**
+ * The iteration at which the stopwatch was last started.
+ *
+ * Used both to avoid starting the stopwatch several times
+ * during the same event loop and to avoid committing stale
+ * stopwatch results.
+ */
+ uint64_t startedAtIteration_;
+
+ /**
+ * Groups used in the current iteration.
+ */
+ PerformanceGroupVector recentGroups_;
+
+ /**
+ * The highest value of the timestamp counter encountered
+ * during this iteration.
+ */
+ uint64_t highestTimestampCounter_;
+};
+
+#if WINVER >= 0x0600
+struct cpuid_t {
+ WORD group_;
+ BYTE number_;
+ cpuid_t(WORD group, BYTE number)
+ : group_(group),
+ number_(number)
+ { }
+ cpuid_t()
+ : group_(0),
+ number_(0)
+ { }
+};
+#else
+ typedef struct {} cpuid_t;
+#endif // defined(WINVER >= 0x0600)
+
+/**
+ * RAII class to start/stop measuring performance when
+ * entering/leaving a compartment.
+ */
+class AutoStopwatch final {
+ // The context with which this object was initialized.
+ // Non-null.
+ JSContext* const cx_;
+
+ // An indication of the number of times we have entered the event
+ // loop. Used only for comparison.
+ uint64_t iteration_;
+
+ // `true` if we are monitoring jank, `false` otherwise.
+ bool isMonitoringJank_;
+ // `true` if we are monitoring CPOW, `false` otherwise.
+ bool isMonitoringCPOW_;
+
+ // Timestamps captured while starting the stopwatch.
+ uint64_t cyclesStart_;
+ uint64_t CPOWTimeStart_;
+
+ // The CPU on which we started the measure. Defined only
+ // if `isMonitoringJank_` is `true`.
+ cpuid_t cpuStart_;
+
+ PerformanceGroupVector groups_;
+
+ public:
+ // If the stopwatch is active, constructing an instance of
+ // AutoStopwatch causes it to become the current owner of the
+ // stopwatch.
+ //
+ // Previous owner is restored upon destruction.
+ explicit AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+ ~AutoStopwatch();
+ private:
+ void inline enter();
+
+ bool inline exit();
+
+ // Attempt to acquire a group
+ // If the group is inactive or if the group already has a stopwatch,
+ // do nothing and return `null`.
+ // Otherwise, bind the group to `this` for the current iteration
+ // and return `group`.
+ PerformanceGroup* acquireGroup(PerformanceGroup* group);
+
+ // Release a group. Noop if `this` is not the stopwatch of
+ // `group` for the current iteration.
+ void releaseGroup(PerformanceGroup* group);
+
+ // Add recent changes to all the groups owned by this stopwatch.
+ // Mark the groups as changed recently.
+ bool addToGroups(uint64_t cyclesDelta, uint64_t CPOWTimeDelta);
+
+ // Add recent changes to a single group. Mark the group as changed recently.
+ bool addToGroup(JSRuntime* runtime, uint64_t cyclesDelta, uint64_t CPOWTimeDelta, PerformanceGroup* group);
+
+ // Update telemetry statistics.
+ void updateTelemetry(const cpuid_t& a, const cpuid_t& b);
+
+ // Perform a subtraction for a quantity that should be monotonic
+ // but is not guaranteed to be so.
+ //
+ // If `start <= end`, return `end - start`.
+ // Otherwise, return `0`.
+ uint64_t inline getDelta(const uint64_t end, const uint64_t start) const;
+
+ // Return the value of the Timestamp Counter, as provided by the CPU.
+ // 0 on platforms for which we do not have access to a Timestamp Counter.
+ uint64_t inline getCycles(JSRuntime*) const;
+
+
+ // Return the identifier of the current CPU, on platforms for which we have
+ // access to the current CPU.
+ cpuid_t inline getCPU() const;
+
+ // Compare two CPU identifiers.
+ bool inline isSameCPU(const cpuid_t& a, const cpuid_t& b) const;
+ private:
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
+};
+
+
+} // namespace js
+
+#endif // vm_Stopwatch_h
diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h
new file mode 100644
index 000000000..7c3f18f6f
--- /dev/null
+++ b/js/src/vm/String-inl.h
@@ -0,0 +1,422 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_String_inl_h
+#define vm_String_inl_h
+
+#include "vm/String.h"
+
+#include "mozilla/PodOperations.h"
+#include "mozilla/Range.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+
+#include "gc/Allocator.h"
+#include "gc/Marking.h"
+
+namespace js {
+
+// Allocate a thin inline string if possible, and a fat inline string if not.
+template <AllowGC allowGC, typename CharT>
+static MOZ_ALWAYS_INLINE JSInlineString*
+AllocateInlineString(ExclusiveContext* cx, size_t len, CharT** chars)
+{
+ MOZ_ASSERT(JSInlineString::lengthFits<CharT>(len));
+
+ if (JSThinInlineString::lengthFits<CharT>(len)) {
+ JSThinInlineString* str = JSThinInlineString::new_<allowGC>(cx);
+ if (!str)
+ return nullptr;
+ *chars = str->init<CharT>(len);
+ return str;
+ }
+
+ JSFatInlineString* str = JSFatInlineString::new_<allowGC>(cx);
+ if (!str)
+ return nullptr;
+ *chars = str->init<CharT>(len);
+ return str;
+}
+
+// Create a thin inline string if possible, and a fat inline string if not.
+template <AllowGC allowGC, typename CharT>
+static MOZ_ALWAYS_INLINE JSInlineString*
+NewInlineString(ExclusiveContext* cx, mozilla::Range<const CharT> chars)
+{
+ /*
+ * Don't bother trying to find a static atom; measurement shows that not
+ * many get here (for one, Atomize is catching them).
+ */
+
+ size_t len = chars.length();
+ CharT* storage;
+ JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage);
+ if (!str)
+ return nullptr;
+
+ mozilla::PodCopy(storage, chars.begin().get(), len);
+ storage[len] = 0;
+ return str;
+}
+
+// Create a thin inline string if possible, and a fat inline string if not.
+template <typename CharT>
+static MOZ_ALWAYS_INLINE JSInlineString*
+NewInlineString(ExclusiveContext* cx, HandleLinearString base, size_t start, size_t length)
+{
+ MOZ_ASSERT(JSInlineString::lengthFits<CharT>(length));
+
+ CharT* chars;
+ JSInlineString* s = AllocateInlineString<CanGC>(cx, length, &chars);
+ if (!s)
+ return nullptr;
+
+ JS::AutoCheckCannotGC nogc;
+ mozilla::PodCopy(chars, base->chars<CharT>(nogc) + start, length);
+ chars[length] = 0;
+ return s;
+}
+
+static inline void
+StringWriteBarrierPost(js::ExclusiveContext* maybecx, JSString** strp)
+{
+}
+
+static inline void
+StringWriteBarrierPostRemove(js::ExclusiveContext* maybecx, JSString** strp)
+{
+}
+
+} /* namespace js */
+
+MOZ_ALWAYS_INLINE bool
+JSString::validateLength(js::ExclusiveContext* maybecx, size_t length)
+{
+ if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
+ js::ReportAllocationOverflow(maybecx);
+ return false;
+ }
+
+ return true;
+}
+
+MOZ_ALWAYS_INLINE void
+JSRope::init(js::ExclusiveContext* cx, JSString* left, JSString* right, size_t length)
+{
+ d.u1.length = length;
+ d.u1.flags = ROPE_FLAGS;
+ if (left->hasLatin1Chars() && right->hasLatin1Chars())
+ d.u1.flags |= LATIN1_CHARS_BIT;
+ d.s.u2.left = left;
+ d.s.u3.right = right;
+ js::StringWriteBarrierPost(cx, &d.s.u2.left);
+ js::StringWriteBarrierPost(cx, &d.s.u3.right);
+}
+
+template <js::AllowGC allowGC>
+MOZ_ALWAYS_INLINE JSRope*
+JSRope::new_(js::ExclusiveContext* cx,
+ typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
+ typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
+ size_t length)
+{
+ if (!validateLength(cx, length))
+ return nullptr;
+ JSRope* str = static_cast<JSRope*>(js::Allocate<JSString, allowGC>(cx));
+ if (!str)
+ return nullptr;
+ str->init(cx, left, right, length);
+ return str;
+}
+
+MOZ_ALWAYS_INLINE void
+JSDependentString::init(js::ExclusiveContext* cx, JSLinearString* base, size_t start,
+ size_t length)
+{
+ MOZ_ASSERT(start + length <= base->length());
+ d.u1.length = length;
+ JS::AutoCheckCannotGC nogc;
+ if (base->hasLatin1Chars()) {
+ d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
+ d.s.u2.nonInlineCharsLatin1 = base->latin1Chars(nogc) + start;
+ } else {
+ d.u1.flags = DEPENDENT_FLAGS;
+ d.s.u2.nonInlineCharsTwoByte = base->twoByteChars(nogc) + start;
+ }
+ d.s.u3.base = base;
+ js::StringWriteBarrierPost(cx, reinterpret_cast<JSString**>(&d.s.u3.base));
+}
+
+MOZ_ALWAYS_INLINE JSLinearString*
+JSDependentString::new_(js::ExclusiveContext* cx, JSLinearString* baseArg, size_t start,
+ size_t length)
+{
+ /*
+ * Try to avoid long chains of dependent strings. We can't avoid these
+ * entirely, however, due to how ropes are flattened.
+ */
+ if (baseArg->isDependent()) {
+ if (mozilla::Maybe<size_t> offset = baseArg->asDependent().baseOffset()) {
+ start += *offset;
+ baseArg = baseArg->asDependent().base();
+ }
+ }
+
+ MOZ_ASSERT(start + length <= baseArg->length());
+
+ /*
+ * Do not create a string dependent on inline chars from another string,
+ * both to avoid the awkward moving-GC hazard this introduces and because it
+ * is more efficient to immediately undepend here.
+ */
+ bool useInline = baseArg->hasTwoByteChars()
+ ? JSInlineString::lengthFits<char16_t>(length)
+ : JSInlineString::lengthFits<JS::Latin1Char>(length);
+ if (useInline) {
+ js::RootedLinearString base(cx, baseArg);
+ return baseArg->hasLatin1Chars()
+ ? js::NewInlineString<JS::Latin1Char>(cx, base, start, length)
+ : js::NewInlineString<char16_t>(cx, base, start, length);
+ }
+
+ if (baseArg->isExternal() && !baseArg->ensureFlat(cx->asJSContext()))
+ return nullptr;
+
+ JSDependentString* str = static_cast<JSDependentString*>(js::Allocate<JSString, js::NoGC>(cx));
+ if (str) {
+ str->init(cx, baseArg, start, length);
+ return str;
+ }
+
+ js::RootedLinearString base(cx, baseArg);
+
+ str = static_cast<JSDependentString*>(js::Allocate<JSString>(cx));
+ if (!str)
+ return nullptr;
+ str->init(cx, base, start, length);
+ return str;
+}
+
+MOZ_ALWAYS_INLINE void
+JSFlatString::init(const char16_t* chars, size_t length)
+{
+ d.u1.length = length;
+ d.u1.flags = FLAT_BIT;
+ d.s.u2.nonInlineCharsTwoByte = chars;
+}
+
+MOZ_ALWAYS_INLINE void
+JSFlatString::init(const JS::Latin1Char* chars, size_t length)
+{
+ d.u1.length = length;
+ d.u1.flags = FLAT_BIT | LATIN1_CHARS_BIT;
+ d.s.u2.nonInlineCharsLatin1 = chars;
+}
+
+template <js::AllowGC allowGC, typename CharT>
+MOZ_ALWAYS_INLINE JSFlatString*
+JSFlatString::new_(js::ExclusiveContext* cx, const CharT* chars, size_t length)
+{
+ MOZ_ASSERT(chars[length] == CharT(0));
+
+ if (!validateLength(cx, length))
+ return nullptr;
+
+ JSFlatString* str;
+ if (cx->compartment()->isAtomsCompartment())
+ str = js::Allocate<js::NormalAtom, allowGC>(cx);
+ else
+ str = static_cast<JSFlatString*>(js::Allocate<JSString, allowGC>(cx));
+ if (!str)
+ return nullptr;
+
+ str->init(chars, length);
+ return str;
+}
+
+inline js::PropertyName*
+JSFlatString::toPropertyName(JSContext* cx)
+{
+#ifdef DEBUG
+ uint32_t dummy;
+ MOZ_ASSERT(!isIndex(&dummy));
+#endif
+ if (isAtom())
+ return asAtom().asPropertyName();
+ JSAtom* atom = js::AtomizeString(cx, this);
+ if (!atom)
+ return nullptr;
+ return atom->asPropertyName();
+}
+
+template <js::AllowGC allowGC>
+MOZ_ALWAYS_INLINE JSThinInlineString*
+JSThinInlineString::new_(js::ExclusiveContext* cx)
+{
+ if (cx->compartment()->isAtomsCompartment())
+ return (JSThinInlineString*)(js::Allocate<js::NormalAtom, allowGC>(cx));
+
+ return static_cast<JSThinInlineString*>(js::Allocate<JSString, allowGC>(cx));
+}
+
+template <js::AllowGC allowGC>
+MOZ_ALWAYS_INLINE JSFatInlineString*
+JSFatInlineString::new_(js::ExclusiveContext* cx)
+{
+ if (cx->compartment()->isAtomsCompartment())
+ return (JSFatInlineString*)(js::Allocate<js::FatInlineAtom, allowGC>(cx));
+
+ return js::Allocate<JSFatInlineString, allowGC>(cx);
+}
+
+template<>
+MOZ_ALWAYS_INLINE JS::Latin1Char*
+JSThinInlineString::init<JS::Latin1Char>(size_t length)
+{
+ MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
+ d.u1.length = length;
+ d.u1.flags = INIT_THIN_INLINE_FLAGS | LATIN1_CHARS_BIT;
+ return d.inlineStorageLatin1;
+}
+
+template<>
+MOZ_ALWAYS_INLINE char16_t*
+JSThinInlineString::init<char16_t>(size_t length)
+{
+ MOZ_ASSERT(lengthFits<char16_t>(length));
+ d.u1.length = length;
+ d.u1.flags = INIT_THIN_INLINE_FLAGS;
+ return d.inlineStorageTwoByte;
+}
+
+template<>
+MOZ_ALWAYS_INLINE JS::Latin1Char*
+JSFatInlineString::init<JS::Latin1Char>(size_t length)
+{
+ MOZ_ASSERT(lengthFits<JS::Latin1Char>(length));
+ d.u1.length = length;
+ d.u1.flags = INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT;
+ return d.inlineStorageLatin1;
+}
+
+template<>
+MOZ_ALWAYS_INLINE char16_t*
+JSFatInlineString::init<char16_t>(size_t length)
+{
+ MOZ_ASSERT(lengthFits<char16_t>(length));
+ d.u1.length = length;
+ d.u1.flags = INIT_FAT_INLINE_FLAGS;
+ return d.inlineStorageTwoByte;
+}
+
+MOZ_ALWAYS_INLINE void
+JSExternalString::init(const char16_t* chars, size_t length, const JSStringFinalizer* fin)
+{
+ MOZ_ASSERT(fin);
+ MOZ_ASSERT(fin->finalize);
+ d.u1.length = length;
+ d.u1.flags = EXTERNAL_FLAGS;
+ d.s.u2.nonInlineCharsTwoByte = chars;
+ d.s.u3.externalFinalizer = fin;
+}
+
+MOZ_ALWAYS_INLINE JSExternalString*
+JSExternalString::new_(JSContext* cx, const char16_t* chars, size_t length,
+ const JSStringFinalizer* fin)
+{
+ if (!validateLength(cx, length))
+ return nullptr;
+ JSExternalString* str = js::Allocate<JSExternalString>(cx);
+ if (!str)
+ return nullptr;
+ str->init(chars, length, fin);
+ cx->updateMallocCounter((length + 1) * sizeof(char16_t));
+ return str;
+}
+
+inline JSLinearString*
+js::StaticStrings::getUnitStringForElement(JSContext* cx, JSString* str, size_t index)
+{
+ MOZ_ASSERT(index < str->length());
+
+ char16_t c;
+ if (!str->getChar(cx, index, &c))
+ return nullptr;
+ if (c < UNIT_STATIC_LIMIT)
+ return getUnit(c);
+ return NewDependentString(cx, str, index, 1);
+}
+
+inline JSAtom*
+js::StaticStrings::getLength2(char16_t c1, char16_t c2)
+{
+ MOZ_ASSERT(fitsInSmallChar(c1));
+ MOZ_ASSERT(fitsInSmallChar(c2));
+ size_t index = (((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2];
+ return length2StaticTable[index];
+}
+
+MOZ_ALWAYS_INLINE void
+JSString::finalize(js::FreeOp* fop)
+{
+ /* FatInline strings are in a different arena. */
+ MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING);
+ MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM);
+
+ if (isFlat())
+ asFlat().finalize(fop);
+ else
+ MOZ_ASSERT(isDependent() || isRope());
+}
+
+inline void
+JSFlatString::finalize(js::FreeOp* fop)
+{
+ MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_STRING);
+ MOZ_ASSERT(getAllocKind() != js::gc::AllocKind::FAT_INLINE_ATOM);
+
+ if (!isInline())
+ fop->free_(nonInlineCharsRaw());
+}
+
+inline void
+JSFatInlineString::finalize(js::FreeOp* fop)
+{
+ MOZ_ASSERT(getAllocKind() == js::gc::AllocKind::FAT_INLINE_STRING);
+
+ if (!isInline())
+ fop->free_(nonInlineCharsRaw());
+}
+
+inline void
+JSAtom::finalize(js::FreeOp* fop)
+{
+ MOZ_ASSERT(JSString::isAtom());
+ MOZ_ASSERT(JSString::isFlat());
+ MOZ_ASSERT(getAllocKind() == js::gc::AllocKind::ATOM ||
+ getAllocKind() == js::gc::AllocKind::FAT_INLINE_ATOM);
+
+ if (!isInline())
+ fop->free_(nonInlineCharsRaw());
+}
+
+inline void
+JSExternalString::finalize(js::FreeOp* fop)
+{
+ if (!JSString::isExternal()) {
+ // This started out as an external string, but was turned into a
+ // non-external string by JSExternalString::ensureFlat.
+ MOZ_ASSERT(isFlat());
+ fop->free_(nonInlineCharsRaw());
+ return;
+ }
+
+ const JSStringFinalizer* fin = externalFinalizer();
+ fin->finalize(zone(), fin, const_cast<char16_t*>(rawTwoByteChars()));
+}
+
+#endif /* vm_String_inl_h */
diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp
new file mode 100644
index 000000000..2f3b8850a
--- /dev/null
+++ b/js/src/vm/String.cpp
@@ -0,0 +1,1442 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/String-inl.h"
+
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/RangedPtr.h"
+#include "mozilla/SizePrintfMacros.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/Unused.h"
+
+#include "gc/Marking.h"
+#include "js/UbiNode.h"
+#include "vm/SPSProfiler.h"
+
+#include "jscntxtinlines.h"
+#include "jscompartmentinlines.h"
+
+using namespace js;
+
+using mozilla::IsSame;
+using mozilla::PodCopy;
+using mozilla::RangedPtr;
+using mozilla::RoundUpPow2;
+
+using JS::AutoCheckCannotGC;
+
+size_t
+JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ // JSRope: do nothing, we'll count all children chars when we hit the leaf strings.
+ if (isRope())
+ return 0;
+
+ MOZ_ASSERT(isLinear());
+
+ // JSDependentString: do nothing, we'll count the chars when we hit the base string.
+ if (isDependent())
+ return 0;
+
+ // JSExternalString: don't count, the chars could be stored anywhere.
+ if (isExternal())
+ return 0;
+
+ MOZ_ASSERT(isFlat());
+
+ // JSExtensibleString: count the full capacity, not just the used space.
+ if (isExtensible()) {
+ JSExtensibleString& extensible = asExtensible();
+ return extensible.hasLatin1Chars()
+ ? mallocSizeOf(extensible.rawLatin1Chars())
+ : mallocSizeOf(extensible.rawTwoByteChars());
+ }
+
+ // JSInlineString, JSFatInlineString [JSInlineAtom, JSFatInlineAtom]: the chars are inline.
+ if (isInline())
+ return 0;
+
+ // JSAtom, JSUndependedString: measure the space for the chars. For
+ // JSUndependedString, there is no need to count the base string, for the
+ // same reason as JSDependentString above.
+ JSFlatString& flat = asFlat();
+ return flat.hasLatin1Chars()
+ ? mallocSizeOf(flat.rawLatin1Chars())
+ : mallocSizeOf(flat.rawTwoByteChars());
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<JSString>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ JSString& str = get();
+ size_t size;
+ if (str.isAtom())
+ size = str.isFatInline() ? sizeof(js::FatInlineAtom) : sizeof(js::NormalAtom);
+ else
+ size = str.isFatInline() ? sizeof(JSFatInlineString) : sizeof(JSString);
+
+ // We can't use mallocSizeof on things in the nursery. At the moment,
+ // strings are never in the nursery, but that may change.
+ MOZ_ASSERT(!IsInsideNursery(&str));
+ size += str.sizeOfExcludingThis(mallocSizeOf);
+
+ return size;
+}
+
+const char16_t JS::ubi::Concrete<JSString>::concreteTypeName[] = u"JSString";
+
+#ifdef DEBUG
+
+template <typename CharT>
+/*static */ void
+JSString::dumpChars(const CharT* s, size_t n, FILE* fp)
+{
+ if (n == SIZE_MAX) {
+ n = 0;
+ while (s[n])
+ n++;
+ }
+
+ fputc('"', fp);
+ for (size_t i = 0; i < n; i++) {
+ char16_t c = s[i];
+ if (c == '\n')
+ fprintf(fp, "\\n");
+ else if (c == '\t')
+ fprintf(fp, "\\t");
+ else if (c >= 32 && c < 127)
+ fputc(s[i], fp);
+ else if (c <= 255)
+ fprintf(fp, "\\x%02x", unsigned(c));
+ else
+ fprintf(fp, "\\u%04x", unsigned(c));
+ }
+ fputc('"', fp);
+}
+
+template void
+JSString::dumpChars(const Latin1Char* s, size_t n, FILE* fp);
+
+template void
+JSString::dumpChars(const char16_t* s, size_t n, FILE* fp);
+
+void
+JSString::dumpCharsNoNewline(FILE* fp)
+{
+ if (JSLinearString* linear = ensureLinear(nullptr)) {
+ AutoCheckCannotGC nogc;
+ if (hasLatin1Chars())
+ dumpChars(linear->latin1Chars(nogc), length(), fp);
+ else
+ dumpChars(linear->twoByteChars(nogc), length(), fp);
+ } else {
+ fprintf(fp, "(oom in JSString::dumpCharsNoNewline)");
+ }
+}
+
+void
+JSString::dump(FILE* fp)
+{
+ if (JSLinearString* linear = ensureLinear(nullptr)) {
+ AutoCheckCannotGC nogc;
+ if (hasLatin1Chars()) {
+ const Latin1Char* chars = linear->latin1Chars(nogc);
+ fprintf(fp, "JSString* (%p) = Latin1Char * (%p) = ", (void*) this,
+ (void*) chars);
+ dumpChars(chars, length(), fp);
+ } else {
+ const char16_t* chars = linear->twoByteChars(nogc);
+ fprintf(fp, "JSString* (%p) = char16_t * (%p) = ", (void*) this,
+ (void*) chars);
+ dumpChars(chars, length(), fp);
+ }
+ } else {
+ fprintf(fp, "(oom in JSString::dump)");
+ }
+ fputc('\n', fp);
+}
+
+void
+JSString::dumpCharsNoNewline()
+{
+ dumpCharsNoNewline(stderr);
+}
+
+void
+JSString::dump()
+{
+ dump(stderr);
+}
+
+void
+JSString::dumpRepresentation(FILE* fp, int indent) const
+{
+ if (isRope()) asRope() .dumpRepresentation(fp, indent);
+ else if (isDependent()) asDependent() .dumpRepresentation(fp, indent);
+ else if (isExternal()) asExternal() .dumpRepresentation(fp, indent);
+ else if (isExtensible()) asExtensible() .dumpRepresentation(fp, indent);
+ else if (isInline()) asInline() .dumpRepresentation(fp, indent);
+ else if (isFlat()) asFlat() .dumpRepresentation(fp, indent);
+ else
+ MOZ_CRASH("Unexpected JSString representation");
+}
+
+void
+JSString::dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const
+{
+ uint32_t flags = d.u1.flags;
+ // Print the string's address as an actual C++ expression, to facilitate
+ // copy-and-paste into a debugger.
+ fprintf(fp, "((%s*) %p) length: %" PRIuSIZE " flags: 0x%x", subclass, this, length(), flags);
+ if (flags & FLAT_BIT) fputs(" FLAT", fp);
+ if (flags & HAS_BASE_BIT) fputs(" HAS_BASE", fp);
+ if (flags & INLINE_CHARS_BIT) fputs(" INLINE_CHARS", fp);
+ if (flags & ATOM_BIT) fputs(" ATOM", fp);
+ if (isPermanentAtom()) fputs(" PERMANENT", fp);
+ if (flags & LATIN1_CHARS_BIT) fputs(" LATIN1", fp);
+ fputc('\n', fp);
+}
+
+void
+JSLinearString::dumpRepresentationChars(FILE* fp, int indent) const
+{
+ if (hasLatin1Chars()) {
+ fprintf(fp, "%*schars: ((Latin1Char*) %p) ", indent, "", rawLatin1Chars());
+ dumpChars(rawLatin1Chars(), length());
+ } else {
+ fprintf(fp, "%*schars: ((char16_t*) %p) ", indent, "", rawTwoByteChars());
+ dumpChars(rawTwoByteChars(), length());
+ }
+ fputc('\n', fp);
+}
+
+bool
+JSString::equals(const char* s)
+{
+ JSLinearString* linear = ensureLinear(nullptr);
+ if (!linear) {
+ fprintf(stderr, "OOM in JSString::equals!\n");
+ return false;
+ }
+
+ return StringEqualsAscii(linear, s);
+}
+#endif /* DEBUG */
+
+template <typename CharT>
+static MOZ_ALWAYS_INLINE bool
+AllocChars(JSString* str, size_t length, CharT** chars, size_t* capacity)
+{
+ /*
+ * String length doesn't include the null char, so include it here before
+ * doubling. Adding the null char after doubling would interact poorly with
+ * round-up malloc schemes.
+ */
+ size_t numChars = length + 1;
+
+ /*
+ * Grow by 12.5% if the buffer is very large. Otherwise, round up to the
+ * next power of 2. This is similar to what we do with arrays; see
+ * JSObject::ensureDenseArrayElements.
+ */
+ static const size_t DOUBLING_MAX = 1024 * 1024;
+ numChars = numChars > DOUBLING_MAX ? numChars + (numChars / 8) : RoundUpPow2(numChars);
+
+ /* Like length, capacity does not include the null char, so take it out. */
+ *capacity = numChars - 1;
+
+ JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
+ *chars = str->zone()->pod_malloc<CharT>(numChars);
+ return *chars != nullptr;
+}
+
+bool
+JSRope::copyLatin1CharsZ(ExclusiveContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
+{
+ return copyCharsInternal<Latin1Char>(cx, out, true);
+}
+
+bool
+JSRope::copyTwoByteCharsZ(ExclusiveContext* cx, ScopedJSFreePtr<char16_t>& out) const
+{
+ return copyCharsInternal<char16_t>(cx, out, true);
+}
+
+bool
+JSRope::copyLatin1Chars(ExclusiveContext* cx, ScopedJSFreePtr<Latin1Char>& out) const
+{
+ return copyCharsInternal<Latin1Char>(cx, out, false);
+}
+
+bool
+JSRope::copyTwoByteChars(ExclusiveContext* cx, ScopedJSFreePtr<char16_t>& out) const
+{
+ return copyCharsInternal<char16_t>(cx, out, false);
+}
+
+template <typename CharT>
+bool
+JSRope::copyCharsInternal(ExclusiveContext* cx, ScopedJSFreePtr<CharT>& out,
+ bool nullTerminate) const
+{
+ /*
+ * Perform non-destructive post-order traversal of the rope, splatting
+ * each node's characters into a contiguous buffer.
+ */
+
+ size_t n = length();
+ if (cx)
+ out.reset(cx->pod_malloc<CharT>(n + 1));
+ else
+ out.reset(js_pod_malloc<CharT>(n + 1));
+
+ if (!out)
+ return false;
+
+ Vector<const JSString*, 8, SystemAllocPolicy> nodeStack;
+ const JSString* str = this;
+ CharT* pos = out;
+ while (true) {
+ if (str->isRope()) {
+ if (!nodeStack.append(str->asRope().rightChild()))
+ return false;
+ str = str->asRope().leftChild();
+ } else {
+ CopyChars(pos, str->asLinear());
+ pos += str->length();
+ if (nodeStack.empty())
+ break;
+ str = nodeStack.popCopy();
+ }
+ }
+
+ MOZ_ASSERT(pos == out + n);
+
+ if (nullTerminate)
+ out[n] = 0;
+
+ return true;
+}
+
+#ifdef DEBUG
+void
+JSRope::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent, "JSRope");
+ indent += 2;
+
+ fprintf(fp, "%*sleft: ", indent, "");
+ leftChild()->dumpRepresentation(fp, indent);
+
+ fprintf(fp, "%*sright: ", indent, "");
+ rightChild()->dumpRepresentation(fp, indent);
+}
+#endif
+
+namespace js {
+
+template <>
+void
+CopyChars(char16_t* dest, const JSLinearString& str)
+{
+ AutoCheckCannotGC nogc;
+ if (str.hasTwoByteChars())
+ PodCopy(dest, str.twoByteChars(nogc), str.length());
+ else
+ CopyAndInflateChars(dest, str.latin1Chars(nogc), str.length());
+}
+
+template <>
+void
+CopyChars(Latin1Char* dest, const JSLinearString& str)
+{
+ AutoCheckCannotGC nogc;
+ if (str.hasLatin1Chars()) {
+ PodCopy(dest, str.latin1Chars(nogc), str.length());
+ } else {
+ /*
+ * When we flatten a TwoByte rope, we turn child ropes (including Latin1
+ * ropes) into TwoByte dependent strings. If one of these strings is
+ * also part of another Latin1 rope tree, we can have a Latin1 rope with
+ * a TwoByte descendent and we end up here when we flatten it. Although
+ * the chars are stored as TwoByte, we know they must be in the Latin1
+ * range, so we can safely deflate here.
+ */
+ size_t len = str.length();
+ const char16_t* chars = str.twoByteChars(nogc);
+ for (size_t i = 0; i < len; i++) {
+ MOZ_ASSERT(chars[i] <= JSString::MAX_LATIN1_CHAR);
+ dest[i] = chars[i];
+ }
+ }
+}
+
+} /* namespace js */
+
+template<JSRope::UsingBarrier b, typename CharT>
+JSFlatString*
+JSRope::flattenInternal(ExclusiveContext* maybecx)
+{
+ /*
+ * Consider the DAG of JSRopes rooted at this JSRope, with non-JSRopes as
+ * its leaves. Mutate the root JSRope into a JSExtensibleString containing
+ * the full flattened text that the root represents, and mutate all other
+ * JSRopes in the interior of the DAG into JSDependentStrings that refer to
+ * this new JSExtensibleString.
+ *
+ * If the leftmost leaf of our DAG is a JSExtensibleString, consider
+ * stealing its buffer for use in our new root, and transforming it into a
+ * JSDependentString too. Do not mutate any of the other leaves.
+ *
+ * Perform a depth-first dag traversal, splatting each node's characters
+ * into a contiguous buffer. Visit each rope node three times:
+ * 1. record position in the buffer and recurse into left child;
+ * 2. recurse into the right child;
+ * 3. transform the node into a dependent string.
+ * To avoid maintaining a stack, tree nodes are mutated to indicate how many
+ * times they have been visited. Since ropes can be dags, a node may be
+ * encountered multiple times during traversal. However, step 3 above leaves
+ * a valid dependent string, so everything works out.
+ *
+ * While ropes avoid all sorts of quadratic cases with string concatenation,
+ * they can't help when ropes are immediately flattened. One idiomatic case
+ * that we'd like to keep linear (and has traditionally been linear in SM
+ * and other JS engines) is:
+ *
+ * while (...) {
+ * s += ...
+ * s.flatten
+ * }
+ *
+ * Two behaviors accomplish this:
+ *
+ * - When the leftmost non-rope in the DAG we're flattening is a
+ * JSExtensibleString with sufficient capacity to hold the entire
+ * flattened string, we just flatten the DAG into its buffer. Then, when
+ * we transform the root of the DAG from a JSRope into a
+ * JSExtensibleString, we steal that buffer, and change the victim from a
+ * JSExtensibleString to a JSDependentString. In this case, the left-hand
+ * side of the string never needs to be copied.
+ *
+ * - Otherwise, we round up the total flattened size and create a fresh
+ * JSExtensibleString with that much capacity. If this in turn becomes the
+ * leftmost leaf of a subsequent flatten, we will hopefully be able to
+ * fill it, as in the case above.
+ *
+ * Note that, even though the code for creating JSDependentStrings avoids
+ * creating dependents of dependents, we can create that situation here: the
+ * JSExtensibleStrings we transform into JSDependentStrings might have
+ * JSDependentStrings pointing to them already. Stealing the buffer doesn't
+ * change its address, only its owning JSExtensibleString, so all chars()
+ * pointers in the JSDependentStrings are still valid.
+ */
+ const size_t wholeLength = length();
+ size_t wholeCapacity;
+ CharT* wholeChars;
+ JSString* str = this;
+ CharT* pos;
+
+ /*
+ * JSString::flattenData is a tagged pointer to the parent node.
+ * The tag indicates what to do when we return to the parent.
+ */
+ static const uintptr_t Tag_Mask = 0x3;
+ static const uintptr_t Tag_FinishNode = 0x0;
+ static const uintptr_t Tag_VisitRightChild = 0x1;
+
+ AutoCheckCannotGC nogc;
+
+ /* Find the left most string, containing the first string. */
+ JSRope* leftMostRope = this;
+ while (leftMostRope->leftChild()->isRope())
+ leftMostRope = &leftMostRope->leftChild()->asRope();
+
+ if (leftMostRope->leftChild()->isExtensible()) {
+ JSExtensibleString& left = leftMostRope->leftChild()->asExtensible();
+ size_t capacity = left.capacity();
+ if (capacity >= wholeLength && left.hasTwoByteChars() == IsSame<CharT, char16_t>::value) {
+ /*
+ * Simulate a left-most traversal from the root to leftMost->leftChild()
+ * via first_visit_node
+ */
+ MOZ_ASSERT(str->isRope());
+ while (str != leftMostRope) {
+ if (b == WithIncrementalBarrier) {
+ JSString::writeBarrierPre(str->d.s.u2.left);
+ JSString::writeBarrierPre(str->d.s.u3.right);
+ }
+ JSString* child = str->d.s.u2.left;
+ MOZ_ASSERT(child->isRope());
+ str->setNonInlineChars(left.nonInlineChars<CharT>(nogc));
+ child->d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
+ str = child;
+ }
+ if (b == WithIncrementalBarrier) {
+ JSString::writeBarrierPre(str->d.s.u2.left);
+ JSString::writeBarrierPre(str->d.s.u3.right);
+ }
+ str->setNonInlineChars(left.nonInlineChars<CharT>(nogc));
+ wholeCapacity = capacity;
+ wholeChars = const_cast<CharT*>(left.nonInlineChars<CharT>(nogc));
+ pos = wholeChars + left.d.u1.length;
+ JS_STATIC_ASSERT(!(EXTENSIBLE_FLAGS & DEPENDENT_FLAGS));
+ left.d.u1.flags ^= (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
+ left.d.s.u3.base = (JSLinearString*)this; /* will be true on exit */
+ StringWriteBarrierPostRemove(maybecx, &left.d.s.u2.left);
+ StringWriteBarrierPost(maybecx, (JSString**)&left.d.s.u3.base);
+ goto visit_right_child;
+ }
+ }
+
+ if (!AllocChars(this, wholeLength, &wholeChars, &wholeCapacity)) {
+ if (maybecx)
+ ReportOutOfMemory(maybecx);
+ return nullptr;
+ }
+
+ pos = wholeChars;
+ first_visit_node: {
+ if (b == WithIncrementalBarrier) {
+ JSString::writeBarrierPre(str->d.s.u2.left);
+ JSString::writeBarrierPre(str->d.s.u3.right);
+ }
+
+ JSString& left = *str->d.s.u2.left;
+ str->setNonInlineChars(pos);
+ StringWriteBarrierPostRemove(maybecx, &str->d.s.u2.left);
+ if (left.isRope()) {
+ /* Return to this node when 'left' done, then goto visit_right_child. */
+ left.d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
+ str = &left;
+ goto first_visit_node;
+ }
+ CopyChars(pos, left.asLinear());
+ pos += left.length();
+ }
+ visit_right_child: {
+ JSString& right = *str->d.s.u3.right;
+ if (right.isRope()) {
+ /* Return to this node when 'right' done, then goto finish_node. */
+ right.d.u1.flattenData = uintptr_t(str) | Tag_FinishNode;
+ str = &right;
+ goto first_visit_node;
+ }
+ CopyChars(pos, right.asLinear());
+ pos += right.length();
+ }
+ finish_node: {
+ if (str == this) {
+ MOZ_ASSERT(pos == wholeChars + wholeLength);
+ *pos = '\0';
+ str->d.u1.length = wholeLength;
+ if (IsSame<CharT, char16_t>::value)
+ str->d.u1.flags = EXTENSIBLE_FLAGS;
+ else
+ str->d.u1.flags = EXTENSIBLE_FLAGS | LATIN1_CHARS_BIT;
+ str->setNonInlineChars(wholeChars);
+ str->d.s.u3.capacity = wholeCapacity;
+ StringWriteBarrierPostRemove(maybecx, &str->d.s.u2.left);
+ StringWriteBarrierPostRemove(maybecx, &str->d.s.u3.right);
+ return &this->asFlat();
+ }
+ uintptr_t flattenData = str->d.u1.flattenData;
+ if (IsSame<CharT, char16_t>::value)
+ str->d.u1.flags = DEPENDENT_FLAGS;
+ else
+ str->d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
+ str->d.u1.length = pos - str->asLinear().nonInlineChars<CharT>(nogc);
+ str->d.s.u3.base = (JSLinearString*)this; /* will be true on exit */
+ StringWriteBarrierPost(maybecx, (JSString**)&str->d.s.u3.base);
+ str = (JSString*)(flattenData & ~Tag_Mask);
+ if ((flattenData & Tag_Mask) == Tag_VisitRightChild)
+ goto visit_right_child;
+ MOZ_ASSERT((flattenData & Tag_Mask) == Tag_FinishNode);
+ goto finish_node;
+ }
+}
+
+template<JSRope::UsingBarrier b>
+JSFlatString*
+JSRope::flattenInternal(ExclusiveContext* maybecx)
+{
+ if (hasTwoByteChars())
+ return flattenInternal<b, char16_t>(maybecx);
+ return flattenInternal<b, Latin1Char>(maybecx);
+}
+
+JSFlatString*
+JSRope::flatten(ExclusiveContext* maybecx)
+{
+ mozilla::Maybe<AutoSPSEntry> sps;
+ if (maybecx && maybecx->isJSContext())
+ sps.emplace(maybecx->asJSContext()->runtime(), "JSRope::flatten");
+
+ if (zone()->needsIncrementalBarrier())
+ return flattenInternal<WithIncrementalBarrier>(maybecx);
+ return flattenInternal<NoBarrier>(maybecx);
+}
+
+template <AllowGC allowGC>
+static JSLinearString*
+EnsureLinear(ExclusiveContext* cx, typename MaybeRooted<JSString*, allowGC>::HandleType string)
+{
+ JSLinearString* linear = string->ensureLinear(cx);
+ // Don't report an exception if GC is not allowed, just return nullptr.
+ if (!linear && !allowGC)
+ cx->recoverFromOutOfMemory();
+ return linear;
+}
+
+template <AllowGC allowGC>
+JSString*
+js::ConcatStrings(ExclusiveContext* cx,
+ typename MaybeRooted<JSString*, allowGC>::HandleType left,
+ typename MaybeRooted<JSString*, allowGC>::HandleType right)
+{
+ MOZ_ASSERT_IF(!left->isAtom(), cx->isInsideCurrentZone(left));
+ MOZ_ASSERT_IF(!right->isAtom(), cx->isInsideCurrentZone(right));
+
+ size_t leftLen = left->length();
+ if (leftLen == 0)
+ return right;
+
+ size_t rightLen = right->length();
+ if (rightLen == 0)
+ return left;
+
+ size_t wholeLength = leftLen + rightLen;
+ if (MOZ_UNLIKELY(wholeLength > JSString::MAX_LENGTH)) {
+ // Don't report an exception if GC is not allowed, just return nullptr.
+ if (allowGC)
+ js::ReportAllocationOverflow(cx);
+ return nullptr;
+ }
+
+ bool isLatin1 = left->hasLatin1Chars() && right->hasLatin1Chars();
+ bool canUseInline = isLatin1
+ ? JSInlineString::lengthFits<Latin1Char>(wholeLength)
+ : JSInlineString::lengthFits<char16_t>(wholeLength);
+ if (canUseInline && cx->isJSContext()) {
+ Latin1Char* latin1Buf = nullptr; // initialize to silence GCC warning
+ char16_t* twoByteBuf = nullptr; // initialize to silence GCC warning
+ JSInlineString* str = isLatin1
+ ? AllocateInlineString<allowGC>(cx, wholeLength, &latin1Buf)
+ : AllocateInlineString<allowGC>(cx, wholeLength, &twoByteBuf);
+ if (!str)
+ return nullptr;
+
+ AutoCheckCannotGC nogc;
+ JSLinearString* leftLinear = EnsureLinear<allowGC>(cx, left);
+ if (!leftLinear)
+ return nullptr;
+ JSLinearString* rightLinear = EnsureLinear<allowGC>(cx, right);
+ if (!rightLinear)
+ return nullptr;
+
+ if (isLatin1) {
+ PodCopy(latin1Buf, leftLinear->latin1Chars(nogc), leftLen);
+ PodCopy(latin1Buf + leftLen, rightLinear->latin1Chars(nogc), rightLen);
+ latin1Buf[wholeLength] = 0;
+ } else {
+ if (leftLinear->hasTwoByteChars())
+ PodCopy(twoByteBuf, leftLinear->twoByteChars(nogc), leftLen);
+ else
+ CopyAndInflateChars(twoByteBuf, leftLinear->latin1Chars(nogc), leftLen);
+ if (rightLinear->hasTwoByteChars())
+ PodCopy(twoByteBuf + leftLen, rightLinear->twoByteChars(nogc), rightLen);
+ else
+ CopyAndInflateChars(twoByteBuf + leftLen, rightLinear->latin1Chars(nogc), rightLen);
+ twoByteBuf[wholeLength] = 0;
+ }
+
+ return str;
+ }
+
+ return JSRope::new_<allowGC>(cx, left, right, wholeLength);
+}
+
+template JSString*
+js::ConcatStrings<CanGC>(ExclusiveContext* cx, HandleString left, HandleString right);
+
+template JSString*
+js::ConcatStrings<NoGC>(ExclusiveContext* cx, JSString* const& left, JSString* const& right);
+
+template <typename CharT>
+JSFlatString*
+JSDependentString::undependInternal(JSContext* cx)
+{
+ size_t n = length();
+ CharT* s = cx->pod_malloc<CharT>(n + 1);
+ if (!s)
+ return nullptr;
+
+ AutoCheckCannotGC nogc;
+ PodCopy(s, nonInlineChars<CharT>(nogc), n);
+ s[n] = '\0';
+ setNonInlineChars<CharT>(s);
+
+ /*
+ * Transform *this into an undepended string so 'base' will remain rooted
+ * for the benefit of any other dependent string that depends on *this.
+ */
+ if (IsSame<CharT, Latin1Char>::value)
+ d.u1.flags = UNDEPENDED_FLAGS | LATIN1_CHARS_BIT;
+ else
+ d.u1.flags = UNDEPENDED_FLAGS;
+
+ return &this->asFlat();
+}
+
+JSFlatString*
+JSDependentString::undepend(JSContext* cx)
+{
+ MOZ_ASSERT(JSString::isDependent());
+ return hasLatin1Chars()
+ ? undependInternal<Latin1Char>(cx)
+ : undependInternal<char16_t>(cx);
+}
+
+#ifdef DEBUG
+void
+JSDependentString::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent, "JSDependentString");
+ indent += 2;
+
+ if (mozilla::Maybe<size_t> offset = baseOffset())
+ fprintf(fp, "%*soffset: %" PRIuSIZE "\n", indent, "", *offset);
+
+ fprintf(fp, "%*sbase: ", indent, "");
+ base()->dumpRepresentation(fp, indent);
+}
+#endif
+
+template <typename CharT>
+/* static */ bool
+JSFlatString::isIndexSlow(const CharT* s, size_t length, uint32_t* indexp)
+{
+ CharT ch = *s;
+
+ if (!JS7_ISDEC(ch))
+ return false;
+
+ if (length > UINT32_CHAR_BUFFER_LENGTH)
+ return false;
+
+ /*
+ * Make sure to account for the '\0' at the end of characters, dereferenced
+ * in the loop below.
+ */
+ RangedPtr<const CharT> cp(s, length + 1);
+ const RangedPtr<const CharT> end(s + length, s, length + 1);
+
+ uint32_t index = JS7_UNDEC(*cp++);
+ uint32_t oldIndex = 0;
+ uint32_t c = 0;
+
+ if (index != 0) {
+ while (JS7_ISDEC(*cp)) {
+ oldIndex = index;
+ c = JS7_UNDEC(*cp);
+ index = 10 * index + c;
+ cp++;
+ }
+ }
+
+ /* It's not an element if there are characters after the number. */
+ if (cp != end)
+ return false;
+
+ /*
+ * Look out for "4294967296" and larger-number strings that fit in
+ * UINT32_CHAR_BUFFER_LENGTH: only unsigned 32-bit integers shall pass.
+ */
+ if (oldIndex < UINT32_MAX / 10 || (oldIndex == UINT32_MAX / 10 && c <= (UINT32_MAX % 10))) {
+ *indexp = index;
+ return true;
+ }
+
+ return false;
+}
+
+template bool
+JSFlatString::isIndexSlow(const Latin1Char* s, size_t length, uint32_t* indexp);
+
+template bool
+JSFlatString::isIndexSlow(const char16_t* s, size_t length, uint32_t* indexp);
+
+/*
+ * Set up some tools to make it easier to generate large tables. After constant
+ * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
+ * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
+ * To use this, define R appropriately, then use Rn(0) (for some value of n), then
+ * undefine R.
+ */
+#define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
+#define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
+#define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
+#define R7(n) R6(n), R6((n) + (1 << 6))
+
+/*
+ * This is used when we generate our table of short strings, so the compiler is
+ * happier if we use |c| as few times as possible.
+ */
+#define FROM_SMALL_CHAR(c) Latin1Char((c) + ((c) < 10 ? '0' : \
+ (c) < 36 ? 'a' - 10 : \
+ 'A' - 36))
+
+/*
+ * Declare length-2 strings. We only store strings where both characters are
+ * alphanumeric. The lower 10 short chars are the numerals, the next 26 are
+ * the lowercase letters, and the next 26 are the uppercase letters.
+ */
+#define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
+ (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
+ (c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
+ StaticStrings::INVALID_SMALL_CHAR)
+
+#define R TO_SMALL_CHAR
+const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) };
+#undef R
+
+#undef R2
+#undef R4
+#undef R6
+#undef R7
+
+bool
+StaticStrings::init(JSContext* cx)
+{
+ AutoLockForExclusiveAccess lock(cx);
+ AutoCompartment ac(cx, cx->runtime()->atomsCompartment(lock), &lock);
+
+ static_assert(UNIT_STATIC_LIMIT - 1 <= JSString::MAX_LATIN1_CHAR,
+ "Unit strings must fit in Latin1Char.");
+
+ using Latin1Range = mozilla::Range<const Latin1Char>;
+
+ for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
+ Latin1Char buffer[] = { Latin1Char(i), '\0' };
+ JSFlatString* s = NewInlineString<NoGC>(cx, Latin1Range(buffer, 1));
+ if (!s)
+ return false;
+ HashNumber hash = mozilla::HashString(buffer, 1);
+ unitStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash);
+ }
+
+ for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
+ Latin1Char buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), '\0' };
+ JSFlatString* s = NewInlineString<NoGC>(cx, Latin1Range(buffer, 2));
+ if (!s)
+ return false;
+ HashNumber hash = mozilla::HashString(buffer, 2);
+ length2StaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash);
+ }
+
+ for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) {
+ if (i < 10) {
+ intStaticTable[i] = unitStaticTable[i + '0'];
+ } else if (i < 100) {
+ size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) +
+ TO_SMALL_CHAR((i % 10) + '0');
+ intStaticTable[i] = length2StaticTable[index];
+ } else {
+ Latin1Char buffer[] = { Latin1Char('0' + (i / 100)),
+ Latin1Char('0' + ((i / 10) % 10)),
+ Latin1Char('0' + (i % 10)),
+ '\0' };
+ JSFlatString* s = NewInlineString<NoGC>(cx, Latin1Range(buffer, 3));
+ if (!s)
+ return false;
+ HashNumber hash = mozilla::HashString(buffer, 3);
+ intStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom(hash);
+ }
+ }
+
+ return true;
+}
+
+void
+StaticStrings::trace(JSTracer* trc)
+{
+ /* These strings never change, so barriers are not needed. */
+
+ for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++)
+ TraceProcessGlobalRoot(trc, unitStaticTable[i], "unit-static-string");
+
+ for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++)
+ TraceProcessGlobalRoot(trc, length2StaticTable[i], "length2-static-string");
+
+ /* This may mark some strings more than once, but so be it. */
+ for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++)
+ TraceProcessGlobalRoot(trc, intStaticTable[i], "int-static-string");
+}
+
+template <typename CharT>
+/* static */ bool
+StaticStrings::isStatic(const CharT* chars, size_t length)
+{
+ switch (length) {
+ case 1: {
+ char16_t c = chars[0];
+ return c < UNIT_STATIC_LIMIT;
+ }
+ case 2:
+ return fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]);
+ case 3:
+ if ('1' <= chars[0] && chars[0] <= '9' &&
+ '0' <= chars[1] && chars[1] <= '9' &&
+ '0' <= chars[2] && chars[2] <= '9') {
+ int i = (chars[0] - '0') * 100 +
+ (chars[1] - '0') * 10 +
+ (chars[2] - '0');
+
+ return unsigned(i) < INT_STATIC_LIMIT;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+/* static */ bool
+StaticStrings::isStatic(JSAtom* atom)
+{
+ AutoCheckCannotGC nogc;
+ return atom->hasLatin1Chars()
+ ? isStatic(atom->latin1Chars(nogc), atom->length())
+ : isStatic(atom->twoByteChars(nogc), atom->length());
+}
+
+bool
+AutoStableStringChars::init(JSContext* cx, JSString* s)
+{
+ RootedLinearString linearString(cx, s->ensureLinear(cx));
+ if (!linearString)
+ return false;
+
+ MOZ_ASSERT(state_ == Uninitialized);
+
+ if (linearString->isExternal() && !linearString->ensureFlat(cx))
+ return false;
+
+ // If the chars are inline then we need to copy them since they may be moved
+ // by a compacting GC.
+ if (baseIsInline(linearString)) {
+ return linearString->hasTwoByteChars() ? copyTwoByteChars(cx, linearString)
+ : copyLatin1Chars(cx, linearString);
+ }
+
+ if (linearString->hasLatin1Chars()) {
+ state_ = Latin1;
+ latin1Chars_ = linearString->rawLatin1Chars();
+ } else {
+ state_ = TwoByte;
+ twoByteChars_ = linearString->rawTwoByteChars();
+ }
+
+ s_ = linearString;
+ return true;
+}
+
+bool
+AutoStableStringChars::initTwoByte(JSContext* cx, JSString* s)
+{
+ RootedLinearString linearString(cx, s->ensureLinear(cx));
+ if (!linearString)
+ return false;
+
+ MOZ_ASSERT(state_ == Uninitialized);
+
+ if (linearString->hasLatin1Chars())
+ return copyAndInflateLatin1Chars(cx, linearString);
+
+ if (linearString->isExternal() && !linearString->ensureFlat(cx))
+ return false;
+
+ // If the chars are inline then we need to copy them since they may be moved
+ // by a compacting GC.
+ if (baseIsInline(linearString))
+ return copyTwoByteChars(cx, linearString);
+
+ state_ = TwoByte;
+ twoByteChars_ = linearString->rawTwoByteChars();
+ s_ = linearString;
+ return true;
+}
+
+bool AutoStableStringChars::baseIsInline(HandleLinearString linearString)
+{
+ JSString* base = linearString;
+ while (base->isDependent())
+ base = base->asDependent().base();
+ return base->isInline();
+}
+
+template <typename T>
+T*
+AutoStableStringChars::allocOwnChars(JSContext* cx, size_t count)
+{
+ static_assert(
+ InlineCapacity >= sizeof(JS::Latin1Char) * (JSFatInlineString::MAX_LENGTH_LATIN1 + 1) &&
+ InlineCapacity >= sizeof(char16_t) * (JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1),
+ "InlineCapacity too small to hold fat inline strings");
+
+ static_assert((JSString::MAX_LENGTH & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0,
+ "Size calculation can overflow");
+ MOZ_ASSERT(count <= (JSString::MAX_LENGTH + 1));
+ size_t size = sizeof(T) * count;
+
+ ownChars_.emplace(cx);
+ if (!ownChars_->resize(size)) {
+ ownChars_.reset();
+ return nullptr;
+ }
+
+ return reinterpret_cast<T*>(ownChars_->begin());
+}
+
+bool
+AutoStableStringChars::copyAndInflateLatin1Chars(JSContext* cx, HandleLinearString linearString)
+{
+ char16_t* chars = allocOwnChars<char16_t>(cx, linearString->length() + 1);
+ if (!chars)
+ return false;
+
+ CopyAndInflateChars(chars, linearString->rawLatin1Chars(),
+ linearString->length());
+ chars[linearString->length()] = 0;
+
+ state_ = TwoByte;
+ twoByteChars_ = chars;
+ s_ = linearString;
+ return true;
+}
+
+bool
+AutoStableStringChars::copyLatin1Chars(JSContext* cx, HandleLinearString linearString)
+{
+ size_t length = linearString->length();
+ JS::Latin1Char* chars = allocOwnChars<JS::Latin1Char>(cx, length + 1);
+ if (!chars)
+ return false;
+
+ PodCopy(chars, linearString->rawLatin1Chars(), length);
+ chars[length] = 0;
+
+ state_ = Latin1;
+ latin1Chars_ = chars;
+ s_ = linearString;
+ return true;
+}
+
+bool
+AutoStableStringChars::copyTwoByteChars(JSContext* cx, HandleLinearString linearString)
+{
+ size_t length = linearString->length();
+ char16_t* chars = allocOwnChars<char16_t>(cx, length + 1);
+ if (!chars)
+ return false;
+
+ PodCopy(chars, linearString->rawTwoByteChars(), length);
+ chars[length] = 0;
+
+ state_ = TwoByte;
+ twoByteChars_ = chars;
+ s_ = linearString;
+ return true;
+}
+
+JSFlatString*
+JSString::ensureFlat(JSContext* cx)
+{
+ if (isFlat())
+ return &asFlat();
+ if (isDependent())
+ return asDependent().undepend(cx);
+ if (isRope())
+ return asRope().flatten(cx);
+ return asExternal().ensureFlat(cx);
+}
+
+JSFlatString*
+JSExternalString::ensureFlat(JSContext* cx)
+{
+ MOZ_ASSERT(hasTwoByteChars());
+
+ size_t n = length();
+ char16_t* s = cx->pod_malloc<char16_t>(n + 1);
+ if (!s)
+ return nullptr;
+
+ // Copy the chars before finalizing the string.
+ {
+ AutoCheckCannotGC nogc;
+ PodCopy(s, nonInlineChars<char16_t>(nogc), n);
+ s[n] = '\0';
+ }
+
+ // Release the external chars.
+ finalize(cx->runtime()->defaultFreeOp());
+
+ // Transform the string into a non-external, flat string.
+ setNonInlineChars<char16_t>(s);
+ d.u1.flags = FLAT_BIT;
+
+ return &this->asFlat();
+}
+
+#ifdef DEBUG
+void
+JSAtom::dump(FILE* fp)
+{
+ fprintf(fp, "JSAtom* (%p) = ", (void*) this);
+ this->JSString::dump(fp);
+}
+
+void
+JSAtom::dump()
+{
+ dump(stderr);
+}
+
+void
+JSExternalString::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent, "JSExternalString");
+ indent += 2;
+
+ fprintf(fp, "%*sfinalizer: ((JSStringFinalizer*) %p)\n", indent, "", externalFinalizer());
+ fprintf(fp, "%*sbase: ", indent, "");
+ base()->dumpRepresentation(fp, indent);
+}
+#endif /* DEBUG */
+
+JSLinearString*
+js::NewDependentString(JSContext* cx, JSString* baseArg, size_t start, size_t length)
+{
+ if (length == 0)
+ return cx->emptyString();
+
+ JSLinearString* base = baseArg->ensureLinear(cx);
+ if (!base)
+ return nullptr;
+
+ if (start == 0 && length == base->length())
+ return base;
+
+ if (base->hasTwoByteChars()) {
+ AutoCheckCannotGC nogc;
+ const char16_t* chars = base->twoByteChars(nogc) + start;
+ if (JSLinearString* staticStr = cx->staticStrings().lookup(chars, length))
+ return staticStr;
+ } else {
+ AutoCheckCannotGC nogc;
+ const Latin1Char* chars = base->latin1Chars(nogc) + start;
+ if (JSLinearString* staticStr = cx->staticStrings().lookup(chars, length))
+ return staticStr;
+ }
+
+ return JSDependentString::new_(cx, base, start, length);
+}
+
+static bool
+CanStoreCharsAsLatin1(const char16_t* s, size_t length)
+{
+ for (const char16_t* end = s + length; s < end; ++s) {
+ if (*s > JSString::MAX_LATIN1_CHAR)
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+CanStoreCharsAsLatin1(const Latin1Char* s, size_t length)
+{
+ MOZ_CRASH("Shouldn't be called for Latin1 chars");
+}
+
+template <AllowGC allowGC>
+static MOZ_ALWAYS_INLINE JSInlineString*
+NewInlineStringDeflated(ExclusiveContext* cx, mozilla::Range<const char16_t> chars)
+{
+ size_t len = chars.length();
+ Latin1Char* storage;
+ JSInlineString* str = AllocateInlineString<allowGC>(cx, len, &storage);
+ if (!str)
+ return nullptr;
+
+ for (size_t i = 0; i < len; i++) {
+ MOZ_ASSERT(chars[i] <= JSString::MAX_LATIN1_CHAR);
+ storage[i] = Latin1Char(chars[i]);
+ }
+ storage[len] = '\0';
+ return str;
+}
+
+template <typename CharT>
+static MOZ_ALWAYS_INLINE JSFlatString*
+TryEmptyOrStaticString(ExclusiveContext* cx, const CharT* chars, size_t n)
+{
+ // Measurements on popular websites indicate empty strings are pretty common
+ // and most strings with length 1 or 2 are in the StaticStrings table. For
+ // length 3 strings that's only about 1%, so we check n <= 2.
+ if (n <= 2) {
+ if (n == 0)
+ return cx->emptyString();
+
+ if (JSFlatString* str = cx->staticStrings().lookup(chars, n))
+ return str;
+ }
+
+ return nullptr;
+}
+
+template <AllowGC allowGC>
+static JSFlatString*
+NewStringDeflated(ExclusiveContext* cx, const char16_t* s, size_t n)
+{
+ if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+ return str;
+
+ if (JSInlineString::lengthFits<Latin1Char>(n))
+ return NewInlineStringDeflated<allowGC>(cx, mozilla::Range<const char16_t>(s, n));
+
+ ScopedJSFreePtr<Latin1Char> news(cx->pod_malloc<Latin1Char>(n + 1));
+ if (!news)
+ return nullptr;
+
+ for (size_t i = 0; i < n; i++) {
+ MOZ_ASSERT(s[i] <= JSString::MAX_LATIN1_CHAR);
+ news.get()[i] = Latin1Char(s[i]);
+ }
+ news[n] = '\0';
+
+ JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
+ if (!str)
+ return nullptr;
+
+ news.forget();
+ return str;
+}
+
+template <AllowGC allowGC>
+static JSFlatString*
+NewStringDeflated(ExclusiveContext* cx, const Latin1Char* s, size_t n)
+{
+ MOZ_CRASH("Shouldn't be called for Latin1 chars");
+}
+
+template <AllowGC allowGC, typename CharT>
+JSFlatString*
+js::NewStringDontDeflate(ExclusiveContext* cx, CharT* chars, size_t length)
+{
+ if (JSFlatString* str = TryEmptyOrStaticString(cx, chars, length)) {
+ // Free |chars| because we're taking possession of it, but it's no
+ // longer needed because we use the static string instead.
+ js_free(chars);
+ return str;
+ }
+
+ if (JSInlineString::lengthFits<CharT>(length)) {
+ JSInlineString* str =
+ NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(chars, length));
+ if (!str)
+ return nullptr;
+
+ js_free(chars);
+ return str;
+ }
+
+ return JSFlatString::new_<allowGC>(cx, chars, length);
+}
+
+template JSFlatString*
+js::NewStringDontDeflate<CanGC>(ExclusiveContext* cx, char16_t* chars, size_t length);
+
+template JSFlatString*
+js::NewStringDontDeflate<NoGC>(ExclusiveContext* cx, char16_t* chars, size_t length);
+
+template JSFlatString*
+js::NewStringDontDeflate<CanGC>(ExclusiveContext* cx, Latin1Char* chars, size_t length);
+
+template JSFlatString*
+js::NewStringDontDeflate<NoGC>(ExclusiveContext* cx, Latin1Char* chars, size_t length);
+
+template <AllowGC allowGC, typename CharT>
+JSFlatString*
+js::NewString(ExclusiveContext* cx, CharT* chars, size_t length)
+{
+ if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(chars, length)) {
+ JSFlatString* s = NewStringDeflated<allowGC>(cx, chars, length);
+ if (!s)
+ return nullptr;
+
+ // Free |chars| because we're taking possession of it but not using it.
+ js_free(chars);
+ return s;
+ }
+
+ return NewStringDontDeflate<allowGC>(cx, chars, length);
+}
+
+template JSFlatString*
+js::NewString<CanGC>(ExclusiveContext* cx, char16_t* chars, size_t length);
+
+template JSFlatString*
+js::NewString<NoGC>(ExclusiveContext* cx, char16_t* chars, size_t length);
+
+template JSFlatString*
+js::NewString<CanGC>(ExclusiveContext* cx, Latin1Char* chars, size_t length);
+
+template JSFlatString*
+js::NewString<NoGC>(ExclusiveContext* cx, Latin1Char* chars, size_t length);
+
+namespace js {
+
+template <AllowGC allowGC, typename CharT>
+JSFlatString*
+NewStringCopyNDontDeflate(ExclusiveContext* cx, const CharT* s, size_t n)
+{
+ if (JSFlatString* str = TryEmptyOrStaticString(cx, s, n))
+ return str;
+
+ if (JSInlineString::lengthFits<CharT>(n))
+ return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
+
+ ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
+ if (!news) {
+ if (!allowGC)
+ cx->recoverFromOutOfMemory();
+ return nullptr;
+ }
+
+ PodCopy(news.get(), s, n);
+ news[n] = 0;
+
+ JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
+ if (!str)
+ return nullptr;
+
+ news.forget();
+ return str;
+}
+
+template JSFlatString*
+NewStringCopyNDontDeflate<CanGC>(ExclusiveContext* cx, const char16_t* s, size_t n);
+
+template JSFlatString*
+NewStringCopyNDontDeflate<NoGC>(ExclusiveContext* cx, const char16_t* s, size_t n);
+
+template JSFlatString*
+NewStringCopyNDontDeflate<CanGC>(ExclusiveContext* cx, const Latin1Char* s, size_t n);
+
+template JSFlatString*
+NewStringCopyNDontDeflate<NoGC>(ExclusiveContext* cx, const Latin1Char* s, size_t n);
+
+JSFlatString*
+NewLatin1StringZ(ExclusiveContext* cx, UniqueChars chars)
+{
+ JSFlatString* str = NewString<CanGC>(cx, (Latin1Char*)chars.get(), strlen(chars.get()));
+ if (!str)
+ return nullptr;
+
+ mozilla::Unused << chars.release();
+ return str;
+}
+
+template <AllowGC allowGC, typename CharT>
+JSFlatString*
+NewStringCopyN(ExclusiveContext* cx, const CharT* s, size_t n)
+{
+ if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(s, n))
+ return NewStringDeflated<allowGC>(cx, s, n);
+
+ return NewStringCopyNDontDeflate<allowGC>(cx, s, n);
+}
+
+template JSFlatString*
+NewStringCopyN<CanGC>(ExclusiveContext* cx, const char16_t* s, size_t n);
+
+template JSFlatString*
+NewStringCopyN<NoGC>(ExclusiveContext* cx, const char16_t* s, size_t n);
+
+template JSFlatString*
+NewStringCopyN<CanGC>(ExclusiveContext* cx, const Latin1Char* s, size_t n);
+
+template JSFlatString*
+NewStringCopyN<NoGC>(ExclusiveContext* cx, const Latin1Char* s, size_t n);
+
+template <js::AllowGC allowGC>
+JSFlatString*
+NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8)
+{
+ JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
+ if (encoding == JS::SmallestEncoding::ASCII)
+ return NewStringCopyN<allowGC>(cx, utf8.begin().get(), utf8.length());
+
+ size_t length;
+ if (encoding == JS::SmallestEncoding::Latin1) {
+ Latin1Char* latin1 = UTF8CharsToNewLatin1CharsZ(cx, utf8, &length).get();
+ if (!latin1)
+ return nullptr;
+
+ JSFlatString* result = NewString<allowGC>(cx, latin1, length);
+ if (!result)
+ js_free((void*)latin1);
+ return result;
+ }
+
+ MOZ_ASSERT(encoding == JS::SmallestEncoding::UTF16);
+
+ char16_t* utf16 = UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length).get();
+ if (!utf16)
+ return nullptr;
+
+ JSFlatString* result = NewString<allowGC>(cx, utf16, length);
+ if (!result)
+ js_free((void*)utf16);
+ return result;
+}
+
+template JSFlatString*
+NewStringCopyUTF8N<CanGC>(JSContext* cx, const JS::UTF8Chars utf8);
+
+} /* namespace js */
+
+#ifdef DEBUG
+void
+JSExtensibleString::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent, "JSExtensibleString");
+ indent += 2;
+
+ fprintf(fp, "%*scapacity: %" PRIuSIZE "\n", indent, "", capacity());
+ dumpRepresentationChars(fp, indent);
+}
+
+void
+JSInlineString::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent,
+ isFatInline() ? "JSFatInlineString" : "JSThinInlineString");
+ indent += 2;
+
+ dumpRepresentationChars(fp, indent);
+}
+
+void
+JSFlatString::dumpRepresentation(FILE* fp, int indent) const
+{
+ dumpRepresentationHeader(fp, indent, "JSFlatString");
+ indent += 2;
+
+ dumpRepresentationChars(fp, indent);
+}
+#endif
diff --git a/js/src/vm/String.h b/js/src/vm/String.h
new file mode 100644
index 000000000..1a0c58575
--- /dev/null
+++ b/js/src/vm/String.h
@@ -0,0 +1,1509 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_String_h
+#define vm_String_h
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/Range.h"
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "jsstr.h"
+
+#include "gc/Barrier.h"
+#include "gc/Heap.h"
+#include "gc/Marking.h"
+#include "gc/Rooting.h"
+#include "js/CharacterEncoding.h"
+#include "js/GCAPI.h"
+#include "js/RootingAPI.h"
+
+class JSDependentString;
+class JSExtensibleString;
+class JSExternalString;
+class JSInlineString;
+class JSRope;
+
+namespace js {
+
+class AutoStableStringChars;
+class StaticStrings;
+class PropertyName;
+
+/* The buffer length required to contain any unsigned 32-bit integer. */
+static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
+
+} /* namespace js */
+
+/*
+ * JavaScript strings
+ *
+ * Conceptually, a JS string is just an array of chars and a length. This array
+ * of chars may or may not be null-terminated and, if it is, the null character
+ * is not included in the length.
+ *
+ * To improve performance of common operations, the following optimizations are
+ * made which affect the engine's representation of strings:
+ *
+ * - The plain vanilla representation is a "flat" string which consists of a
+ * string header in the GC heap and a malloc'd null terminated char array.
+ *
+ * - To avoid copying a substring of an existing "base" string , a "dependent"
+ * string (JSDependentString) can be created which points into the base
+ * string's char array.
+ *
+ * - To avoid O(n^2) char buffer copying, a "rope" node (JSRope) can be created
+ * to represent a delayed string concatenation. Concatenation (called
+ * flattening) is performed if and when a linear char array is requested. In
+ * general, ropes form a binary dag whose internal nodes are JSRope string
+ * headers with no associated char array and whose leaf nodes are either flat
+ * or dependent strings.
+ *
+ * - To avoid copying the leftmost string when flattening, we may produce an
+ * "extensible" string, which tracks not only its actual length but also its
+ * buffer's overall size. If such an "extensible" string appears as the
+ * leftmost string in a subsequent flatten, and its buffer has enough unused
+ * space, we can simply flatten the rest of the ropes into its buffer,
+ * leaving its text in place. We then transfer ownership of its buffer to the
+ * flattened rope, and mutate the donor extensible string into a dependent
+ * string referencing its original buffer.
+ *
+ * (The term "extensible" does not imply that we ever 'realloc' the buffer.
+ * Extensible strings may have dependent strings pointing into them, and the
+ * JSAPI hands out pointers to flat strings' buffers, so resizing with
+ * 'realloc' is generally not possible.)
+ *
+ * - To avoid allocating small char arrays, short strings can be stored inline
+ * in the string header (JSInlineString). These come in two flavours:
+ * JSThinInlineString, which is the same size as JSString; and
+ * JSFatInlineString, which has a larger header and so can fit more chars.
+ *
+ * - To avoid comparing O(n) string equality comparison, strings can be
+ * canonicalized to "atoms" (JSAtom) such that there is a single atom with a
+ * given (length,chars).
+ *
+ * - To avoid copying all strings created through the JSAPI, an "external"
+ * string (JSExternalString) can be created whose chars are managed by the
+ * JSAPI client.
+ *
+ * - To avoid using two bytes per character for every string, string characters
+ * are stored as Latin1 instead of TwoByte if all characters are representable
+ * in Latin1.
+ *
+ * Although all strings share the same basic memory layout, we can conceptually
+ * arrange them into a hierarchy of operations/invariants and represent this
+ * hierarchy in C++ with classes:
+ *
+ * C++ type operations+fields / invariants+properties
+ * ========================== =========================================
+ * JSString (abstract) get(Latin1|TwoByte)CharsZ, get(Latin1|TwoByte)Chars, length / -
+ * | \
+ * | JSRope leftChild, rightChild / -
+ * |
+ * JSLinearString (abstract) latin1Chars, twoByteChars / might be null-terminated
+ * | |
+ * | +-- JSDependentString base / -
+ * | |
+ * | +-- JSExternalString - / char array memory managed by embedding
+ * |
+ * JSFlatString - / null terminated
+ * | |
+ * | +-- JSExtensibleString tracks total buffer capacity (including current text)
+ * | |
+ * | +-- JSUndependedString original dependent base / -
+ * | |
+ * | +-- JSInlineString (abstract) - / chars stored in header
+ * | |
+ * | +-- JSThinInlineString - / header is normal
+ * | |
+ * | +-- JSFatInlineString - / header is fat
+ * |
+ * JSAtom (abstract) - / string equality === pointer equality
+ * | |
+ * | +-- js::NormalAtom - JSFlatString + atom hash code
+ * | |
+ * | +-- js::FatInlineAtom - JSFatInlineString + atom hash code
+ * |
+ * js::PropertyName - / chars don't contain an index (uint32_t)
+ *
+ * Classes marked with (abstract) above are not literally C++ Abstract Base
+ * Classes (since there are no virtual functions, pure or not, in this
+ * hierarchy), but have the same meaning: there are no strings with this type as
+ * its most-derived type.
+ *
+ * Atoms can additionally be permanent, i.e. unable to be collected, and can
+ * be combined with other string types to create additional most-derived types
+ * that satisfy the invariants of more than one of the abovementioned
+ * most-derived types. Furthermore, each atom stores a hash number (based on its
+ * chars). This hash number is used as key in the atoms table and when the atom
+ * is used as key in a JS Map/Set.
+ *
+ * Derived string types can be queried from ancestor types via isX() and
+ * retrieved with asX() debug-only-checked casts.
+ *
+ * The ensureX() operations mutate 'this' in place to effectively the type to be
+ * at least X (e.g., ensureLinear will change a JSRope to be a JSFlatString).
+ */
+
+class JSString : public js::gc::TenuredCell
+{
+ protected:
+ static const size_t NUM_INLINE_CHARS_LATIN1 = 2 * sizeof(void*) / sizeof(JS::Latin1Char);
+ static const size_t NUM_INLINE_CHARS_TWO_BYTE = 2 * sizeof(void*) / sizeof(char16_t);
+
+ /* Fields only apply to string types commented on the right. */
+ struct Data
+ {
+ union {
+ struct {
+ uint32_t flags; /* JSString */
+ uint32_t length; /* JSString */
+ };
+ uintptr_t flattenData; /* JSRope (temporary while flattening) */
+ } u1;
+ union {
+ union {
+ /* JS(Fat)InlineString */
+ JS::Latin1Char inlineStorageLatin1[NUM_INLINE_CHARS_LATIN1];
+ char16_t inlineStorageTwoByte[NUM_INLINE_CHARS_TWO_BYTE];
+ };
+ struct {
+ union {
+ const JS::Latin1Char* nonInlineCharsLatin1; /* JSLinearString, except JS(Fat)InlineString */
+ const char16_t* nonInlineCharsTwoByte;/* JSLinearString, except JS(Fat)InlineString */
+ JSString* left; /* JSRope */
+ } u2;
+ union {
+ JSLinearString* base; /* JS(Dependent|Undepended)String */
+ JSString* right; /* JSRope */
+ size_t capacity; /* JSFlatString (extensible) */
+ const JSStringFinalizer* externalFinalizer;/* JSExternalString */
+ } u3;
+ } s;
+ };
+ } d;
+
+ public:
+ /* Flags exposed only for jits */
+
+ /*
+ * The Flags Word
+ *
+ * The flags word stores both the string's type and its character encoding.
+ *
+ * If LATIN1_CHARS_BIT is set, the string's characters are stored as Latin1
+ * instead of TwoByte. This flag can also be set for ropes, if both the
+ * left and right nodes are Latin1. Flattening will result in a Latin1
+ * string in this case.
+ *
+ * The other flags store the string's type. Instead of using a dense index
+ * to represent the most-derived type, string types are encoded to allow
+ * single-op tests for hot queries (isRope, isDependent, isFlat, isAtom)
+ * which, in view of subtyping, would require slower
+ * (isX() || isY() || isZ()).
+ *
+ * The string type encoding can be summarized as follows. The "instance
+ * encoding" entry for a type specifies the flag bits used to create a
+ * string instance of that type. Abstract types have no instances and thus
+ * have no such entry. The "subtype predicate" entry for a type specifies
+ * the predicate used to query whether a JSString instance is subtype
+ * (reflexively) of that type.
+ *
+ * String Instance Subtype
+ * type encoding predicate
+ * ------------------------------------
+ * Rope 000000 000000
+ * Linear - !000000
+ * HasBase - xxxx1x
+ * Dependent 000010 000010
+ * External 100000 100000
+ * Flat - xxxxx1
+ * Undepended 000011 000011
+ * Extensible 010001 010001
+ * Inline 000101 xxx1xx
+ * FatInline 010101 x1x1xx
+ * Atom 001001 xx1xxx
+ * PermanentAtom 101001 1x1xxx
+ * InlineAtom - xx11xx
+ * FatInlineAtom - x111xx
+ *
+ * Note that the first 4 flag bits (from right to left in the previous table)
+ * have the following meaning and can be used for some hot queries:
+ *
+ * Bit 0: IsFlat
+ * Bit 1: HasBase (Dependent, Undepended)
+ * Bit 2: IsInline (Inline, FatInline)
+ * Bit 3: IsAtom (Atom, PermanentAtom)
+ *
+ * "HasBase" here refers to the two string types that have a 'base' field:
+ * JSDependentString and JSUndependedString.
+ * A JSUndependedString is a JSDependentString which has been 'fixed' (by ensureFixed)
+ * to be null-terminated. In such cases, the string must keep marking its base since
+ * there may be any number of *other* JSDependentStrings transitively depending on it.
+ *
+ */
+
+ static const uint32_t FLAT_BIT = JS_BIT(0);
+ static const uint32_t HAS_BASE_BIT = JS_BIT(1);
+ static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
+ static const uint32_t ATOM_BIT = JS_BIT(3);
+
+ static const uint32_t ROPE_FLAGS = 0;
+ static const uint32_t DEPENDENT_FLAGS = HAS_BASE_BIT;
+ static const uint32_t UNDEPENDED_FLAGS = FLAT_BIT | HAS_BASE_BIT;
+ static const uint32_t EXTENSIBLE_FLAGS = FLAT_BIT | JS_BIT(4);
+ static const uint32_t EXTERNAL_FLAGS = JS_BIT(5);
+
+ static const uint32_t FAT_INLINE_MASK = INLINE_CHARS_BIT | JS_BIT(4);
+ static const uint32_t PERMANENT_ATOM_MASK = ATOM_BIT | JS_BIT(5);
+
+ /* Initial flags for thin inline and fat inline strings. */
+ static const uint32_t INIT_THIN_INLINE_FLAGS = FLAT_BIT | INLINE_CHARS_BIT;
+ static const uint32_t INIT_FAT_INLINE_FLAGS = FLAT_BIT | FAT_INLINE_MASK;
+
+ static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
+
+ static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
+
+ static const uint32_t MAX_LENGTH = js::MaxStringLength;
+
+ static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
+
+ /*
+ * Helper function to validate that a string of a given length is
+ * representable by a JSString. An allocation overflow is reported if false
+ * is returned.
+ */
+ static inline bool validateLength(js::ExclusiveContext* maybecx, size_t length);
+
+ static void staticAsserts() {
+ static_assert(JSString::MAX_LENGTH < UINT32_MAX, "Length must fit in 32 bits");
+ static_assert(sizeof(JSString) ==
+ (offsetof(JSString, d.inlineStorageLatin1) +
+ NUM_INLINE_CHARS_LATIN1 * sizeof(char)),
+ "Inline Latin1 chars must fit in a JSString");
+ static_assert(sizeof(JSString) ==
+ (offsetof(JSString, d.inlineStorageTwoByte) +
+ NUM_INLINE_CHARS_TWO_BYTE * sizeof(char16_t)),
+ "Inline char16_t chars must fit in a JSString");
+
+ /* Ensure js::shadow::String has the same layout. */
+ using js::shadow::String;
+ static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
+ "shadow::String length offset must match JSString");
+ static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),
+ "shadow::String flags offset must match JSString");
+ static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
+ "shadow::String nonInlineChars offset must match JSString");
+ static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
+ "shadow::String nonInlineChars offset must match JSString");
+ static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
+ "shadow::String inlineStorage offset must match JSString");
+ static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(String, inlineStorageTwoByte),
+ "shadow::String inlineStorage offset must match JSString");
+ static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
+ "shadow::String::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
+ static_assert(LATIN1_CHARS_BIT == String::LATIN1_CHARS_BIT,
+ "shadow::String::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
+ static_assert(TYPE_FLAGS_MASK == String::TYPE_FLAGS_MASK,
+ "shadow::String::TYPE_FLAGS_MASK must match JSString::TYPE_FLAGS_MASK");
+ static_assert(ROPE_FLAGS == String::ROPE_FLAGS,
+ "shadow::String::ROPE_FLAGS must match JSString::ROPE_FLAGS");
+ }
+
+ /* Avoid lame compile errors in JSRope::flatten */
+ friend class JSRope;
+
+ friend class js::gc::RelocationOverlay;
+
+ protected:
+ template <typename CharT>
+ MOZ_ALWAYS_INLINE
+ void setNonInlineChars(const CharT* chars);
+
+ public:
+ /* All strings have length. */
+
+ MOZ_ALWAYS_INLINE
+ size_t length() const {
+ return d.u1.length;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool empty() const {
+ return d.u1.length == 0;
+ }
+
+ inline bool getChar(js::ExclusiveContext* cx, size_t index, char16_t* code);
+
+ /* Strings have either Latin1 or TwoByte chars. */
+ bool hasLatin1Chars() const {
+ return d.u1.flags & LATIN1_CHARS_BIT;
+ }
+ bool hasTwoByteChars() const {
+ return !(d.u1.flags & LATIN1_CHARS_BIT);
+ }
+
+ /* Fallible conversions to more-derived string types. */
+
+ inline JSLinearString* ensureLinear(js::ExclusiveContext* cx);
+ JSFlatString* ensureFlat(JSContext* cx);
+
+ static bool ensureLinear(js::ExclusiveContext* cx, JSString* str) {
+ return str->ensureLinear(cx) != nullptr;
+ }
+
+ /* Type query and debug-checked casts */
+
+ MOZ_ALWAYS_INLINE
+ bool isRope() const {
+ return (d.u1.flags & TYPE_FLAGS_MASK) == ROPE_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSRope& asRope() const {
+ MOZ_ASSERT(isRope());
+ return *(JSRope*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isLinear() const {
+ return !isRope();
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSLinearString& asLinear() const {
+ MOZ_ASSERT(JSString::isLinear());
+ return *(JSLinearString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isDependent() const {
+ return (d.u1.flags & TYPE_FLAGS_MASK) == DEPENDENT_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSDependentString& asDependent() const {
+ MOZ_ASSERT(isDependent());
+ return *(JSDependentString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isFlat() const {
+ return d.u1.flags & FLAT_BIT;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSFlatString& asFlat() const {
+ MOZ_ASSERT(isFlat());
+ return *(JSFlatString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isExtensible() const {
+ return (d.u1.flags & TYPE_FLAGS_MASK) == EXTENSIBLE_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSExtensibleString& asExtensible() const {
+ MOZ_ASSERT(isExtensible());
+ return *(JSExtensibleString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isInline() const {
+ return d.u1.flags & INLINE_CHARS_BIT;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSInlineString& asInline() const {
+ MOZ_ASSERT(isInline());
+ return *(JSInlineString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isFatInline() const {
+ return (d.u1.flags & FAT_INLINE_MASK) == FAT_INLINE_MASK;
+ }
+
+ /* For hot code, prefer other type queries. */
+ bool isExternal() const {
+ return (d.u1.flags & TYPE_FLAGS_MASK) == EXTERNAL_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSExternalString& asExternal() const {
+ MOZ_ASSERT(isExternal());
+ return *(JSExternalString*)this;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isUndepended() const {
+ return (d.u1.flags & TYPE_FLAGS_MASK) == UNDEPENDED_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isAtom() const {
+ return d.u1.flags & ATOM_BIT;
+ }
+
+ MOZ_ALWAYS_INLINE
+ bool isPermanentAtom() const {
+ return (d.u1.flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_MASK;
+ }
+
+ MOZ_ALWAYS_INLINE
+ JSAtom& asAtom() const {
+ MOZ_ASSERT(isAtom());
+ return *(JSAtom*)this;
+ }
+
+ /* Only called by the GC for dependent or undepended strings. */
+
+ inline bool hasBase() const {
+ return d.u1.flags & HAS_BASE_BIT;
+ }
+
+ inline JSLinearString* base() const;
+
+ void traceBase(JSTracer* trc);
+
+ /* Only called by the GC for strings with the AllocKind::STRING kind. */
+
+ inline void finalize(js::FreeOp* fop);
+
+ /* Gets the number of bytes that the chars take on the heap. */
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ /* Offsets for direct field from jit code. */
+
+ static size_t offsetOfLength() {
+ return offsetof(JSString, d.u1.length);
+ }
+ static size_t offsetOfFlags() {
+ return offsetof(JSString, d.u1.flags);
+ }
+
+ static size_t offsetOfNonInlineChars() {
+ static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) ==
+ offsetof(JSString, d.s.u2.nonInlineCharsLatin1),
+ "nonInlineCharsTwoByte and nonInlineCharsLatin1 must have same offset");
+ return offsetof(JSString, d.s.u2.nonInlineCharsTwoByte);
+ }
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::String;
+
+#ifdef DEBUG
+ void dump(FILE* fp);
+ void dumpCharsNoNewline(FILE* fp);
+ void dump();
+ void dumpCharsNoNewline();
+ void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const;
+
+ template <typename CharT>
+ static void dumpChars(const CharT* s, size_t len, FILE* fp=stderr);
+
+ bool equals(const char* s);
+#endif
+
+ void traceChildren(JSTracer* trc);
+
+ static MOZ_ALWAYS_INLINE void readBarrier(JSString* thing) {
+ if (thing->isPermanentAtom())
+ return;
+
+ TenuredCell::readBarrier(thing);
+ }
+
+ static MOZ_ALWAYS_INLINE void writeBarrierPre(JSString* thing) {
+ if (isNullLike(thing) || thing->isPermanentAtom())
+ return;
+
+ TenuredCell::writeBarrierPre(thing);
+ }
+
+ private:
+ JSString() = delete;
+ JSString(const JSString& other) = delete;
+ void operator=(const JSString& other) = delete;
+};
+
+class JSRope : public JSString
+{
+ template <typename CharT>
+ bool copyCharsInternal(js::ExclusiveContext* cx, js::ScopedJSFreePtr<CharT>& out,
+ bool nullTerminate) const;
+
+ enum UsingBarrier { WithIncrementalBarrier, NoBarrier };
+
+ template<UsingBarrier b, typename CharT>
+ JSFlatString* flattenInternal(js::ExclusiveContext* cx);
+
+ template<UsingBarrier b>
+ JSFlatString* flattenInternal(js::ExclusiveContext* cx);
+
+ friend class JSString;
+ JSFlatString* flatten(js::ExclusiveContext* cx);
+
+ void init(js::ExclusiveContext* cx, JSString* left, JSString* right, size_t length);
+
+ public:
+ template <js::AllowGC allowGC>
+ static inline JSRope* new_(js::ExclusiveContext* cx,
+ typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
+ typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
+ size_t length);
+
+ bool copyLatin1Chars(js::ExclusiveContext* cx,
+ js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
+ bool copyTwoByteChars(js::ExclusiveContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
+
+ bool copyLatin1CharsZ(js::ExclusiveContext* cx,
+ js::ScopedJSFreePtr<JS::Latin1Char>& out) const;
+ bool copyTwoByteCharsZ(js::ExclusiveContext* cx, js::ScopedJSFreePtr<char16_t>& out) const;
+
+ template <typename CharT>
+ bool copyChars(js::ExclusiveContext* cx, js::ScopedJSFreePtr<CharT>& out) const;
+
+ JSString* leftChild() const {
+ MOZ_ASSERT(isRope());
+ return d.s.u2.left;
+ }
+
+ JSString* rightChild() const {
+ MOZ_ASSERT(isRope());
+ return d.s.u3.right;
+ }
+
+ void traceChildren(JSTracer* trc);
+
+ static size_t offsetOfLeft() {
+ return offsetof(JSRope, d.s.u2.left);
+ }
+ static size_t offsetOfRight() {
+ return offsetof(JSRope, d.s.u3.right);
+ }
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSRope) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSLinearString : public JSString
+{
+ friend class JSString;
+ friend class js::AutoStableStringChars;
+
+ /* Vacuous and therefore unimplemented. */
+ JSLinearString* ensureLinear(js::ExclusiveContext* cx) = delete;
+ bool isLinear() const = delete;
+ JSLinearString& asLinear() const = delete;
+
+ protected:
+ /* Returns void pointer to latin1/twoByte chars, for finalizers. */
+ MOZ_ALWAYS_INLINE
+ void* nonInlineCharsRaw() const {
+ MOZ_ASSERT(!isInline());
+ static_assert(offsetof(JSLinearString, d.s.u2.nonInlineCharsTwoByte) ==
+ offsetof(JSLinearString, d.s.u2.nonInlineCharsLatin1),
+ "nonInlineCharsTwoByte and nonInlineCharsLatin1 must have same offset");
+ return (void*)d.s.u2.nonInlineCharsTwoByte;
+ }
+
+ MOZ_ALWAYS_INLINE const JS::Latin1Char* rawLatin1Chars() const;
+ MOZ_ALWAYS_INLINE const char16_t* rawTwoByteChars() const;
+
+ public:
+ template<typename CharT>
+ MOZ_ALWAYS_INLINE
+ const CharT* nonInlineChars(const JS::AutoCheckCannotGC& nogc) const;
+
+ MOZ_ALWAYS_INLINE
+ const JS::Latin1Char* nonInlineLatin1Chars(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(!isInline());
+ MOZ_ASSERT(hasLatin1Chars());
+ return d.s.u2.nonInlineCharsLatin1;
+ }
+
+ MOZ_ALWAYS_INLINE
+ const char16_t* nonInlineTwoByteChars(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(!isInline());
+ MOZ_ASSERT(hasTwoByteChars());
+ return d.s.u2.nonInlineCharsTwoByte;
+ }
+
+ template<typename CharT>
+ MOZ_ALWAYS_INLINE
+ const CharT* chars(const JS::AutoCheckCannotGC& nogc) const;
+
+ MOZ_ALWAYS_INLINE
+ const JS::Latin1Char* latin1Chars(const JS::AutoCheckCannotGC& nogc) const {
+ return rawLatin1Chars();
+ }
+
+ MOZ_ALWAYS_INLINE
+ const char16_t* twoByteChars(const JS::AutoCheckCannotGC& nogc) const {
+ return rawTwoByteChars();
+ }
+
+ mozilla::Range<const JS::Latin1Char> latin1Range(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(JSString::isLinear());
+ return mozilla::Range<const JS::Latin1Char>(latin1Chars(nogc), length());
+ }
+
+ mozilla::Range<const char16_t> twoByteRange(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(JSString::isLinear());
+ return mozilla::Range<const char16_t>(twoByteChars(nogc), length());
+ }
+
+ MOZ_ALWAYS_INLINE
+ char16_t latin1OrTwoByteChar(size_t index) const {
+ MOZ_ASSERT(JSString::isLinear());
+ MOZ_ASSERT(index < length());
+ JS::AutoCheckCannotGC nogc;
+ return hasLatin1Chars() ? latin1Chars(nogc)[index] : twoByteChars(nogc)[index];
+ }
+
+#ifdef DEBUG
+ void dumpRepresentationChars(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSLinearString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSDependentString : public JSLinearString
+{
+ friend class JSString;
+ JSFlatString* undepend(JSContext* cx);
+
+ template <typename CharT>
+ JSFlatString* undependInternal(JSContext* cx);
+
+ void init(js::ExclusiveContext* cx, JSLinearString* base, size_t start,
+ size_t length);
+
+ /* Vacuous and therefore unimplemented. */
+ bool isDependent() const = delete;
+ JSDependentString& asDependent() const = delete;
+
+ /* The offset of this string's chars in base->chars(). */
+ MOZ_ALWAYS_INLINE mozilla::Maybe<size_t> baseOffset() const {
+ MOZ_ASSERT(JSString::isDependent());
+ JS::AutoCheckCannotGC nogc;
+ if (MOZ_UNLIKELY(base()->isUndepended()))
+ return mozilla::Nothing();
+ size_t offset;
+ if (hasTwoByteChars())
+ offset = twoByteChars(nogc) - base()->twoByteChars(nogc);
+ else
+ offset = latin1Chars(nogc) - base()->latin1Chars(nogc);
+ MOZ_ASSERT(offset < base()->length());
+ return mozilla::Some(offset);
+ }
+
+ public:
+ static inline JSLinearString* new_(js::ExclusiveContext* cx, JSLinearString* base,
+ size_t start, size_t length);
+
+ inline static size_t offsetOfBase() {
+ return offsetof(JSDependentString, d.s.u3.base);
+ }
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSDependentString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSFlatString : public JSLinearString
+{
+ /* Vacuous and therefore unimplemented. */
+ JSFlatString* ensureFlat(JSContext* cx) = delete;
+ bool isFlat() const = delete;
+ JSFlatString& asFlat() const = delete;
+
+ template <typename CharT>
+ static bool isIndexSlow(const CharT* s, size_t length, uint32_t* indexp);
+
+ void init(const char16_t* chars, size_t length);
+ void init(const JS::Latin1Char* chars, size_t length);
+
+ public:
+ template <js::AllowGC allowGC, typename CharT>
+ static inline JSFlatString* new_(js::ExclusiveContext* cx,
+ const CharT* chars, size_t length);
+
+ /*
+ * Returns true if this string's characters store an unsigned 32-bit
+ * integer value, initializing *indexp to that value if so. (Thus if
+ * calling isIndex returns true, js::IndexToString(cx, *indexp) will be a
+ * string equal to this string.)
+ */
+ inline bool isIndex(uint32_t* indexp) const {
+ MOZ_ASSERT(JSString::isFlat());
+ JS::AutoCheckCannotGC nogc;
+ if (hasLatin1Chars()) {
+ const JS::Latin1Char* s = latin1Chars(nogc);
+ return JS7_ISDEC(*s) && isIndexSlow(s, length(), indexp);
+ }
+ const char16_t* s = twoByteChars(nogc);
+ return JS7_ISDEC(*s) && isIndexSlow(s, length(), indexp);
+ }
+
+ /*
+ * Returns a property name represented by this string, or null on failure.
+ * You must verify that this is not an index per isIndex before calling
+ * this method.
+ */
+ inline js::PropertyName* toPropertyName(JSContext* cx);
+
+ /*
+ * Once a JSFlatString sub-class has been added to the atom state, this
+ * operation changes the string to the JSAtom type, in place.
+ */
+ MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoAtom(js::HashNumber hash);
+ MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoPermanentAtom(js::HashNumber hash);
+
+ inline void finalize(js::FreeOp* fop);
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSFlatString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSExtensibleString : public JSFlatString
+{
+ /* Vacuous and therefore unimplemented. */
+ bool isExtensible() const = delete;
+ JSExtensibleString& asExtensible() const = delete;
+
+ public:
+ MOZ_ALWAYS_INLINE
+ size_t capacity() const {
+ MOZ_ASSERT(JSString::isExtensible());
+ return d.s.u3.capacity;
+ }
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSExtensibleString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSInlineString : public JSFlatString
+{
+ public:
+ MOZ_ALWAYS_INLINE
+ const JS::Latin1Char* latin1Chars(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(JSString::isInline());
+ MOZ_ASSERT(hasLatin1Chars());
+ return d.inlineStorageLatin1;
+ }
+
+ MOZ_ALWAYS_INLINE
+ const char16_t* twoByteChars(const JS::AutoCheckCannotGC& nogc) const {
+ MOZ_ASSERT(JSString::isInline());
+ MOZ_ASSERT(hasTwoByteChars());
+ return d.inlineStorageTwoByte;
+ }
+
+ template<typename CharT>
+ static bool lengthFits(size_t length);
+
+ static size_t offsetOfInlineStorage() {
+ return offsetof(JSInlineString, d.inlineStorageTwoByte);
+ }
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSInlineString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+/*
+ * On 32-bit platforms, JSThinInlineString can store 7 Latin1 characters or 3
+ * TwoByte characters (excluding null terminator) inline. On 64-bit platforms,
+ * these numbers are 15 and 7, respectively.
+ */
+class JSThinInlineString : public JSInlineString
+{
+ public:
+ static const size_t MAX_LENGTH_LATIN1 = NUM_INLINE_CHARS_LATIN1 - 1;
+ static const size_t MAX_LENGTH_TWO_BYTE = NUM_INLINE_CHARS_TWO_BYTE - 1;
+
+ template <js::AllowGC allowGC>
+ static inline JSThinInlineString* new_(js::ExclusiveContext* cx);
+
+ template <typename CharT>
+ inline CharT* init(size_t length);
+
+ template<typename CharT>
+ static bool lengthFits(size_t length);
+};
+
+static_assert(sizeof(JSThinInlineString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+/*
+ * On both 32-bit and 64-bit platforms, MAX_LENGTH_TWO_BYTE is 11 and
+ * MAX_LENGTH_LATIN1 is 23 (excluding null terminator). This is deliberate,
+ * in order to minimize potential performance differences between 32-bit and
+ * 64-bit platforms.
+ *
+ * There are still some differences due to NUM_INLINE_CHARS_* being different.
+ * E.g. TwoByte strings of length 4--7 will be JSFatInlineStrings on 32-bit
+ * platforms and JSThinInlineStrings on 64-bit platforms. But the more
+ * significant transition from inline strings to non-inline strings occurs at
+ * length 11 (for TwoByte strings) and 23 (Latin1 strings) on both 32-bit and
+ * 64-bit platforms.
+ */
+class JSFatInlineString : public JSInlineString
+{
+ static const size_t INLINE_EXTENSION_CHARS_LATIN1 = 24 - NUM_INLINE_CHARS_LATIN1;
+ static const size_t INLINE_EXTENSION_CHARS_TWO_BYTE = 12 - NUM_INLINE_CHARS_TWO_BYTE;
+
+ protected: /* to fool clang into not warning this is unused */
+ union {
+ char inlineStorageExtensionLatin1[INLINE_EXTENSION_CHARS_LATIN1];
+ char16_t inlineStorageExtensionTwoByte[INLINE_EXTENSION_CHARS_TWO_BYTE];
+ };
+
+ public:
+ template <js::AllowGC allowGC>
+ static inline JSFatInlineString* new_(js::ExclusiveContext* cx);
+
+ static const size_t MAX_LENGTH_LATIN1 = JSString::NUM_INLINE_CHARS_LATIN1 +
+ INLINE_EXTENSION_CHARS_LATIN1
+ -1 /* null terminator */;
+
+ static const size_t MAX_LENGTH_TWO_BYTE = JSString::NUM_INLINE_CHARS_TWO_BYTE +
+ INLINE_EXTENSION_CHARS_TWO_BYTE
+ -1 /* null terminator */;
+
+ template <typename CharT>
+ inline CharT* init(size_t length);
+
+ template<typename CharT>
+ static bool lengthFits(size_t length);
+
+ /* Only called by the GC for strings with the AllocKind::FAT_INLINE_STRING kind. */
+
+ MOZ_ALWAYS_INLINE void finalize(js::FreeOp* fop);
+};
+
+static_assert(sizeof(JSFatInlineString) % js::gc::CellSize == 0,
+ "fat inline strings shouldn't waste space up to the next cell "
+ "boundary");
+
+class JSExternalString : public JSLinearString
+{
+ void init(const char16_t* chars, size_t length, const JSStringFinalizer* fin);
+
+ /* Vacuous and therefore unimplemented. */
+ bool isExternal() const = delete;
+ JSExternalString& asExternal() const = delete;
+
+ public:
+ static inline JSExternalString* new_(JSContext* cx, const char16_t* chars, size_t length,
+ const JSStringFinalizer* fin);
+
+ const JSStringFinalizer* externalFinalizer() const {
+ MOZ_ASSERT(JSString::isExternal());
+ return d.s.u3.externalFinalizer;
+ }
+
+ /*
+ * External chars are never allocated inline or in the nursery, so we can
+ * safely expose this without requiring an AutoCheckCannotGC argument.
+ */
+ const char16_t* twoByteChars() const {
+ return rawTwoByteChars();
+ }
+
+ /* Only called by the GC for strings with the AllocKind::EXTERNAL_STRING kind. */
+
+ inline void finalize(js::FreeOp* fop);
+
+ JSFlatString* ensureFlat(JSContext* cx);
+
+#ifdef DEBUG
+ void dumpRepresentation(FILE* fp, int indent) const;
+#endif
+};
+
+static_assert(sizeof(JSExternalString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSUndependedString : public JSFlatString
+{
+ /*
+ * JSUndependedString is not explicitly used and is only present for
+ * consistency. See JSDependentString::undepend for how a JSDependentString
+ * gets morphed into a JSUndependedString.
+ */
+};
+
+static_assert(sizeof(JSUndependedString) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+class JSAtom : public JSFlatString
+{
+ /* Vacuous and therefore unimplemented. */
+ bool isAtom() const = delete;
+ JSAtom& asAtom() const = delete;
+
+ public:
+ /* Returns the PropertyName for this. isIndex() must be false. */
+ inline js::PropertyName* asPropertyName();
+
+ inline void finalize(js::FreeOp* fop);
+
+ MOZ_ALWAYS_INLINE
+ bool isPermanent() const {
+ return JSString::isPermanentAtom();
+ }
+
+ // Transform this atom into a permanent atom. This is only done during
+ // initialization of the runtime.
+ MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
+ d.u1.flags |= PERMANENT_ATOM_MASK;
+ }
+
+ inline js::HashNumber hash() const;
+ inline void initHash(js::HashNumber hash);
+
+#ifdef DEBUG
+ void dump(FILE* fp);
+ void dump();
+#endif
+};
+
+static_assert(sizeof(JSAtom) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+namespace js {
+
+class NormalAtom : public JSAtom
+{
+ protected: // Silence Clang unused-field warning.
+ HashNumber hash_;
+ uint32_t padding_; // Ensure the size is a multiple of gc::CellSize.
+
+ public:
+ HashNumber hash() const {
+ return hash_;
+ }
+ void initHash(HashNumber hash) {
+ hash_ = hash;
+ }
+};
+
+static_assert(sizeof(NormalAtom) == sizeof(JSString) + sizeof(uint64_t),
+ "NormalAtom must have size of a string + HashNumber, "
+ "aligned to gc::CellSize");
+
+class FatInlineAtom : public JSAtom
+{
+ protected: // Silence Clang unused-field warning.
+ char inlineStorage_[sizeof(JSFatInlineString) - sizeof(JSString)];
+ HashNumber hash_;
+ uint32_t padding_; // Ensure the size is a multiple of gc::CellSize.
+
+ public:
+ HashNumber hash() const {
+ return hash_;
+ }
+ void initHash(HashNumber hash) {
+ hash_ = hash;
+ }
+};
+
+static_assert(sizeof(FatInlineAtom) == sizeof(JSFatInlineString) + sizeof(uint64_t),
+ "FatInlineAtom must have size of a fat inline string + HashNumber, "
+ "aligned to gc::CellSize");
+
+} // namespace js
+
+inline js::HashNumber
+JSAtom::hash() const
+{
+ if (isFatInline())
+ return static_cast<const js::FatInlineAtom*>(this)->hash();
+ return static_cast<const js::NormalAtom*>(this)->hash();
+}
+
+inline void
+JSAtom::initHash(js::HashNumber hash)
+{
+ if (isFatInline())
+ return static_cast<js::FatInlineAtom*>(this)->initHash(hash);
+ return static_cast<js::NormalAtom*>(this)->initHash(hash);
+}
+
+MOZ_ALWAYS_INLINE JSAtom*
+JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash)
+{
+ d.u1.flags |= ATOM_BIT;
+ JSAtom* atom = &asAtom();
+ atom->initHash(hash);
+ return atom;
+}
+
+MOZ_ALWAYS_INLINE JSAtom*
+JSFlatString::morphAtomizedStringIntoPermanentAtom(js::HashNumber hash)
+{
+ d.u1.flags |= PERMANENT_ATOM_MASK;
+ JSAtom* atom = &asAtom();
+ atom->initHash(hash);
+ return atom;
+}
+
+namespace js {
+
+class StaticStrings
+{
+ private:
+ /* Bigger chars cannot be in a length-2 string. */
+ static const size_t SMALL_CHAR_LIMIT = 128U;
+ static const size_t NUM_SMALL_CHARS = 64U;
+
+ JSAtom* length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS];
+
+ public:
+ /* We keep these public for the JITs. */
+ static const size_t UNIT_STATIC_LIMIT = 256U;
+ JSAtom* unitStaticTable[UNIT_STATIC_LIMIT];
+
+ static const size_t INT_STATIC_LIMIT = 256U;
+ JSAtom* intStaticTable[INT_STATIC_LIMIT];
+
+ StaticStrings() {
+ mozilla::PodZero(this);
+ }
+
+ bool init(JSContext* cx);
+ void trace(JSTracer* trc);
+
+ static bool hasUint(uint32_t u) { return u < INT_STATIC_LIMIT; }
+
+ JSAtom* getUint(uint32_t u) {
+ MOZ_ASSERT(hasUint(u));
+ return intStaticTable[u];
+ }
+
+ static bool hasInt(int32_t i) {
+ return uint32_t(i) < INT_STATIC_LIMIT;
+ }
+
+ JSAtom* getInt(int32_t i) {
+ MOZ_ASSERT(hasInt(i));
+ return getUint(uint32_t(i));
+ }
+
+ static bool hasUnit(char16_t c) { return c < UNIT_STATIC_LIMIT; }
+
+ JSAtom* getUnit(char16_t c) {
+ MOZ_ASSERT(hasUnit(c));
+ return unitStaticTable[c];
+ }
+
+ /* May not return atom, returns null on (reported) failure. */
+ inline JSLinearString* getUnitStringForElement(JSContext* cx, JSString* str, size_t index);
+
+ template <typename CharT>
+ static bool isStatic(const CharT* chars, size_t len);
+ static bool isStatic(JSAtom* atom);
+
+ /* Return null if no static atom exists for the given (chars, length). */
+ template <typename CharT>
+ JSAtom* lookup(const CharT* chars, size_t length) {
+ switch (length) {
+ case 1: {
+ char16_t c = chars[0];
+ if (c < UNIT_STATIC_LIMIT)
+ return getUnit(c);
+ return nullptr;
+ }
+ case 2:
+ if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]))
+ return getLength2(chars[0], chars[1]);
+ return nullptr;
+ case 3:
+ /*
+ * Here we know that JSString::intStringTable covers only 256 (or at least
+ * not 1000 or more) chars. We rely on order here to resolve the unit vs.
+ * int string/length-2 string atom identity issue by giving priority to unit
+ * strings for "0" through "9" and length-2 strings for "10" through "99".
+ */
+ static_assert(INT_STATIC_LIMIT <= 999,
+ "static int strings assumed below to be at most "
+ "three digits");
+ if ('1' <= chars[0] && chars[0] <= '9' &&
+ '0' <= chars[1] && chars[1] <= '9' &&
+ '0' <= chars[2] && chars[2] <= '9') {
+ int i = (chars[0] - '0') * 100 +
+ (chars[1] - '0') * 10 +
+ (chars[2] - '0');
+
+ if (unsigned(i) < INT_STATIC_LIMIT)
+ return getInt(i);
+ }
+ return nullptr;
+ }
+
+ return nullptr;
+ }
+
+ private:
+ typedef uint8_t SmallChar;
+ static const SmallChar INVALID_SMALL_CHAR = -1;
+
+ static bool fitsInSmallChar(char16_t c) {
+ return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR;
+ }
+
+ static const SmallChar toSmallChar[];
+
+ JSAtom* getLength2(char16_t c1, char16_t c2);
+ JSAtom* getLength2(uint32_t u) {
+ MOZ_ASSERT(u < 100);
+ return getLength2('0' + u / 10, '0' + u % 10);
+ }
+};
+
+/*
+ * Represents an atomized string which does not contain an index (that is, an
+ * unsigned 32-bit value). Thus for any PropertyName propname,
+ * ToString(ToUint32(propname)) never equals propname.
+ *
+ * To more concretely illustrate the utility of PropertyName, consider that it
+ * is used to partition, in a type-safe manner, the ways to refer to a
+ * property, as follows:
+ *
+ * - uint32_t indexes,
+ * - PropertyName strings which don't encode uint32_t indexes, and
+ * - jsspecial special properties (non-ES5 properties like object-valued
+ * jsids, JSID_EMPTY, JSID_VOID, and maybe in the future Harmony-proposed
+ * private names).
+ */
+class PropertyName : public JSAtom
+{
+ private:
+ /* Vacuous and therefore unimplemented. */
+ PropertyName* asPropertyName() = delete;
+};
+
+static_assert(sizeof(PropertyName) == sizeof(JSString),
+ "string subclasses must be binary-compatible with JSString");
+
+static MOZ_ALWAYS_INLINE jsid
+NameToId(PropertyName* name)
+{
+ return NON_INTEGER_ATOM_TO_JSID(name);
+}
+
+using PropertyNameVector = JS::GCVector<PropertyName*>;
+
+template <typename CharT>
+void
+CopyChars(CharT* dest, const JSLinearString& str);
+
+static inline UniqueChars
+StringToNewUTF8CharsZ(ExclusiveContext* maybecx, JSString& str)
+{
+ JS::AutoCheckCannotGC nogc;
+
+ JSLinearString* linear = str.ensureLinear(maybecx);
+ if (!linear)
+ return nullptr;
+
+ return UniqueChars(linear->hasLatin1Chars()
+ ? JS::CharsToNewUTF8CharsZ(maybecx, linear->latin1Range(nogc)).c_str()
+ : JS::CharsToNewUTF8CharsZ(maybecx, linear->twoByteRange(nogc)).c_str());
+}
+
+/* GC-allocate a string descriptor for the given malloc-allocated chars. */
+template <js::AllowGC allowGC, typename CharT>
+extern JSFlatString*
+NewString(js::ExclusiveContext* cx, CharT* chars, size_t length);
+
+/* Like NewString, but doesn't try to deflate to Latin1. */
+template <js::AllowGC allowGC, typename CharT>
+extern JSFlatString*
+NewStringDontDeflate(js::ExclusiveContext* cx, CharT* chars, size_t length);
+
+extern JSLinearString*
+NewDependentString(JSContext* cx, JSString* base, size_t start, size_t length);
+
+/* Take ownership of an array of Latin1Chars. */
+extern JSFlatString*
+NewLatin1StringZ(js::ExclusiveContext* cx, UniqueChars chars);
+
+/* Copy a counted string and GC-allocate a descriptor for it. */
+template <js::AllowGC allowGC, typename CharT>
+extern JSFlatString*
+NewStringCopyN(js::ExclusiveContext* cx, const CharT* s, size_t n);
+
+template <js::AllowGC allowGC>
+inline JSFlatString*
+NewStringCopyN(ExclusiveContext* cx, const char* s, size_t n)
+{
+ return NewStringCopyN<allowGC>(cx, reinterpret_cast<const Latin1Char*>(s), n);
+}
+
+/* Like NewStringCopyN, but doesn't try to deflate to Latin1. */
+template <js::AllowGC allowGC, typename CharT>
+extern JSFlatString*
+NewStringCopyNDontDeflate(js::ExclusiveContext* cx, const CharT* s, size_t n);
+
+/* Copy a C string and GC-allocate a descriptor for it. */
+template <js::AllowGC allowGC>
+inline JSFlatString*
+NewStringCopyZ(js::ExclusiveContext* cx, const char16_t* s)
+{
+ return NewStringCopyN<allowGC>(cx, s, js_strlen(s));
+}
+
+template <js::AllowGC allowGC>
+inline JSFlatString*
+NewStringCopyZ(js::ExclusiveContext* cx, const char* s)
+{
+ return NewStringCopyN<allowGC>(cx, s, strlen(s));
+}
+
+template <js::AllowGC allowGC>
+extern JSFlatString*
+NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8);
+
+template <js::AllowGC allowGC>
+inline JSFlatString*
+NewStringCopyUTF8Z(JSContext* cx, const JS::ConstUTF8CharsZ utf8)
+{
+ return NewStringCopyUTF8N<allowGC>(cx, JS::UTF8Chars(utf8.c_str(), strlen(utf8.c_str())));
+}
+
+JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
+
+} /* namespace js */
+
+// Addon IDs are interned atoms which are never destroyed. This detail is
+// not exposed outside the API.
+class JSAddonId : public JSAtom
+{};
+
+MOZ_ALWAYS_INLINE bool
+JSString::getChar(js::ExclusiveContext* cx, size_t index, char16_t* code)
+{
+ MOZ_ASSERT(index < length());
+
+ /*
+ * Optimization for one level deep ropes.
+ * This is common for the following pattern:
+ *
+ * while() {
+ * text = text.substr(0, x) + "bla" + text.substr(x)
+ * test.charCodeAt(x + 1)
+ * }
+ */
+ JSString* str;
+ if (isRope()) {
+ JSRope* rope = &asRope();
+ if (uint32_t(index) < rope->leftChild()->length()) {
+ str = rope->leftChild();
+ } else {
+ str = rope->rightChild();
+ index -= rope->leftChild()->length();
+ }
+ } else {
+ str = this;
+ }
+
+ if (!str->ensureLinear(cx))
+ return false;
+
+ *code = str->asLinear().latin1OrTwoByteChar(index);
+ return true;
+}
+
+MOZ_ALWAYS_INLINE JSLinearString*
+JSString::ensureLinear(js::ExclusiveContext* cx)
+{
+ return isLinear()
+ ? &asLinear()
+ : asRope().flatten(cx);
+}
+
+inline JSLinearString*
+JSString::base() const
+{
+ MOZ_ASSERT(hasBase());
+ MOZ_ASSERT(!d.s.u3.base->isInline());
+ return d.s.u3.base;
+}
+
+template<>
+MOZ_ALWAYS_INLINE const char16_t*
+JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC& nogc) const
+{
+ return nonInlineTwoByteChars(nogc);
+}
+
+template<>
+MOZ_ALWAYS_INLINE const JS::Latin1Char*
+JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC& nogc) const
+{
+ return nonInlineLatin1Chars(nogc);
+}
+
+template<>
+MOZ_ALWAYS_INLINE const char16_t*
+JSLinearString::chars(const JS::AutoCheckCannotGC& nogc) const
+{
+ return rawTwoByteChars();
+}
+
+template<>
+MOZ_ALWAYS_INLINE const JS::Latin1Char*
+JSLinearString::chars(const JS::AutoCheckCannotGC& nogc) const
+{
+ return rawLatin1Chars();
+}
+
+template <>
+MOZ_ALWAYS_INLINE bool
+JSRope::copyChars<JS::Latin1Char>(js::ExclusiveContext* cx,
+ js::ScopedJSFreePtr<JS::Latin1Char>& out) const
+{
+ return copyLatin1Chars(cx, out);
+}
+
+template <>
+MOZ_ALWAYS_INLINE bool
+JSRope::copyChars<char16_t>(js::ExclusiveContext* cx, js::ScopedJSFreePtr<char16_t>& out) const
+{
+ return copyTwoByteChars(cx, out);
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSThinInlineString::lengthFits<JS::Latin1Char>(size_t length)
+{
+ return length <= MAX_LENGTH_LATIN1;
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSThinInlineString::lengthFits<char16_t>(size_t length)
+{
+ return length <= MAX_LENGTH_TWO_BYTE;
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSFatInlineString::lengthFits<JS::Latin1Char>(size_t length)
+{
+ static_assert((INLINE_EXTENSION_CHARS_LATIN1 * sizeof(char)) % js::gc::CellSize == 0,
+ "fat inline strings' Latin1 characters don't exactly "
+ "fill subsequent cells and thus are wasteful");
+ static_assert(MAX_LENGTH_LATIN1 + 1 ==
+ (sizeof(JSFatInlineString) -
+ offsetof(JSFatInlineString, d.inlineStorageLatin1)) / sizeof(char),
+ "MAX_LENGTH_LATIN1 must be one less than inline Latin1 "
+ "storage count");
+
+ return length <= MAX_LENGTH_LATIN1;
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSFatInlineString::lengthFits<char16_t>(size_t length)
+{
+ static_assert((INLINE_EXTENSION_CHARS_TWO_BYTE * sizeof(char16_t)) % js::gc::CellSize == 0,
+ "fat inline strings' char16_t characters don't exactly "
+ "fill subsequent cells and thus are wasteful");
+ static_assert(MAX_LENGTH_TWO_BYTE + 1 ==
+ (sizeof(JSFatInlineString) -
+ offsetof(JSFatInlineString, d.inlineStorageTwoByte)) / sizeof(char16_t),
+ "MAX_LENGTH_TWO_BYTE must be one less than inline "
+ "char16_t storage count");
+
+ return length <= MAX_LENGTH_TWO_BYTE;
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSInlineString::lengthFits<JS::Latin1Char>(size_t length)
+{
+ // If it fits in a fat inline string, it fits in any inline string.
+ return JSFatInlineString::lengthFits<JS::Latin1Char>(length);
+}
+
+template<>
+MOZ_ALWAYS_INLINE bool
+JSInlineString::lengthFits<char16_t>(size_t length)
+{
+ // If it fits in a fat inline string, it fits in any inline string.
+ return JSFatInlineString::lengthFits<char16_t>(length);
+}
+
+template<>
+MOZ_ALWAYS_INLINE void
+JSString::setNonInlineChars(const char16_t* chars)
+{
+ d.s.u2.nonInlineCharsTwoByte = chars;
+}
+
+template<>
+MOZ_ALWAYS_INLINE void
+JSString::setNonInlineChars(const JS::Latin1Char* chars)
+{
+ d.s.u2.nonInlineCharsLatin1 = chars;
+}
+
+MOZ_ALWAYS_INLINE const JS::Latin1Char*
+JSLinearString::rawLatin1Chars() const
+{
+ MOZ_ASSERT(JSString::isLinear());
+ MOZ_ASSERT(hasLatin1Chars());
+ return isInline() ? d.inlineStorageLatin1 : d.s.u2.nonInlineCharsLatin1;
+}
+
+MOZ_ALWAYS_INLINE const char16_t*
+JSLinearString::rawTwoByteChars() const
+{
+ MOZ_ASSERT(JSString::isLinear());
+ MOZ_ASSERT(hasTwoByteChars());
+ return isInline() ? d.inlineStorageTwoByte : d.s.u2.nonInlineCharsTwoByte;
+}
+
+inline js::PropertyName*
+JSAtom::asPropertyName()
+{
+#ifdef DEBUG
+ uint32_t dummy;
+ MOZ_ASSERT(!isIndex(&dummy));
+#endif
+ return static_cast<js::PropertyName*>(this);
+}
+
+#endif /* vm_String_h */
diff --git a/js/src/vm/StringBuffer.cpp b/js/src/vm/StringBuffer.cpp
new file mode 100644
index 000000000..fd8cdbbd5
--- /dev/null
+++ b/js/src/vm/StringBuffer.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/StringBuffer.h"
+
+#include "mozilla/Range.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/String-inl.h"
+
+using namespace js;
+
+template <typename CharT, class Buffer>
+static CharT*
+ExtractWellSized(ExclusiveContext* cx, Buffer& cb)
+{
+ size_t capacity = cb.capacity();
+ size_t length = cb.length();
+
+ CharT* buf = cb.extractOrCopyRawBuffer();
+ if (!buf)
+ return nullptr;
+
+ /* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
+ MOZ_ASSERT(capacity >= length);
+ if (length > Buffer::sMaxInlineStorage && capacity - length > length / 4) {
+ CharT* tmp = cx->zone()->pod_realloc<CharT>(buf, capacity, length + 1);
+ if (!tmp) {
+ js_free(buf);
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ buf = tmp;
+ }
+
+ return buf;
+}
+
+char16_t*
+StringBuffer::stealChars()
+{
+ if (isLatin1() && !inflateChars())
+ return nullptr;
+
+ return ExtractWellSized<char16_t>(cx, twoByteChars());
+}
+
+bool
+StringBuffer::inflateChars()
+{
+ MOZ_ASSERT(isLatin1());
+
+ TwoByteCharBuffer twoByte(cx);
+
+ /*
+ * Note: we don't use Vector::capacity() because it always returns a
+ * value >= sInlineCapacity. Since Latin1CharBuffer::sInlineCapacity >
+ * TwoByteCharBuffer::sInlineCapacitychars, we'd always malloc here.
+ */
+ size_t capacity = Max(reserved_, latin1Chars().length());
+ if (!twoByte.reserve(capacity))
+ return false;
+
+ twoByte.infallibleAppend(latin1Chars().begin(), latin1Chars().length());
+
+ cb.destroy();
+ cb.construct<TwoByteCharBuffer>(Move(twoByte));
+ return true;
+}
+
+template <typename CharT, class Buffer>
+static JSFlatString*
+FinishStringFlat(ExclusiveContext* cx, StringBuffer& sb, Buffer& cb)
+{
+ size_t len = sb.length();
+ if (!sb.append('\0'))
+ return nullptr;
+
+ ScopedJSFreePtr<CharT> buf(ExtractWellSized<CharT>(cx, cb));
+ if (!buf)
+ return nullptr;
+
+ JSFlatString* str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
+ if (!str)
+ return nullptr;
+
+ /*
+ * The allocation was made on a TempAllocPolicy, so account for the string
+ * data on the string's zone.
+ */
+ str->zone()->updateMallocCounter(sizeof(CharT) * len);
+
+ buf.forget();
+ return str;
+}
+
+JSFlatString*
+StringBuffer::finishString()
+{
+ size_t len = length();
+ if (len == 0)
+ return cx->names().empty;
+
+ if (!JSString::validateLength(cx, len))
+ return nullptr;
+
+ JS_STATIC_ASSERT(JSFatInlineString::MAX_LENGTH_TWO_BYTE < TwoByteCharBuffer::InlineLength);
+ JS_STATIC_ASSERT(JSFatInlineString::MAX_LENGTH_LATIN1 < Latin1CharBuffer::InlineLength);
+
+ if (isLatin1()) {
+ if (JSInlineString::lengthFits<Latin1Char>(len)) {
+ mozilla::Range<const Latin1Char> range(latin1Chars().begin(), len);
+ return NewInlineString<CanGC>(cx, range);
+ }
+ } else {
+ if (JSInlineString::lengthFits<char16_t>(len)) {
+ mozilla::Range<const char16_t> range(twoByteChars().begin(), len);
+ return NewInlineString<CanGC>(cx, range);
+ }
+ }
+
+ return isLatin1()
+ ? FinishStringFlat<Latin1Char>(cx, *this, latin1Chars())
+ : FinishStringFlat<char16_t>(cx, *this, twoByteChars());
+}
+
+JSAtom*
+StringBuffer::finishAtom()
+{
+ size_t len = length();
+ if (len == 0)
+ return cx->names().empty;
+
+ if (isLatin1()) {
+ JSAtom* atom = AtomizeChars(cx, latin1Chars().begin(), len);
+ latin1Chars().clear();
+ return atom;
+ }
+
+ JSAtom* atom = AtomizeChars(cx, twoByteChars().begin(), len);
+ twoByteChars().clear();
+ return atom;
+}
+
+bool
+js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
+{
+ RootedValue v(cx, arg);
+ if (!ToPrimitive(cx, JSTYPE_STRING, &v))
+ return false;
+
+ if (v.isString())
+ return sb.append(v.toString());
+ if (v.isNumber())
+ return NumberValueToStringBuffer(cx, v, sb);
+ if (v.isBoolean())
+ return BooleanToStringBuffer(v.toBoolean(), sb);
+ if (v.isNull())
+ return sb.append(cx->names().null);
+ if (v.isSymbol()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING);
+ return false;
+ }
+ MOZ_ASSERT(v.isUndefined());
+ return sb.append(cx->names().undefined);
+}
diff --git a/js/src/vm/StringBuffer.h b/js/src/vm/StringBuffer.h
new file mode 100644
index 000000000..19da43526
--- /dev/null
+++ b/js/src/vm/StringBuffer.h
@@ -0,0 +1,343 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_StringBuffer_h
+#define vm_StringBuffer_h
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MaybeOneOf.h"
+
+#include "jscntxt.h"
+
+#include "js/Vector.h"
+
+namespace js {
+
+/*
+ * String builder that eagerly checks for over-allocation past the maximum
+ * string length.
+ *
+ * Any operation which would exceed the maximum string length causes an
+ * exception report on the context and results in a failed return value.
+ *
+ * Well-sized extractions (which waste no more than 1/4 of their char
+ * buffer space) are guaranteed for strings built by this interface.
+ * See |extractWellSized|.
+ */
+class StringBuffer
+{
+ /*
+ * The Vector's buffer may be either stolen or copied, so we need to use
+ * TempAllocPolicy and account for the memory manually when stealing.
+ */
+ typedef Vector<Latin1Char, 64> Latin1CharBuffer;
+ typedef Vector<char16_t, 32> TwoByteCharBuffer;
+
+ ExclusiveContext* cx;
+
+ /*
+ * If Latin1 strings are enabled, cb starts out as a Latin1CharBuffer. When
+ * a TwoByte char is appended, inflateChars() constructs a TwoByteCharBuffer
+ * and copies the Latin1 chars.
+ */
+ mozilla::MaybeOneOf<Latin1CharBuffer, TwoByteCharBuffer> cb;
+
+#ifdef DEBUG
+ /*
+ * Make sure ensureTwoByteChars() is called before calling
+ * infallibleAppend(char16_t).
+ */
+ bool hasEnsuredTwoByteChars_;
+#endif
+
+ /* Number of reserve()'d chars, see inflateChars. */
+ size_t reserved_;
+
+ StringBuffer(const StringBuffer& other) = delete;
+ void operator=(const StringBuffer& other) = delete;
+
+ MOZ_ALWAYS_INLINE bool isLatin1() const { return cb.constructed<Latin1CharBuffer>(); }
+ MOZ_ALWAYS_INLINE bool isTwoByte() const { return !isLatin1(); }
+
+ MOZ_ALWAYS_INLINE Latin1CharBuffer& latin1Chars() { return cb.ref<Latin1CharBuffer>(); }
+ MOZ_ALWAYS_INLINE TwoByteCharBuffer& twoByteChars() { return cb.ref<TwoByteCharBuffer>(); }
+
+ MOZ_ALWAYS_INLINE const Latin1CharBuffer& latin1Chars() const {
+ return cb.ref<Latin1CharBuffer>();
+ }
+ MOZ_ALWAYS_INLINE const TwoByteCharBuffer& twoByteChars() const {
+ return cb.ref<TwoByteCharBuffer>();
+ }
+
+ MOZ_MUST_USE bool inflateChars();
+
+ public:
+ explicit StringBuffer(ExclusiveContext* cx)
+ : cx(cx)
+#ifdef DEBUG
+ , hasEnsuredTwoByteChars_(false)
+#endif
+ , reserved_(0)
+ {
+ cb.construct<Latin1CharBuffer>(cx);
+ }
+
+ void clear() {
+ if (isLatin1())
+ latin1Chars().clear();
+ else
+ twoByteChars().clear();
+ }
+ MOZ_MUST_USE bool reserve(size_t len) {
+ if (len > reserved_)
+ reserved_ = len;
+ return isLatin1() ? latin1Chars().reserve(len) : twoByteChars().reserve(len);
+ }
+ MOZ_MUST_USE bool resize(size_t len) {
+ return isLatin1() ? latin1Chars().resize(len) : twoByteChars().resize(len);
+ }
+ bool empty() const {
+ return isLatin1() ? latin1Chars().empty() : twoByteChars().empty();
+ }
+ size_t length() const {
+ return isLatin1() ? latin1Chars().length() : twoByteChars().length();
+ }
+ char16_t getChar(size_t idx) const {
+ return isLatin1() ? latin1Chars()[idx] : twoByteChars()[idx];
+ }
+
+ MOZ_MUST_USE bool ensureTwoByteChars() {
+ if (isLatin1() && !inflateChars())
+ return false;
+
+#ifdef DEBUG
+ hasEnsuredTwoByteChars_ = true;
+#endif
+ return true;
+ }
+
+ MOZ_MUST_USE bool append(const char16_t c) {
+ if (isLatin1()) {
+ if (c <= JSString::MAX_LATIN1_CHAR)
+ return latin1Chars().append(Latin1Char(c));
+ if (!inflateChars())
+ return false;
+ }
+ return twoByteChars().append(c);
+ }
+ MOZ_MUST_USE bool append(Latin1Char c) {
+ return isLatin1() ? latin1Chars().append(c) : twoByteChars().append(c);
+ }
+ MOZ_MUST_USE bool append(char c) {
+ return append(Latin1Char(c));
+ }
+
+ inline MOZ_MUST_USE bool append(const char16_t* begin, const char16_t* end);
+
+ MOZ_MUST_USE bool append(const char16_t* chars, size_t len) {
+ return append(chars, chars + len);
+ }
+
+ MOZ_MUST_USE bool append(const Latin1Char* begin, const Latin1Char* end) {
+ return isLatin1() ? latin1Chars().append(begin, end) : twoByteChars().append(begin, end);
+ }
+ MOZ_MUST_USE bool append(const Latin1Char* chars, size_t len) {
+ return append(chars, chars + len);
+ }
+
+ MOZ_MUST_USE bool append(const JS::ConstCharPtr chars, size_t len) {
+ return append(chars.get(), chars.get() + len);
+ }
+ MOZ_MUST_USE bool appendN(Latin1Char c, size_t n) {
+ return isLatin1() ? latin1Chars().appendN(c, n) : twoByteChars().appendN(c, n);
+ }
+
+ inline MOZ_MUST_USE bool append(JSString* str);
+ inline MOZ_MUST_USE bool append(JSLinearString* str);
+ inline MOZ_MUST_USE bool appendSubstring(JSString* base, size_t off, size_t len);
+ inline MOZ_MUST_USE bool appendSubstring(JSLinearString* base, size_t off, size_t len);
+
+ MOZ_MUST_USE bool append(const char* chars, size_t len) {
+ return append(reinterpret_cast<const Latin1Char*>(chars), len);
+ }
+
+ template <size_t ArrayLength>
+ MOZ_MUST_USE bool append(const char (&array)[ArrayLength]) {
+ return append(array, ArrayLength - 1); /* No trailing '\0'. */
+ }
+
+ /* Infallible variants usable when the corresponding space is reserved. */
+ void infallibleAppend(Latin1Char c) {
+ if (isLatin1())
+ latin1Chars().infallibleAppend(c);
+ else
+ twoByteChars().infallibleAppend(c);
+ }
+ void infallibleAppend(char c) {
+ infallibleAppend(Latin1Char(c));
+ }
+ void infallibleAppend(const Latin1Char* chars, size_t len) {
+ if (isLatin1())
+ latin1Chars().infallibleAppend(chars, len);
+ else
+ twoByteChars().infallibleAppend(chars, len);
+ }
+ void infallibleAppend(const char* chars, size_t len) {
+ infallibleAppend(reinterpret_cast<const Latin1Char*>(chars), len);
+ }
+
+ void infallibleAppendSubstring(JSLinearString* base, size_t off, size_t len);
+
+ /*
+ * Because inflation is fallible, these methods should only be used after
+ * calling ensureTwoByteChars().
+ */
+ void infallibleAppend(const char16_t* chars, size_t len) {
+ MOZ_ASSERT(hasEnsuredTwoByteChars_);
+ twoByteChars().infallibleAppend(chars, len);
+ }
+ void infallibleAppend(char16_t c) {
+ MOZ_ASSERT(hasEnsuredTwoByteChars_);
+ twoByteChars().infallibleAppend(c);
+ }
+
+ bool isUnderlyingBufferLatin1() const { return isLatin1(); }
+
+ char16_t* rawTwoByteBegin() { return twoByteChars().begin(); }
+ char16_t* rawTwoByteEnd() { return twoByteChars().end(); }
+ const char16_t* rawTwoByteBegin() const { return twoByteChars().begin(); }
+ const char16_t* rawTwoByteEnd() const { return twoByteChars().end(); }
+
+ Latin1Char* rawLatin1Begin() { return latin1Chars().begin(); }
+ Latin1Char* rawLatin1End() { return latin1Chars().end(); }
+ const Latin1Char* rawLatin1Begin() const { return latin1Chars().begin(); }
+ const Latin1Char* rawLatin1End() const { return latin1Chars().end(); }
+
+ /*
+ * Creates a string from the characters in this buffer, then (regardless
+ * whether string creation succeeded or failed) empties the buffer.
+ */
+ JSFlatString* finishString();
+
+ /* Identical to finishString() except that an atom is created. */
+ JSAtom* finishAtom();
+
+ /*
+ * Creates a raw string from the characters in this buffer. The string is
+ * exactly the characters in this buffer (inflated to TwoByte), it is *not*
+ * null-terminated unless the last appended character was '\0'.
+ */
+ char16_t* stealChars();
+};
+
+inline bool
+StringBuffer::append(const char16_t* begin, const char16_t* end)
+{
+ MOZ_ASSERT(begin <= end);
+ if (isLatin1()) {
+ while (true) {
+ if (begin >= end)
+ return true;
+ if (*begin > JSString::MAX_LATIN1_CHAR)
+ break;
+ if (!latin1Chars().append(*begin))
+ return false;
+ ++begin;
+ }
+ if (!inflateChars())
+ return false;
+ }
+ return twoByteChars().append(begin, end);
+}
+
+inline bool
+StringBuffer::append(JSLinearString* str)
+{
+ JS::AutoCheckCannotGC nogc;
+ if (isLatin1()) {
+ if (str->hasLatin1Chars())
+ return latin1Chars().append(str->latin1Chars(nogc), str->length());
+ if (!inflateChars())
+ return false;
+ }
+ return str->hasLatin1Chars()
+ ? twoByteChars().append(str->latin1Chars(nogc), str->length())
+ : twoByteChars().append(str->twoByteChars(nogc), str->length());
+}
+
+inline void
+StringBuffer::infallibleAppendSubstring(JSLinearString* base, size_t off, size_t len)
+{
+ MOZ_ASSERT(off + len <= base->length());
+ MOZ_ASSERT_IF(base->hasTwoByteChars(), isTwoByte());
+
+ JS::AutoCheckCannotGC nogc;
+ if (base->hasLatin1Chars())
+ infallibleAppend(base->latin1Chars(nogc) + off, len);
+ else
+ infallibleAppend(base->twoByteChars(nogc) + off, len);
+}
+
+inline bool
+StringBuffer::appendSubstring(JSLinearString* base, size_t off, size_t len)
+{
+ MOZ_ASSERT(off + len <= base->length());
+
+ JS::AutoCheckCannotGC nogc;
+ if (isLatin1()) {
+ if (base->hasLatin1Chars())
+ return latin1Chars().append(base->latin1Chars(nogc) + off, len);
+ if (!inflateChars())
+ return false;
+ }
+ return base->hasLatin1Chars()
+ ? twoByteChars().append(base->latin1Chars(nogc) + off, len)
+ : twoByteChars().append(base->twoByteChars(nogc) + off, len);
+}
+
+inline bool
+StringBuffer::appendSubstring(JSString* base, size_t off, size_t len)
+{
+ JSLinearString* linear = base->ensureLinear(cx);
+ if (!linear)
+ return false;
+
+ return appendSubstring(linear, off, len);
+}
+
+inline bool
+StringBuffer::append(JSString* str)
+{
+ JSLinearString* linear = str->ensureLinear(cx);
+ if (!linear)
+ return false;
+
+ return append(linear);
+}
+
+/* ES5 9.8 ToString, appending the result to the string buffer. */
+extern bool
+ValueToStringBufferSlow(JSContext* cx, const Value& v, StringBuffer& sb);
+
+inline bool
+ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb)
+{
+ if (v.isString())
+ return sb.append(v.toString());
+
+ return ValueToStringBufferSlow(cx, v, sb);
+}
+
+/* ES5 9.8 ToString for booleans, appending the result to the string buffer. */
+inline bool
+BooleanToStringBuffer(bool b, StringBuffer& sb)
+{
+ return b ? sb.append("true") : sb.append("false");
+}
+
+} /* namespace js */
+
+#endif /* vm_StringBuffer_h */
diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h
new file mode 100644
index 000000000..5fc1656f6
--- /dev/null
+++ b/js/src/vm/StringObject-inl.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_StringObject_inl_h
+#define vm_StringObject_inl_h
+
+#include "vm/StringObject.h"
+
+#include "jsobjinlines.h"
+
+#include "vm/Shape-inl.h"
+
+namespace js {
+
+inline bool
+StringObject::init(JSContext* cx, HandleString str)
+{
+ MOZ_ASSERT(numFixedSlots() == 2);
+
+ Rooted<StringObject*> self(cx, this);
+
+ if (!EmptyShape::ensureInitialCustomShape<StringObject>(cx, self))
+ return false;
+
+ MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT);
+
+ self->setStringThis(str);
+
+ return true;
+}
+
+inline StringObject*
+StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind)
+{
+ JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+ if (!obj)
+ return nullptr;
+ Rooted<StringObject*> strobj(cx, &obj->as<StringObject>());
+ if (!strobj->init(cx, str))
+ return nullptr;
+ return strobj;
+}
+
+} // namespace js
+
+#endif /* vm_StringObject_inl_h */
diff --git a/js/src/vm/StringObject.h b/js/src/vm/StringObject.h
new file mode 100644
index 000000000..119e3d9fa
--- /dev/null
+++ b/js/src/vm/StringObject.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_StringObject_h
+#define vm_StringObject_h
+
+#include "jsobj.h"
+#include "jsstr.h"
+
+#include "vm/Shape.h"
+
+namespace js {
+
+class StringObject : public NativeObject
+{
+ static const unsigned PRIMITIVE_VALUE_SLOT = 0;
+ static const unsigned LENGTH_SLOT = 1;
+
+ public:
+ static const unsigned RESERVED_SLOTS = 2;
+
+ static const Class class_;
+
+ /*
+ * Creates a new String object boxing the given string. The object's
+ * [[Prototype]] is determined from context.
+ */
+ static inline StringObject* create(JSContext* cx, HandleString str,
+ HandleObject proto = nullptr,
+ NewObjectKind newKind = GenericObject);
+
+ /*
+ * Compute the initial shape to associate with fresh String objects, which
+ * encodes the initial length property. Return the shape after changing
+ * |obj|'s last property to it.
+ */
+ static Shape*
+ assignInitialShape(ExclusiveContext* cx, Handle<StringObject*> obj);
+
+ JSString* unbox() const {
+ return getFixedSlot(PRIMITIVE_VALUE_SLOT).toString();
+ }
+
+ inline size_t length() const {
+ return size_t(getFixedSlot(LENGTH_SLOT).toInt32());
+ }
+
+ static size_t offsetOfPrimitiveValue() {
+ return getFixedSlotOffset(PRIMITIVE_VALUE_SLOT);
+ }
+ static size_t offsetOfLength() {
+ return getFixedSlotOffset(LENGTH_SLOT);
+ }
+
+ private:
+ inline bool init(JSContext* cx, HandleString str);
+
+ void setStringThis(JSString* str) {
+ MOZ_ASSERT(getReservedSlot(PRIMITIVE_VALUE_SLOT).isUndefined());
+ setFixedSlot(PRIMITIVE_VALUE_SLOT, StringValue(str));
+ setFixedSlot(LENGTH_SLOT, Int32Value(int32_t(str->length())));
+ }
+
+ /* For access to init, as String.prototype is special. */
+ friend JSObject*
+ js::InitStringClass(JSContext* cx, HandleObject global);
+};
+
+} // namespace js
+
+#endif /* vm_StringObject_h */
diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
new file mode 100644
index 000000000..4b01cda85
--- /dev/null
+++ b/js/src/vm/StructuredClone.cpp
@@ -0,0 +1,2785 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This file implements the structured clone algorithm of
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#safe-passing-of-structured-data
+ *
+ * The implementation differs slightly in that it uses an explicit stack, and
+ * the "memory" maps source objects to sequential integer indexes rather than
+ * directly pointing to destination objects. As a result, the order in which
+ * things are added to the memory must exactly match the order in which they
+ * are placed into 'allObjs', an analogous array of back-referenceable
+ * destination objects constructed while reading.
+ *
+ * For the most part, this is easy: simply add objects to the memory when first
+ * encountering them. But reading in a typed array requires an ArrayBuffer for
+ * construction, so objects cannot just be added to 'allObjs' in the order they
+ * are created. If they were, ArrayBuffers would come before typed arrays when
+ * in fact the typed array was added to 'memory' first.
+ *
+ * So during writing, we add objects to the memory when first encountering
+ * them. When reading a typed array, a placeholder is pushed onto allObjs until
+ * the ArrayBuffer has been read, then it is updated with the actual typed
+ * array object.
+ */
+
+#include "js/StructuredClone.h"
+
+#include "mozilla/CheckedInt.h"
+#include "mozilla/EndianUtils.h"
+#include "mozilla/FloatingPoint.h"
+
+#include <algorithm>
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsdate.h"
+#include "jswrapper.h"
+
+#include "builtin/MapObject.h"
+#include "js/Date.h"
+#include "js/GCHashTable.h"
+#include "vm/SavedFrame.h"
+#include "vm/SharedArrayObject.h"
+#include "vm/TypedArrayObject.h"
+#include "vm/WrapperObject.h"
+
+#include "jscntxtinlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+
+using mozilla::BitwiseCast;
+using mozilla::IsNaN;
+using mozilla::LittleEndian;
+using mozilla::NativeEndian;
+using mozilla::NumbersAreIdentical;
+using JS::CanonicalizeNaN;
+
+// When you make updates here, make sure you consider whether you need to bump the
+// value of JS_STRUCTURED_CLONE_VERSION in js/public/StructuredClone.h. You will
+// likely need to increment the version if anything at all changes in the serialization
+// format.
+//
+// Note that SCTAG_END_OF_KEYS is written into the serialized form and should have
+// a stable ID, it need not be at the end of the list and should not be used for
+// sizing data structures.
+
+enum StructuredDataType : uint32_t {
+ /* Structured data types provided by the engine */
+ SCTAG_FLOAT_MAX = 0xFFF00000,
+ SCTAG_HEADER = 0xFFF10000,
+ SCTAG_NULL = 0xFFFF0000,
+ SCTAG_UNDEFINED,
+ SCTAG_BOOLEAN,
+ SCTAG_INT32,
+ SCTAG_STRING,
+ SCTAG_DATE_OBJECT,
+ SCTAG_REGEXP_OBJECT,
+ SCTAG_ARRAY_OBJECT,
+ SCTAG_OBJECT_OBJECT,
+ SCTAG_ARRAY_BUFFER_OBJECT,
+ SCTAG_BOOLEAN_OBJECT,
+ SCTAG_STRING_OBJECT,
+ SCTAG_NUMBER_OBJECT,
+ SCTAG_BACK_REFERENCE_OBJECT,
+ SCTAG_DO_NOT_USE_1, // Required for backwards compatibility
+ SCTAG_DO_NOT_USE_2, // Required for backwards compatibility
+ SCTAG_TYPED_ARRAY_OBJECT,
+ SCTAG_MAP_OBJECT,
+ SCTAG_SET_OBJECT,
+ SCTAG_END_OF_KEYS,
+ SCTAG_DO_NOT_USE_3, // Required for backwards compatibility
+ SCTAG_DATA_VIEW_OBJECT,
+ SCTAG_SAVED_FRAME_OBJECT,
+
+ // No new tags before principals.
+ SCTAG_JSPRINCIPALS,
+ SCTAG_NULL_JSPRINCIPALS,
+ SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM,
+ SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM,
+
+ SCTAG_SHARED_ARRAY_BUFFER_OBJECT,
+
+ SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100,
+ SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8,
+ SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8,
+ SCTAG_TYPED_ARRAY_V1_INT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int16,
+ SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint16,
+ SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int32,
+ SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint32,
+ SCTAG_TYPED_ARRAY_V1_FLOAT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float32,
+ SCTAG_TYPED_ARRAY_V1_FLOAT64 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float64,
+ SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8Clamped,
+ SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::MaxTypedArrayViewType - 1,
+
+ /*
+ * Define a separate range of numbers for Transferable-only tags, since
+ * they are not used for persistent clone buffers and therefore do not
+ * require bumping JS_STRUCTURED_CLONE_VERSION.
+ */
+ SCTAG_TRANSFER_MAP_HEADER = 0xFFFF0200,
+ SCTAG_TRANSFER_MAP_PENDING_ENTRY,
+ SCTAG_TRANSFER_MAP_ARRAY_BUFFER,
+ SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER,
+ SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES,
+
+ SCTAG_END_OF_BUILTIN_TYPES
+};
+
+/*
+ * Format of transfer map:
+ * <SCTAG_TRANSFER_MAP_HEADER, TransferableMapHeader(UNREAD|TRANSFERRED)>
+ * numTransferables (64 bits)
+ * array of:
+ * <SCTAG_TRANSFER_MAP_*, TransferableOwnership>
+ * pointer (64 bits)
+ * extraData (64 bits), eg byte length for ArrayBuffers
+ */
+
+// Data associated with an SCTAG_TRANSFER_MAP_HEADER that tells whether the
+// contents have been read out yet or not.
+enum TransferableMapHeader {
+ SCTAG_TM_UNREAD = 0,
+ SCTAG_TM_TRANSFERRED
+};
+
+static inline uint64_t
+PairToUInt64(uint32_t tag, uint32_t data)
+{
+ return uint64_t(data) | (uint64_t(tag) << 32);
+}
+
+namespace js {
+
+template<typename T, typename AllocPolicy>
+struct BufferIterator {
+ typedef mozilla::BufferList<AllocPolicy> BufferList;
+
+ explicit BufferIterator(BufferList& buffer)
+ : mBuffer(buffer)
+ , mIter(buffer.Iter())
+ {
+ JS_STATIC_ASSERT(8 % sizeof(T) == 0);
+ }
+
+ BufferIterator(const BufferIterator& other)
+ : mBuffer(other.mBuffer)
+ , mIter(other.mIter)
+ {
+ }
+
+ BufferIterator& operator=(const BufferIterator& other)
+ {
+ MOZ_ASSERT(&mBuffer == &other.mBuffer);
+ mIter = other.mIter;
+ return *this;
+ }
+
+ BufferIterator operator++(int) {
+ BufferIterator ret = *this;
+ if (!mIter.AdvanceAcrossSegments(mBuffer, sizeof(T))) {
+ MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
+ }
+ return ret;
+ }
+
+ BufferIterator& operator+=(size_t size) {
+ if (!mIter.AdvanceAcrossSegments(mBuffer, size)) {
+ MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
+ }
+ return *this;
+ }
+
+ size_t operator-(const BufferIterator& other) {
+ MOZ_ASSERT(&mBuffer == &other.mBuffer);
+ return mBuffer.RangeLength(other.mIter, mIter);
+ }
+
+ void next() {
+ if (!mIter.AdvanceAcrossSegments(mBuffer, sizeof(T))) {
+ MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
+ }
+ }
+
+ bool done() const {
+ return mIter.Done();
+ }
+
+ bool readBytes(char* outData, size_t size) {
+ return mBuffer.ReadBytes(mIter, outData, size);
+ }
+
+ void write(const T& data) {
+ MOZ_ASSERT(mIter.HasRoomFor(sizeof(T)));
+ *reinterpret_cast<T*>(mIter.Data()) = data;
+ }
+
+ T peek() const {
+ MOZ_ASSERT(mIter.HasRoomFor(sizeof(T)));
+ return *reinterpret_cast<T*>(mIter.Data());
+ }
+
+ bool canPeek() const {
+ return mIter.HasRoomFor(sizeof(T));
+ }
+
+ BufferList& mBuffer;
+ typename BufferList::IterImpl mIter;
+};
+
+struct SCOutput {
+ public:
+ using Iter = BufferIterator<uint64_t, TempAllocPolicy>;
+
+ explicit SCOutput(JSContext* cx);
+
+ JSContext* context() const { return cx; }
+
+ bool write(uint64_t u);
+ bool writePair(uint32_t tag, uint32_t data);
+ bool writeDouble(double d);
+ bool writeBytes(const void* p, size_t nbytes);
+ bool writeChars(const Latin1Char* p, size_t nchars);
+ bool writeChars(const char16_t* p, size_t nchars);
+ bool writePtr(const void*);
+
+ template <class T>
+ bool writeArray(const T* p, size_t nbytes);
+
+ bool extractBuffer(JSStructuredCloneData* data);
+ void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure);
+
+ uint64_t tell() const { return buf.Size(); }
+ uint64_t count() const { return buf.Size() / sizeof(uint64_t); }
+ Iter iter() {
+ return BufferIterator<uint64_t, TempAllocPolicy>(buf);
+ }
+
+ size_t offset(Iter dest) {
+ return dest - iter();
+ }
+
+ private:
+ JSContext* cx;
+ mozilla::BufferList<TempAllocPolicy> buf;
+};
+
+class SCInput {
+ typedef js::BufferIterator<uint64_t, SystemAllocPolicy> BufferIterator;
+
+ public:
+ SCInput(JSContext* cx, JSStructuredCloneData& data);
+
+ JSContext* context() const { return cx; }
+
+ static void getPtr(uint64_t data, void** ptr);
+ static void getPair(uint64_t data, uint32_t* tagp, uint32_t* datap);
+
+ bool read(uint64_t* p);
+ bool readNativeEndian(uint64_t* p);
+ bool readPair(uint32_t* tagp, uint32_t* datap);
+ bool readDouble(double* p);
+ bool readBytes(void* p, size_t nbytes);
+ bool readChars(Latin1Char* p, size_t nchars);
+ bool readChars(char16_t* p, size_t nchars);
+ bool readPtr(void**);
+
+ bool get(uint64_t* p);
+ bool getPair(uint32_t* tagp, uint32_t* datap);
+
+ const BufferIterator& tell() const { return point; }
+ void seekTo(const BufferIterator& pos) { point = pos; }
+ void seekBy(size_t pos) { point += pos; }
+
+ template <class T>
+ bool readArray(T* p, size_t nelems);
+
+ bool reportTruncated() {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "truncated");
+ return false;
+ }
+
+ private:
+ void staticAssertions() {
+ JS_STATIC_ASSERT(sizeof(char16_t) == 2);
+ JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
+ }
+
+ JSContext* cx;
+ BufferIterator point;
+};
+
+} /* namespace js */
+
+struct JSStructuredCloneReader {
+ public:
+ explicit JSStructuredCloneReader(SCInput& in, JS::StructuredCloneScope scope,
+ const JSStructuredCloneCallbacks* cb,
+ void* cbClosure)
+ : in(in), allowedScope(scope), objs(in.context()), allObjs(in.context()),
+ callbacks(cb), closure(cbClosure) { }
+
+ SCInput& input() { return in; }
+ bool read(MutableHandleValue vp);
+
+ private:
+ JSContext* context() { return in.context(); }
+
+ bool readHeader();
+ bool readTransferMap();
+
+ template <typename CharT>
+ JSString* readStringImpl(uint32_t nchars);
+ JSString* readString(uint32_t data);
+
+ bool checkDouble(double d);
+ bool readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp,
+ bool v1Read = false);
+ bool readDataView(uint32_t byteLength, MutableHandleValue vp);
+ bool readArrayBuffer(uint32_t nbytes, MutableHandleValue vp);
+ bool readSharedArrayBuffer(uint32_t nbytes, MutableHandleValue vp);
+ bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp);
+ JSObject* readSavedFrame(uint32_t principalsTag);
+ bool startRead(MutableHandleValue vp);
+
+ SCInput& in;
+
+ // The widest scope that the caller will accept, where
+ // SameProcessSameThread is the widest (it can store anything it wants) and
+ // DifferentProcess is the narrowest (it cannot contain pointers and must
+ // be valid cross-process.)
+ JS::StructuredCloneScope allowedScope;
+
+ // The scope the buffer was generated for (what sort of buffer it is.) The
+ // scope is not just a permissions thing; it also affects the storage
+ // format (eg a Transferred ArrayBuffer can be stored as a pointer for
+ // SameProcessSameThread but must have its contents in the clone buffer for
+ // DifferentProcess.)
+ JS::StructuredCloneScope storedScope;
+
+ // Stack of objects with properties remaining to be read.
+ AutoValueVector objs;
+
+ // Stack of all objects read during this deserialization
+ AutoValueVector allObjs;
+
+ // The user defined callbacks that will be used for cloning.
+ const JSStructuredCloneCallbacks* callbacks;
+
+ // Any value passed to JS_ReadStructuredClone.
+ void* closure;
+
+ friend bool JS_ReadTypedArray(JSStructuredCloneReader* r, MutableHandleValue vp);
+};
+
+struct JSStructuredCloneWriter {
+ public:
+ explicit JSStructuredCloneWriter(JSContext* cx,
+ JS::StructuredCloneScope scope,
+ JS::CloneDataPolicy cloneDataPolicy,
+ const JSStructuredCloneCallbacks* cb,
+ void* cbClosure,
+ const Value& tVal)
+ : out(cx), scope(scope), objs(out.context()),
+ counts(out.context()), entries(out.context()),
+ memory(out.context()), callbacks(cb),
+ closure(cbClosure), transferable(out.context(), tVal),
+ transferableObjects(out.context(), GCHashSet<JSObject*>(cx)),
+ cloneDataPolicy(cloneDataPolicy)
+ {}
+
+ ~JSStructuredCloneWriter();
+
+ bool init() {
+ if (!memory.init()) {
+ ReportOutOfMemory(context());
+ return false;
+ }
+ return parseTransferable() && writeHeader() && writeTransferMap();
+ }
+
+ bool write(HandleValue v);
+
+ SCOutput& output() { return out; }
+
+ bool extractBuffer(JSStructuredCloneData* data) {
+ bool success = out.extractBuffer(data);
+ if (success) {
+ data->setOptionalCallbacks(callbacks, closure,
+ OwnTransferablePolicy::OwnsTransferablesIfAny);
+ }
+ return success;
+ }
+
+ JS::StructuredCloneScope cloneScope() const { return scope; }
+
+ private:
+ JSStructuredCloneWriter() = delete;
+ JSStructuredCloneWriter(const JSStructuredCloneWriter&) = delete;
+
+ JSContext* context() { return out.context(); }
+
+ bool writeHeader();
+ bool writeTransferMap();
+
+ bool writeString(uint32_t tag, JSString* str);
+ bool writeArrayBuffer(HandleObject obj);
+ bool writeTypedArray(HandleObject obj);
+ bool writeDataView(HandleObject obj);
+ bool writeSharedArrayBuffer(HandleObject obj);
+ bool startObject(HandleObject obj, bool* backref);
+ bool startWrite(HandleValue v);
+ bool traverseObject(HandleObject obj);
+ bool traverseMap(HandleObject obj);
+ bool traverseSet(HandleObject obj);
+ bool traverseSavedFrame(HandleObject obj);
+
+ bool reportDataCloneError(uint32_t errorId);
+
+ bool parseTransferable();
+ bool transferOwnership();
+
+ inline void checkStack();
+
+ SCOutput out;
+
+ // The (address space, thread) scope within which this clone is valid.
+ JS::StructuredCloneScope scope;
+
+ // Vector of objects with properties remaining to be written.
+ //
+ // NB: These can span multiple compartments, so the compartment must be
+ // entered before any manipulation is performed.
+ AutoValueVector objs;
+
+ // counts[i] is the number of entries of objs[i] remaining to be written.
+ // counts.length() == objs.length() and sum(counts) == entries.length().
+ Vector<size_t> counts;
+
+ // For JSObject: Property IDs as value
+ // For Map: Key followed by value
+ // For Set: Key
+ // For SavedFrame: parent SavedFrame
+ AutoValueVector entries;
+
+ // The "memory" list described in the HTML5 internal structured cloning
+ // algorithm. memory is a superset of objs; items are never removed from
+ // Memory until a serialization operation is finished
+ using CloneMemory = GCHashMap<JSObject*,
+ uint32_t,
+ MovableCellHasher<JSObject*>,
+ SystemAllocPolicy>;
+ Rooted<CloneMemory> memory;
+
+ // The user defined callbacks that will be used for cloning.
+ const JSStructuredCloneCallbacks* callbacks;
+
+ // Any value passed to JS_WriteStructuredClone.
+ void* closure;
+
+ // Set of transferable objects
+ RootedValue transferable;
+ Rooted<GCHashSet<JSObject*>> transferableObjects;
+
+ const JS::CloneDataPolicy cloneDataPolicy;
+
+ friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str);
+ friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v);
+ friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj);
+};
+
+JS_FRIEND_API(uint64_t)
+js::GetSCOffset(JSStructuredCloneWriter* writer)
+{
+ MOZ_ASSERT(writer);
+ return writer->output().count() * sizeof(uint64_t);
+}
+
+JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
+JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX);
+JS_STATIC_ASSERT(Scalar::Int8 == 0);
+
+static void
+ReportDataCloneError(JSContext* cx,
+ const JSStructuredCloneCallbacks* callbacks,
+ uint32_t errorId)
+{
+ if (callbacks && callbacks->reportError) {
+ callbacks->reportError(cx, errorId);
+ return;
+ }
+
+ switch (errorId) {
+ case JS_SCERR_DUP_TRANSFERABLE:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_DUP_TRANSFERABLE);
+ break;
+
+ case JS_SCERR_TRANSFERABLE:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_NOT_TRANSFERABLE);
+ break;
+
+ case JS_SCERR_UNSUPPORTED_TYPE:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_UNSUPPORTED_TYPE);
+ break;
+
+ default:
+ MOZ_CRASH("Unkown errorId");
+ break;
+ }
+}
+
+bool
+WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp,
+ JS::StructuredCloneScope scope,
+ JS::CloneDataPolicy cloneDataPolicy,
+ const JSStructuredCloneCallbacks* cb, void* cbClosure,
+ const Value& transferable)
+{
+ JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable);
+ return w.init() && w.write(v) && w.extractBuffer(bufp);
+}
+
+bool
+ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data,
+ JS::StructuredCloneScope scope, MutableHandleValue vp,
+ const JSStructuredCloneCallbacks* cb, void* cbClosure)
+{
+ SCInput in(cx, data);
+ JSStructuredCloneReader r(in, scope, cb, cbClosure);
+ return r.read(vp);
+}
+
+// If the given buffer contains Transferables, free them. Note that custom
+// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
+// delete their transferables.
+template<typename AllocPolicy>
+static void
+DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
+ const JSStructuredCloneCallbacks* cb, void* cbClosure)
+{
+ auto point = BufferIterator<uint64_t, AllocPolicy>(buffer);
+ if (point.done())
+ return; // Empty buffer
+
+ uint32_t tag, data;
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ SCInput::getPair(point.peek(), &tag, &data);
+ point.next();
+
+ if (tag == SCTAG_HEADER) {
+ if (point.done())
+ return;
+
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ SCInput::getPair(point.peek(), &tag, &data);
+ point.next();
+ }
+
+ if (tag != SCTAG_TRANSFER_MAP_HEADER)
+ return;
+
+ if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+ return;
+
+ // freeTransfer should not GC
+ JS::AutoSuppressGCAnalysis nogc;
+
+ if (point.done())
+ return;
+
+ uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
+ point.next();
+ while (numTransferables--) {
+ if (!point.canPeek())
+ return;
+
+ uint32_t ownership;
+ SCInput::getPair(point.peek(), &tag, &ownership);
+ point.next();
+ MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+ if (!point.canPeek())
+ return;
+
+ void* content;
+ SCInput::getPtr(point.peek(), &content);
+ point.next();
+ if (!point.canPeek())
+ return;
+
+ uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
+ point.next();
+
+ if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
+ continue;
+
+ if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
+ js_free(content);
+ } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
+ JS_ReleaseMappedArrayBufferContents(content, extraData);
+ } else if (cb && cb->freeTransfer) {
+ cb->freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, cbClosure);
+ } else {
+ MOZ_ASSERT(false, "unknown ownership");
+ }
+ }
+}
+
+static bool
+StructuredCloneHasTransferObjects(const JSStructuredCloneData& data)
+{
+ auto iter = data.Iter();
+
+ if (data.Size() < sizeof(uint64_t))
+ return false;
+
+ uint64_t u;
+ data.ReadBytes(iter, reinterpret_cast<char*>(&u), sizeof(u));
+ uint32_t tag = uint32_t(u >> 32);
+ return (tag == SCTAG_TRANSFER_MAP_HEADER);
+}
+
+namespace js {
+
+SCInput::SCInput(JSContext* cx, JSStructuredCloneData& data)
+ : cx(cx), point(data)
+{
+
+ static_assert(JSStructuredCloneData::kSegmentAlignment % 8 == 0,
+ "structured clone buffer reads should be aligned");
+ MOZ_ASSERT(data.Size() % 8 == 0);
+}
+
+bool
+SCInput::read(uint64_t* p)
+{
+ if (!point.canPeek()) {
+ *p = 0; /* initialize to shut GCC up */
+ return reportTruncated();
+ }
+ *p = NativeEndian::swapFromLittleEndian(point.peek());
+ point.next();
+ return true;
+}
+
+bool
+SCInput::readNativeEndian(uint64_t* p)
+{
+ if (!point.canPeek()) {
+ *p = 0; /* initialize to shut GCC up */
+ return reportTruncated();
+ }
+ *p = point.peek();
+ point.next();
+ return true;
+}
+
+bool
+SCInput::readPair(uint32_t* tagp, uint32_t* datap)
+{
+ uint64_t u;
+ bool ok = read(&u);
+ if (ok) {
+ *tagp = uint32_t(u >> 32);
+ *datap = uint32_t(u);
+ }
+ return ok;
+}
+
+bool
+SCInput::get(uint64_t* p)
+{
+ if (!point.canPeek())
+ return reportTruncated();
+ *p = NativeEndian::swapFromLittleEndian(point.peek());
+ return true;
+}
+
+bool
+SCInput::getPair(uint32_t* tagp, uint32_t* datap)
+{
+ uint64_t u = 0;
+ if (!get(&u))
+ return false;
+
+ *tagp = uint32_t(u >> 32);
+ *datap = uint32_t(u);
+ return true;
+}
+
+void
+SCInput::getPair(uint64_t data, uint32_t* tagp, uint32_t* datap)
+{
+ uint64_t u = NativeEndian::swapFromLittleEndian(data);
+ *tagp = uint32_t(u >> 32);
+ *datap = uint32_t(u);
+}
+
+bool
+SCInput::readDouble(double* p)
+{
+ union {
+ uint64_t u;
+ double d;
+ } pun;
+ if (!read(&pun.u))
+ return false;
+ *p = CanonicalizeNaN(pun.d);
+ return true;
+}
+
+template <typename T>
+static void
+swapFromLittleEndianInPlace(T* ptr, size_t nelems)
+{
+ if (nelems > 0)
+ NativeEndian::swapFromLittleEndianInPlace(ptr, nelems);
+}
+
+template <>
+void
+swapFromLittleEndianInPlace(uint8_t* ptr, size_t nelems)
+{}
+
+template <class T>
+bool
+SCInput::readArray(T* p, size_t nelems)
+{
+ if (!nelems)
+ return true;
+
+ JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
+
+ /*
+ * Fail if nelems is so huge as to make JS_HOWMANY overflow or if nwords is
+ * larger than the remaining data.
+ */
+ size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
+ if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems)
+ return reportTruncated();
+
+ size_t size = sizeof(T) * nelems;
+ if (!point.readBytes(reinterpret_cast<char*>(p), size))
+ return false;
+
+ swapFromLittleEndianInPlace(p, nelems);
+
+ point += sizeof(uint64_t) * nwords - size;
+
+ return true;
+}
+
+bool
+SCInput::readBytes(void* p, size_t nbytes)
+{
+ return readArray((uint8_t*) p, nbytes);
+}
+
+bool
+SCInput::readChars(Latin1Char* p, size_t nchars)
+{
+ static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
+ return readBytes(p, nchars);
+}
+
+bool
+SCInput::readChars(char16_t* p, size_t nchars)
+{
+ MOZ_ASSERT(sizeof(char16_t) == sizeof(uint16_t));
+ return readArray((uint16_t*) p, nchars);
+}
+
+void
+SCInput::getPtr(uint64_t data, void** ptr)
+{
+ // No endianness conversion is used for pointers, since they are not sent
+ // across address spaces anyway.
+ *ptr = reinterpret_cast<void*>(data);
+}
+
+bool
+SCInput::readPtr(void** p)
+{
+ uint64_t u;
+ if (!readNativeEndian(&u))
+ return false;
+ *p = reinterpret_cast<void*>(NativeEndian::swapFromLittleEndian(u));
+ return true;
+}
+
+SCOutput::SCOutput(JSContext* cx)
+ : cx(cx)
+ , buf(0, 0, 4096, cx)
+{
+}
+
+bool
+SCOutput::write(uint64_t u)
+{
+ uint64_t v = NativeEndian::swapToLittleEndian(u);
+ return buf.WriteBytes(reinterpret_cast<char*>(&v), sizeof(u));
+}
+
+bool
+SCOutput::writePair(uint32_t tag, uint32_t data)
+{
+ /*
+ * As it happens, the tag word appears after the data word in the output.
+ * This is because exponents occupy the last 2 bytes of doubles on the
+ * little-endian platforms we care most about.
+ *
+ * For example, TrueValue() is written using writePair(SCTAG_BOOLEAN, 1).
+ * PairToUInt64 produces the number 0xFFFF000200000001.
+ * That is written out as the bytes 01 00 00 00 02 00 FF FF.
+ */
+ return write(PairToUInt64(tag, data));
+}
+
+static inline double
+ReinterpretPairAsDouble(uint32_t tag, uint32_t data)
+{
+ return BitwiseCast<double>(PairToUInt64(tag, data));
+}
+
+bool
+SCOutput::writeDouble(double d)
+{
+ return write(BitwiseCast<uint64_t>(CanonicalizeNaN(d)));
+}
+
+template <typename T>
+static T
+swapToLittleEndian(T value)
+{
+ return NativeEndian::swapToLittleEndian(value);
+}
+
+template <>
+uint8_t
+swapToLittleEndian(uint8_t value)
+{
+ return value;
+}
+
+template <class T>
+bool
+SCOutput::writeArray(const T* p, size_t nelems)
+{
+ JS_STATIC_ASSERT(8 % sizeof(T) == 0);
+ JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
+
+ if (nelems == 0)
+ return true;
+
+ if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems) {
+ ReportAllocationOverflow(context());
+ return false;
+ }
+
+ for (size_t i = 0; i < nelems; i++) {
+ T value = swapToLittleEndian(p[i]);
+ if (!buf.WriteBytes(reinterpret_cast<char*>(&value), sizeof(value)))
+ return false;
+ }
+
+ // zero-pad to 8 bytes boundary
+ size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
+ size_t padbytes = sizeof(uint64_t) * nwords - sizeof(T) * nelems;
+ char zero = 0;
+ for (size_t i = 0; i < padbytes; i++) {
+ if (!buf.WriteBytes(&zero, sizeof(zero)))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+SCOutput::writeBytes(const void* p, size_t nbytes)
+{
+ return writeArray((const uint8_t*) p, nbytes);
+}
+
+bool
+SCOutput::writeChars(const char16_t* p, size_t nchars)
+{
+ static_assert(sizeof(char16_t) == sizeof(uint16_t),
+ "required so that treating char16_t[] memory as uint16_t[] "
+ "memory is permissible");
+ return writeArray((const uint16_t*) p, nchars);
+}
+
+bool
+SCOutput::writeChars(const Latin1Char* p, size_t nchars)
+{
+ static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
+ return writeBytes(p, nchars);
+}
+
+bool
+SCOutput::writePtr(const void* p)
+{
+ return write(reinterpret_cast<uint64_t>(p));
+}
+
+bool
+SCOutput::extractBuffer(JSStructuredCloneData* data)
+{
+ bool success;
+ mozilla::BufferList<SystemAllocPolicy> out =
+ buf.MoveFallible<SystemAllocPolicy>(&success);
+ if (!success) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ *data = JSStructuredCloneData(Move(out));
+ return true;
+}
+
+void
+SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure)
+{
+ DiscardTransferables(buf, cb, cbClosure);
+}
+
+} /* namespace js */
+
+JSStructuredCloneData::~JSStructuredCloneData()
+{
+ if (!Size())
+ return;
+ if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
+ DiscardTransferables(*this, callbacks_, closure_);
+}
+
+JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
+
+JSStructuredCloneWriter::~JSStructuredCloneWriter()
+{
+ // Free any transferable data left lying around in the buffer
+ if (out.count()) {
+ out.discardTransferables(callbacks, closure);
+ }
+}
+
+bool
+JSStructuredCloneWriter::parseTransferable()
+{
+ // NOTE: The transferables set is tested for non-emptiness at various
+ // junctures in structured cloning, so this set must be initialized
+ // by this method in all non-error cases.
+ MOZ_ASSERT(!transferableObjects.initialized(),
+ "parseTransferable called with stale data");
+
+ if (transferable.isNull() || transferable.isUndefined())
+ return transferableObjects.init(0);
+
+ if (!transferable.isObject())
+ return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+
+ JSContext* cx = context();
+ RootedObject array(cx, &transferable.toObject());
+ bool isArray;
+ if (!JS_IsArrayObject(cx, array, &isArray))
+ return false;
+ if (!isArray)
+ return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+
+ uint32_t length;
+ if (!JS_GetArrayLength(cx, array, &length))
+ return false;
+
+ // Initialize the set for the provided array's length.
+ if (!transferableObjects.init(length))
+ return false;
+
+ if (length == 0)
+ return true;
+
+ RootedValue v(context());
+ RootedObject tObj(context());
+
+ for (uint32_t i = 0; i < length; ++i) {
+ if (!CheckForInterrupt(cx))
+ return false;
+
+ if (!JS_GetElement(cx, array, i, &v))
+ return false;
+
+ if (!v.isObject())
+ return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+ tObj = &v.toObject();
+
+ // Backward compatibility, see bug 1302036 and bug 1302037.
+ if (tObj->is<SharedArrayBufferObject>()) {
+ if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage,
+ nullptr, JSMSG_SC_SAB_TRANSFER))
+ return false;
+ continue;
+ }
+
+ // No duplicates allowed
+ auto p = transferableObjects.lookupForAdd(tObj);
+ if (p)
+ return reportDataCloneError(JS_SCERR_DUP_TRANSFERABLE);
+
+ if (!transferableObjects.add(p, tObj))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId)
+{
+ ReportDataCloneError(context(), callbacks, errorId);
+ return false;
+}
+
+bool
+JSStructuredCloneWriter::writeString(uint32_t tag, JSString* str)
+{
+ JSLinearString* linear = str->ensureLinear(context());
+ if (!linear)
+ return false;
+
+ static_assert(JSString::MAX_LENGTH <= INT32_MAX, "String length must fit in 31 bits");
+
+ uint32_t length = linear->length();
+ uint32_t lengthAndEncoding = length | (uint32_t(linear->hasLatin1Chars()) << 31);
+ if (!out.writePair(tag, lengthAndEncoding))
+ return false;
+
+ JS::AutoCheckCannotGC nogc;
+ return linear->hasLatin1Chars()
+ ? out.writeChars(linear->latin1Chars(nogc), length)
+ : out.writeChars(linear->twoByteChars(nogc), length);
+}
+
+inline void
+JSStructuredCloneWriter::checkStack()
+{
+#ifdef DEBUG
+ /* To avoid making serialization O(n^2), limit stack-checking at 10. */
+ const size_t MAX = 10;
+
+ size_t limit = Min(counts.length(), MAX);
+ MOZ_ASSERT(objs.length() == counts.length());
+ size_t total = 0;
+ for (size_t i = 0; i < limit; i++) {
+ MOZ_ASSERT(total + counts[i] >= total);
+ total += counts[i];
+ }
+ if (counts.length() <= MAX)
+ MOZ_ASSERT(total == entries.length());
+ else
+ MOZ_ASSERT(total <= entries.length());
+
+ size_t j = objs.length();
+ for (size_t i = 0; i < limit; i++) {
+ --j;
+ MOZ_ASSERT(memory.has(&objs[j].toObject()));
+ }
+#endif
+}
+
+/*
+ * Write out a typed array. Note that post-v1 structured clone buffers do not
+ * perform endianness conversion on stored data, so multibyte typed arrays
+ * cannot be deserialized into a different endianness machine. Endianness
+ * conversion would prevent sharing ArrayBuffers: if you have Int8Array and
+ * Int16Array views of the same ArrayBuffer, should the data bytes be
+ * byte-swapped when writing or not? The Int8Array requires them to not be
+ * swapped; the Int16Array requires that they are.
+ */
+bool
+JSStructuredCloneWriter::writeTypedArray(HandleObject obj)
+{
+ Rooted<TypedArrayObject*> tarr(context(), &CheckedUnwrap(obj)->as<TypedArrayObject>());
+ JSAutoCompartment ac(context(), tarr);
+
+ if (!TypedArrayObject::ensureHasBuffer(context(), tarr))
+ return false;
+
+ if (!out.writePair(SCTAG_TYPED_ARRAY_OBJECT, tarr->length()))
+ return false;
+ uint64_t type = tarr->type();
+ if (!out.write(type))
+ return false;
+
+ // Write out the ArrayBuffer tag and contents
+ RootedValue val(context(), TypedArrayObject::bufferValue(tarr));
+ if (!startWrite(val))
+ return false;
+
+ return out.write(tarr->byteOffset());
+}
+
+bool
+JSStructuredCloneWriter::writeDataView(HandleObject obj)
+{
+ Rooted<DataViewObject*> view(context(), &CheckedUnwrap(obj)->as<DataViewObject>());
+ JSAutoCompartment ac(context(), view);
+
+ if (!out.writePair(SCTAG_DATA_VIEW_OBJECT, view->byteLength()))
+ return false;
+
+ // Write out the ArrayBuffer tag and contents
+ RootedValue val(context(), DataViewObject::bufferValue(view));
+ if (!startWrite(val))
+ return false;
+
+ return out.write(view->byteOffset());
+}
+
+bool
+JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj)
+{
+ ArrayBufferObject& buffer = CheckedUnwrap(obj)->as<ArrayBufferObject>();
+ JSAutoCompartment ac(context(), &buffer);
+
+ return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer.byteLength()) &&
+ out.writeBytes(buffer.dataPointer(), buffer.byteLength());
+}
+
+bool
+JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
+{
+ if (!cloneDataPolicy.isSharedArrayBufferAllowed()) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_NOT_CLONABLE,
+ "SharedArrayBuffer");
+ return false;
+ }
+
+ Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
+ SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
+
+ // Avoids a race condition where the parent thread frees the buffer
+ // before the child has accepted the transferable.
+ rawbuf->addReference();
+
+ intptr_t p = reinterpret_cast<intptr_t>(rawbuf);
+ return out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT, static_cast<uint32_t>(sizeof(p))) &&
+ out.writeBytes(&p, sizeof(p));
+}
+
+bool
+JSStructuredCloneWriter::startObject(HandleObject obj, bool* backref)
+{
+ /* Handle cycles in the object graph. */
+ CloneMemory::AddPtr p = memory.lookupForAdd(obj);
+ if ((*backref = p.found()))
+ return out.writePair(SCTAG_BACK_REFERENCE_OBJECT, p->value());
+ if (!memory.add(p, obj, memory.count())) {
+ ReportOutOfMemory(context());
+ return false;
+ }
+
+ if (memory.count() == UINT32_MAX) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_NEED_DIET,
+ "object graph to serialize");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+JSStructuredCloneWriter::traverseObject(HandleObject obj)
+{
+ /*
+ * Get enumerable property ids and put them in reverse order so that they
+ * will come off the stack in forward order.
+ */
+ AutoIdVector properties(context());
+ if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties))
+ return false;
+
+ for (size_t i = properties.length(); i > 0; --i) {
+ MOZ_ASSERT(JSID_IS_STRING(properties[i - 1]) || JSID_IS_INT(properties[i - 1]));
+ RootedValue val(context(), IdToValue(properties[i - 1]));
+ if (!entries.append(val))
+ return false;
+ }
+
+ /* Push obj and count to the stack. */
+ if (!objs.append(ObjectValue(*obj)) || !counts.append(properties.length()))
+ return false;
+
+ checkStack();
+
+ /* Write the header for obj. */
+ ESClass cls;
+ if (!GetBuiltinClass(context(), obj, &cls))
+ return false;
+ return out.writePair(cls == ESClass::Array ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
+}
+
+bool
+JSStructuredCloneWriter::traverseMap(HandleObject obj)
+{
+ Rooted<GCVector<Value>> newEntries(context(), GCVector<Value>(context()));
+ {
+ // If there is no wrapper, the compartment munging is a no-op.
+ RootedObject unwrapped(context(), CheckedUnwrap(obj));
+ MOZ_ASSERT(unwrapped);
+ JSAutoCompartment ac(context(), unwrapped);
+ if (!MapObject::getKeysAndValuesInterleaved(context(), unwrapped, &newEntries))
+ return false;
+ }
+ if (!context()->compartment()->wrap(context(), &newEntries))
+ return false;
+
+ for (size_t i = newEntries.length(); i > 0; --i) {
+ if (!entries.append(newEntries[i - 1]))
+ return false;
+ }
+
+ /* Push obj and count to the stack. */
+ if (!objs.append(ObjectValue(*obj)) || !counts.append(newEntries.length()))
+ return false;
+
+ checkStack();
+
+ /* Write the header for obj. */
+ return out.writePair(SCTAG_MAP_OBJECT, 0);
+}
+
+bool
+JSStructuredCloneWriter::traverseSet(HandleObject obj)
+{
+ Rooted<GCVector<Value>> keys(context(), GCVector<Value>(context()));
+ {
+ // If there is no wrapper, the compartment munging is a no-op.
+ RootedObject unwrapped(context(), CheckedUnwrap(obj));
+ MOZ_ASSERT(unwrapped);
+ JSAutoCompartment ac(context(), unwrapped);
+ if (!SetObject::keys(context(), unwrapped, &keys))
+ return false;
+ }
+ if (!context()->compartment()->wrap(context(), &keys))
+ return false;
+
+ for (size_t i = keys.length(); i > 0; --i) {
+ if (!entries.append(keys[i - 1]))
+ return false;
+ }
+
+ /* Push obj and count to the stack. */
+ if (!objs.append(ObjectValue(*obj)) || !counts.append(keys.length()))
+ return false;
+
+ checkStack();
+
+ /* Write the header for obj. */
+ return out.writePair(SCTAG_SET_OBJECT, 0);
+}
+
+// Objects are written as a "preorder" traversal of the object graph: object
+// "headers" (the class tag and any data needed for initial construction) are
+// visited first, then the children are recursed through (where children are
+// properties, Set or Map entries, etc.). So for example
+//
+// m = new Map();
+// m.set(key1 = {}, value1 = {})
+//
+// would be stored as
+//
+// <Map tag>
+// <key1 class tag>
+// <value1 class tag>
+// <end-of-children marker for key1>
+// <end-of-children marker for value1>
+// <end-of-children marker for Map>
+//
+// Notice how the end-of-children marker for key1 is sandwiched between the
+// value1 beginning and end.
+bool
+JSStructuredCloneWriter::traverseSavedFrame(HandleObject obj)
+{
+ RootedObject unwrapped(context(), js::CheckedUnwrap(obj));
+ MOZ_ASSERT(unwrapped && unwrapped->is<SavedFrame>());
+
+ RootedSavedFrame savedFrame(context(), &unwrapped->as<SavedFrame>());
+
+ RootedObject parent(context(), savedFrame->getParent());
+ if (!context()->compartment()->wrap(context(), &parent))
+ return false;
+
+ if (!objs.append(ObjectValue(*obj)) ||
+ !entries.append(parent ? ObjectValue(*parent) : NullValue()) ||
+ !counts.append(1))
+ {
+ return false;
+ }
+
+ checkStack();
+
+ // Write the SavedFrame tag and the SavedFrame's principals.
+
+ if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsSystem) {
+ if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT,
+ SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM))
+ {
+ return false;
+ };
+ } else if (savedFrame->getPrincipals() == &ReconstructedSavedFramePrincipals::IsNotSystem) {
+ if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT,
+ SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM))
+ {
+ return false;
+ }
+ } else {
+ if (auto principals = savedFrame->getPrincipals()) {
+ if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_JSPRINCIPALS) ||
+ !principals->write(context(), this))
+ {
+ return false;
+ }
+ } else {
+ if (!out.writePair(SCTAG_SAVED_FRAME_OBJECT, SCTAG_NULL_JSPRINCIPALS))
+ return false;
+ }
+ }
+
+ // Write the SavedFrame's reserved slots, except for the parent, which is
+ // queued on objs for further traversal.
+
+ RootedValue val(context());
+
+ val = StringValue(savedFrame->getSource());
+ if (!startWrite(val))
+ return false;
+
+ val = NumberValue(savedFrame->getLine());
+ if (!startWrite(val))
+ return false;
+
+ val = NumberValue(savedFrame->getColumn());
+ if (!startWrite(val))
+ return false;
+
+ auto name = savedFrame->getFunctionDisplayName();
+ val = name ? StringValue(name) : NullValue();
+ if (!startWrite(val))
+ return false;
+
+ auto cause = savedFrame->getAsyncCause();
+ val = cause ? StringValue(cause) : NullValue();
+ if (!startWrite(val))
+ return false;
+
+ return true;
+}
+
+bool
+JSStructuredCloneWriter::startWrite(HandleValue v)
+{
+ assertSameCompartment(context(), v);
+
+ if (v.isString()) {
+ return writeString(SCTAG_STRING, v.toString());
+ } else if (v.isInt32()) {
+ return out.writePair(SCTAG_INT32, v.toInt32());
+ } else if (v.isDouble()) {
+ return out.writeDouble(v.toDouble());
+ } else if (v.isBoolean()) {
+ return out.writePair(SCTAG_BOOLEAN, v.toBoolean());
+ } else if (v.isNull()) {
+ return out.writePair(SCTAG_NULL, 0);
+ } else if (v.isUndefined()) {
+ return out.writePair(SCTAG_UNDEFINED, 0);
+ } else if (v.isObject()) {
+ RootedObject obj(context(), &v.toObject());
+
+ bool backref;
+ if (!startObject(obj, &backref))
+ return false;
+ if (backref)
+ return true;
+
+ ESClass cls;
+ if (!GetBuiltinClass(context(), obj, &cls))
+ return false;
+
+ if (cls == ESClass::RegExp) {
+ RegExpGuard re(context());
+ if (!RegExpToShared(context(), obj, &re))
+ return false;
+ return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
+ writeString(SCTAG_STRING, re->getSource());
+ } else if (cls == ESClass::Date) {
+ RootedValue unboxed(context());
+ if (!Unbox(context(), obj, &unboxed))
+ return false;
+ return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(unboxed.toNumber());
+ } else if (JS_IsTypedArrayObject(obj)) {
+ return writeTypedArray(obj);
+ } else if (JS_IsDataViewObject(obj)) {
+ return writeDataView(obj);
+ } else if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) {
+ return writeArrayBuffer(obj);
+ } else if (JS_IsSharedArrayBufferObject(obj)) {
+ return writeSharedArrayBuffer(obj);
+ } else if (cls == ESClass::Object) {
+ return traverseObject(obj);
+ } else if (cls == ESClass::Array) {
+ return traverseObject(obj);
+ } else if (cls == ESClass::Boolean) {
+ RootedValue unboxed(context());
+ if (!Unbox(context(), obj, &unboxed))
+ return false;
+ return out.writePair(SCTAG_BOOLEAN_OBJECT, unboxed.toBoolean());
+ } else if (cls == ESClass::Number) {
+ RootedValue unboxed(context());
+ if (!Unbox(context(), obj, &unboxed))
+ return false;
+ return out.writePair(SCTAG_NUMBER_OBJECT, 0) && out.writeDouble(unboxed.toNumber());
+ } else if (cls == ESClass::String) {
+ RootedValue unboxed(context());
+ if (!Unbox(context(), obj, &unboxed))
+ return false;
+ return writeString(SCTAG_STRING_OBJECT, unboxed.toString());
+ } else if (cls == ESClass::Map) {
+ return traverseMap(obj);
+ } else if (cls == ESClass::Set) {
+ return traverseSet(obj);
+ } else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
+ return traverseSavedFrame(obj);
+ }
+
+ if (callbacks && callbacks->write)
+ return callbacks->write(context(), this, obj, closure);
+ /* else fall through */
+ }
+
+ return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE);
+}
+
+bool
+JSStructuredCloneWriter::writeHeader()
+{
+ return out.writePair(SCTAG_HEADER, (uint32_t)scope);
+}
+
+bool
+JSStructuredCloneWriter::writeTransferMap()
+{
+ if (transferableObjects.empty())
+ return true;
+
+ if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_UNREAD))
+ return false;
+
+ if (!out.write(transferableObjects.count()))
+ return false;
+
+ RootedObject obj(context());
+ for (auto tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
+ obj = tr.front();
+ if (!memory.put(obj, memory.count())) {
+ ReportOutOfMemory(context());
+ return false;
+ }
+
+ // Emit a placeholder pointer. We defer stealing the data until later
+ // (and, if necessary, detaching this object if it's an ArrayBuffer).
+ if (!out.writePair(SCTAG_TRANSFER_MAP_PENDING_ENTRY, JS::SCTAG_TMO_UNFILLED))
+ return false;
+ if (!out.writePtr(nullptr)) // Pointer to ArrayBuffer contents.
+ return false;
+ if (!out.write(0)) // extraData
+ return false;
+ }
+
+ return true;
+}
+
+bool
+JSStructuredCloneWriter::transferOwnership()
+{
+ if (transferableObjects.empty())
+ return true;
+
+ // Walk along the transferables and the transfer map at the same time,
+ // grabbing out pointers from the transferables and stuffing them into the
+ // transfer map.
+ auto point = out.iter();
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ MOZ_ASSERT(uint32_t(NativeEndian::swapFromLittleEndian(point.peek()) >> 32) == SCTAG_HEADER);
+ point++;
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ MOZ_ASSERT(uint32_t(NativeEndian::swapFromLittleEndian(point.peek()) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
+ point++;
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ MOZ_ASSERT(NativeEndian::swapFromLittleEndian(point.peek()) == transferableObjects.count());
+ point++;
+
+ JSContext* cx = context();
+ RootedObject obj(cx);
+ for (auto tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
+ obj = tr.front();
+
+ uint32_t tag;
+ JS::TransferableOwnership ownership;
+ void* content;
+ uint64_t extraData;
+
+#if DEBUG
+ SCInput::getPair(point.peek(), &tag, (uint32_t*) &ownership);
+ MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+ MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED);
+#endif
+
+ ESClass cls;
+ if (!GetBuiltinClass(cx, obj, &cls))
+ return false;
+
+ if (cls == ESClass::ArrayBuffer) {
+ tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
+
+ // The current setup of the array buffer inheritance hierarchy doesn't
+ // lend itself well to generic manipulation via proxies.
+ Rooted<ArrayBufferObject*> arrayBuffer(cx, &CheckedUnwrap(obj)->as<ArrayBufferObject>());
+ JSAutoCompartment ac(cx, arrayBuffer);
+ size_t nbytes = arrayBuffer->byteLength();
+
+ if (arrayBuffer->isWasm() || arrayBuffer->isPreparedForAsmJS()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
+ return false;
+ }
+
+ if (scope == JS::StructuredCloneScope::DifferentProcess) {
+ // Write Transferred ArrayBuffers in DifferentProcess scope at
+ // the end of the clone buffer, and store the offset within the
+ // buffer to where the ArrayBuffer was written. Note that this
+ // will invalidate the current position iterator.
+
+ size_t pointOffset = out.offset(point);
+ tag = SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER;
+ ownership = JS::SCTAG_TMO_UNOWNED;
+ content = nullptr;
+ extraData = out.tell() - pointOffset; // Offset from tag to current end of buffer
+ if (!writeArrayBuffer(arrayBuffer))
+ return false;
+
+ // Must refresh the point iterator after its collection has
+ // been modified.
+ point = out.iter();
+ point += pointOffset;
+
+ if (!JS_DetachArrayBuffer(cx, arrayBuffer))
+ return false;
+ } else {
+ bool hasStealableContents = arrayBuffer->hasStealableContents();
+
+ ArrayBufferObject::BufferContents bufContents =
+ ArrayBufferObject::stealContents(cx, arrayBuffer, hasStealableContents);
+ if (!bufContents)
+ return false; // already transferred data
+
+ content = bufContents.data();
+ if (bufContents.kind() == ArrayBufferObject::MAPPED)
+ ownership = JS::SCTAG_TMO_MAPPED_DATA;
+ else
+ ownership = JS::SCTAG_TMO_ALLOC_DATA;
+ extraData = nbytes;
+ }
+ } else {
+ if (!callbacks || !callbacks->writeTransfer)
+ return reportDataCloneError(JS_SCERR_TRANSFERABLE);
+ if (!callbacks->writeTransfer(cx, obj, closure, &tag, &ownership, &content, &extraData))
+ return false;
+ MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+ }
+
+ point.write(NativeEndian::swapToLittleEndian(PairToUInt64(tag, ownership)));
+ point.next();
+ point.write(NativeEndian::swapToLittleEndian(reinterpret_cast<uint64_t>(content)));
+ point.next();
+ point.write(NativeEndian::swapToLittleEndian(extraData));
+ point.next();
+ }
+
+#if DEBUG
+ // Make sure there aren't any more transfer map entries after the expected
+ // number we read out.
+ if (!point.done()) {
+ uint32_t tag, data;
+ SCInput::getPair(point.peek(), &tag, &data);
+ MOZ_ASSERT(tag < SCTAG_TRANSFER_MAP_HEADER || tag >= SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES);
+ }
+#endif
+ return true;
+}
+
+bool
+JSStructuredCloneWriter::write(HandleValue v)
+{
+ if (!startWrite(v))
+ return false;
+
+ while (!counts.empty()) {
+ RootedObject obj(context(), &objs.back().toObject());
+ AutoCompartment ac(context(), obj);
+ if (counts.back()) {
+ counts.back()--;
+ RootedValue key(context(), entries.back());
+ entries.popBack();
+ checkStack();
+
+ ESClass cls;
+ if (!GetBuiltinClass(context(), obj, &cls))
+ return false;
+
+ if (cls == ESClass::Map) {
+ counts.back()--;
+ RootedValue val(context(), entries.back());
+ entries.popBack();
+ checkStack();
+
+ if (!startWrite(key) || !startWrite(val))
+ return false;
+ } else if (cls == ESClass::Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
+ if (!startWrite(key))
+ return false;
+ } else {
+ RootedId id(context());
+ if (!ValueToId<CanGC>(context(), key, &id))
+ return false;
+ MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
+
+ /*
+ * If obj still has an own property named id, write it out.
+ * The cost of re-checking could be avoided by using
+ * NativeIterators.
+ */
+ bool found;
+ if (!HasOwnProperty(context(), obj, id, &found))
+ return false;
+
+ if (found) {
+ RootedValue val(context());
+ if (!startWrite(key) ||
+ !GetProperty(context(), obj, obj, id, &val) ||
+ !startWrite(val))
+ {
+ return false;
+ }
+ }
+ }
+ } else {
+ if (!out.writePair(SCTAG_END_OF_KEYS, 0))
+ return false;
+ objs.popBack();
+ counts.popBack();
+ }
+ }
+
+ memory.clear();
+ return transferOwnership();
+}
+
+bool
+JSStructuredCloneReader::checkDouble(double d)
+{
+ if (!JS::IsCanonicalized(d)) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "unrecognized NaN");
+ return false;
+ }
+ return true;
+}
+
+namespace {
+
+template <typename CharT>
+class Chars {
+ JSContext* cx;
+ CharT* p;
+ public:
+ explicit Chars(JSContext* cx) : cx(cx), p(nullptr) {}
+ ~Chars() { js_free(p); }
+
+ bool allocate(size_t len) {
+ MOZ_ASSERT(!p);
+ // We're going to null-terminate!
+ p = cx->pod_malloc<CharT>(len + 1);
+ if (p) {
+ p[len] = CharT(0);
+ return true;
+ }
+ return false;
+ }
+ CharT* get() { return p; }
+ void forget() { p = nullptr; }
+};
+
+} /* anonymous namespace */
+
+template <typename CharT>
+JSString*
+JSStructuredCloneReader::readStringImpl(uint32_t nchars)
+{
+ if (nchars > JSString::MAX_LENGTH) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "string length");
+ return nullptr;
+ }
+ Chars<CharT> chars(context());
+ if (!chars.allocate(nchars) || !in.readChars(chars.get(), nchars))
+ return nullptr;
+ JSString* str = NewString<CanGC>(context(), chars.get(), nchars);
+ if (str)
+ chars.forget();
+ return str;
+}
+
+JSString*
+JSStructuredCloneReader::readString(uint32_t data)
+{
+ uint32_t nchars = data & JS_BITMASK(31);
+ bool latin1 = data & (1 << 31);
+ return latin1 ? readStringImpl<Latin1Char>(nchars) : readStringImpl<char16_t>(nchars);
+}
+
+static uint32_t
+TagToV1ArrayType(uint32_t tag)
+{
+ MOZ_ASSERT(tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX);
+ return tag - SCTAG_TYPED_ARRAY_V1_MIN;
+}
+
+bool
+JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp,
+ bool v1Read)
+{
+ if (arrayType > Scalar::Uint8Clamped) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "unhandled typed array element type");
+ return false;
+ }
+
+ // Push a placeholder onto the allObjs list to stand in for the typed array
+ uint32_t placeholderIndex = allObjs.length();
+ Value dummy = UndefinedValue();
+ if (!allObjs.append(dummy))
+ return false;
+
+ // Read the ArrayBuffer object and its contents (but no properties)
+ RootedValue v(context());
+ uint32_t byteOffset;
+ if (v1Read) {
+ if (!readV1ArrayBuffer(arrayType, nelems, &v))
+ return false;
+ byteOffset = 0;
+ } else {
+ if (!startRead(&v))
+ return false;
+ uint64_t n;
+ if (!in.read(&n))
+ return false;
+ byteOffset = n;
+ }
+ if (!v.isObject() || !v.toObject().is<ArrayBufferObjectMaybeShared>()) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "typed array must be backed by an ArrayBuffer");
+ return false;
+ }
+
+ RootedObject buffer(context(), &v.toObject());
+ RootedObject obj(context(), nullptr);
+
+ switch (arrayType) {
+ case Scalar::Int8:
+ obj = JS_NewInt8ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Uint8:
+ obj = JS_NewUint8ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Int16:
+ obj = JS_NewInt16ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Uint16:
+ obj = JS_NewUint16ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Int32:
+ obj = JS_NewInt32ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Uint32:
+ obj = JS_NewUint32ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Float32:
+ obj = JS_NewFloat32ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Float64:
+ obj = JS_NewFloat64ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::Uint8Clamped:
+ obj = JS_NewUint8ClampedArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ default:
+ MOZ_CRASH("Can't happen: arrayType range checked above");
+ }
+
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+
+ allObjs[placeholderIndex].set(vp);
+
+ return true;
+}
+
+bool
+JSStructuredCloneReader::readDataView(uint32_t byteLength, MutableHandleValue vp)
+{
+ // Push a placeholder onto the allObjs list to stand in for the DataView.
+ uint32_t placeholderIndex = allObjs.length();
+ Value dummy = UndefinedValue();
+ if (!allObjs.append(dummy))
+ return false;
+
+ // Read the ArrayBuffer object and its contents (but no properties).
+ RootedValue v(context());
+ if (!startRead(&v))
+ return false;
+ if (!v.isObject() || !v.toObject().is<ArrayBufferObjectMaybeShared>()) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "DataView must be backed by an ArrayBuffer");
+ return false;
+ }
+
+ // Read byteOffset.
+ uint64_t n;
+ if (!in.read(&n))
+ return false;
+ uint32_t byteOffset = n;
+
+ RootedObject buffer(context(), &v.toObject());
+ RootedObject obj(context(), JS_NewDataView(context(), buffer, byteOffset, byteLength));
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+
+ allObjs[placeholderIndex].set(vp);
+
+ return true;
+}
+
+bool
+JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, MutableHandleValue vp)
+{
+ JSObject* obj = ArrayBufferObject::create(context(), nbytes);
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+ ArrayBufferObject& buffer = obj->as<ArrayBufferObject>();
+ MOZ_ASSERT(buffer.byteLength() == nbytes);
+ return in.readArray(buffer.dataPointer(), nbytes);
+}
+
+bool
+JSStructuredCloneReader::readSharedArrayBuffer(uint32_t nbytes, MutableHandleValue vp)
+{
+ intptr_t p;
+ in.readBytes(&p, sizeof(p));
+
+ SharedArrayRawBuffer* rawbuf = reinterpret_cast<SharedArrayRawBuffer*>(p);
+
+ // There's no guarantee that the receiving agent has enabled shared memory
+ // even if the transmitting agent has done so. Ideally we'd check at the
+ // transmission point, but that's tricky, and it will be a very rare problem
+ // in any case. Just fail at the receiving end if we can't handle it.
+
+ if (!context()->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
+ // The sending side performed a reference increment before sending.
+ // Account for that here before leaving.
+ if (rawbuf)
+ rawbuf->dropReference();
+
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_SAB_DISABLED);
+ return false;
+ }
+
+ // The constructor absorbs the reference count increment performed by the sender.
+ JSObject* obj = SharedArrayBufferObject::New(context(), rawbuf);
+
+ vp.setObject(*obj);
+ return true;
+}
+
+/*
+ * Read in the data for a structured clone version 1 ArrayBuffer, performing
+ * endianness-conversion while reading.
+ */
+bool
+JSStructuredCloneReader::readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
+ MutableHandleValue vp)
+{
+ if (arrayType > Scalar::Uint8Clamped) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "invalid TypedArray type");
+ return false;
+ }
+
+ mozilla::CheckedInt<size_t> nbytes =
+ mozilla::CheckedInt<size_t>(nelems) *
+ TypedArrayElemSize(static_cast<Scalar::Type>(arrayType));
+ if (!nbytes.isValid() || nbytes.value() > UINT32_MAX) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "invalid typed array size");
+ return false;
+ }
+
+ JSObject* obj = ArrayBufferObject::create(context(), nbytes.value());
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+ ArrayBufferObject& buffer = obj->as<ArrayBufferObject>();
+ MOZ_ASSERT(buffer.byteLength() == nbytes);
+
+ switch (arrayType) {
+ case Scalar::Int8:
+ case Scalar::Uint8:
+ case Scalar::Uint8Clamped:
+ return in.readArray((uint8_t*) buffer.dataPointer(), nelems);
+ case Scalar::Int16:
+ case Scalar::Uint16:
+ return in.readArray((uint16_t*) buffer.dataPointer(), nelems);
+ case Scalar::Int32:
+ case Scalar::Uint32:
+ case Scalar::Float32:
+ return in.readArray((uint32_t*) buffer.dataPointer(), nelems);
+ case Scalar::Float64:
+ return in.readArray((uint64_t*) buffer.dataPointer(), nelems);
+ default:
+ MOZ_CRASH("Can't happen: arrayType range checked by caller");
+ }
+}
+
+static bool
+PrimitiveToObject(JSContext* cx, MutableHandleValue vp)
+{
+ JSObject* obj = js::PrimitiveToObject(cx, vp);
+ if (!obj)
+ return false;
+
+ vp.setObject(*obj);
+ return true;
+}
+
+bool
+JSStructuredCloneReader::startRead(MutableHandleValue vp)
+{
+ uint32_t tag, data;
+
+ if (!in.readPair(&tag, &data))
+ return false;
+
+ switch (tag) {
+ case SCTAG_NULL:
+ vp.setNull();
+ break;
+
+ case SCTAG_UNDEFINED:
+ vp.setUndefined();
+ break;
+
+ case SCTAG_INT32:
+ vp.setInt32(data);
+ break;
+
+ case SCTAG_BOOLEAN:
+ case SCTAG_BOOLEAN_OBJECT:
+ vp.setBoolean(!!data);
+ if (tag == SCTAG_BOOLEAN_OBJECT && !PrimitiveToObject(context(), vp))
+ return false;
+ break;
+
+ case SCTAG_STRING:
+ case SCTAG_STRING_OBJECT: {
+ JSString* str = readString(data);
+ if (!str)
+ return false;
+ vp.setString(str);
+ if (tag == SCTAG_STRING_OBJECT && !PrimitiveToObject(context(), vp))
+ return false;
+ break;
+ }
+
+ case SCTAG_NUMBER_OBJECT: {
+ double d;
+ if (!in.readDouble(&d) || !checkDouble(d))
+ return false;
+ vp.setDouble(d);
+ if (!PrimitiveToObject(context(), vp))
+ return false;
+ break;
+ }
+
+ case SCTAG_DATE_OBJECT: {
+ double d;
+ if (!in.readDouble(&d) || !checkDouble(d))
+ return false;
+ JS::ClippedTime t = JS::TimeClip(d);
+ if (!NumbersAreIdentical(d, t.toDouble())) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "date");
+ return false;
+ }
+ JSObject* obj = NewDateObjectMsec(context(), t);
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+ break;
+ }
+
+ case SCTAG_REGEXP_OBJECT: {
+ RegExpFlag flags = RegExpFlag(data);
+ uint32_t tag2, stringData;
+ if (!in.readPair(&tag2, &stringData))
+ return false;
+ if (tag2 != SCTAG_STRING) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "regexp");
+ return false;
+ }
+ JSString* str = readString(stringData);
+ if (!str)
+ return false;
+
+ RootedAtom atom(context(), AtomizeString(context(), str));
+ if (!atom)
+ return false;
+
+ RegExpObject* reobj = RegExpObject::create(context(), atom, flags, nullptr,
+ context()->tempLifoAlloc());
+ if (!reobj)
+ return false;
+ vp.setObject(*reobj);
+ break;
+ }
+
+ case SCTAG_ARRAY_OBJECT:
+ case SCTAG_OBJECT_OBJECT: {
+ JSObject* obj = (tag == SCTAG_ARRAY_OBJECT)
+ ? (JSObject*) NewDenseEmptyArray(context())
+ : (JSObject*) NewBuiltinClassInstance<PlainObject>(context());
+ if (!obj || !objs.append(ObjectValue(*obj)))
+ return false;
+ vp.setObject(*obj);
+ break;
+ }
+
+ case SCTAG_BACK_REFERENCE_OBJECT: {
+ if (data >= allObjs.length() || !allObjs[data].isObject()) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "invalid back reference in input");
+ return false;
+ }
+ vp.set(allObjs[data]);
+ return true;
+ }
+
+ case SCTAG_TRANSFER_MAP_HEADER:
+ case SCTAG_TRANSFER_MAP_PENDING_ENTRY:
+ // We should be past all the transfer map tags.
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "invalid input");
+ return false;
+
+ case SCTAG_ARRAY_BUFFER_OBJECT:
+ if (!readArrayBuffer(data, vp))
+ return false;
+ break;
+
+ case SCTAG_SHARED_ARRAY_BUFFER_OBJECT:
+ if (!readSharedArrayBuffer(data, vp))
+ return false;
+ break;
+
+ case SCTAG_TYPED_ARRAY_OBJECT: {
+ // readTypedArray adds the array to allObjs.
+ uint64_t arrayType;
+ if (!in.read(&arrayType))
+ return false;
+ return readTypedArray(arrayType, data, vp);
+ }
+
+ case SCTAG_DATA_VIEW_OBJECT: {
+ // readDataView adds the array to allObjs.
+ return readDataView(data, vp);
+ }
+
+ case SCTAG_MAP_OBJECT: {
+ JSObject* obj = MapObject::create(context());
+ if (!obj || !objs.append(ObjectValue(*obj)))
+ return false;
+ vp.setObject(*obj);
+ break;
+ }
+
+ case SCTAG_SET_OBJECT: {
+ JSObject* obj = SetObject::create(context());
+ if (!obj || !objs.append(ObjectValue(*obj)))
+ return false;
+ vp.setObject(*obj);
+ break;
+ }
+
+ case SCTAG_SAVED_FRAME_OBJECT: {
+ auto obj = readSavedFrame(data);
+ if (!obj || !objs.append(ObjectValue(*obj)))
+ return false;
+ vp.setObject(*obj);
+ break;
+ }
+
+ default: {
+ if (tag <= SCTAG_FLOAT_MAX) {
+ double d = ReinterpretPairAsDouble(tag, data);
+ if (!checkDouble(d))
+ return false;
+ vp.setNumber(d);
+ break;
+ }
+
+ if (SCTAG_TYPED_ARRAY_V1_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
+ // A v1-format typed array
+ // readTypedArray adds the array to allObjs
+ return readTypedArray(TagToV1ArrayType(tag), data, vp, true);
+ }
+
+ if (!callbacks || !callbacks->read) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "unsupported type");
+ return false;
+ }
+ JSObject* obj = callbacks->read(context(), this, tag, data, closure);
+ if (!obj)
+ return false;
+ vp.setObject(*obj);
+ }
+ }
+
+ if (vp.isObject() && !allObjs.append(vp))
+ return false;
+
+ return true;
+}
+
+bool
+JSStructuredCloneReader::readHeader()
+{
+ uint32_t tag, data;
+ if (!in.getPair(&tag, &data))
+ return in.reportTruncated();
+
+ if (tag != SCTAG_HEADER) {
+ // Old structured clone buffer. We must have read it from disk or
+ // somewhere, so we can assume it's scope-compatible.
+ return true;
+ }
+
+ MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+ if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) &&
+ data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) &&
+ data != uint32_t(JS::StructuredCloneScope::DifferentProcess))
+ {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "invalid structured clone scope");
+ return false;
+ }
+ storedScope = JS::StructuredCloneScope(data);
+ if (storedScope < allowedScope) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "incompatible structured clone scope");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+JSStructuredCloneReader::readTransferMap()
+{
+ JSContext* cx = context();
+ auto headerPos = in.tell();
+
+ uint32_t tag, data;
+ if (!in.getPair(&tag, &data))
+ return in.reportTruncated();
+
+ if (tag != SCTAG_TRANSFER_MAP_HEADER || TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+ return true;
+
+ uint64_t numTransferables;
+ MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+ if (!in.read(&numTransferables))
+ return false;
+
+ for (uint64_t i = 0; i < numTransferables; i++) {
+ auto pos = in.tell();
+
+ if (!in.readPair(&tag, &data))
+ return false;
+
+ MOZ_ASSERT(tag != SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+ RootedObject obj(cx);
+
+ void* content;
+ if (!in.readPtr(&content))
+ return false;
+
+ uint64_t extraData;
+ if (!in.read(&extraData))
+ return false;
+
+ if (tag == SCTAG_TRANSFER_MAP_ARRAY_BUFFER) {
+ if (storedScope == JS::StructuredCloneScope::DifferentProcess) {
+ // Transferred ArrayBuffers in a DifferentProcess clone buffer
+ // are treated as if they weren't Transferred at all.
+ continue;
+ }
+
+ size_t nbytes = extraData;
+ MOZ_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA ||
+ data == JS::SCTAG_TMO_MAPPED_DATA);
+ if (data == JS::SCTAG_TMO_ALLOC_DATA)
+ obj = JS_NewArrayBufferWithContents(cx, nbytes, content);
+ else if (data == JS::SCTAG_TMO_MAPPED_DATA)
+ obj = JS_NewMappedArrayBufferWithContents(cx, nbytes, content);
+ } else if (tag == SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER) {
+ auto savedPos = in.tell();
+ auto guard = mozilla::MakeScopeExit([&] {
+ in.seekTo(savedPos);
+ });
+ in.seekTo(pos);
+ in.seekBy(static_cast<size_t>(extraData));
+
+ uint32_t tag, data;
+ if (!in.readPair(&tag, &data))
+ return false;
+ MOZ_ASSERT(tag == SCTAG_ARRAY_BUFFER_OBJECT);
+ RootedValue val(cx);
+ if (!readArrayBuffer(data, &val))
+ return false;
+ obj = &val.toObject();
+ } else {
+ if (!callbacks || !callbacks->readTransfer) {
+ ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
+ return false;
+ }
+ if (!callbacks->readTransfer(cx, this, tag, content, extraData, closure, &obj))
+ return false;
+ MOZ_ASSERT(obj);
+ MOZ_ASSERT(!cx->isExceptionPending());
+ }
+
+ // On failure, the buffer will still own the data (since its ownership
+ // will not get set to SCTAG_TMO_UNOWNED), so the data will be freed by
+ // DiscardTransferables.
+ if (!obj)
+ return false;
+
+ // Mark the SCTAG_TRANSFER_MAP_* entry as no longer owned by the input
+ // buffer.
+ pos.write(PairToUInt64(tag, JS::SCTAG_TMO_UNOWNED));
+ MOZ_ASSERT(!pos.done());
+
+ if (!allObjs.append(ObjectValue(*obj)))
+ return false;
+ }
+
+ // Mark the whole transfer map as consumed.
+#ifdef DEBUG
+ SCInput::getPair(headerPos.peek(), &tag, &data);
+ MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_HEADER);
+ MOZ_ASSERT(TransferableMapHeader(data) != SCTAG_TM_TRANSFERRED);
+#endif
+ headerPos.write(PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED));
+
+ return true;
+}
+
+JSObject*
+JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag)
+{
+ RootedSavedFrame savedFrame(context(), SavedFrame::create(context()));
+ if (!savedFrame)
+ return nullptr;
+
+ JSPrincipals* principals;
+ if (principalsTag == SCTAG_JSPRINCIPALS) {
+ if (!context()->runtime()->readPrincipals) {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_UNSUPPORTED_TYPE);
+ return nullptr;
+ }
+
+ if (!context()->runtime()->readPrincipals(context(), this, &principals))
+ return nullptr;
+ } else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_SYSTEM) {
+ principals = &ReconstructedSavedFramePrincipals::IsSystem;
+ principals->refcount++;
+ } else if (principalsTag == SCTAG_RECONSTRUCTED_SAVED_FRAME_PRINCIPALS_IS_NOT_SYSTEM) {
+ principals = &ReconstructedSavedFramePrincipals::IsNotSystem;
+ principals->refcount++;
+ } else if (principalsTag == SCTAG_NULL_JSPRINCIPALS) {
+ principals = nullptr;
+ } else {
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ "bad SavedFrame principals");
+ return nullptr;
+ }
+ savedFrame->initPrincipalsAlreadyHeld(principals);
+
+ RootedValue source(context());
+ if (!startRead(&source) || !source.isString())
+ return nullptr;
+ auto atomSource = AtomizeString(context(), source.toString());
+ if (!atomSource)
+ return nullptr;
+ savedFrame->initSource(atomSource);
+
+ RootedValue lineVal(context());
+ uint32_t line;
+ if (!startRead(&lineVal) || !lineVal.isNumber() || !ToUint32(context(), lineVal, &line))
+ return nullptr;
+ savedFrame->initLine(line);
+
+ RootedValue columnVal(context());
+ uint32_t column;
+ if (!startRead(&columnVal) || !columnVal.isNumber() || !ToUint32(context(), columnVal, &column))
+ return nullptr;
+ savedFrame->initColumn(column);
+
+ RootedValue name(context());
+ if (!startRead(&name) || !(name.isString() || name.isNull()))
+ return nullptr;
+ JSAtom* atomName = nullptr;
+ if (name.isString()) {
+ atomName = AtomizeString(context(), name.toString());
+ if (!atomName)
+ return nullptr;
+ }
+ savedFrame->initFunctionDisplayName(atomName);
+
+ RootedValue cause(context());
+ if (!startRead(&cause) || !(cause.isString() || cause.isNull()))
+ return nullptr;
+ JSAtom* atomCause = nullptr;
+ if (cause.isString()) {
+ atomCause = AtomizeString(context(), cause.toString());
+ if (!atomCause)
+ return nullptr;
+ }
+ savedFrame->initAsyncCause(atomCause);
+
+ return savedFrame;
+}
+
+// Perform the whole recursive reading procedure.
+bool
+JSStructuredCloneReader::read(MutableHandleValue vp)
+{
+ if (!readHeader())
+ return false;
+
+ if (!readTransferMap())
+ return false;
+
+ // Start out by reading in the main object and pushing it onto the 'objs'
+ // stack. The data related to this object and its descendants extends from
+ // here to the SCTAG_END_OF_KEYS at the end of the stream.
+ if (!startRead(vp))
+ return false;
+
+ // Stop when the stack shows that all objects have been read.
+ while (objs.length() != 0) {
+ // What happens depends on the top obj on the objs stack.
+ RootedObject obj(context(), &objs.back().toObject());
+
+ uint32_t tag, data;
+ if (!in.getPair(&tag, &data))
+ return false;
+
+ if (tag == SCTAG_END_OF_KEYS) {
+ // Pop the current obj off the stack, since we are done with it and
+ // its children.
+ MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+ objs.popBack();
+ continue;
+ }
+
+ // The input stream contains a sequence of "child" values, whose
+ // interpretation depends on the type of obj. These values can be
+ // anything, and startRead() will push onto 'objs' for any non-leaf
+ // value (i.e., anything that may contain children).
+ //
+ // startRead() will allocate the (empty) object, but note that when
+ // startRead() returns, 'key' is not yet initialized with any of its
+ // properties. Those will be filled in by returning to the head of this
+ // loop, processing the first child obj, and continuing until all
+ // children have been fully created.
+ //
+ // Note that this means the ordering in the stream is a little funky
+ // for things like Map. See the comment above startWrite() for an
+ // example.
+ RootedValue key(context());
+ if (!startRead(&key))
+ return false;
+
+ if (key.isNull() &&
+ !(obj->is<MapObject>() || obj->is<SetObject>() || obj->is<SavedFrame>()))
+ {
+ // Backwards compatibility: Null formerly indicated the end of
+ // object properties.
+ objs.popBack();
+ continue;
+ }
+
+ // Set object: the values between obj header (from startRead()) and
+ // SCTAG_END_OF_KEYS are all interpreted as values to add to the set.
+ if (obj->is<SetObject>()) {
+ if (!SetObject::add(context(), obj, key))
+ return false;
+ continue;
+ }
+
+ // SavedFrame object: there is one following value, the parent
+ // SavedFrame, which is either null or another SavedFrame object.
+ if (obj->is<SavedFrame>()) {
+ SavedFrame* parentFrame;
+ if (key.isNull())
+ parentFrame = nullptr;
+ else if (key.isObject() && key.toObject().is<SavedFrame>())
+ parentFrame = &key.toObject().as<SavedFrame>();
+ else
+ return false;
+
+ obj->as<SavedFrame>().initParent(parentFrame);
+ continue;
+ }
+
+ // Everything else uses a series of key,value,key,value,... Value
+ // objects.
+ RootedValue val(context());
+ if (!startRead(&val))
+ return false;
+
+ if (obj->is<MapObject>()) {
+ // For a Map, store those <key,value> pairs in the contained map
+ // data structure.
+ if (!MapObject::set(context(), obj, key, val))
+ return false;
+ } else {
+ // For any other Object, interpret them as plain properties.
+ RootedId id(context());
+ if (!ValueToId<CanGC>(context(), key, &id))
+ return false;
+
+ if (!DefineProperty(context(), obj, id, val))
+ return false;
+ }
+ }
+
+ allObjs.clear();
+
+ return true;
+}
+
+using namespace js;
+
+JS_PUBLIC_API(bool)
+JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& buf,
+ uint32_t version, JS::StructuredCloneScope scope,
+ MutableHandleValue vp,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+
+ if (version > JS_STRUCTURED_CLONE_VERSION) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_BAD_CLONE_VERSION);
+ return false;
+ }
+ const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
+ return ReadStructuredClone(cx, buf, scope, vp, callbacks, closure);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteStructuredClone(JSContext* cx, HandleValue value, JSStructuredCloneData* bufp,
+ JS::StructuredCloneScope scope,
+ JS::CloneDataPolicy cloneDataPolicy,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure, HandleValue transferable)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+ assertSameCompartment(cx, value);
+
+ const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
+ return WriteStructuredClone(cx, value, bufp, scope, cloneDataPolicy, callbacks, closure,
+ transferable);
+}
+
+JS_PUBLIC_API(bool)
+JS_StructuredCloneHasTransferables(JSStructuredCloneData& data,
+ bool* hasTransferable)
+{
+ *hasTransferable = StructuredCloneHasTransferObjects(data);
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure)
+{
+ AssertHeapIsIdle(cx);
+ CHECK_REQUEST(cx);
+
+ // Strings are associated with zones, not compartments,
+ // so we copy the string by wrapping it.
+ if (value.isString()) {
+ RootedString strValue(cx, value.toString());
+ if (!cx->compartment()->wrap(cx, &strValue)) {
+ return false;
+ }
+ vp.setString(strValue);
+ return true;
+ }
+
+ const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
+
+ JSAutoStructuredCloneBuffer buf(JS::StructuredCloneScope::SameProcessSameThread, callbacks, closure);
+ {
+ // If we use Maybe<AutoCompartment> here, G++ can't tell that the
+ // destructor is only called when Maybe::construct was called, and
+ // we get warnings about using uninitialized variables.
+ if (value.isObject()) {
+ AutoCompartment ac(cx, &value.toObject());
+ if (!buf.write(cx, value, callbacks, closure))
+ return false;
+ } else {
+ if (!buf.write(cx, value, callbacks, closure))
+ return false;
+ }
+ }
+
+ return buf.read(cx, vp, callbacks, closure);
+}
+
+JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
+ : scope_(other.scope_)
+{
+ data_.ownTransferables_ = other.data_.ownTransferables_;
+ other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
+}
+
+JSAutoStructuredCloneBuffer&
+JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
+{
+ MOZ_ASSERT(&other != this);
+ MOZ_ASSERT(scope_ == other.scope_);
+ clear();
+ data_.ownTransferables_ = other.data_.ownTransferables_;
+ other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
+ return *this;
+}
+
+void
+JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* optionalClosure)
+{
+ if (!data_.Size())
+ return;
+
+ const JSStructuredCloneCallbacks* callbacks =
+ optionalCallbacks ? optionalCallbacks : data_.callbacks_;
+ void* closure = optionalClosure ? optionalClosure : data_.closure_;
+
+ if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
+ DiscardTransferables(data_, callbacks, closure);
+ data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
+ data_.Clear();
+ version_ = 0;
+}
+
+bool
+JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t version,
+ const JSStructuredCloneCallbacks* callbacks,
+ void* closure)
+{
+ // transferable objects cannot be copied
+ if (StructuredCloneHasTransferObjects(srcData))
+ return false;
+
+ clear();
+
+ auto iter = srcData.Iter();
+ while (!iter.Done()) {
+ data_.WriteBytes(iter.Data(), iter.RemainingInSegment());
+ iter.Advance(srcData, iter.RemainingInSegment());
+ }
+
+ version_ = version;
+ data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
+ return true;
+}
+
+void
+JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version,
+ const JSStructuredCloneCallbacks* callbacks,
+ void* closure)
+{
+ clear();
+ data_ = Move(data);
+ version_ = version;
+ data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
+}
+
+void
+JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versionp,
+ const JSStructuredCloneCallbacks** callbacks,
+ void** closure)
+{
+ if (versionp)
+ *versionp = version_;
+ if (callbacks)
+ *callbacks = data_.callbacks_;
+ if (closure)
+ *closure = data_.closure_;
+ *data = Move(data_);
+
+ version_ = 0;
+ data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
+}
+
+bool
+JSAutoStructuredCloneBuffer::read(JSContext* cx, MutableHandleValue vp,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure)
+{
+ MOZ_ASSERT(cx);
+ return !!JS_ReadStructuredClone(cx, data_, version_, scope_, vp,
+ optionalCallbacks, closure);
+}
+
+bool
+JSAutoStructuredCloneBuffer::write(JSContext* cx, HandleValue value,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure)
+{
+ HandleValue transferable = UndefinedHandleValue;
+ return write(cx, value, transferable, JS::CloneDataPolicy().denySharedArrayBuffer(), optionalCallbacks, closure);
+}
+
+bool
+JSAutoStructuredCloneBuffer::write(JSContext* cx, HandleValue value,
+ HandleValue transferable, JS::CloneDataPolicy cloneDataPolicy,
+ const JSStructuredCloneCallbacks* optionalCallbacks,
+ void* closure)
+{
+ clear();
+ bool ok = JS_WriteStructuredClone(cx, value, &data_,
+ scope_, cloneDataPolicy,
+ optionalCallbacks, closure,
+ transferable);
+
+ if (ok) {
+ data_.ownTransferables_ = OwnTransferablePolicy::OwnsTransferablesIfAny;
+ } else {
+ version_ = JS_STRUCTURED_CLONE_VERSION;
+ data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
+ }
+ return ok;
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2)
+{
+ return r->input().readPair((uint32_t*) p1, (uint32_t*) p2);
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadBytes(JSStructuredCloneReader* r, void* p, size_t len)
+{
+ return r->input().readBytes(p, len);
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadTypedArray(JSStructuredCloneReader* r, MutableHandleValue vp)
+{
+ uint32_t tag, nelems;
+ if (!r->input().readPair(&tag, &nelems))
+ return false;
+ if (tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
+ return r->readTypedArray(TagToV1ArrayType(tag), nelems, vp, true);
+ } else if (tag == SCTAG_TYPED_ARRAY_OBJECT) {
+ uint64_t arrayType;
+ if (!r->input().read(&arrayType))
+ return false;
+ return r->readTypedArray(arrayType, nelems, vp);
+ } else {
+ JS_ReportErrorNumberASCII(r->context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
+ "expected type array");
+ return false;
+ }
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, uint32_t data)
+{
+ return w->output().writePair(tag, data);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len)
+{
+ return w->output().writeBytes(p, len);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteString(JSStructuredCloneWriter* w, HandleString str)
+{
+ return w->writeString(SCTAG_STRING, str);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v)
+{
+ MOZ_ASSERT(v.isObject());
+ assertSameCompartment(w->context(), v);
+ RootedObject obj(w->context(), &v.toObject());
+ return w->writeTypedArray(obj);
+}
+
+JS_PUBLIC_API(bool)
+JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj)
+{
+ w->memory.remove(w->memory.lookup(obj));
+
+ return true;
+}
+
+JS_PUBLIC_API(JS::StructuredCloneScope)
+JS_GetStructuredCloneScope(JSStructuredCloneWriter* w)
+{
+ return w->cloneScope();
+}
diff --git a/js/src/vm/Symbol.cpp b/js/src/vm/Symbol.cpp
new file mode 100644
index 000000000..59903c38a
--- /dev/null
+++ b/js/src/vm/Symbol.cpp
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Symbol.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+
+#include "builtin/SymbolObject.h"
+#include "gc/Allocator.h"
+#include "gc/Rooting.h"
+#include "vm/StringBuffer.h"
+
+#include "jscompartmentinlines.h"
+
+using JS::Symbol;
+using namespace js;
+
+Symbol*
+Symbol::newInternal(ExclusiveContext* cx, JS::SymbolCode code, uint32_t hash, JSAtom* description,
+ AutoLockForExclusiveAccess& lock)
+{
+ MOZ_ASSERT(cx->compartment() == cx->atomsCompartment(lock));
+
+ // Following js::AtomizeString, we grudgingly forgo last-ditch GC here.
+ Symbol* p = Allocate<JS::Symbol, NoGC>(cx);
+ if (!p) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ return new (p) Symbol(code, hash, description);
+}
+
+Symbol*
+Symbol::new_(ExclusiveContext* cx, JS::SymbolCode code, JSString* description)
+{
+ JSAtom* atom = nullptr;
+ if (description) {
+ atom = AtomizeString(cx, description);
+ if (!atom)
+ return nullptr;
+ }
+
+ // Lock to allocate. If symbol allocation becomes a bottleneck, this can
+ // probably be replaced with an assertion that we're on the main thread.
+ AutoLockForExclusiveAccess lock(cx);
+ AutoCompartment ac(cx, cx->atomsCompartment(lock), &lock);
+ return newInternal(cx, code, cx->compartment()->randomHashCode(), atom, lock);
+}
+
+Symbol*
+Symbol::for_(js::ExclusiveContext* cx, HandleString description)
+{
+ JSAtom* atom = AtomizeString(cx, description);
+ if (!atom)
+ return nullptr;
+
+ AutoLockForExclusiveAccess lock(cx);
+
+ SymbolRegistry& registry = cx->symbolRegistry(lock);
+ SymbolRegistry::AddPtr p = registry.lookupForAdd(atom);
+ if (p)
+ return *p;
+
+ AutoCompartment ac(cx, cx->atomsCompartment(lock), &lock);
+ Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom->hash(), atom, lock);
+ if (!sym)
+ return nullptr;
+
+ // p is still valid here because we have held the lock since the
+ // lookupForAdd call, and newInternal can't GC.
+ if (!registry.add(p, sym)) {
+ // SystemAllocPolicy does not report OOM.
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ return sym;
+}
+
+#ifdef DEBUG
+void
+Symbol::dump(FILE* fp)
+{
+ if (isWellKnownSymbol()) {
+ // All the well-known symbol names are ASCII.
+ description_->dumpCharsNoNewline(fp);
+ } else if (code_ == SymbolCode::InSymbolRegistry || code_ == SymbolCode::UniqueSymbol) {
+ fputs(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" : "Symbol(", fp);
+
+ if (description_)
+ description_->dumpCharsNoNewline(fp);
+ else
+ fputs("undefined", fp);
+
+ fputc(')', fp);
+
+ if (code_ == SymbolCode::UniqueSymbol)
+ fprintf(fp, "@%p", (void*) this);
+ } else {
+ fprintf(fp, "<Invalid Symbol code=%u>", unsigned(code_));
+ }
+}
+#endif // DEBUG
+
+bool
+js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, MutableHandleValue result)
+{
+ // steps 2-5
+ StringBuffer sb(cx);
+ if (!sb.append("Symbol("))
+ return false;
+ RootedString str(cx, sym->description());
+ if (str) {
+ if (!sb.append(str))
+ return false;
+ }
+ if (!sb.append(')'))
+ return false;
+
+ // step 6
+ str = sb.finishString();
+ if (!str)
+ return false;
+ result.setString(str);
+ return true;
+}
+
+bool
+js::IsSymbolOrSymbolWrapper(const Value& v)
+{
+ return v.isSymbol() || (v.isObject() && v.toObject().is<SymbolObject>());
+}
+
+JS::Symbol*
+js::ToSymbolPrimitive(const Value& v)
+{
+ MOZ_ASSERT(IsSymbolOrSymbolWrapper(v));
+ return v.isSymbol() ? v.toSymbol() : v.toObject().as<SymbolObject>().unbox();
+}
+
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<JS::Symbol>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ // If we start allocating symbols in the nursery, we will need to update
+ // this method.
+ MOZ_ASSERT(get().isTenured());
+ return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+}
diff --git a/js/src/vm/Symbol.h b/js/src/vm/Symbol.h
new file mode 100644
index 000000000..2872fa3c6
--- /dev/null
+++ b/js/src/vm/Symbol.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Symbol_h
+#define vm_Symbol_h
+
+#include "mozilla/Attributes.h"
+
+#include <stdio.h>
+
+#include "jsalloc.h"
+#include "jsapi.h"
+
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "js/GCHashTable.h"
+#include "js/RootingAPI.h"
+#include "js/TypeDecls.h"
+#include "js/Utility.h"
+#include "vm/String.h"
+
+namespace js {
+class AutoLockForExclusiveAccess;
+} // namespace js
+
+namespace JS {
+
+class Symbol : public js::gc::TenuredCell
+{
+ private:
+ SymbolCode code_;
+
+ // Each Symbol gets its own hash code so that we don't have to use
+ // addresses as hash codes (a security hazard).
+ js::HashNumber hash_;
+
+ JSAtom* description_;
+
+ // The minimum allocation size is sizeof(JSString): 16 bytes on 32-bit
+ // architectures and 24 bytes on 64-bit. A size_t of padding makes Symbol
+ // the minimum size on both.
+ size_t unused_;
+
+ Symbol(SymbolCode code, js::HashNumber hash, JSAtom* desc)
+ : code_(code), hash_(hash), description_(desc)
+ {
+ // Silence warnings about unused_ being... unused.
+ (void)unused_;
+ }
+
+ Symbol(const Symbol&) = delete;
+ void operator=(const Symbol&) = delete;
+
+ static Symbol*
+ newInternal(js::ExclusiveContext* cx, SymbolCode code, js::HashNumber hash,
+ JSAtom* description, js::AutoLockForExclusiveAccess& lock);
+
+ public:
+ static Symbol* new_(js::ExclusiveContext* cx, SymbolCode code, JSString* description);
+ static Symbol* for_(js::ExclusiveContext* cx, js::HandleString description);
+
+ JSAtom* description() const { return description_; }
+ SymbolCode code() const { return code_; }
+ js::HashNumber hash() const { return hash_; }
+
+ bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::Symbol;
+ inline void traceChildren(JSTracer* trc) {
+ if (description_)
+ js::TraceManuallyBarrieredEdge(trc, &description_, "description");
+ }
+ inline void finalize(js::FreeOp*) {}
+
+ static MOZ_ALWAYS_INLINE void writeBarrierPre(Symbol* thing) {
+ if (thing && !thing->isWellKnownSymbol())
+ thing->asTenured().writeBarrierPre(thing);
+ }
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(this);
+ }
+
+#ifdef DEBUG
+ void dump(FILE* fp = stderr);
+#endif
+};
+
+} /* namespace JS */
+
+namespace js {
+
+/* Hash policy used by the SymbolRegistry. */
+struct HashSymbolsByDescription
+{
+ typedef JS::Symbol* Key;
+ typedef JSAtom* Lookup;
+
+ static HashNumber hash(Lookup l) {
+ return HashNumber(l->hash());
+ }
+ static bool match(Key sym, Lookup l) {
+ return sym->description() == l;
+ }
+};
+
+/*
+ * The runtime-wide symbol registry, used to implement Symbol.for().
+ *
+ * ES6 draft rev 25 (2014 May 22) calls this the GlobalSymbolRegistry List. In
+ * our implementation, it is not global. There is one per JSRuntime. The
+ * symbols in the symbol registry, like all symbols, are allocated in the atoms
+ * compartment and can be directly referenced from any compartment. They are
+ * never shared across runtimes.
+ *
+ * The memory management strategy here is modeled after js::AtomSet. It's like
+ * a WeakSet. The registry itself does not keep any symbols alive; when a
+ * symbol in the registry is collected, the registry entry is removed. No GC
+ * nondeterminism is exposed to scripts, because there is no API for
+ * enumerating the symbol registry, querying its size, etc.
+ */
+class SymbolRegistry : public GCHashSet<ReadBarrieredSymbol,
+ HashSymbolsByDescription,
+ SystemAllocPolicy>
+{
+ public:
+ SymbolRegistry() {}
+};
+
+} /* namespace js */
+
+namespace js {
+
+// ES6 rev 27 (2014 Aug 24) 19.4.3.3
+bool
+SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym, JS::MutableHandleValue result);
+
+bool
+IsSymbolOrSymbolWrapper(const JS::Value& v);
+
+JS::Symbol*
+ToSymbolPrimitive(const JS::Value& v);
+
+} /* namespace js */
+
+#endif /* vm_Symbol_h */
diff --git a/js/src/vm/TaggedProto.cpp b/js/src/vm/TaggedProto.cpp
new file mode 100644
index 000000000..8bc99d2f2
--- /dev/null
+++ b/js/src/vm/TaggedProto.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TaggedProto.h"
+
+#include "jsfun.h"
+#include "jsobj.h"
+
+#include "gc/Barrier.h"
+#include "gc/Zone.h"
+
+#include "vm/Caches-inl.h"
+
+namespace js {
+
+/* static */ void
+InternalBarrierMethods<TaggedProto>::preBarrier(TaggedProto& proto)
+{
+ InternalBarrierMethods<JSObject*>::preBarrier(proto.toObjectOrNull());
+}
+
+/* static */ void
+InternalBarrierMethods<TaggedProto>::postBarrier(TaggedProto* vp, TaggedProto prev,
+ TaggedProto next)
+{
+ JSObject* prevObj = prev.isObject() ? prev.toObject() : nullptr;
+ JSObject* nextObj = next.isObject() ? next.toObject() : nullptr;
+ InternalBarrierMethods<JSObject*>::postBarrier(reinterpret_cast<JSObject**>(vp), prevObj,
+ nextObj);
+}
+
+/* static */ void
+InternalBarrierMethods<TaggedProto>::readBarrier(const TaggedProto& proto)
+{
+ InternalBarrierMethods<JSObject*>::readBarrier(proto.toObjectOrNull());
+}
+
+} // namespace js
+
+js::HashNumber
+js::TaggedProto::hashCode() const
+{
+ return Zone::UniqueIdToHash(uniqueId());
+}
+
+bool
+js::TaggedProto::hasUniqueId() const
+{
+ if (!isObject())
+ return true;
+ JSObject* obj = toObject();
+ return obj->zone()->hasUniqueId(obj);
+}
+
+bool
+js::TaggedProto::ensureUniqueId() const
+{
+ if (!isObject())
+ return true;
+ uint64_t unusedId;
+ JSObject* obj = toObject();
+ return obj->zone()->getUniqueId(obj, &unusedId);
+}
+
+uint64_t
+js::TaggedProto::uniqueId() const
+{
+ if (isDynamic())
+ return uint64_t(1);
+ JSObject* obj = toObjectOrNull();
+ if (!obj)
+ return uint64_t(0);
+ return obj->zone()->getUniqueIdInfallible(obj);
+}
diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h
new file mode 100644
index 000000000..c06affe7b
--- /dev/null
+++ b/js/src/vm/TaggedProto.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_TaggedProto_h
+#define vm_TaggedProto_h
+
+#include "gc/Tracer.h"
+
+namespace js {
+
+// Information about an object prototype, which can be either a particular
+// object, null, or a lazily generated object. The latter is only used by
+// certain kinds of proxies.
+class TaggedProto
+{
+ public:
+ static JSObject * const LazyProto;
+
+ TaggedProto() : proto(nullptr) {}
+ TaggedProto(const TaggedProto& other) : proto(other.proto) {}
+ explicit TaggedProto(JSObject* proto) : proto(proto) {}
+
+ uintptr_t toWord() const { return uintptr_t(proto); }
+
+ bool isDynamic() const {
+ return proto == LazyProto;
+ }
+ bool isObject() const {
+ /* Skip nullptr and LazyProto. */
+ return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
+ }
+ JSObject* toObject() const {
+ MOZ_ASSERT(isObject());
+ return proto;
+ }
+ JSObject* toObjectOrNull() const {
+ MOZ_ASSERT(!proto || isObject());
+ return proto;
+ }
+ JSObject* raw() const { return proto; }
+
+ bool operator ==(const TaggedProto& other) const { return proto == other.proto; }
+ bool operator !=(const TaggedProto& other) const { return proto != other.proto; }
+
+ HashNumber hashCode() const;
+
+ bool hasUniqueId() const;
+ bool ensureUniqueId() const;
+ uint64_t uniqueId() const;
+
+ void trace(JSTracer* trc) {
+ if (isObject())
+ TraceManuallyBarrieredEdge(trc, &proto, "TaggedProto");
+ }
+
+ private:
+ JSObject* proto;
+};
+
+template <>
+struct InternalBarrierMethods<TaggedProto>
+{
+ static void preBarrier(TaggedProto& proto);
+
+ static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
+
+ static void readBarrier(const TaggedProto& proto);
+
+ static bool isMarkableTaggedPointer(TaggedProto proto) {
+ return proto.isObject();
+ }
+
+ static bool isMarkable(TaggedProto proto) {
+ return proto.isObject();
+ }
+};
+
+template<class Outer>
+class TaggedProtoOperations
+{
+ const TaggedProto& value() const {
+ return static_cast<const Outer*>(this)->get();
+ }
+
+ public:
+ uintptr_t toWord() const { return value().toWord(); }
+ inline bool isDynamic() const { return value().isDynamic(); }
+ inline bool isObject() const { return value().isObject(); }
+ inline JSObject* toObject() const { return value().toObject(); }
+ inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
+ JSObject* raw() const { return value().raw(); }
+ HashNumber hashCode() const { return value().hashCode(); }
+ uint64_t uniqueId() const { return value().uniqueId(); }
+};
+
+template <>
+class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto>>
+{};
+
+template <>
+class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto>>
+{};
+
+template <>
+class BarrieredBaseMixins<TaggedProto> : public TaggedProtoOperations<GCPtr<TaggedProto>>
+{};
+
+// If the TaggedProto is a JSObject pointer, convert to that type and call |f|
+// with the pointer. If the TaggedProto is lazy, calls F::defaultValue.
+template <typename F, typename... Args>
+auto
+DispatchTyped(F f, const TaggedProto& proto, Args&&... args)
+ -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
+{
+ if (proto.isObject())
+ return f(proto.toObject(), mozilla::Forward<Args>(args)...);
+ return F::defaultValue(proto);
+}
+
+// Since JSObject pointers are either nullptr or a valid object and since the
+// object layout of TaggedProto is identical to a bare object pointer, we can
+// safely treat a pointer to an already-rooted object (e.g. HandleObject) as a
+// pointer to a TaggedProto.
+inline Handle<TaggedProto>
+AsTaggedProto(HandleObject obj)
+{
+ static_assert(sizeof(JSObject*) == sizeof(TaggedProto),
+ "TaggedProto must be binary compatible with JSObject");
+ return Handle<TaggedProto>::fromMarkedLocation(
+ reinterpret_cast<TaggedProto const*>(obj.address()));
+}
+
+} // namespace js
+
+#endif // vm_TaggedProto_h
diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp
new file mode 100644
index 000000000..69e2cc41d
--- /dev/null
+++ b/js/src/vm/Time.cpp
@@ -0,0 +1,382 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* PR time code. */
+
+#include "vm/Time.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MathAlgorithms.h"
+
+#ifdef SOLARIS
+#define _REENTRANT 1
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "jstypes.h"
+#include "jsutil.h"
+
+#ifdef XP_WIN
+#include <windef.h>
+#include <winbase.h>
+#include <crtdbg.h> /* for _CrtSetReportMode */
+#include <mmsystem.h> /* for timeBegin/EndPeriod */
+#include <stdlib.h> /* for _set_invalid_parameter_handler */
+
+#include "prinit.h"
+
+#endif
+
+#ifdef XP_UNIX
+
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+extern int gettimeofday(struct timeval* tv);
+#endif
+
+#include <sys/time.h>
+
+#endif /* XP_UNIX */
+
+using mozilla::DebugOnly;
+
+#if defined(XP_UNIX)
+int64_t
+PRMJ_Now()
+{
+ struct timeval tv;
+
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+ gettimeofday(&tv);
+#else
+ gettimeofday(&tv, 0);
+#endif /* _SVID_GETTOD */
+
+ return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
+}
+
+#else
+
+// Returns the number of microseconds since the Unix epoch.
+static double
+FileTimeToUnixMicroseconds(const FILETIME& ft)
+{
+ // Get the time in 100ns intervals.
+ int64_t t = (int64_t(ft.dwHighDateTime) << 32) | int64_t(ft.dwLowDateTime);
+
+ // The Windows epoch is around 1600. The Unix epoch is around 1970.
+ // Subtract the difference.
+ static const int64_t TimeToEpochIn100ns = 0x19DB1DED53E8000;
+ t -= TimeToEpochIn100ns;
+
+ // Divide by 10 to convert to microseconds.
+ return double(t) * 0.1;
+}
+
+struct CalibrationData {
+ double freq; /* The performance counter frequency */
+ double offset; /* The low res 'epoch' */
+ double timer_offset; /* The high res 'epoch' */
+
+ bool calibrated;
+
+ CRITICAL_SECTION data_lock;
+};
+
+static CalibrationData calibration = { 0 };
+
+static void
+NowCalibrate()
+{
+ MOZ_ASSERT(calibration.freq > 0);
+
+ // By wrapping a timeBegin/EndPeriod pair of calls around this loop,
+ // the loop seems to take much less time (1 ms vs 15ms) on Vista.
+ timeBeginPeriod(1);
+ FILETIME ft, ftStart;
+ GetSystemTimeAsFileTime(&ftStart);
+ do {
+ GetSystemTimeAsFileTime(&ft);
+ } while (memcmp(&ftStart, &ft, sizeof(ft)) == 0);
+ timeEndPeriod(1);
+
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+
+ calibration.offset = FileTimeToUnixMicroseconds(ft);
+ calibration.timer_offset = double(now.QuadPart);
+ calibration.calibrated = true;
+}
+
+static const unsigned DataLockSpinCount = 4096;
+
+static void (WINAPI* pGetSystemTimePreciseAsFileTime)(LPFILETIME) = nullptr;
+
+void
+PRMJ_NowInit()
+{
+ memset(&calibration, 0, sizeof(calibration));
+
+ // According to the documentation, QueryPerformanceFrequency will never
+ // return false or return a non-zero frequency on systems that run
+ // Windows XP or later. Also, the frequency is fixed so we only have to
+ // query it once.
+ LARGE_INTEGER liFreq;
+ DebugOnly<BOOL> res = QueryPerformanceFrequency(&liFreq);
+ MOZ_ASSERT(res);
+ calibration.freq = double(liFreq.QuadPart);
+ MOZ_ASSERT(calibration.freq > 0.0);
+
+ InitializeCriticalSectionAndSpinCount(&calibration.data_lock, DataLockSpinCount);
+
+ // Windows 8 has a new API function we can use.
+ if (HMODULE h = GetModuleHandle("kernel32.dll")) {
+ pGetSystemTimePreciseAsFileTime =
+ (void (WINAPI*)(LPFILETIME))GetProcAddress(h, "GetSystemTimePreciseAsFileTime");
+ }
+}
+
+void
+PRMJ_NowShutdown()
+{
+ DeleteCriticalSection(&calibration.data_lock);
+}
+
+#define MUTEX_LOCK(m) EnterCriticalSection(m)
+#define MUTEX_UNLOCK(m) LeaveCriticalSection(m)
+#define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c))
+
+// Please see bug 363258 for why the win32 timing code is so complex.
+int64_t
+PRMJ_Now()
+{
+ if (pGetSystemTimePreciseAsFileTime) {
+ // Windows 8 has a new API function that does all the work.
+ FILETIME ft;
+ pGetSystemTimePreciseAsFileTime(&ft);
+ return int64_t(FileTimeToUnixMicroseconds(ft));
+ }
+
+ bool calibrated = false;
+ bool needsCalibration = !calibration.calibrated;
+ double cachedOffset = 0.0;
+ while (true) {
+ if (needsCalibration) {
+ MUTEX_LOCK(&calibration.data_lock);
+
+ // Recalibrate only if no one else did before us.
+ if (calibration.offset == cachedOffset) {
+ // Since calibration can take a while, make any other
+ // threads immediately wait.
+ MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
+
+ NowCalibrate();
+
+ calibrated = true;
+
+ // Restore spin count.
+ MUTEX_SETSPINCOUNT(&calibration.data_lock, DataLockSpinCount);
+ }
+
+ MUTEX_UNLOCK(&calibration.data_lock);
+ }
+
+ // Calculate a low resolution time.
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ double lowresTime = FileTimeToUnixMicroseconds(ft);
+
+ // Grab high resolution time.
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ double highresTimerValue = double(now.QuadPart);
+
+ MUTEX_LOCK(&calibration.data_lock);
+ double highresTime = calibration.offset +
+ PRMJ_USEC_PER_SEC * (highresTimerValue - calibration.timer_offset) / calibration.freq;
+ cachedOffset = calibration.offset;
+ MUTEX_UNLOCK(&calibration.data_lock);
+
+ // Assume the NT kernel ticks every 15.6 ms. Unfortunately there's no
+ // good way to determine this (NtQueryTimerResolution is an undocumented
+ // API), but 15.6 ms seems to be the max possible value. Hardcoding 15.6
+ // means we'll recalibrate if the highres and lowres timers diverge by
+ // more than 30 ms.
+ static const double KernelTickInMicroseconds = 15625.25;
+
+ // Check for clock skew.
+ double diff = lowresTime - highresTime;
+
+ // For some reason that I have not determined, the skew can be
+ // up to twice a kernel tick. This does not seem to happen by
+ // itself, but I have only seen it triggered by another program
+ // doing some kind of file I/O. The symptoms are a negative diff
+ // followed by an equally large positive diff.
+ if (mozilla::Abs(diff) <= 2 * KernelTickInMicroseconds) {
+ // No detectable clock skew.
+ return int64_t(highresTime);
+ }
+
+ if (calibrated) {
+ // If we already calibrated once this instance, and the
+ // clock is still skewed, then either the processor(s) are
+ // wildly changing clockspeed or the system is so busy that
+ // we get switched out for long periods of time. In either
+ // case, it would be infeasible to make use of high
+ // resolution results for anything, so let's resort to old
+ // behavior for this call. It's possible that in the
+ // future, the user will want the high resolution timer, so
+ // we don't disable it entirely.
+ return int64_t(lowresTime);
+ }
+
+ // It is possible that when we recalibrate, we will return a
+ // value less than what we have returned before; this is
+ // unavoidable. We cannot tell the different between a
+ // faulty QueryPerformanceCounter implementation and user
+ // changes to the operating system time. Since we must
+ // respect user changes to the operating system time, we
+ // cannot maintain the invariant that Date.now() never
+ // decreases; the old implementation has this behavior as
+ // well.
+ needsCalibration = true;
+ }
+}
+#endif
+
+#ifdef XP_WIN
+static void
+PRMJ_InvalidParameterHandler(const wchar_t* expression,
+ const wchar_t* function,
+ const wchar_t* file,
+ unsigned int line,
+ uintptr_t pReserved)
+{
+ /* empty */
+}
+#endif
+
+/* Format a time value into a buffer. Same semantics as strftime() */
+size_t
+PRMJ_FormatTime(char* buf, int buflen, const char* fmt, PRMJTime* prtm)
+{
+ size_t result = 0;
+#if defined(XP_UNIX) || defined(XP_WIN)
+ struct tm a;
+ int fake_tm_year = 0;
+#ifdef XP_WIN
+ _invalid_parameter_handler oldHandler;
+ int oldReportMode;
+#endif
+
+ memset(&a, 0, sizeof(struct tm));
+
+ a.tm_sec = prtm->tm_sec;
+ a.tm_min = prtm->tm_min;
+ a.tm_hour = prtm->tm_hour;
+ a.tm_mday = prtm->tm_mday;
+ a.tm_mon = prtm->tm_mon;
+ a.tm_wday = prtm->tm_wday;
+
+ /*
+ * On systems where |struct tm| has members tm_gmtoff and tm_zone, we
+ * must fill in those values, or else strftime will return wrong results
+ * (e.g., bug 511726, bug 554338).
+ */
+#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TM_ZONE_TM_GMTOFF)
+ {
+ /*
+ * Fill out |td| to the time represented by |prtm|, leaving the
+ * timezone fields zeroed out. localtime_r will then fill in the
+ * timezone fields for that local time according to the system's
+ * timezone parameters.
+ */
+ struct tm td;
+ memset(&td, 0, sizeof(td));
+ td.tm_sec = prtm->tm_sec;
+ td.tm_min = prtm->tm_min;
+ td.tm_hour = prtm->tm_hour;
+ td.tm_mday = prtm->tm_mday;
+ td.tm_mon = prtm->tm_mon;
+ td.tm_wday = prtm->tm_wday;
+ td.tm_year = prtm->tm_year - 1900;
+ td.tm_yday = prtm->tm_yday;
+ td.tm_isdst = prtm->tm_isdst;
+ time_t t = mktime(&td);
+ localtime_r(&t, &td);
+
+ a.tm_gmtoff = td.tm_gmtoff;
+ a.tm_zone = td.tm_zone;
+ }
+#endif
+
+ /*
+ * Years before 1900 and after 9999 cause strftime() to abort on Windows.
+ * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then
+ * replace matching substrings in the strftime() result with the real year.
+ * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit
+ * year formats (%y) work correctly (since we won't find the fake year
+ * in that case).
+ * e.g. new Date(1873, 0).toLocaleFormat('%Y %y') => "1873 73"
+ * See bug 327869.
+ */
+#define FAKE_YEAR_BASE 9900
+ if (prtm->tm_year < 1900 || prtm->tm_year > 9999) {
+ fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100;
+ a.tm_year = fake_tm_year - 1900;
+ }
+ else {
+ a.tm_year = prtm->tm_year - 1900;
+ }
+ a.tm_yday = prtm->tm_yday;
+ a.tm_isdst = prtm->tm_isdst;
+
+ /*
+ * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
+ * are null. This doesn't quite work, though - the timezone is off by
+ * tzoff + dst. (And mktime seems to return -1 for the exact dst
+ * changeover time.)
+ */
+
+#ifdef XP_WIN
+ oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler);
+ oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);
+#endif
+
+ result = strftime(buf, buflen, fmt, &a);
+
+#ifdef XP_WIN
+ _set_invalid_parameter_handler(oldHandler);
+ _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
+#endif
+
+ if (fake_tm_year && result) {
+ char real_year[16];
+ char fake_year[16];
+ size_t real_year_len;
+ size_t fake_year_len;
+ char* p;
+
+ sprintf(real_year, "%d", prtm->tm_year);
+ real_year_len = strlen(real_year);
+ sprintf(fake_year, "%d", fake_tm_year);
+ fake_year_len = strlen(fake_year);
+
+ /* Replace the fake year in the result with the real year. */
+ for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) {
+ size_t new_result = result + real_year_len - fake_year_len;
+ if ((int)new_result >= buflen) {
+ return 0;
+ }
+ memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len));
+ memcpy(p, real_year, real_year_len);
+ result = new_result;
+ *(buf + result) = '\0';
+ }
+ }
+#endif
+ return result;
+}
diff --git a/js/src/vm/Time.h b/js/src/vm/Time.h
new file mode 100644
index 000000000..36122b9fe
--- /dev/null
+++ b/js/src/vm/Time.h
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Time_h
+#define vm_Time_h
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Broken down form of 64 bit time value.
+ */
+struct PRMJTime {
+ int32_t tm_usec; /* microseconds of second (0-999999) */
+ int8_t tm_sec; /* seconds of minute (0-59) */
+ int8_t tm_min; /* minutes of hour (0-59) */
+ int8_t tm_hour; /* hour of day (0-23) */
+ int8_t tm_mday; /* day of month (1-31) */
+ int8_t tm_mon; /* month of year (0-11) */
+ int8_t tm_wday; /* 0=sunday, 1=monday, ... */
+ int32_t tm_year; /* absolute year, AD */
+ int16_t tm_yday; /* day of year (0 to 365) */
+ int8_t tm_isdst; /* non-zero if DST in effect */
+};
+
+/* Some handy constants */
+#define PRMJ_USEC_PER_SEC 1000000L
+#define PRMJ_USEC_PER_MSEC 1000L
+
+/* Return the current local time in micro-seconds */
+extern int64_t
+PRMJ_Now();
+
+/* Initialize the resources associated with PRMJ_Now. */
+#if defined(XP_WIN)
+extern void
+PRMJ_NowInit();
+#else
+inline void
+PRMJ_NowInit() {}
+#endif
+
+/* Release the resources associated with PRMJ_Now; don't call PRMJ_Now again */
+#ifdef XP_WIN
+extern void
+PRMJ_NowShutdown();
+#else
+inline void
+PRMJ_NowShutdown() {}
+#endif
+
+/* Format a time value into a buffer. Same semantics as strftime() */
+extern size_t
+PRMJ_FormatTime(char* buf, int buflen, const char* fmt, PRMJTime* tm);
+
+
+/**
+ * Requesting the number of cycles from the CPU.
+ *
+ * `rdtsc`, or Read TimeStamp Cycle, is an instruction provided by
+ * x86-compatible CPUs that lets processes request the number of
+ * cycles spent by the CPU executing instructions since the CPU was
+ * started. It may be used for performance monitoring, but you should
+ * be aware of the following limitations.
+ *
+ *
+ * 1. The value is *not* monotonic.
+ *
+ * The value is reset to 0 whenever a CPU is turned off (e.g. computer
+ * in full hibernation, single CPU going turned off). Moreover, on
+ * multi-core/multi-CPU architectures, the cycles of each core/CPU are
+ * generally not synchronized. Therefore, is a process or thread is
+ * rescheduled to another core/CPU, the result of `rdtsc` may decrease
+ * arbitrarily.
+ *
+ * The only way to prevent this is to pin your thread to a particular
+ * CPU, which is generally not a good idea.
+ *
+ *
+ *
+ * 2. The value increases independently.
+ *
+ * The value may increase whenever the CPU executes an instruction,
+ * regardless of the process that has issued this
+ * instruction. Moreover, if a process or thread is rescheduled to
+ * another core/CPU, the result of `rdtsc` may increase arbitrarily.
+ *
+ * The only way to prevent this is to ensure that your thread is the
+ * sole owner of the CPU. See [1] for an example. This is also
+ * generally not a good idea.
+ *
+ *
+ *
+ * 3. The value does not measure time.
+ *
+ * On older architectures (pre-Pentium 4), there was no constant mapping
+ * between rdtsc and CPU time.
+ *
+ *
+ * 4. Instructions may be reordered.
+ *
+ * The CPU can reorder instructions. Also, rdtsc does not necessarily
+ * wait until all previous instructions have finished executing before
+ * reading the counter. Similarly, subsequent instructions may begin
+ * execution before the read operation is performed. If you use rdtsc
+ * for micro-benchmarking, you may end up measuring something else
+ * than what you expect. See [1] for a study of countermeasures.
+ *
+ *
+ * ** Performance
+ *
+ * According to unchecked sources on the web, the overhead of rdtsc is
+ * expected to be 150-200 cycles on old architectures, 6-50 on newer
+ * architectures. Agner's instruction tables [2] seem to confirm the latter
+ * results.
+ *
+ *
+ * [1]
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
+ * [2] http://www.agner.org/optimize/instruction_tables.pdf
+ */
+
+#define MOZ_HAVE_RDTSC 1
+
+#if defined(_WIN32)
+
+#include <intrin.h>
+static __inline uint64_t
+ReadTimestampCounter(void)
+{
+ return __rdtsc();
+}
+
+#elif defined(__i386__)
+
+static __inline__ uint64_t
+ReadTimestampCounter(void)
+{
+ uint64_t x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+
+#elif defined(__x86_64__)
+
+static __inline__ uint64_t
+ReadTimestampCounter(void)
+{
+ unsigned hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
+}
+
+#else
+
+#undef MOZ_HAVE_RDTSC
+
+#endif
+
+#endif /* vm_Time_h */
diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp
new file mode 100644
index 000000000..3d6183b3c
--- /dev/null
+++ b/js/src/vm/TraceLogging.cpp
@@ -0,0 +1,1085 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TraceLogging.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/ScopeExit.h"
+
+#include <string.h>
+
+#include "jsapi.h"
+#include "jsprf.h"
+#include "jsscript.h"
+
+#include "jit/BaselineJIT.h"
+#include "jit/CompileWrappers.h"
+#include "threading/LockGuard.h"
+#include "vm/Runtime.h"
+#include "vm/Time.h"
+#include "vm/TraceLoggingGraph.h"
+
+#include "jit/JitFrames-inl.h"
+
+using namespace js;
+using namespace js::jit;
+
+using mozilla::DebugOnly;
+using mozilla::NativeEndian;
+
+TraceLoggerThreadState* traceLoggerState = nullptr;
+
+#if defined(MOZ_HAVE_RDTSC)
+
+uint64_t inline rdtsc() {
+ return ReadTimestampCounter();
+}
+
+#elif defined(__powerpc__)
+static __inline__ uint64_t
+rdtsc(void)
+{
+ uint64_t result=0;
+ uint32_t upper, lower,tmp;
+ __asm__ volatile(
+ "0: \n"
+ "\tmftbu %0 \n"
+ "\tmftb %1 \n"
+ "\tmftbu %2 \n"
+ "\tcmpw %2,%0 \n"
+ "\tbne 0b \n"
+ : "=r"(upper),"=r"(lower),"=r"(tmp)
+ );
+ result = upper;
+ result = result<<32;
+ result = result|lower;
+
+ return result;
+
+}
+#elif defined(__arm__)
+
+#include <sys/time.h>
+
+static __inline__ uint64_t
+rdtsc(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ uint64_t ret = tv.tv_sec;
+ ret *= 1000000;
+ ret += tv.tv_usec;
+ return ret;
+}
+
+#else
+
+static __inline__ uint64_t
+rdtsc(void)
+{
+ return 0;
+}
+
+#endif // defined(MOZ_HAVE_RDTSC)
+
+static bool
+EnsureTraceLoggerState()
+{
+ if (MOZ_LIKELY(traceLoggerState))
+ return true;
+
+ traceLoggerState = js_new<TraceLoggerThreadState>();
+ if (!traceLoggerState)
+ return false;
+
+ if (!traceLoggerState->init()) {
+ DestroyTraceLoggerThreadState();
+ return false;
+ }
+
+ return true;
+}
+
+void
+js::DestroyTraceLoggerThreadState()
+{
+ if (traceLoggerState) {
+ js_delete(traceLoggerState);
+ traceLoggerState = nullptr;
+ }
+}
+
+void
+js::DestroyTraceLoggerMainThread(JSRuntime* runtime)
+{
+ if (!EnsureTraceLoggerState())
+ return;
+ traceLoggerState->destroyMainThread(runtime);
+}
+
+bool
+TraceLoggerThread::init()
+{
+ if (!pointerMap.init())
+ return false;
+ if (!textIdPayloads.init())
+ return false;
+ if (!events.init())
+ return false;
+
+ // Minimum amount of capacity needed for operation to allow flushing.
+ // Flushing requires space for the actual event and two spaces to log the
+ // start and stop of flushing.
+ if (!events.ensureSpaceBeforeAdd(3))
+ return false;
+
+ return true;
+}
+
+void
+TraceLoggerThread::initGraph()
+{
+ // Create a graph. I don't like this is called reset, but it locks the
+ // graph into the UniquePtr. So it gets deleted when TraceLoggerThread
+ // is destructed.
+ graph.reset(js_new<TraceLoggerGraph>());
+ if (!graph.get())
+ return;
+
+ MOZ_ASSERT(traceLoggerState);
+ uint64_t start = rdtsc() - traceLoggerState->startupTime;
+ if (!graph->init(start)) {
+ graph = nullptr;
+ return;
+ }
+
+ // Report the textIds to the graph.
+ for (uint32_t i = 0; i < TraceLogger_LastTreeItem; i++) {
+ TraceLoggerTextId id = TraceLoggerTextId(i);
+ graph->addTextId(i, TLTextIdString(id));
+ }
+ graph->addTextId(TraceLogger_LastTreeItem, "TraceLogger internal");
+ for (uint32_t i = TraceLogger_LastTreeItem + 1; i < TraceLogger_Last; i++) {
+ TraceLoggerTextId id = TraceLoggerTextId(i);
+ graph->addTextId(i, TLTextIdString(id));
+ }
+}
+
+TraceLoggerThread::~TraceLoggerThread()
+{
+ if (graph.get()) {
+ if (!failed)
+ graph->log(events);
+ graph = nullptr;
+ }
+
+ if (textIdPayloads.initialized()) {
+ for (TextIdHashMap::Range r = textIdPayloads.all(); !r.empty(); r.popFront())
+ js_delete(r.front().value());
+ }
+}
+
+bool
+TraceLoggerThread::enable()
+{
+ if (enabled_ > 0) {
+ enabled_++;
+ return true;
+ }
+
+ if (failed)
+ return false;
+
+ enabled_ = 1;
+ logTimestamp(TraceLogger_Enable);
+
+ return true;
+}
+
+bool
+TraceLoggerThread::fail(JSContext* cx, const char* error)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL, error);
+ failed = true;
+ enabled_ = 0;
+
+ return false;
+}
+
+bool
+TraceLoggerThread::enable(JSContext* cx)
+{
+ if (!enable())
+ return fail(cx, "internal error");
+
+ if (enabled_ == 1) {
+ // Get the top Activation to log the top script/pc (No inlined frames).
+ ActivationIterator iter(cx->runtime());
+ Activation* act = iter.activation();
+
+ if (!act)
+ return fail(cx, "internal error");
+
+ JSScript* script = nullptr;
+ int32_t engine = 0;
+
+ if (act->isJit()) {
+ JitFrameIterator it(iter);
+
+ while (!it.isScripted() && !it.done())
+ ++it;
+
+ MOZ_ASSERT(!it.done());
+ MOZ_ASSERT(it.isIonJS() || it.isBaselineJS());
+
+ script = it.script();
+ engine = it.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
+ } else if (act->isWasm()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL,
+ "not yet supported in wasm code");
+ return false;
+ } else {
+ MOZ_ASSERT(act->isInterpreter());
+ InterpreterFrame* fp = act->asInterpreter()->current();
+ MOZ_ASSERT(!fp->runningInJit());
+
+ script = fp->script();
+ engine = TraceLogger_Interpreter;
+ }
+ if (script->compartment() != cx->compartment())
+ return fail(cx, "compartment mismatch");
+
+ TraceLoggerEvent event(this, TraceLogger_Scripts, script);
+ startEvent(event);
+ startEvent(engine);
+ }
+
+ return true;
+}
+
+bool
+TraceLoggerThread::disable(bool force, const char* error)
+{
+ if (failed) {
+ MOZ_ASSERT(enabled_ == 0);
+ return false;
+ }
+
+ if (enabled_ == 0)
+ return true;
+
+ if (enabled_ > 1 && !force) {
+ enabled_--;
+ return true;
+ }
+
+ if (force)
+ traceLoggerState->maybeSpewError(error);
+
+ logTimestamp(TraceLogger_Disable);
+ enabled_ = 0;
+
+ return true;
+}
+
+const char*
+TraceLoggerThread::eventText(uint32_t id)
+{
+ if (id < TraceLogger_Last)
+ return TLTextIdString(static_cast<TraceLoggerTextId>(id));
+
+ TextIdHashMap::Ptr p = textIdPayloads.lookup(id);
+ MOZ_ASSERT(p);
+
+ return p->value()->string();
+}
+
+bool
+TraceLoggerThread::textIdIsScriptEvent(uint32_t id)
+{
+ if (id < TraceLogger_Last)
+ return false;
+
+ // Currently this works by checking if text begins with "script".
+ const char* str = eventText(id);
+ return EqualChars(str, "script", 6);
+}
+
+void
+TraceLoggerThread::extractScriptDetails(uint32_t textId, const char** filename, size_t* filename_len,
+ const char** lineno, size_t* lineno_len, const char** colno,
+ size_t* colno_len)
+{
+ MOZ_ASSERT(textIdIsScriptEvent(textId));
+
+ const char* script = eventText(textId);
+
+ // Get the start of filename (remove 'script ' at the start).
+ MOZ_ASSERT(EqualChars(script, "script ", 7));
+ *filename = script + 7;
+
+ // Get the start of lineno and colno.
+ *lineno = script;
+ *colno = script;
+ const char* next = script - 1;
+ while ((next = strchr(next + 1, ':'))) {
+ *lineno = *colno;
+ *colno = next;
+ }
+
+ MOZ_ASSERT(*lineno && *lineno != script);
+ MOZ_ASSERT(*colno && *colno != script);
+
+ // Remove the ':' at the front.
+ *lineno = *lineno + 1;
+ *colno = *colno + 1;
+
+ *filename_len = *lineno - *filename - 1;
+ *lineno_len = *colno - *lineno - 1;
+ *colno_len = strlen(*colno);
+}
+
+TraceLoggerEventPayload*
+TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId textId)
+{
+ TextIdHashMap::AddPtr p = textIdPayloads.lookupForAdd(textId);
+ if (p) {
+ MOZ_ASSERT(p->value()->textId() == textId); // Sanity check.
+ return p->value();
+ }
+
+ TraceLoggerEventPayload* payload = js_new<TraceLoggerEventPayload>(textId, (char*)nullptr);
+ if (!payload)
+ return nullptr;
+
+ if (!textIdPayloads.add(p, textId, payload))
+ return nullptr;
+
+ return payload;
+}
+
+TraceLoggerEventPayload*
+TraceLoggerThread::getOrCreateEventPayload(const char* text)
+{
+ PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void*)text);
+ if (p) {
+ MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
+ return p->value();
+ }
+
+ TraceLoggerEventPayload* payload = nullptr;
+
+ startEvent(TraceLogger_Internal);
+ auto guardInternalStopEvent = mozilla::MakeScopeExit([&] {
+ stopEvent(TraceLogger_Internal);
+ if (payload)
+ payload->release();
+ });
+
+ char* str = js_strdup(text);
+ if (!str)
+ return nullptr;
+
+ uint32_t textId = nextTextId;
+
+ payload = js_new<TraceLoggerEventPayload>(textId, str);
+ if (!payload) {
+ js_free(str);
+ return nullptr;
+ }
+
+ if (!textIdPayloads.putNew(textId, payload)) {
+ js_delete(payload);
+ payload = nullptr;
+ return nullptr;
+ }
+
+ // Temporarily mark the payload as used. To make sure it doesn't get GC'ed.
+ payload->use();
+
+ if (graph.get())
+ graph->addTextId(textId, str);
+
+ nextTextId++;
+
+ if (!pointerMap.add(p, text, payload))
+ return nullptr;
+
+ return payload;
+}
+
+TraceLoggerEventPayload*
+TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char* filename,
+ size_t lineno, size_t colno, const void* ptr)
+{
+ MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
+ type == TraceLogger_InlinedScripts);
+
+ if (!filename)
+ filename = "<unknown>";
+
+ // Only log scripts when enabled otherwise return the global Scripts textId,
+ // which will get filtered out.
+ MOZ_ASSERT(traceLoggerState);
+ if (!traceLoggerState->isTextIdEnabled(type))
+ return getOrCreateEventPayload(type);
+
+ PointerHashMap::AddPtr p;
+ if (ptr) {
+ p = pointerMap.lookupForAdd(ptr);
+ if (p) {
+ MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check.
+ return p->value();
+ }
+ }
+
+ TraceLoggerEventPayload* payload = nullptr;
+
+ startEvent(TraceLogger_Internal);
+ auto guardInternalStopEvent = mozilla::MakeScopeExit([&] {
+ stopEvent(TraceLogger_Internal);
+ if (payload)
+ payload->release();
+ });
+
+ // Compute the length of the string to create.
+ size_t lenFilename = strlen(filename);
+ size_t lenLineno = 1;
+ for (size_t i = lineno; i /= 10; lenLineno++);
+ size_t lenColno = 1;
+ for (size_t i = colno; i /= 10; lenColno++);
+
+ size_t len = 7 + lenFilename + 1 + lenLineno + 1 + lenColno;
+ char* str = js_pod_malloc<char>(len + 1);
+ if (!str)
+ return nullptr;
+
+ DebugOnly<size_t> ret =
+ snprintf(str, len + 1, "script %s:%" PRIuSIZE ":%" PRIuSIZE, filename, lineno, colno);
+ MOZ_ASSERT(ret == len);
+ MOZ_ASSERT(strlen(str) == len);
+
+ uint32_t textId = nextTextId;
+ payload = js_new<TraceLoggerEventPayload>(textId, str);
+ if (!payload) {
+ js_free(str);
+ return nullptr;
+ }
+
+ if (!textIdPayloads.putNew(textId, payload)) {
+ js_delete(payload);
+ payload = nullptr;
+ return nullptr;
+ }
+
+ // Temporarily mark the payload as used. To make sure it doesn't get GC'ed.
+ payload->use();
+
+ if (graph.get())
+ graph->addTextId(textId, str);
+
+ nextTextId++;
+
+ if (ptr) {
+ if (!pointerMap.add(p, ptr, payload))
+ return nullptr;
+ }
+
+ return payload;
+}
+
+TraceLoggerEventPayload*
+TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, JSScript* script)
+{
+ return getOrCreateEventPayload(type, script->filename(), script->lineno(), script->column(),
+ nullptr);
+}
+
+TraceLoggerEventPayload*
+TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type,
+ const JS::ReadOnlyCompileOptions& script)
+{
+ return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, nullptr);
+}
+
+void
+TraceLoggerThread::startEvent(TraceLoggerTextId id) {
+ startEvent(uint32_t(id));
+}
+
+void
+TraceLoggerThread::startEvent(const TraceLoggerEvent& event) {
+ if (!event.hasPayload()) {
+ if (!enabled())
+ return;
+ startEvent(TraceLogger_Error);
+ disable(/* force = */ true, "TraceLogger encountered an empty event. "
+ "Potentially due to OOM during creation of "
+ "this event. Disabling TraceLogger.");
+ return;
+ }
+ startEvent(event.payload()->textId());
+}
+
+void
+TraceLoggerThread::startEvent(uint32_t id)
+{
+ MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
+ MOZ_ASSERT(traceLoggerState);
+ if (!traceLoggerState->isTextIdEnabled(id))
+ return;
+
+#ifdef DEBUG
+ if (enabled_ > 0) {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!graphStack.append(id))
+ oomUnsafe.crash("Could not add item to debug stack.");
+ }
+#endif
+
+ log(id);
+}
+
+void
+TraceLoggerThread::stopEvent(TraceLoggerTextId id) {
+ stopEvent(uint32_t(id));
+}
+
+void
+TraceLoggerThread::stopEvent(const TraceLoggerEvent& event) {
+ if (!event.hasPayload()) {
+ stopEvent(TraceLogger_Error);
+ return;
+ }
+ stopEvent(event.payload()->textId());
+}
+
+void
+TraceLoggerThread::stopEvent(uint32_t id)
+{
+ MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
+ MOZ_ASSERT(traceLoggerState);
+ if (!traceLoggerState->isTextIdEnabled(id))
+ return;
+
+#ifdef DEBUG
+ if (enabled_ > 0 && !graphStack.empty()) {
+ uint32_t prev = graphStack.popCopy();
+ if (id == TraceLogger_Error || prev == TraceLogger_Error) {
+ // When encountering an Error id the stack will most likely not be correct anymore.
+ // Ignore this.
+ } else if (id == TraceLogger_Engine) {
+ MOZ_ASSERT(prev == TraceLogger_IonMonkey || prev == TraceLogger_Baseline ||
+ prev == TraceLogger_Interpreter);
+ } else if (id == TraceLogger_Scripts) {
+ MOZ_ASSERT(prev >= TraceLogger_Last);
+ } else if (id >= TraceLogger_Last) {
+ MOZ_ASSERT(prev >= TraceLogger_Last);
+ MOZ_ASSERT_IF(prev != id, strcmp(eventText(id), eventText(prev)) == 0);
+ } else {
+ MOZ_ASSERT(id == prev);
+ }
+ }
+#endif
+
+ log(TraceLogger_Stop);
+}
+
+void
+TraceLoggerThread::logTimestamp(TraceLoggerTextId id)
+{
+ logTimestamp(uint32_t(id));
+}
+
+void
+TraceLoggerThread::logTimestamp(uint32_t id)
+{
+ MOZ_ASSERT(id > TraceLogger_LastTreeItem && id < TraceLogger_Last);
+ log(id);
+}
+
+void
+TraceLoggerThread::log(uint32_t id)
+{
+ if (enabled_ == 0)
+ return;
+
+#ifdef DEBUG
+ if (id == TraceLogger_Disable)
+ graphStack.clear();
+#endif
+
+ MOZ_ASSERT(traceLoggerState);
+
+ // We request for 3 items to add, since if we don't have enough room
+ // we record the time it took to make more space. To log this information
+ // we need 2 extra free entries.
+ if (!events.hasSpaceForAdd(3)) {
+ uint64_t start = rdtsc() - traceLoggerState->startupTime;
+
+ if (!events.ensureSpaceBeforeAdd(3)) {
+ if (graph.get())
+ graph->log(events);
+
+ iteration_++;
+ events.clear();
+
+ // Remove the item in the pointerMap for which the payloads
+ // have no uses anymore
+ for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) {
+ if (e.front().value()->uses() != 0)
+ continue;
+
+ TextIdHashMap::Ptr p = textIdPayloads.lookup(e.front().value()->textId());
+ MOZ_ASSERT(p);
+ textIdPayloads.remove(p);
+
+ e.removeFront();
+ }
+
+ // Free all payloads that have no uses anymore.
+ for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) {
+ if (e.front().value()->uses() == 0) {
+ js_delete(e.front().value());
+ e.removeFront();
+ }
+ }
+ }
+
+ // Log the time it took to flush the events as being from the
+ // Tracelogger.
+ if (graph.get()) {
+ MOZ_ASSERT(events.hasSpaceForAdd(2));
+ EventEntry& entryStart = events.pushUninitialized();
+ entryStart.time = start;
+ entryStart.textId = TraceLogger_Internal;
+
+ EventEntry& entryStop = events.pushUninitialized();
+ entryStop.time = rdtsc() - traceLoggerState->startupTime;
+ entryStop.textId = TraceLogger_Stop;
+ }
+
+ }
+
+ uint64_t time = rdtsc() - traceLoggerState->startupTime;
+
+ EventEntry& entry = events.pushUninitialized();
+ entry.time = time;
+ entry.textId = id;
+}
+
+TraceLoggerThreadState::~TraceLoggerThreadState()
+{
+ while (TraceLoggerMainThread* logger = traceLoggerMainThreadList.popFirst())
+ js_delete(logger);
+
+ if (threadLoggers.initialized()) {
+ for (ThreadLoggerHashMap::Range r = threadLoggers.all(); !r.empty(); r.popFront())
+ js_delete(r.front().value());
+
+ threadLoggers.finish();
+ }
+
+#ifdef DEBUG
+ initialized = false;
+#endif
+}
+
+static bool
+ContainsFlag(const char* str, const char* flag)
+{
+ size_t flaglen = strlen(flag);
+ const char* index = strstr(str, flag);
+ while (index) {
+ if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ','))
+ return true;
+ index = strstr(index + flaglen, flag);
+ }
+ return false;
+}
+
+bool
+TraceLoggerThreadState::init()
+{
+ if (!threadLoggers.init())
+ return false;
+
+ const char* env = getenv("TLLOG");
+ if (!env)
+ env = "";
+
+ if (strstr(env, "help")) {
+ fflush(nullptr);
+ printf(
+ "\n"
+ "usage: TLLOG=option,option,option,... where options can be:\n"
+ "\n"
+ "Collections:\n"
+ " Default Output all default. It includes:\n"
+ " AnnotateScripts, Bailout, Baseline, BaselineCompilation, GC,\n"
+ " GCAllocation, GCSweeping, Interpreter, IonAnalysis, IonCompilation,\n"
+ " IonLinking, IonMonkey, MinorGC, ParserCompileFunction,\n"
+ " ParserCompileScript, ParserCompileLazy, ParserCompileModule,\n"
+ " IrregexpCompile, IrregexpExecute, Scripts, Engine, WasmCompilation\n"
+ "\n"
+ " IonCompiler Output all information about compilation. It includes:\n"
+ " IonCompilation, IonLinking, PruneUnusedBranches, FoldTests,\n"
+ " SplitCriticalEdges, RenumberBlocks, ScalarReplacement, \n"
+ " DominatorTree, PhiAnalysis, MakeLoopsContiguous, ApplyTypes, \n"
+ " EagerSimdUnbox, AliasAnalysis, GVN, LICM, Sincos, RangeAnalysis, \n"
+ " LoopUnrolling, FoldLinearArithConstants, EffectiveAddressAnalysis, \n"
+ " AlignmentMaskAnalysis, EliminateDeadCode, ReorderInstructions, \n"
+ " EdgeCaseAnalysis, EliminateRedundantChecks, \n"
+ " AddKeepAliveInstructions, GenerateLIR, RegisterAllocation, \n"
+ " GenerateCode, Scripts, IonBuilderRestartLoop\n"
+ "\n"
+ " VMSpecific Output the specific name of the VM call"
+ "\n"
+ "Specific log items:\n"
+ );
+ for (uint32_t i = 1; i < TraceLogger_Last; i++) {
+ TraceLoggerTextId id = TraceLoggerTextId(i);
+ if (!TLTextIdIsTogglable(id))
+ continue;
+ printf(" %s\n", TLTextIdString(id));
+ }
+ printf("\n");
+ exit(0);
+ /*NOTREACHED*/
+ }
+
+ for (uint32_t i = 1; i < TraceLogger_Last; i++) {
+ TraceLoggerTextId id = TraceLoggerTextId(i);
+ if (TLTextIdIsTogglable(id))
+ enabledTextIds[i] = ContainsFlag(env, TLTextIdString(id));
+ else
+ enabledTextIds[i] = true;
+ }
+
+ if (ContainsFlag(env, "Default")) {
+ enabledTextIds[TraceLogger_AnnotateScripts] = true;
+ enabledTextIds[TraceLogger_Bailout] = true;
+ enabledTextIds[TraceLogger_Baseline] = true;
+ enabledTextIds[TraceLogger_BaselineCompilation] = true;
+ enabledTextIds[TraceLogger_GC] = true;
+ enabledTextIds[TraceLogger_GCAllocation] = true;
+ enabledTextIds[TraceLogger_GCSweeping] = true;
+ enabledTextIds[TraceLogger_Interpreter] = true;
+ enabledTextIds[TraceLogger_IonAnalysis] = true;
+ enabledTextIds[TraceLogger_IonCompilation] = true;
+ enabledTextIds[TraceLogger_IonLinking] = true;
+ enabledTextIds[TraceLogger_IonMonkey] = true;
+ enabledTextIds[TraceLogger_MinorGC] = true;
+ enabledTextIds[TraceLogger_ParserCompileFunction] = true;
+ enabledTextIds[TraceLogger_ParserCompileLazy] = true;
+ enabledTextIds[TraceLogger_ParserCompileScript] = true;
+ enabledTextIds[TraceLogger_ParserCompileModule] = true;
+ enabledTextIds[TraceLogger_IrregexpCompile] = true;
+ enabledTextIds[TraceLogger_IrregexpExecute] = true;
+ enabledTextIds[TraceLogger_Scripts] = true;
+ enabledTextIds[TraceLogger_Engine] = true;
+ enabledTextIds[TraceLogger_WasmCompilation] = true;
+ }
+
+ if (ContainsFlag(env, "IonCompiler")) {
+ enabledTextIds[TraceLogger_IonCompilation] = true;
+ enabledTextIds[TraceLogger_IonLinking] = true;
+ enabledTextIds[TraceLogger_PruneUnusedBranches] = true;
+ enabledTextIds[TraceLogger_FoldTests] = true;
+ enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
+ enabledTextIds[TraceLogger_RenumberBlocks] = true;
+ enabledTextIds[TraceLogger_ScalarReplacement] = true;
+ enabledTextIds[TraceLogger_DominatorTree] = true;
+ enabledTextIds[TraceLogger_PhiAnalysis] = true;
+ enabledTextIds[TraceLogger_MakeLoopsContiguous] = true;
+ enabledTextIds[TraceLogger_ApplyTypes] = true;
+ enabledTextIds[TraceLogger_EagerSimdUnbox] = true;
+ enabledTextIds[TraceLogger_AliasAnalysis] = true;
+ enabledTextIds[TraceLogger_GVN] = true;
+ enabledTextIds[TraceLogger_LICM] = true;
+ enabledTextIds[TraceLogger_Sincos] = true;
+ enabledTextIds[TraceLogger_RangeAnalysis] = true;
+ enabledTextIds[TraceLogger_LoopUnrolling] = true;
+ enabledTextIds[TraceLogger_FoldLinearArithConstants] = true;
+ enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
+ enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true;
+ enabledTextIds[TraceLogger_EliminateDeadCode] = true;
+ enabledTextIds[TraceLogger_ReorderInstructions] = true;
+ enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
+ enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
+ enabledTextIds[TraceLogger_AddKeepAliveInstructions] = true;
+ enabledTextIds[TraceLogger_GenerateLIR] = true;
+ enabledTextIds[TraceLogger_RegisterAllocation] = true;
+ enabledTextIds[TraceLogger_GenerateCode] = true;
+ enabledTextIds[TraceLogger_Scripts] = true;
+ enabledTextIds[TraceLogger_IonBuilderRestartLoop] = true;
+ }
+
+ enabledTextIds[TraceLogger_Interpreter] = enabledTextIds[TraceLogger_Engine];
+ enabledTextIds[TraceLogger_Baseline] = enabledTextIds[TraceLogger_Engine];
+ enabledTextIds[TraceLogger_IonMonkey] = enabledTextIds[TraceLogger_Engine];
+
+ enabledTextIds[TraceLogger_Error] = true;
+
+ const char* options = getenv("TLOPTIONS");
+ if (options) {
+ if (strstr(options, "help")) {
+ fflush(nullptr);
+ printf(
+ "\n"
+ "usage: TLOPTIONS=option,option,option,... where options can be:\n"
+ "\n"
+ " EnableMainThread Start logging the main thread immediately.\n"
+ " EnableOffThread Start logging helper threads immediately.\n"
+ " EnableGraph Enable spewing the tracelogging graph to a file.\n"
+ " Errors Report errors during tracing to stderr.\n"
+ );
+ printf("\n");
+ exit(0);
+ /*NOTREACHED*/
+ }
+
+ if (strstr(options, "EnableMainThread"))
+ mainThreadEnabled = true;
+ if (strstr(options, "EnableOffThread"))
+ offThreadEnabled = true;
+ if (strstr(options, "EnableGraph"))
+ graphSpewingEnabled = true;
+ if (strstr(options, "Errors"))
+ spewErrors = true;
+ }
+
+ startupTime = rdtsc();
+
+#ifdef DEBUG
+ initialized = true;
+#endif
+
+ return true;
+}
+
+void
+TraceLoggerThreadState::enableTextId(JSContext* cx, uint32_t textId)
+{
+ MOZ_ASSERT(TLTextIdIsTogglable(textId));
+
+ if (enabledTextIds[textId])
+ return;
+
+ ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
+
+ enabledTextIds[textId] = true;
+ if (textId == TraceLogger_Engine) {
+ enabledTextIds[TraceLogger_IonMonkey] = true;
+ enabledTextIds[TraceLogger_Baseline] = true;
+ enabledTextIds[TraceLogger_Interpreter] = true;
+ }
+
+ if (textId == TraceLogger_Scripts)
+ jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), true);
+ if (textId == TraceLogger_Engine)
+ jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), true);
+
+}
+void
+TraceLoggerThreadState::disableTextId(JSContext* cx, uint32_t textId)
+{
+ MOZ_ASSERT(TLTextIdIsTogglable(textId));
+
+ if (!enabledTextIds[textId])
+ return;
+
+ ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
+
+ enabledTextIds[textId] = false;
+ if (textId == TraceLogger_Engine) {
+ enabledTextIds[TraceLogger_IonMonkey] = false;
+ enabledTextIds[TraceLogger_Baseline] = false;
+ enabledTextIds[TraceLogger_Interpreter] = false;
+ }
+
+ if (textId == TraceLogger_Scripts)
+ jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), false);
+ if (textId == TraceLogger_Engine)
+ jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), false);
+}
+
+
+TraceLoggerThread*
+js::TraceLoggerForMainThread(CompileRuntime* runtime)
+{
+ if (!EnsureTraceLoggerState())
+ return nullptr;
+ return traceLoggerState->forMainThread(runtime);
+}
+
+TraceLoggerThread*
+TraceLoggerThreadState::forMainThread(CompileRuntime* runtime)
+{
+ return forMainThread(runtime->mainThread());
+}
+
+TraceLoggerThread*
+js::TraceLoggerForMainThread(JSRuntime* runtime)
+{
+ if (!EnsureTraceLoggerState())
+ return nullptr;
+ return traceLoggerState->forMainThread(runtime);
+}
+
+TraceLoggerThread*
+TraceLoggerThreadState::forMainThread(JSRuntime* runtime)
+{
+ return forMainThread(&runtime->mainThread);
+}
+
+TraceLoggerThread*
+TraceLoggerThreadState::forMainThread(PerThreadData* mainThread)
+{
+ MOZ_ASSERT(initialized);
+ if (!mainThread->traceLogger) {
+ LockGuard<Mutex> guard(lock);
+
+ TraceLoggerMainThread* logger = js_new<TraceLoggerMainThread>();
+ if (!logger)
+ return nullptr;
+
+ if (!logger->init()) {
+ js_delete(logger);
+ return nullptr;
+ }
+
+ traceLoggerMainThreadList.insertFront(logger);
+ mainThread->traceLogger = logger;
+
+ if (graphSpewingEnabled)
+ logger->initGraph();
+
+ if (mainThreadEnabled)
+ logger->enable();
+ }
+
+ return mainThread->traceLogger;
+}
+
+void
+TraceLoggerThreadState::destroyMainThread(JSRuntime* runtime)
+{
+ MOZ_ASSERT(initialized);
+ PerThreadData* mainThread = &runtime->mainThread;
+ if (mainThread->traceLogger) {
+ LockGuard<Mutex> guard(lock);
+
+ mainThread->traceLogger->remove();
+ js_delete(mainThread->traceLogger);
+ mainThread->traceLogger = nullptr;
+ }
+}
+
+TraceLoggerThread*
+js::TraceLoggerForCurrentThread()
+{
+ if (!EnsureTraceLoggerState())
+ return nullptr;
+ return traceLoggerState->forThread(ThisThread::GetId());
+}
+
+TraceLoggerThread*
+TraceLoggerThreadState::forThread(const Thread::Id& thread)
+{
+ return nullptr;
+}
+
+bool
+js::TraceLogTextIdEnabled(uint32_t textId)
+{
+ if (!EnsureTraceLoggerState())
+ return false;
+ return traceLoggerState->isTextIdEnabled(textId);
+}
+
+void
+js::TraceLogEnableTextId(JSContext* cx, uint32_t textId)
+{
+ if (!EnsureTraceLoggerState())
+ return;
+ traceLoggerState->enableTextId(cx, textId);
+}
+void
+js::TraceLogDisableTextId(JSContext* cx, uint32_t textId)
+{
+ if (!EnsureTraceLoggerState())
+ return;
+ traceLoggerState->disableTextId(cx, textId);
+}
+
+TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId textId)
+{
+ payload_ = nullptr;
+ if (logger) {
+ payload_ = logger->getOrCreateEventPayload(textId);
+ if (payload_)
+ payload_->use();
+ }
+}
+
+TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId type,
+ JSScript* script)
+{
+ payload_ = nullptr;
+ if (logger) {
+ payload_ = logger->getOrCreateEventPayload(type, script);
+ if (payload_)
+ payload_->use();
+ }
+}
+
+TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId type,
+ const JS::ReadOnlyCompileOptions& compileOptions)
+{
+ payload_ = nullptr;
+ if (logger) {
+ payload_ = logger->getOrCreateEventPayload(type, compileOptions);
+ if (payload_)
+ payload_->use();
+ }
+}
+
+TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread* logger, const char* text)
+{
+ payload_ = nullptr;
+ if (logger) {
+ payload_ = logger->getOrCreateEventPayload(text);
+ if (payload_)
+ payload_->use();
+ }
+}
+
+TraceLoggerEvent::~TraceLoggerEvent()
+{
+ if (payload_)
+ payload_->release();
+}
+
+TraceLoggerEvent&
+TraceLoggerEvent::operator=(const TraceLoggerEvent& other)
+{
+ if (other.hasPayload())
+ other.payload()->use();
+ if (hasPayload())
+ payload()->release();
+
+ payload_ = other.payload_;
+
+ return *this;
+}
+
+TraceLoggerEvent::TraceLoggerEvent(const TraceLoggerEvent& other)
+{
+ payload_ = other.payload_;
+ if (hasPayload())
+ payload()->use();
+}
diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h
new file mode 100644
index 000000000..92ebecef2
--- /dev/null
+++ b/js/src/vm/TraceLogging.h
@@ -0,0 +1,564 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TraceLogging_h
+#define TraceLogging_h
+
+#include "mozilla/GuardObjects.h"
+#include "mozilla/LinkedList.h"
+
+#include "jsalloc.h"
+
+#include "js/HashTable.h"
+#include "js/TypeDecls.h"
+#include "js/Vector.h"
+#include "threading/Thread.h"
+#include "vm/MutexIDs.h"
+#include "vm/TraceLoggingGraph.h"
+#include "vm/TraceLoggingTypes.h"
+
+struct JSRuntime;
+
+namespace JS {
+ class ReadOnlyCompileOptions;
+} // namespace JS
+
+namespace js {
+class PerThreadData;
+
+namespace jit {
+ class CompileRuntime;
+} // namespace jit
+
+/*
+ * Tracelogging overview.
+ *
+ * Tracelogging makes it possible to trace the occurrence of a single event
+ * and/or the start and stop of an event. This is implemented with as low
+ * overhead as possible to not interfere with running.
+ *
+ * Logging something is done in 3 stages.
+ * 1) Get the tracelogger of the current thread.
+ * - TraceLoggerForMainThread(JSRuntime*)
+ * - TraceLoggerForCurrentThread(); // Should NOT be used for the mainthread.
+ *
+ * 2) Optionally create a TraceLoggerEvent for the text that needs to get logged. This
+ * step takes some time, so try to do this beforehand, outside the hot
+ * path and don't do unnecessary repetitions, since it will cripple
+ * performance.
+ * - TraceLoggerEvent event(logger, "foo");
+ *
+ * There are also some predefined events. They are located in
+ * TraceLoggerTextId. They don't require to create an TraceLoggerEvent and
+ * can also be used as an argument to these functions.
+ *
+ * 3) Log the occurrence of a single event:
+ * - TraceLogTimestamp(logger, TraceLoggerTextId);
+ * Note: it is temporarily not supported to provide an TraceLoggerEvent as
+ * argument to log the occurrence of a single event.
+ *
+ * or log the start and stop of an event:
+ * - TraceLogStartEvent(logger, TraceLoggerTextId);
+ * - TraceLogStartEvent(logger, TraceLoggerEvent);
+ * - TraceLogStopEvent(logger, TraceLoggerTextId);
+ * - TraceLogStopEvent(logger, TraceLoggerEvent);
+ *
+ * or the start/stop of an event with a RAII class:
+ * - AutoTraceLog atl(logger, TraceLoggerTextId);
+ * - AutoTraceLog atl(logger, TraceLoggerEvent);
+ */
+
+class AutoTraceLog;
+class TraceLoggerEventPayload;
+class TraceLoggerThread;
+
+/**
+ * An event that can be used to report start/stop events to TraceLogger. It
+ * prepares the given info by requesting a TraceLoggerEventPayload containing
+ * the string to report and an unique id. It also increases the useCount of
+ * this payload, so it cannot get removed.
+ */
+class TraceLoggerEvent {
+ private:
+ TraceLoggerEventPayload* payload_;
+
+ public:
+ TraceLoggerEvent() { payload_ = nullptr; };
+#ifdef JS_TRACE_LOGGING
+ TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId textId);
+ TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId type, JSScript* script);
+ TraceLoggerEvent(TraceLoggerThread* logger, TraceLoggerTextId type,
+ const JS::ReadOnlyCompileOptions& compileOptions);
+ TraceLoggerEvent(TraceLoggerThread* logger, const char* text);
+ TraceLoggerEvent(const TraceLoggerEvent& event);
+ TraceLoggerEvent& operator=(const TraceLoggerEvent& other);
+ ~TraceLoggerEvent();
+#else
+ TraceLoggerEvent (TraceLoggerThread* logger, TraceLoggerTextId textId) {}
+ TraceLoggerEvent (TraceLoggerThread* logger, TraceLoggerTextId type, JSScript* script) {}
+ TraceLoggerEvent (TraceLoggerThread* logger, TraceLoggerTextId type,
+ const JS::ReadOnlyCompileOptions& compileOptions) {}
+ TraceLoggerEvent (TraceLoggerThread* logger, const char* text) {}
+ TraceLoggerEvent(const TraceLoggerEvent& event) {}
+ TraceLoggerEvent& operator=(const TraceLoggerEvent& other) {};
+ ~TraceLoggerEvent() {}
+#endif
+
+ TraceLoggerEventPayload* payload() const {
+ MOZ_ASSERT(hasPayload());
+ return payload_;
+ }
+ bool hasPayload() const {
+ return !!payload_;
+ }
+};
+
+/**
+ * An internal class holding the string information to report, together with an
+ * unique id and a useCount. Whenever this useCount reaches 0, this event
+ * cannot get started/stopped anymore. Consumers may still request the
+ * string information.
+ */
+class TraceLoggerEventPayload {
+ uint32_t textId_;
+ UniqueChars string_;
+ uint32_t uses_;
+
+ public:
+ TraceLoggerEventPayload(uint32_t textId, char* string)
+ : textId_(textId),
+ string_(string),
+ uses_(0)
+ { }
+
+ ~TraceLoggerEventPayload() {
+ MOZ_ASSERT(uses_ == 0);
+ }
+
+ uint32_t textId() {
+ return textId_;
+ }
+ const char* string() {
+ return string_.get();
+ }
+ uint32_t uses() {
+ return uses_;
+ }
+ void use() {
+ uses_++;
+ }
+ void release() {
+ uses_--;
+ }
+};
+
+class TraceLoggerThread
+{
+#ifdef JS_TRACE_LOGGING
+ private:
+ typedef HashMap<const void*,
+ TraceLoggerEventPayload*,
+ PointerHasher<const void*, 3>,
+ SystemAllocPolicy> PointerHashMap;
+ typedef HashMap<uint32_t,
+ TraceLoggerEventPayload*,
+ DefaultHasher<uint32_t>,
+ SystemAllocPolicy> TextIdHashMap;
+
+ uint32_t enabled_;
+ bool failed;
+
+ UniquePtr<TraceLoggerGraph> graph;
+
+ PointerHashMap pointerMap;
+ TextIdHashMap textIdPayloads;
+ uint32_t nextTextId;
+
+ ContinuousSpace<EventEntry> events;
+
+ // Every time the events get flushed, this count is increased by one.
+ // Together with events.lastEntryId(), this gives an unique id for every
+ // event.
+ uint32_t iteration_;
+
+#ifdef DEBUG
+ typedef Vector<uint32_t, 1, js::SystemAllocPolicy > GraphStack;
+ GraphStack graphStack;
+#endif
+
+ public:
+ AutoTraceLog* top;
+
+ TraceLoggerThread()
+ : enabled_(0),
+ failed(false),
+ graph(),
+ nextTextId(TraceLogger_Last),
+ iteration_(0),
+ top(nullptr)
+ { }
+
+ bool init();
+ ~TraceLoggerThread();
+
+ bool init(uint32_t loggerId);
+ void initGraph();
+
+ bool enable();
+ bool enable(JSContext* cx);
+ bool disable(bool force = false, const char* = "");
+ bool enabled() { return enabled_ > 0; }
+
+ private:
+ bool fail(JSContext* cx, const char* error);
+
+ public:
+ // Given the previous iteration and size, return an array of events
+ // (there could be lost events). At the same time update the iteration and
+ // 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(*lastSize <= events.size());
+ *num = events.size() - *lastSize;
+ start = events.data() + *lastSize;
+ } else {
+ *num = events.size();
+ start = events.data();
+ }
+
+ getIterationAndSize(lastIteration, lastSize);
+ return start;
+ }
+
+ void getIterationAndSize(uint32_t* iteration, uint32_t* size) const {
+ *iteration = iteration_;
+ *size = events.size();
+ }
+
+ // Extract the details filename, lineNumber and columnNumber out of a event
+ // containing script information.
+ void extractScriptDetails(uint32_t textId, const char** filename, size_t* filename_len,
+ const char** lineno, size_t* lineno_len, const char** colno,
+ size_t* colno_len);
+
+ 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(lastSize <= events.size());
+ return false;
+ }
+
+ // If we are in the next 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;
+ }
+
+ const char* eventText(uint32_t id);
+ bool textIdIsScriptEvent(uint32_t id);
+
+ // The createTextId functions map a unique input to a logger ID.
+ // This can be used to give start and stop events. Calls to these functions should be
+ // limited if possible, because of the overhead.
+ // Note: it is not allowed to use them in logTimestamp.
+ TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId textId);
+ TraceLoggerEventPayload* getOrCreateEventPayload(const char* text);
+ TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId type, JSScript* script);
+ TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId type,
+ const JS::ReadOnlyCompileOptions& script);
+ private:
+ TraceLoggerEventPayload* getOrCreateEventPayload(TraceLoggerTextId type, const char* filename,
+ size_t lineno, size_t colno, const void* p);
+
+ public:
+ // Log an event (no start/stop, only the timestamp is recorded).
+ void logTimestamp(TraceLoggerTextId id);
+
+ // Record timestamps for start and stop of an event.
+ void startEvent(TraceLoggerTextId id);
+ void startEvent(const TraceLoggerEvent& event);
+ void stopEvent(TraceLoggerTextId id);
+ void stopEvent(const TraceLoggerEvent& event);
+
+ // These functions are actually private and shouldn't be used in normal
+ // code. They are made public so they can be used in assembly.
+ void logTimestamp(uint32_t id);
+ void startEvent(uint32_t id);
+ void stopEvent(uint32_t id);
+ private:
+ void stopEvent();
+ void log(uint32_t id);
+
+ public:
+ static unsigned offsetOfEnabled() {
+ return offsetof(TraceLoggerThread, enabled_);
+ }
+#endif
+};
+
+#ifdef JS_TRACE_LOGGING
+class TraceLoggerMainThread
+ : public TraceLoggerThread,
+ public mozilla::LinkedListElement<TraceLoggerMainThread>
+{
+
+};
+#endif
+
+class TraceLoggerThreadState
+{
+#ifdef JS_TRACE_LOGGING
+ typedef HashMap<Thread::Id,
+ TraceLoggerThread*,
+ Thread::Hasher,
+ SystemAllocPolicy> ThreadLoggerHashMap;
+
+#ifdef DEBUG
+ bool initialized;
+#endif
+
+ bool enabledTextIds[TraceLogger_Last];
+ bool mainThreadEnabled;
+ bool offThreadEnabled;
+ bool graphSpewingEnabled;
+ bool spewErrors;
+ ThreadLoggerHashMap threadLoggers;
+ mozilla::LinkedList<TraceLoggerMainThread> traceLoggerMainThreadList;
+
+ public:
+ uint64_t startupTime;
+ Mutex lock;
+
+ TraceLoggerThreadState()
+ :
+#ifdef DEBUG
+ initialized(false),
+#endif
+ mainThreadEnabled(false),
+ offThreadEnabled(false),
+ graphSpewingEnabled(false),
+ spewErrors(false),
+ lock(js::mutexid::TraceLoggerThreadState)
+ { }
+
+ bool init();
+ ~TraceLoggerThreadState();
+
+ TraceLoggerThread* forMainThread(JSRuntime* runtime);
+ TraceLoggerThread* forMainThread(jit::CompileRuntime* runtime);
+ TraceLoggerThread* forThread(const Thread::Id& thread);
+ void destroyMainThread(JSRuntime* runtime);
+
+ bool isTextIdEnabled(uint32_t textId) {
+ if (textId < TraceLogger_Last)
+ return enabledTextIds[textId];
+ return true;
+ }
+ void enableTextId(JSContext* cx, uint32_t textId);
+ void disableTextId(JSContext* cx, uint32_t textId);
+ void maybeSpewError(const char* text) {
+ if (spewErrors)
+ fprintf(stderr, "%s\n", text);
+ }
+
+ private:
+ TraceLoggerThread* forMainThread(PerThreadData* mainThread);
+#endif
+};
+
+#ifdef JS_TRACE_LOGGING
+void DestroyTraceLoggerThreadState();
+void DestroyTraceLoggerMainThread(JSRuntime* runtime);
+
+TraceLoggerThread* TraceLoggerForMainThread(JSRuntime* runtime);
+TraceLoggerThread* TraceLoggerForMainThread(jit::CompileRuntime* runtime);
+TraceLoggerThread* TraceLoggerForCurrentThread();
+#else
+inline TraceLoggerThread* TraceLoggerForMainThread(JSRuntime* runtime) {
+ return nullptr;
+};
+inline TraceLoggerThread* TraceLoggerForMainThread(jit::CompileRuntime* runtime) {
+ return nullptr;
+};
+inline TraceLoggerThread* TraceLoggerForCurrentThread() {
+ return nullptr;
+};
+#endif
+
+inline bool TraceLoggerEnable(TraceLoggerThread* logger) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ return logger->enable();
+#endif
+ return false;
+}
+inline bool TraceLoggerEnable(TraceLoggerThread* logger, JSContext* cx) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ return logger->enable(cx);
+#endif
+ return false;
+}
+inline bool TraceLoggerDisable(TraceLoggerThread* logger) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ return logger->disable();
+#endif
+ return false;
+}
+
+#ifdef JS_TRACE_LOGGING
+bool TraceLogTextIdEnabled(uint32_t textId);
+void TraceLogEnableTextId(JSContext* cx, uint32_t textId);
+void TraceLogDisableTextId(JSContext* cx, uint32_t textId);
+#else
+inline bool TraceLogTextIdEnabled(uint32_t textId) {
+ return false;
+}
+inline void TraceLogEnableTextId(JSContext* cx, uint32_t textId) {}
+inline void TraceLogDisableTextId(JSContext* cx, uint32_t textId) {}
+#endif
+inline void TraceLogTimestamp(TraceLoggerThread* logger, TraceLoggerTextId textId) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->logTimestamp(textId);
+#endif
+}
+inline void TraceLogStartEvent(TraceLoggerThread* logger, TraceLoggerTextId textId) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->startEvent(textId);
+#endif
+}
+inline void TraceLogStartEvent(TraceLoggerThread* logger, const TraceLoggerEvent& event) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->startEvent(event);
+#endif
+}
+inline void TraceLogStopEvent(TraceLoggerThread* logger, TraceLoggerTextId textId) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->stopEvent(textId);
+#endif
+}
+inline void TraceLogStopEvent(TraceLoggerThread* logger, const TraceLoggerEvent& event) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->stopEvent(event);
+#endif
+}
+
+// Helper functions for assembly. May not be used otherwise.
+inline void TraceLogTimestampPrivate(TraceLoggerThread* logger, uint32_t id) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->logTimestamp(id);
+#endif
+}
+inline void TraceLogStartEventPrivate(TraceLoggerThread* logger, uint32_t id) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->startEvent(id);
+#endif
+}
+inline void TraceLogStopEventPrivate(TraceLoggerThread* logger, uint32_t id) {
+#ifdef JS_TRACE_LOGGING
+ if (logger)
+ logger->stopEvent(id);
+#endif
+}
+
+// Automatic logging at the start and end of function call.
+class MOZ_RAII AutoTraceLog
+{
+#ifdef JS_TRACE_LOGGING
+ TraceLoggerThread* logger;
+ union {
+ const TraceLoggerEvent* event;
+ TraceLoggerTextId id;
+ } payload;
+ bool isEvent;
+ bool executed;
+ AutoTraceLog* prev;
+
+ public:
+ AutoTraceLog(TraceLoggerThread* logger,
+ const TraceLoggerEvent& event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : logger(logger),
+ isEvent(true),
+ executed(false)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ payload.event = &event;
+ if (logger) {
+ logger->startEvent(event);
+
+ prev = logger->top;
+ logger->top = this;
+ }
+ }
+
+ AutoTraceLog(TraceLoggerThread* logger, TraceLoggerTextId id MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : logger(logger),
+ isEvent(false),
+ executed(false)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ payload.id = id;
+ if (logger) {
+ logger->startEvent(id);
+
+ prev = logger->top;
+ logger->top = this;
+ }
+ }
+
+ ~AutoTraceLog()
+ {
+ if (logger) {
+ while (this != logger->top)
+ logger->top->stop();
+ stop();
+ }
+ }
+ private:
+ void stop() {
+ if (!executed) {
+ executed = true;
+ if (isEvent)
+ logger->stopEvent(*payload.event);
+ else
+ logger->stopEvent(payload.id);
+ }
+
+ if (logger->top == this)
+ logger->top = prev;
+ }
+#else
+ public:
+ AutoTraceLog(TraceLoggerThread* logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+ AutoTraceLog(TraceLoggerThread* logger,
+ const TraceLoggerEvent& event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+#endif
+
+ private:
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+} // namespace js
+
+#endif /* TraceLogging_h */
diff --git a/js/src/vm/TraceLoggingGraph.cpp b/js/src/vm/TraceLoggingGraph.cpp
new file mode 100644
index 000000000..6f6792e98
--- /dev/null
+++ b/js/src/vm/TraceLoggingGraph.cpp
@@ -0,0 +1,649 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TraceLoggingGraph.h"
+
+#ifdef XP_WIN
+#include <process.h>
+#define getpid _getpid
+#else
+#include <unistd.h>
+#endif
+
+#include "mozilla/EndianUtils.h"
+#include "mozilla/ScopeExit.h"
+
+#include "jsstr.h"
+
+#include "js/UniquePtr.h"
+#include "threading/LockGuard.h"
+#include "threading/Thread.h"
+#include "vm/TraceLogging.h"
+
+#ifndef DEFAULT_TRACE_LOG_DIR
+# if defined(_WIN32)
+# define DEFAULT_TRACE_LOG_DIR "."
+# else
+# define DEFAULT_TRACE_LOG_DIR "/tmp/"
+# endif
+#endif
+
+using mozilla::MakeScopeExit;
+using mozilla::NativeEndian;
+
+TraceLoggerGraphState* traceLoggerGraphState = nullptr;
+
+// gcc and clang have these in symcat.h, but MSVC does not.
+#ifndef STRINGX
+# define STRINGX(x) #x
+#endif
+#ifndef XSTRING
+# define XSTRING(macro) STRINGX(macro)
+#endif
+
+#define MAX_LOGGERS 999
+
+// Return a filename relative to the output directory. %u and %d substitutions
+// are allowed, with %u standing for a full 32-bit number and %d standing for
+// an up to 3-digit number.
+static js::UniqueChars
+MOZ_FORMAT_PRINTF(1, 2)
+AllocTraceLogFilename(const char* pattern, ...) {
+ js::UniqueChars filename;
+
+ va_list ap;
+
+ static const char* outdir = getenv("TLDIR") ? getenv("TLDIR") : DEFAULT_TRACE_LOG_DIR;
+ size_t len = strlen(outdir) + 1; // "+ 1" is for the '/'
+
+ for (const char* p = pattern; *p; p++) {
+ if (*p == '%') {
+ p++;
+ if (*p == 'u')
+ len += sizeof("4294967295") - 1;
+ else if (*p == 'd')
+ len += sizeof(XSTRING(MAX_LOGGERS)) - 1;
+ else
+ MOZ_CRASH("Invalid format");
+ } else {
+ len++;
+ }
+ }
+
+ len++; // For the terminating NUL.
+
+ filename.reset((char*) js_malloc(len));
+ if (!filename)
+ return nullptr;
+ char* rest = filename.get() + sprintf(filename.get(), "%s/", outdir);
+
+ va_start(ap, pattern);
+ int ret = vsnprintf(rest, len, pattern, ap);
+ va_end(ap);
+ if (ret < 0)
+ return nullptr;
+
+ MOZ_ASSERT(size_t(ret) <= len - (strlen(outdir) + 1),
+ "overran TL filename buffer; %d given too large a value?");
+
+ return filename;
+}
+
+bool
+TraceLoggerGraphState::init()
+{
+ pid_ = (uint32_t) getpid();
+
+ js::UniqueChars filename = AllocTraceLogFilename("tl-data.%u.json", pid_);
+ out = fopen(filename.get(), "w");
+ if (!out) {
+ fprintf(stderr, "warning: failed to create TraceLogger output file %s\n", filename.get());
+ return false;
+ }
+
+ fprintf(out, "[");
+
+ // Write the latest tl-data.*.json file to tl-data.json.
+ // In most cases that is the wanted file.
+ js::UniqueChars masterFilename = AllocTraceLogFilename("tl-data.json");
+ if (FILE* last = fopen(masterFilename.get(), "w")) {
+ char *basename = strrchr(filename.get(), '/');
+ basename = basename ? basename + 1 : filename.get();
+ fprintf(last, "\"%s\"", basename);
+ fclose(last);
+ }
+
+#ifdef DEBUG
+ initialized = true;
+#endif
+ return true;
+}
+
+TraceLoggerGraphState::~TraceLoggerGraphState()
+{
+ if (out) {
+ fprintf(out, "]");
+ fclose(out);
+ out = nullptr;
+ }
+
+#ifdef DEBUG
+ initialized = false;
+#endif
+}
+
+uint32_t
+TraceLoggerGraphState::nextLoggerId()
+{
+ js::LockGuard<js::Mutex> guard(lock);
+
+ MOZ_ASSERT(initialized);
+
+ if (numLoggers > MAX_LOGGERS) {
+ fputs("TraceLogging: Can't create more than " XSTRING(MAX_LOGGERS) " different loggers.",
+ stderr);
+ return uint32_t(-1);
+ }
+
+ if (numLoggers > 0) {
+ int written = fprintf(out, ",\n");
+ if (written < 0) {
+ fprintf(stderr, "TraceLogging: Error while writing.\n");
+ return uint32_t(-1);
+ }
+ }
+
+ int written = fprintf(out, "{\"tree\":\"tl-tree.%u.%d.tl\", \"events\":\"tl-event.%u.%d.tl\", "
+ "\"dict\":\"tl-dict.%u.%d.json\", \"treeFormat\":\"64,64,31,1,32\"",
+ pid_, numLoggers, pid_, numLoggers, pid_, numLoggers);
+
+ if (written > 0) {
+ char threadName[16];
+ js::ThisThread::GetName(threadName, sizeof(threadName));
+ if (threadName[0])
+ written = fprintf(out, ", \"threadName\":\"%s\"", threadName);
+ }
+
+ if (written > 0)
+ written = fprintf(out, "}");
+
+ if (written < 0) {
+ fprintf(stderr, "TraceLogging: Error while writing.\n");
+ return uint32_t(-1);
+ }
+
+ return numLoggers++;
+}
+
+static bool
+EnsureTraceLoggerGraphState()
+{
+ if (MOZ_LIKELY(traceLoggerGraphState))
+ return true;
+
+ traceLoggerGraphState = js_new<TraceLoggerGraphState>();
+ if (!traceLoggerGraphState)
+ return false;
+
+ if (!traceLoggerGraphState->init()) {
+ js::DestroyTraceLoggerGraphState();
+ return false;
+ }
+
+ return true;
+}
+
+void
+js::DestroyTraceLoggerGraphState()
+{
+ if (traceLoggerGraphState) {
+ js_delete(traceLoggerGraphState);
+ traceLoggerGraphState = nullptr;
+ }
+}
+
+bool
+TraceLoggerGraph::init(uint64_t startTimestamp)
+{
+ auto fail = MakeScopeExit([&] { failed = true; });
+
+ if (!tree.init())
+ return false;
+ if (!stack.init())
+ return false;
+
+ if (!EnsureTraceLoggerGraphState())
+ return false;
+
+ uint32_t loggerId = traceLoggerGraphState->nextLoggerId();
+ if (loggerId == uint32_t(-1))
+ return false;
+
+ uint32_t pid = traceLoggerGraphState->pid();
+
+ js::UniqueChars dictFilename = AllocTraceLogFilename("tl-dict.%u.%d.json", pid, loggerId);
+ dictFile = fopen(dictFilename.get(), "w");
+ if (!dictFile)
+ return false;
+ auto cleanupDict = MakeScopeExit([&] { fclose(dictFile); dictFile = nullptr; });
+
+ js::UniqueChars treeFilename = AllocTraceLogFilename("tl-tree.%u.%d.tl", pid, loggerId);
+ treeFile = fopen(treeFilename.get(), "w+b");
+ if (!treeFile)
+ return false;
+ auto cleanupTree = MakeScopeExit([&] { fclose(treeFile); treeFile = nullptr; });
+
+ js::UniqueChars eventFilename = AllocTraceLogFilename("tl-event.%u.%d.tl", pid, loggerId);
+ eventFile = fopen(eventFilename.get(), "wb");
+ if (!eventFile)
+ return false;
+ auto cleanupEvent = MakeScopeExit([&] { fclose(eventFile); eventFile = nullptr; });
+
+ // Create the top tree node and corresponding first stack item.
+ TreeEntry& treeEntry = tree.pushUninitialized();
+ treeEntry.setStart(startTimestamp);
+ treeEntry.setStop(0);
+ treeEntry.setTextId(0);
+ treeEntry.setHasChildren(false);
+ treeEntry.setNextId(0);
+
+ StackEntry& stackEntry = stack.pushUninitialized();
+ stackEntry.setTreeId(0);
+ stackEntry.setLastChildId(0);
+ stackEntry.setActive(true);
+
+ if (fprintf(dictFile, "[") < 0) {
+ fprintf(stderr, "TraceLogging: Error while writing.\n");
+ return false;
+ }
+
+ fail.release();
+ cleanupDict.release();
+ cleanupTree.release();
+ cleanupEvent.release();
+
+ return true;
+}
+
+TraceLoggerGraph::~TraceLoggerGraph()
+{
+ // Write dictionary to disk
+ if (dictFile) {
+ int written = fprintf(dictFile, "]");
+ if (written < 0)
+ fprintf(stderr, "TraceLogging: Error while writing.\n");
+ fclose(dictFile);
+
+ dictFile = nullptr;
+ }
+
+ if (!failed && treeFile) {
+ // Make sure every start entry has a corresponding stop value.
+ // We temporarily enable logging for this. Stop doesn't need any extra data,
+ // so is safe to do even when we have encountered OOM.
+ enabled = true;
+ while (stack.size() > 1)
+ stopEvent(0);
+ enabled = false;
+ }
+
+ if (!failed && !flush()) {
+ fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
+ enabled = false;
+ failed = true;
+ }
+
+ if (treeFile) {
+ fclose(treeFile);
+ treeFile = nullptr;
+ }
+
+ if (eventFile) {
+ fclose(eventFile);
+ eventFile = nullptr;
+ }
+}
+
+bool
+TraceLoggerGraph::flush()
+{
+ MOZ_ASSERT(!failed);
+
+ if (treeFile) {
+ // Format data in big endian.
+ for (size_t i = 0; i < tree.size(); i++)
+ entryToBigEndian(&tree[i]);
+
+ int success = fseek(treeFile, 0, SEEK_END);
+ if (success != 0)
+ return false;
+
+ size_t bytesWritten = fwrite(tree.data(), sizeof(TreeEntry), tree.size(), treeFile);
+ if (bytesWritten < tree.size())
+ return false;
+
+ treeOffset += tree.size();
+ tree.clear();
+ }
+
+ return true;
+}
+
+void
+TraceLoggerGraph::entryToBigEndian(TreeEntry* entry)
+{
+ entry->start_ = NativeEndian::swapToBigEndian(entry->start_);
+ entry->stop_ = NativeEndian::swapToBigEndian(entry->stop_);
+ uint32_t data = (entry->u.s.textId_ << 1) + entry->u.s.hasChildren_;
+ entry->u.value_ = NativeEndian::swapToBigEndian(data);
+ entry->nextId_ = NativeEndian::swapToBigEndian(entry->nextId_);
+}
+
+void
+TraceLoggerGraph::entryToSystemEndian(TreeEntry* entry)
+{
+ entry->start_ = NativeEndian::swapFromBigEndian(entry->start_);
+ entry->stop_ = NativeEndian::swapFromBigEndian(entry->stop_);
+
+ uint32_t data = NativeEndian::swapFromBigEndian(entry->u.value_);
+ entry->u.s.textId_ = data >> 1;
+ entry->u.s.hasChildren_ = data & 0x1;
+
+ entry->nextId_ = NativeEndian::swapFromBigEndian(entry->nextId_);
+}
+
+void
+TraceLoggerGraph::startEvent(uint32_t id, uint64_t timestamp)
+{
+ if (failed || enabled == 0)
+ return;
+
+ if (!tree.hasSpaceForAdd()) {
+ if (tree.size() >= treeSizeFlushLimit() || !tree.ensureSpaceBeforeAdd()) {
+ if (!flush()) {
+ fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
+ enabled = false;
+ failed = true;
+ return;
+ }
+ }
+ }
+
+ if (!startEventInternal(id, timestamp)) {
+ fprintf(stderr, "TraceLogging: Failed to start an event.\n");
+ enabled = false;
+ failed = true;
+ return;
+ }
+}
+
+TraceLoggerGraph::StackEntry&
+TraceLoggerGraph::getActiveAncestor()
+{
+ uint32_t parentId = stack.lastEntryId();
+ while (!stack[parentId].active())
+ parentId--;
+ return stack[parentId];
+}
+
+bool
+TraceLoggerGraph::startEventInternal(uint32_t id, uint64_t timestamp)
+{
+ if (!stack.ensureSpaceBeforeAdd())
+ return false;
+
+ // Patch up the tree to be correct. There are two scenarios:
+ // 1) Parent has no children yet. So update parent to include children.
+ // 2) Parent has already children. Update last child to link to the new
+ // child.
+ StackEntry& parent = getActiveAncestor();
+#ifdef DEBUG
+ TreeEntry entry;
+ if (!getTreeEntry(parent.treeId(), &entry))
+ return false;
+#endif
+
+ if (parent.lastChildId() == 0) {
+ MOZ_ASSERT(!entry.hasChildren());
+ MOZ_ASSERT(parent.treeId() == treeOffset + tree.size() - 1);
+
+ if (!updateHasChildren(parent.treeId()))
+ return false;
+ } else {
+ MOZ_ASSERT(entry.hasChildren());
+
+ if (!updateNextId(parent.lastChildId(), tree.size() + treeOffset))
+ return false;
+ }
+
+ // Add a new tree entry.
+ TreeEntry& treeEntry = tree.pushUninitialized();
+ treeEntry.setStart(timestamp);
+ treeEntry.setStop(0);
+ treeEntry.setTextId(id);
+ treeEntry.setHasChildren(false);
+ treeEntry.setNextId(0);
+
+ // Add a new stack entry.
+ StackEntry& stackEntry = stack.pushUninitialized();
+ stackEntry.setTreeId(tree.lastEntryId() + treeOffset);
+ stackEntry.setLastChildId(0);
+ stackEntry.setActive(true);
+
+ // Set the last child of the parent to this newly added entry.
+ parent.setLastChildId(tree.lastEntryId() + treeOffset);
+
+ return true;
+}
+
+void
+TraceLoggerGraph::stopEvent(uint32_t id, uint64_t timestamp)
+{
+#ifdef DEBUG
+ if (id != TraceLogger_Scripts &&
+ id != TraceLogger_Engine &&
+ stack.size() > 1 &&
+ stack.lastEntry().active())
+ {
+ TreeEntry entry;
+ MOZ_ASSERT(getTreeEntry(stack.lastEntry().treeId(), &entry));
+ MOZ_ASSERT(entry.textId() == id);
+ }
+#endif
+
+ stopEvent(timestamp);
+}
+
+void
+TraceLoggerGraph::stopEvent(uint64_t timestamp)
+{
+ if (enabled && stack.lastEntry().active()) {
+ if (!updateStop(stack.lastEntry().treeId(), timestamp)) {
+ fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
+ enabled = false;
+ failed = true;
+ return;
+ }
+ }
+ if (stack.size() == 1) {
+ if (!enabled)
+ return;
+
+ // Forcefully disable logging. We have no stack information anymore.
+ logTimestamp(TraceLogger_Disable, timestamp);
+ return;
+ }
+ stack.pop();
+}
+
+void
+TraceLoggerGraph::logTimestamp(uint32_t id, uint64_t timestamp)
+{
+ if (failed)
+ return;
+
+ if (id == TraceLogger_Enable)
+ enabled = true;
+
+ if (!enabled)
+ return;
+
+ if (id == TraceLogger_Disable)
+ disable(timestamp);
+
+ MOZ_ASSERT(eventFile);
+
+ // Format data in big endian
+ timestamp = NativeEndian::swapToBigEndian(timestamp);
+ id = NativeEndian::swapToBigEndian(id);
+
+ // The layout of the event log in the log file is:
+ // [timestamp, textId]
+ size_t itemsWritten = 0;
+ itemsWritten += fwrite(&timestamp, sizeof(uint64_t), 1, eventFile);
+ itemsWritten += fwrite(&id, sizeof(uint32_t), 1, eventFile);
+ if (itemsWritten < 2) {
+ failed = true;
+ enabled = false;
+ }
+}
+
+bool
+TraceLoggerGraph::getTreeEntry(uint32_t treeId, TreeEntry* entry)
+{
+ // Entry is still in memory
+ if (treeId >= treeOffset) {
+ *entry = tree[treeId - treeOffset];
+ return true;
+ }
+
+ int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
+ if (success != 0)
+ return false;
+
+ size_t itemsRead = fread((void*)entry, sizeof(TreeEntry), 1, treeFile);
+ if (itemsRead < 1)
+ return false;
+
+ entryToSystemEndian(entry);
+ return true;
+}
+
+bool
+TraceLoggerGraph::saveTreeEntry(uint32_t treeId, TreeEntry* entry)
+{
+ int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
+ if (success != 0)
+ return false;
+
+ entryToBigEndian(entry);
+
+ size_t itemsWritten = fwrite(entry, sizeof(TreeEntry), 1, treeFile);
+ if (itemsWritten < 1)
+ return false;
+
+ return true;
+}
+
+bool
+TraceLoggerGraph::updateHasChildren(uint32_t treeId, bool hasChildren)
+{
+ if (treeId < treeOffset) {
+ TreeEntry entry;
+ if (!getTreeEntry(treeId, &entry))
+ return false;
+ entry.setHasChildren(hasChildren);
+ if (!saveTreeEntry(treeId, &entry))
+ return false;
+ return true;
+ }
+
+ tree[treeId - treeOffset].setHasChildren(hasChildren);
+ return true;
+}
+
+bool
+TraceLoggerGraph::updateNextId(uint32_t treeId, uint32_t nextId)
+{
+ if (treeId < treeOffset) {
+ TreeEntry entry;
+ if (!getTreeEntry(treeId, &entry))
+ return false;
+ entry.setNextId(nextId);
+ if (!saveTreeEntry(treeId, &entry))
+ return false;
+ return true;
+ }
+
+ tree[treeId - treeOffset].setNextId(nextId);
+ return true;
+}
+
+bool
+TraceLoggerGraph::updateStop(uint32_t treeId, uint64_t timestamp)
+{
+ if (treeId < treeOffset) {
+ TreeEntry entry;
+ if (!getTreeEntry(treeId, &entry))
+ return false;
+ entry.setStop(timestamp);
+ if (!saveTreeEntry(treeId, &entry))
+ return false;
+ return true;
+ }
+
+ tree[treeId - treeOffset].setStop(timestamp);
+ return true;
+}
+
+void
+TraceLoggerGraph::disable(uint64_t timestamp)
+{
+ MOZ_ASSERT(enabled);
+ while (stack.size() > 1)
+ stopEvent(timestamp);
+
+ enabled = false;
+}
+
+void
+TraceLoggerGraph::log(ContinuousSpace<EventEntry>& events)
+{
+ for (uint32_t i = 0; i < events.size(); i++) {
+ if (events[i].textId == TraceLogger_Stop)
+ stopEvent(events[i].time);
+ else if (TLTextIdIsTreeEvent(events[i].textId))
+ startEvent(events[i].textId, events[i].time);
+ else
+ logTimestamp(events[i].textId, events[i].time);
+ }
+}
+
+void
+TraceLoggerGraph::addTextId(uint32_t id, const char* text)
+{
+ if (failed)
+ return;
+
+ // Assume ids are given in order. Which is currently true.
+#ifdef DEBUG
+ MOZ_ASSERT(id == nextTextId);
+ nextTextId++;
+#endif
+
+ if (id > 0) {
+ int written = fprintf(dictFile, ",\n");
+ if (written < 0) {
+ failed = true;
+ return;
+ }
+ }
+
+ if (!js::FileEscapedString(dictFile, text, strlen(text), '"'))
+ failed = true;
+}
+
+#undef getpid
diff --git a/js/src/vm/TraceLoggingGraph.h b/js/src/vm/TraceLoggingGraph.h
new file mode 100644
index 000000000..6d596952b
--- /dev/null
+++ b/js/src/vm/TraceLoggingGraph.h
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TraceLoggingGraph_h
+#define TraceLoggingGraph_h
+
+#include "js/TypeDecls.h"
+#include "vm/MutexIDs.h"
+#include "vm/TraceLoggingTypes.h"
+
+/*
+ * The output of a tracelogging session is saved in /tmp/tl-data.json.
+ * The format of that file is a JS array per tracelogger (=thread), with a map
+ * containing:
+ * - dict: Name of the file containing a json table with the log text.
+ * All other files only contain a index to this table when logging.
+ * - events: Name of the file containing a flat list of log events saved
+ * in binary format.
+ * (64bit: Time Stamp Counter, 32bit index to dict)
+ * - tree: Name of the file containing the events with duration. The content
+ * is already in a tree data structure. This is also saved in a
+ * binary file.
+ * - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
+ * There are currently no other formats to save the tree.
+ * - 64,64,31,1,32 signifies how many bytes are used for the different
+ * parts of the tree.
+ * => 64 bits: Time Stamp Counter of start of event.
+ * => 64 bits: Time Stamp Counter of end of event.
+ * => 31 bits: Index to dict file containing the log text.
+ * => 1 bit: Boolean signifying if this entry has children.
+ * When true, the child can be found just right after this entry.
+ * => 32 bits: Containing the ID of the next event on the same depth
+ * or 0 if there isn't an event on the same depth anymore.
+ *
+ * /-> The position in the file. Id is this divided by size of entry.
+ * | So in this case this would be 1 (192bits per entry).
+ * | /-> Indicates there are children. The
+ * | | first child is located at current
+ * | | ID + 1. So 1 + 1 in this case: 2.
+ * | | Or 0x00180 in the tree file.
+ * | | /-> Next event on the same depth is
+ * | | | located at 4. So 0x00300 in the
+ * | | | tree file.
+ * 0x0000C0: [start, end, dictId, 1, 4]
+ *
+ *
+ * Example:
+ * 0x0: [start, end, dictId, 1, 0]
+ * |
+ * /----------------------------------\
+ * | |
+ * 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0]
+ * |
+ * /----------------------------------\
+ * | |
+ * 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0]
+ */
+
+namespace js {
+void DestroyTraceLoggerGraphState();
+} // namespace js
+
+class TraceLoggerGraphState
+{
+ uint32_t numLoggers;
+ uint32_t pid_;
+
+ // File pointer to the "tl-data.json" file. (Explained above).
+ FILE* out;
+
+#ifdef DEBUG
+ bool initialized;
+#endif
+
+ public:
+ js::Mutex lock;
+
+ public:
+ TraceLoggerGraphState()
+ : numLoggers(0)
+ , pid_(0)
+ , out(nullptr)
+#ifdef DEBUG
+ , initialized(false)
+#endif
+ , lock(js::mutexid::TraceLoggerGraphState)
+ {}
+
+ bool init();
+ ~TraceLoggerGraphState();
+
+ uint32_t nextLoggerId();
+ uint32_t pid() { return pid_; }
+};
+
+class TraceLoggerGraph
+{
+ // The layout of the tree in memory and in the log file. Readable by JS
+ // using TypedArrays.
+ struct TreeEntry {
+ uint64_t start_;
+ uint64_t stop_;
+ union {
+ struct {
+ uint32_t textId_: 31;
+ uint32_t hasChildren_: 1;
+ } s;
+ uint32_t value_;
+ } u;
+ uint32_t nextId_;
+
+ TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
+ uint32_t nextId)
+ {
+ start_ = start;
+ stop_ = stop;
+ u.s.textId_ = textId;
+ u.s.hasChildren_ = hasChildren;
+ nextId_ = nextId;
+ }
+ TreeEntry()
+ { }
+ uint64_t start() {
+ return start_;
+ }
+ uint64_t stop() {
+ return stop_;
+ }
+ uint32_t textId() {
+ return u.s.textId_;
+ }
+ bool hasChildren() {
+ return u.s.hasChildren_;
+ }
+ uint32_t nextId() {
+ return nextId_;
+ }
+ void setStart(uint64_t start) {
+ start_ = start;
+ }
+ void setStop(uint64_t stop) {
+ stop_ = stop;
+ }
+ void setTextId(uint32_t textId) {
+ MOZ_ASSERT(textId < uint32_t(1 << 31));
+ u.s.textId_ = textId;
+ }
+ void setHasChildren(bool hasChildren) {
+ u.s.hasChildren_ = hasChildren;
+ }
+ void setNextId(uint32_t nextId) {
+ nextId_ = nextId;
+ }
+ };
+
+ // Helper structure for keeping track of the current entries in
+ // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
+ // is used to know if a subtree doesn't need to get logged.
+ struct StackEntry {
+ uint32_t treeId_;
+ uint32_t lastChildId_;
+ struct {
+ uint32_t textId_: 31;
+ uint32_t active_: 1;
+ } s;
+ StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
+ : treeId_(treeId), lastChildId_(lastChildId)
+ {
+ s.textId_ = 0;
+ s.active_ = active;
+ }
+ uint32_t treeId() {
+ return treeId_;
+ }
+ uint32_t lastChildId() {
+ return lastChildId_;
+ }
+ uint32_t textId() {
+ return s.textId_;
+ }
+ bool active() {
+ return s.active_;
+ }
+ void setTreeId(uint32_t treeId) {
+ treeId_ = treeId;
+ }
+ void setLastChildId(uint32_t lastChildId) {
+ lastChildId_ = lastChildId;
+ }
+ void setTextId(uint32_t textId) {
+ MOZ_ASSERT(textId < uint32_t(1<<31));
+ s.textId_ = textId;
+ }
+ void setActive(bool active) {
+ s.active_ = active;
+ }
+ };
+
+ public:
+ TraceLoggerGraph() {}
+ ~TraceLoggerGraph();
+
+ bool init(uint64_t timestamp);
+
+ // Link a textId with a particular text.
+ void addTextId(uint32_t id, const char* text);
+
+ // Create a tree out of all the given events.
+ void log(ContinuousSpace<EventEntry>& events);
+
+ static size_t treeSizeFlushLimit() {
+ // Allow tree size to grow to 100MB.
+ return 100 * 1024 * 1024 / sizeof(TreeEntry);
+ }
+
+ private:
+ bool failed = false;
+ bool enabled = false;
+#ifdef DEBUG
+ uint32_t nextTextId = 0;
+#endif
+
+ FILE* dictFile = nullptr;
+ FILE* treeFile = nullptr;
+ FILE* eventFile = nullptr;
+
+ ContinuousSpace<TreeEntry> tree;
+ ContinuousSpace<StackEntry> stack;
+ uint32_t treeOffset = 0;
+
+ // Helper functions that convert a TreeEntry in different endianness
+ // in place.
+ void entryToBigEndian(TreeEntry* entry);
+ void entryToSystemEndian(TreeEntry* entry);
+
+ // Helper functions to get/save a tree from file.
+ bool getTreeEntry(uint32_t treeId, TreeEntry* entry);
+ bool saveTreeEntry(uint32_t treeId, TreeEntry* entry);
+
+ // Return the first StackEntry that is active.
+ StackEntry& getActiveAncestor();
+
+ // This contains the meat of startEvent, except the test for enough space,
+ // the test if tracelogger is enabled and the timestamp computation.
+ void startEvent(uint32_t id, uint64_t timestamp);
+ bool startEventInternal(uint32_t id, uint64_t timestamp);
+
+ // Update functions that can adjust the items in the tree,
+ // both in memory or already written to disk.
+ bool updateHasChildren(uint32_t treeId, bool hasChildren = true);
+ bool updateNextId(uint32_t treeId, uint32_t nextId);
+ bool updateStop(uint32_t treeId, uint64_t timestamp);
+
+ // Flush the tree.
+ bool flush();
+
+ // Stop a tree event.
+ void stopEvent(uint32_t id, uint64_t timestamp);
+ void stopEvent(uint64_t timestamp);
+
+ // Log an (non-tree) event.
+ void logTimestamp(uint32_t id, uint64_t timestamp);
+
+ // Disable logging and forcefully report all not yet stopped tree events
+ // as stopped.
+ void disable(uint64_t timestamp);
+};
+
+#endif /* TraceLoggingGraph_h */
diff --git a/js/src/vm/TraceLoggingTypes.cpp b/js/src/vm/TraceLoggingTypes.cpp
new file mode 100644
index 000000000..188bedd9e
--- /dev/null
+++ b/js/src/vm/TraceLoggingTypes.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TraceLoggingTypes.h"
+
+class JSLinearString;
+
+uint32_t
+TLStringToTextId(JSLinearString* str)
+{
+#define NAME(textId) if (js::StringEqualsAscii(str, #textId)) return TraceLogger_ ## textId;
+ TRACELOGGER_TREE_ITEMS(NAME)
+ TRACELOGGER_LOG_ITEMS(NAME)
+#undef NAME
+ return TraceLogger_Error;
+}
+
diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h
new file mode 100644
index 000000000..aa2dfe6bb
--- /dev/null
+++ b/js/src/vm/TraceLoggingTypes.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TraceLoggingTypes_h
+#define TraceLoggingTypes_h
+
+#include "jsalloc.h"
+#include "jsstr.h"
+
+// Tree items, meaning they have a start and stop and form a nested tree.
+#define TRACELOGGER_TREE_ITEMS(_) \
+ _(AnnotateScripts) \
+ _(Baseline) \
+ _(BaselineCompilation) \
+ _(Engine) \
+ _(GC) \
+ _(GCAllocation) \
+ _(GCSweeping) \
+ _(Interpreter) \
+ _(InlinedScripts) \
+ _(IonAnalysis) \
+ _(IonCompilation) \
+ _(IonCompilationPaused) \
+ _(IonLinking) \
+ _(IonMonkey) \
+ _(IrregexpCompile) \
+ _(IrregexpExecute) \
+ _(MinorGC) \
+ _(ParserCompileFunction) \
+ _(ParserCompileLazy) \
+ _(ParserCompileScript) \
+ _(ParserCompileModule) \
+ _(Scripts) \
+ _(VM) \
+ _(CompressSource) \
+ _(WasmCompilation) \
+ _(Call) \
+ \
+ /* Specific passes during ion compilation */ \
+ _(PruneUnusedBranches) \
+ _(FoldTests) \
+ _(SplitCriticalEdges) \
+ _(RenumberBlocks) \
+ _(ScalarReplacement) \
+ _(DominatorTree) \
+ _(PhiAnalysis) \
+ _(MakeLoopsContiguous) \
+ _(ApplyTypes) \
+ _(EagerSimdUnbox) \
+ _(AliasAnalysis) \
+ _(GVN) \
+ _(LICM) \
+ _(Sincos) \
+ _(RangeAnalysis) \
+ _(LoopUnrolling) \
+ _(Sink) \
+ _(RemoveUnnecessaryBitops) \
+ _(FoldLinearArithConstants) \
+ _(EffectiveAddressAnalysis) \
+ _(AlignmentMaskAnalysis) \
+ _(EliminateDeadCode) \
+ _(ReorderInstructions) \
+ _(EdgeCaseAnalysis) \
+ _(EliminateRedundantChecks) \
+ _(AddKeepAliveInstructions) \
+ _(GenerateLIR) \
+ _(RegisterAllocation) \
+ _(GenerateCode) \
+ _(IonBuilderRestartLoop) \
+ _(VMSpecific)
+
+// Log items, with timestamp only.
+#define TRACELOGGER_LOG_ITEMS(_) \
+ _(Bailout) \
+ _(Invalidation) \
+ _(Disable) \
+ _(Enable) \
+ _(Stop)
+
+// Predefined IDs for common operations. These IDs can be used
+// without using TraceLogCreateTextId, because there are already created.
+enum TraceLoggerTextId {
+ TraceLogger_Error = 0,
+ TraceLogger_Internal,
+#define DEFINE_TEXT_ID(textId) TraceLogger_ ## textId,
+ TRACELOGGER_TREE_ITEMS(DEFINE_TEXT_ID)
+ TraceLogger_LastTreeItem,
+ TRACELOGGER_LOG_ITEMS(DEFINE_TEXT_ID)
+#undef DEFINE_TEXT_ID
+ TraceLogger_Last
+};
+
+inline const char*
+TLTextIdString(TraceLoggerTextId id)
+{
+ switch (id) {
+ case TraceLogger_Error:
+ return "TraceLogger failed to process text";
+ case TraceLogger_Internal:
+ return "TraceLogger overhead";
+#define NAME(textId) case TraceLogger_ ## textId: return #textId;
+ TRACELOGGER_TREE_ITEMS(NAME)
+ TRACELOGGER_LOG_ITEMS(NAME)
+#undef NAME
+ default:
+ MOZ_CRASH();
+ }
+}
+
+uint32_t
+TLStringToTextId(JSLinearString* str);
+
+// Return whether a given item id can be enabled/disabled.
+inline bool
+TLTextIdIsTogglable(uint32_t id)
+{
+ if (id == TraceLogger_Error)
+ return false;
+ if (id == TraceLogger_Internal)
+ return false;
+ if (id == TraceLogger_Stop)
+ return false;
+ // Actually never used. But added here so it doesn't show as toggle
+ if (id == TraceLogger_LastTreeItem)
+ return false;
+ if (id == TraceLogger_Last)
+ return false;
+ // Cannot toggle the logging of one engine on/off, because at the stop
+ // event it is sometimes unknown which engine was running.
+ if (id == TraceLogger_IonMonkey || id == TraceLogger_Baseline || id == TraceLogger_Interpreter)
+ return false;
+ return true;
+}
+
+inline bool
+TLTextIdIsTreeEvent(uint32_t id)
+{
+ // Everything between TraceLogger_Error and TraceLogger_LastTreeItem are tree events and
+ // atm also every custom event.
+ return (id > TraceLogger_Error && id < TraceLogger_LastTreeItem) ||
+ id >= TraceLogger_Last;
+}
+
+template <class T>
+class ContinuousSpace {
+ T* data_;
+ uint32_t size_;
+ uint32_t capacity_;
+
+ // The maximum number of bytes of RAM a continuous space structure can take.
+ static const uint32_t LIMIT = 200 * 1024 * 1024;
+
+ public:
+ ContinuousSpace ()
+ : data_(nullptr)
+ { }
+
+ bool init() {
+ capacity_ = 64;
+ size_ = 0;
+ data_ = (T*) js_malloc(capacity_ * sizeof(T));
+ if (!data_)
+ return false;
+
+ return true;
+ }
+
+ ~ContinuousSpace()
+ {
+ js_free(data_);
+ data_ = nullptr;
+ }
+
+ static uint32_t maxSize() {
+ return LIMIT / sizeof(T);
+ }
+
+ T* data() {
+ return data_;
+ }
+
+ uint32_t capacity() const {
+ return capacity_;
+ }
+
+ uint32_t size() const {
+ return size_;
+ }
+
+ bool empty() const {
+ return size_ == 0;
+ }
+
+ uint32_t lastEntryId() const {
+ MOZ_ASSERT(!empty());
+ return size_ - 1;
+ }
+
+ T& lastEntry() {
+ return data()[lastEntryId()];
+ }
+
+ bool hasSpaceForAdd(uint32_t count = 1) {
+ if (size_ + count <= capacity_)
+ return true;
+ return false;
+ }
+
+ bool ensureSpaceBeforeAdd(uint32_t count = 1) {
+ MOZ_ASSERT(data_);
+ if (hasSpaceForAdd(count))
+ return true;
+
+ // Limit the size of a continuous buffer.
+ if (size_ + count > maxSize())
+ return false;
+
+ uint32_t nCapacity = capacity_ * 2;
+ nCapacity = (nCapacity < maxSize()) ? nCapacity : maxSize();
+
+ T* entries = (T*) js_realloc(data_, nCapacity * sizeof(T));
+ if (!entries)
+ return false;
+
+ data_ = entries;
+ capacity_ = nCapacity;
+
+ return true;
+ }
+
+ T& operator[](size_t i) {
+ MOZ_ASSERT(i < size_);
+ return data()[i];
+ }
+
+ void push(T& data) {
+ MOZ_ASSERT(size_ < capacity_);
+ data()[size_++] = data;
+ }
+
+ T& pushUninitialized() {
+ MOZ_ASSERT(size_ < capacity_);
+ return data()[size_++];
+ }
+
+ void pop() {
+ MOZ_ASSERT(!empty());
+ size_--;
+ }
+
+ void clear() {
+ size_ = 0;
+ }
+};
+
+// The layout of the event log in memory and in the log file.
+// Readable by JS using TypedArrays.
+struct EventEntry {
+ uint64_t time;
+ uint32_t textId;
+ EventEntry(uint64_t time, uint32_t textId)
+ : time(time), textId(textId)
+ { }
+};
+
+#endif /* TraceLoggingTypes_h */
diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h
new file mode 100644
index 000000000..da47fa898
--- /dev/null
+++ b/js/src/vm/TypeInference-inl.h
@@ -0,0 +1,1130 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Inline members for javascript type inference. */
+
+#ifndef vm_TypeInference_inl_h
+#define vm_TypeInference_inl_h
+
+#include "vm/TypeInference.h"
+
+#include "mozilla/BinarySearch.h"
+#include "mozilla/Casting.h"
+#include "mozilla/PodOperations.h"
+
+#include "builtin/SymbolObject.h"
+#include "jit/BaselineJIT.h"
+#include "vm/ArrayObject.h"
+#include "vm/BooleanObject.h"
+#include "vm/NumberObject.h"
+#include "vm/SharedArrayObject.h"
+#include "vm/StringObject.h"
+#include "vm/TypedArrayObject.h"
+#include "vm/UnboxedObject.h"
+
+#include "jscntxtinlines.h"
+
+#include "vm/ObjectGroup-inl.h"
+
+namespace js {
+
+/////////////////////////////////////////////////////////////////////
+// CompilerOutput & RecompileInfo
+/////////////////////////////////////////////////////////////////////
+
+inline jit::IonScript*
+CompilerOutput::ion() const
+{
+ // Note: If type constraints are generated before compilation has finished
+ // (i.e. after IonBuilder but before CodeGenerator::link) then a valid
+ // CompilerOutput may not yet have an associated IonScript.
+ MOZ_ASSERT(isValid());
+ jit::IonScript* ion = script()->maybeIonScript();
+ MOZ_ASSERT(ion != ION_COMPILING_SCRIPT);
+ return ion;
+}
+
+inline CompilerOutput*
+RecompileInfo::compilerOutput(TypeZone& types) const
+{
+ if (generation != types.generation) {
+ if (!types.sweepCompilerOutputs || outputIndex >= types.sweepCompilerOutputs->length())
+ return nullptr;
+ CompilerOutput* output = &(*types.sweepCompilerOutputs)[outputIndex];
+ if (!output->isValid())
+ return nullptr;
+ output = &(*types.compilerOutputs)[output->sweepIndex()];
+ return output->isValid() ? output : nullptr;
+ }
+
+ if (!types.compilerOutputs || outputIndex >= types.compilerOutputs->length())
+ return nullptr;
+ CompilerOutput* output = &(*types.compilerOutputs)[outputIndex];
+ return output->isValid() ? output : nullptr;
+}
+
+inline CompilerOutput*
+RecompileInfo::compilerOutput(JSContext* cx) const
+{
+ return compilerOutput(cx->zone()->types);
+}
+
+inline bool
+RecompileInfo::shouldSweep(TypeZone& types)
+{
+ CompilerOutput* output = compilerOutput(types);
+ if (!output || !output->isValid())
+ return true;
+
+ // If this info is for a compilation that occurred after sweeping started,
+ // the index is already correct.
+ MOZ_ASSERT_IF(generation == types.generation,
+ outputIndex == output - types.compilerOutputs->begin());
+
+ // Update this info for the output's index in the zone's compiler outputs.
+ outputIndex = output - types.compilerOutputs->begin();
+ generation = types.generation;
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Types
+/////////////////////////////////////////////////////////////////////
+
+/* static */ inline TypeSet::ObjectKey*
+TypeSet::ObjectKey::get(JSObject* obj)
+{
+ MOZ_ASSERT(obj);
+ if (obj->isSingleton())
+ return (ObjectKey*) (uintptr_t(obj) | 1);
+ return (ObjectKey*) obj->group();
+}
+
+/* static */ inline TypeSet::ObjectKey*
+TypeSet::ObjectKey::get(ObjectGroup* group)
+{
+ MOZ_ASSERT(group);
+ if (group->singleton())
+ return (ObjectKey*) (uintptr_t(group->singleton()) | 1);
+ return (ObjectKey*) group;
+}
+
+inline ObjectGroup*
+TypeSet::ObjectKey::groupNoBarrier()
+{
+ MOZ_ASSERT(isGroup());
+ return (ObjectGroup*) this;
+}
+
+inline JSObject*
+TypeSet::ObjectKey::singletonNoBarrier()
+{
+ MOZ_ASSERT(isSingleton());
+ return (JSObject*) (uintptr_t(this) & ~1);
+}
+
+inline ObjectGroup*
+TypeSet::ObjectKey::group()
+{
+ ObjectGroup* res = groupNoBarrier();
+ ObjectGroup::readBarrier(res);
+ return res;
+}
+
+inline JSObject*
+TypeSet::ObjectKey::singleton()
+{
+ JSObject* res = singletonNoBarrier();
+ JSObject::readBarrier(res);
+ return res;
+}
+
+inline JSCompartment*
+TypeSet::ObjectKey::maybeCompartment()
+{
+ if (isSingleton())
+ return singleton()->compartment();
+
+ return group()->compartment();
+}
+
+/* static */ inline TypeSet::Type
+TypeSet::ObjectType(JSObject* obj)
+{
+ if (obj->isSingleton())
+ return Type(uintptr_t(obj) | 1);
+ return Type(uintptr_t(obj->group()));
+}
+
+/* static */ inline TypeSet::Type
+TypeSet::ObjectType(ObjectGroup* group)
+{
+ if (group->singleton())
+ return Type(uintptr_t(group->singleton()) | 1);
+ return Type(uintptr_t(group));
+}
+
+/* static */ inline TypeSet::Type
+TypeSet::ObjectType(ObjectKey* obj)
+{
+ return Type(uintptr_t(obj));
+}
+
+inline TypeSet::Type
+TypeSet::GetValueType(const Value& val)
+{
+ if (val.isDouble())
+ return TypeSet::DoubleType();
+ if (val.isObject())
+ return TypeSet::ObjectType(&val.toObject());
+ return TypeSet::PrimitiveType(val.extractNonDoubleType());
+}
+
+inline bool
+TypeSet::IsUntrackedValue(const Value& val)
+{
+ return val.isMagic() && (val.whyMagic() == JS_OPTIMIZED_OUT ||
+ val.whyMagic() == JS_UNINITIALIZED_LEXICAL);
+}
+
+inline TypeSet::Type
+TypeSet::GetMaybeUntrackedValueType(const Value& val)
+{
+ return IsUntrackedValue(val) ? UnknownType() : GetValueType(val);
+}
+
+inline TypeFlags
+PrimitiveTypeFlag(JSValueType type)
+{
+ switch (type) {
+ case JSVAL_TYPE_UNDEFINED:
+ return TYPE_FLAG_UNDEFINED;
+ case JSVAL_TYPE_NULL:
+ return TYPE_FLAG_NULL;
+ case JSVAL_TYPE_BOOLEAN:
+ return TYPE_FLAG_BOOLEAN;
+ case JSVAL_TYPE_INT32:
+ return TYPE_FLAG_INT32;
+ case JSVAL_TYPE_DOUBLE:
+ return TYPE_FLAG_DOUBLE;
+ case JSVAL_TYPE_STRING:
+ return TYPE_FLAG_STRING;
+ case JSVAL_TYPE_SYMBOL:
+ return TYPE_FLAG_SYMBOL;
+ case JSVAL_TYPE_MAGIC:
+ return TYPE_FLAG_LAZYARGS;
+ default:
+ MOZ_CRASH("Bad JSValueType");
+ }
+}
+
+inline JSValueType
+TypeFlagPrimitive(TypeFlags flags)
+{
+ switch (flags) {
+ case TYPE_FLAG_UNDEFINED:
+ return JSVAL_TYPE_UNDEFINED;
+ case TYPE_FLAG_NULL:
+ return JSVAL_TYPE_NULL;
+ case TYPE_FLAG_BOOLEAN:
+ return JSVAL_TYPE_BOOLEAN;
+ case TYPE_FLAG_INT32:
+ return JSVAL_TYPE_INT32;
+ case TYPE_FLAG_DOUBLE:
+ return JSVAL_TYPE_DOUBLE;
+ case TYPE_FLAG_STRING:
+ return JSVAL_TYPE_STRING;
+ case TYPE_FLAG_SYMBOL:
+ return JSVAL_TYPE_SYMBOL;
+ case TYPE_FLAG_LAZYARGS:
+ return JSVAL_TYPE_MAGIC;
+ default:
+ MOZ_CRASH("Bad TypeFlags");
+ }
+}
+
+/*
+ * Get the canonical representation of an id to use when doing inference. This
+ * maintains the constraint that if two different jsids map to the same property
+ * in JS (e.g. 3 and "3"), they have the same type representation.
+ */
+inline jsid
+IdToTypeId(jsid id)
+{
+ MOZ_ASSERT(!JSID_IS_EMPTY(id));
+
+ // All properties which can be stored in an object's dense elements must
+ // map to the aggregate property for index types.
+ return JSID_IS_INT(id) ? JSID_VOID : id;
+}
+
+const char * TypeIdStringImpl(jsid id);
+
+/* Convert an id for printing during debug. */
+static inline const char*
+TypeIdString(jsid id)
+{
+#ifdef DEBUG
+ return TypeIdStringImpl(id);
+#else
+ return "(missing)";
+#endif
+}
+
+/*
+ * Structure for type inference entry point functions. All functions which can
+ * change type information must use this, and functions which depend on
+ * intermediate types (i.e. JITs) can use this to ensure that intermediate
+ * information is not collected and does not change.
+ *
+ * Ensures that GC cannot occur. Does additional sanity checking that inference
+ * is not reentrant and that recompilations occur properly.
+ */
+struct AutoEnterAnalysis
+{
+ // For use when initializing an UnboxedLayout. The UniquePtr's destructor
+ // must run when GC is not suppressed.
+ UniquePtr<UnboxedLayout> unboxedLayoutToCleanUp;
+
+ // Prevent GC activity in the middle of analysis.
+ gc::AutoSuppressGC suppressGC;
+
+ // Allow clearing inference info on OOM during incremental sweeping.
+ AutoClearTypeInferenceStateOnOOM oom;
+
+ // Pending recompilations to perform before execution of JIT code can resume.
+ RecompileInfoVector pendingRecompiles;
+
+ // Prevent us from calling the objectMetadataCallback.
+ js::AutoSuppressAllocationMetadataBuilder suppressMetadata;
+
+ FreeOp* freeOp;
+ Zone* zone;
+
+ explicit AutoEnterAnalysis(ExclusiveContext* cx)
+ : suppressGC(cx), oom(cx->zone()), suppressMetadata(cx)
+ {
+ init(cx->defaultFreeOp(), cx->zone());
+ }
+
+ AutoEnterAnalysis(FreeOp* fop, Zone* zone)
+ : suppressGC(zone->runtimeFromMainThread()->contextFromMainThread()),
+ oom(zone), suppressMetadata(zone)
+ {
+ init(fop, zone);
+ }
+
+ ~AutoEnterAnalysis()
+ {
+ if (this != zone->types.activeAnalysis)
+ return;
+
+ zone->types.activeAnalysis = nullptr;
+
+ if (!pendingRecompiles.empty())
+ zone->types.processPendingRecompiles(freeOp, pendingRecompiles);
+ }
+
+ private:
+ void init(FreeOp* fop, Zone* zone) {
+ this->freeOp = fop;
+ this->zone = zone;
+
+ if (!zone->types.activeAnalysis)
+ zone->types.activeAnalysis = this;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+// Interface functions
+/////////////////////////////////////////////////////////////////////
+
+void MarkIteratorUnknownSlow(JSContext* cx);
+
+void TypeMonitorCallSlow(JSContext* cx, JSObject* callee, const CallArgs& args,
+ bool constructing);
+
+/*
+ * Monitor a javascript call, either on entry to the interpreter or made
+ * from within the interpreter.
+ */
+inline void
+TypeMonitorCall(JSContext* cx, const js::CallArgs& args, bool constructing)
+{
+ if (args.callee().is<JSFunction>()) {
+ JSFunction* fun = &args.callee().as<JSFunction>();
+ if (fun->isInterpreted() && fun->nonLazyScript()->types())
+ TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
+ }
+}
+
+inline bool
+TrackPropertyTypes(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ if (obj->hasLazyGroup() || obj->group()->unknownProperties())
+ return false;
+
+ if (obj->isSingleton() && !obj->group()->maybeGetProperty(id))
+ return false;
+
+ return true;
+}
+
+void
+EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id);
+
+inline bool
+CanHaveEmptyPropertyTypesForOwnProperty(JSObject* obj)
+{
+ // Per the comment on TypeSet::propertySet, property type sets for global
+ // objects may be empty for 'own' properties if the global property still
+ // has its initial undefined value.
+ return obj->is<GlobalObject>();
+}
+
+inline bool
+PropertyHasBeenMarkedNonConstant(JSObject* obj, jsid id)
+{
+ // Non-constant properties are only relevant for singleton objects.
+ if (!obj->isSingleton())
+ return true;
+
+ // EnsureTrackPropertyTypes must have been called on this object.
+ if (obj->group()->unknownProperties())
+ return true;
+ HeapTypeSet* types = obj->group()->maybeGetProperty(IdToTypeId(id));
+ return types->nonConstantProperty();
+}
+
+inline bool
+HasTypePropertyId(JSObject* obj, jsid id, TypeSet::Type type)
+{
+ if (obj->hasLazyGroup())
+ return true;
+
+ if (obj->group()->unknownProperties())
+ return true;
+
+ if (HeapTypeSet* types = obj->group()->maybeGetProperty(IdToTypeId(id)))
+ return types->hasType(type);
+
+ return false;
+}
+
+inline bool
+HasTypePropertyId(JSObject* obj, jsid id, const Value& value)
+{
+ return HasTypePropertyId(obj, id, TypeSet::GetValueType(value));
+}
+
+void AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, jsid id, TypeSet::Type type);
+void AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, jsid id, const Value& value);
+
+/* Add a possible type for a property of obj. */
+inline void
+AddTypePropertyId(ExclusiveContext* cx, JSObject* obj, jsid id, TypeSet::Type type)
+{
+ id = IdToTypeId(id);
+ if (TrackPropertyTypes(cx, obj, id))
+ AddTypePropertyId(cx, obj->group(), obj, id, type);
+}
+
+inline void
+AddTypePropertyId(ExclusiveContext* cx, JSObject* obj, jsid id, const Value& value)
+{
+ id = IdToTypeId(id);
+ if (TrackPropertyTypes(cx, obj, id))
+ AddTypePropertyId(cx, obj->group(), obj, id, value);
+}
+
+inline void
+MarkObjectGroupFlags(ExclusiveContext* cx, JSObject* obj, ObjectGroupFlags flags)
+{
+ if (!obj->hasLazyGroup() && !obj->group()->hasAllFlags(flags))
+ obj->group()->setFlags(cx, flags);
+}
+
+inline void
+MarkObjectGroupUnknownProperties(ExclusiveContext* cx, ObjectGroup* obj)
+{
+ if (!obj->unknownProperties())
+ obj->markUnknown(cx);
+}
+
+inline void
+MarkTypePropertyNonData(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ id = IdToTypeId(id);
+ if (TrackPropertyTypes(cx, obj, id))
+ obj->group()->markPropertyNonData(cx, obj, id);
+}
+
+inline void
+MarkTypePropertyNonWritable(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ id = IdToTypeId(id);
+ if (TrackPropertyTypes(cx, obj, id))
+ obj->group()->markPropertyNonWritable(cx, obj, id);
+}
+
+/* Mark a state change on a particular object. */
+inline void
+MarkObjectStateChange(ExclusiveContext* cx, JSObject* obj)
+{
+ if (!obj->hasLazyGroup() && !obj->group()->unknownProperties())
+ obj->group()->markStateChange(cx);
+}
+
+/* Interface helpers for JSScript*. */
+extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, TypeSet::Type type);
+extern void TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const Value& rval);
+
+/////////////////////////////////////////////////////////////////////
+// Script interface functions
+/////////////////////////////////////////////////////////////////////
+
+/* static */ inline unsigned
+TypeScript::NumTypeSets(JSScript* script)
+{
+ size_t num = script->nTypeSets() + 1 /* this */;
+ if (JSFunction* fun = script->functionNonDelazifying())
+ num += fun->nargs();
+ return num;
+}
+
+/* static */ inline StackTypeSet*
+TypeScript::ThisTypes(JSScript* script)
+{
+ TypeScript* types = script->types();
+ return types ? types->typeArray() + script->nTypeSets() : nullptr;
+}
+
+/*
+ * Note: for non-escaping arguments, argTypes reflect only the initial type of
+ * the variable (e.g. passed values for argTypes, or undefined for localTypes)
+ * and not types from subsequent assignments.
+ */
+
+/* static */ inline StackTypeSet*
+TypeScript::ArgTypes(JSScript* script, unsigned i)
+{
+ MOZ_ASSERT(i < script->functionNonDelazifying()->nargs());
+ TypeScript* types = script->types();
+ return types ? types->typeArray() + script->nTypeSets() + 1 + i : nullptr;
+}
+
+template <typename TYPESET>
+/* static */ inline TYPESET*
+TypeScript::BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
+ uint32_t* hint, TYPESET* typeArray)
+{
+ MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
+ uint32_t offset = script->pcToOffset(pc);
+
+ // See if this pc is the next typeset opcode after the last one looked up.
+ if ((*hint + 1) < script->nTypeSets() && bytecodeMap[*hint + 1] == offset) {
+ (*hint)++;
+ return typeArray + *hint;
+ }
+
+ // See if this pc is the same as the last one looked up.
+ if (bytecodeMap[*hint] == offset)
+ return typeArray + *hint;
+
+ // Fall back to a binary search. We'll either find the exact offset, or
+ // there are more JOF_TYPESET opcodes than nTypeSets in the script (as can
+ // happen if the script is very long) and we'll use the last location.
+ size_t loc;
+#ifdef DEBUG
+ bool found =
+#endif
+ mozilla::BinarySearch(bytecodeMap, 0, script->nTypeSets() - 1, offset, &loc);
+
+ MOZ_ASSERT_IF(found, bytecodeMap[loc] == offset);
+ *hint = mozilla::AssertedCast<uint32_t>(loc);
+ return typeArray + *hint;
+}
+
+/* static */ inline StackTypeSet*
+TypeScript::BytecodeTypes(JSScript* script, jsbytecode* pc)
+{
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(script->runtimeFromMainThread()));
+ TypeScript* types = script->types();
+ if (!types)
+ return nullptr;
+ uint32_t* hint = script->baselineScript()->bytecodeTypeMap() + script->nTypeSets();
+ return BytecodeTypes(script, pc, script->baselineScript()->bytecodeTypeMap(),
+ hint, types->typeArray());
+}
+
+/* static */ inline void
+TypeScript::Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, const js::Value& rval)
+{
+ TypeMonitorResult(cx, script, pc, rval);
+}
+
+/* static */ inline void
+TypeScript::Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, TypeSet::Type type)
+{
+ TypeMonitorResult(cx, script, pc, type);
+}
+
+/* static */ inline void
+TypeScript::Monitor(JSContext* cx, const js::Value& rval)
+{
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ Monitor(cx, script, pc, rval);
+}
+
+/* static */ inline void
+TypeScript::MonitorAssign(JSContext* cx, HandleObject obj, jsid id)
+{
+ if (!obj->isSingleton()) {
+ /*
+ * Mark as unknown any object which has had dynamic assignments to
+ * non-integer properties at SETELEM opcodes. This avoids making large
+ * numbers of type properties for hashmap-style objects. We don't need
+ * to do this for objects with singleton type, because type properties
+ * are only constructed for them when analyzed scripts depend on those
+ * specific properties.
+ */
+ uint32_t i;
+ if (IdIsIndex(id, &i))
+ return;
+
+ // But if we don't have too many properties yet, don't do anything. The
+ // idea here is that normal object initialization should not trigger
+ // deoptimization in most cases, while actual usage as a hashmap should.
+ ObjectGroup* group = obj->group();
+ if (group->basePropertyCount() < 128)
+ return;
+ MarkObjectGroupUnknownProperties(cx, group);
+ }
+}
+
+/* static */ inline void
+TypeScript::SetThis(JSContext* cx, JSScript* script, TypeSet::Type type)
+{
+ assertSameCompartment(cx, script, type);
+
+ StackTypeSet* types = ThisTypes(script);
+ if (!types)
+ return;
+
+ if (!types->hasType(type)) {
+ AutoEnterAnalysis enter(cx);
+
+ InferSpew(ISpewOps, "externalType: setThis %p: %s",
+ script, TypeSet::TypeString(type));
+ types->addType(cx, type);
+ }
+}
+
+/* static */ inline void
+TypeScript::SetThis(JSContext* cx, JSScript* script, const js::Value& value)
+{
+ SetThis(cx, script, TypeSet::GetValueType(value));
+}
+
+/* static */ inline void
+TypeScript::SetArgument(JSContext* cx, JSScript* script, unsigned arg, TypeSet::Type type)
+{
+ assertSameCompartment(cx, script, type);
+
+ StackTypeSet* types = ArgTypes(script, arg);
+ if (!types)
+ return;
+
+ if (!types->hasType(type)) {
+ AutoEnterAnalysis enter(cx);
+
+ InferSpew(ISpewOps, "externalType: setArg %p %u: %s",
+ script, arg, TypeSet::TypeString(type));
+ types->addType(cx, type);
+ }
+}
+
+/* static */ inline void
+TypeScript::SetArgument(JSContext* cx, JSScript* script, unsigned arg, const js::Value& value)
+{
+ SetArgument(cx, script, arg, TypeSet::GetValueType(value));
+}
+
+/////////////////////////////////////////////////////////////////////
+// TypeHashSet
+/////////////////////////////////////////////////////////////////////
+
+// Hashing code shared by objects in TypeSets and properties in ObjectGroups.
+struct TypeHashSet
+{
+ // The sets of objects in a type set grow monotonically, are usually empty,
+ // almost always small, and sometimes big. For empty or singleton sets, the
+ // the pointer refers directly to the value. For sets fitting into
+ // SET_ARRAY_SIZE, an array of this length is used to store the elements.
+ // For larger sets, a hash table filled to 25%-50% of capacity is used,
+ // with collisions resolved by linear probing.
+ static const unsigned SET_ARRAY_SIZE = 8;
+ static const unsigned SET_CAPACITY_OVERFLOW = 1u << 30;
+
+ // Get the capacity of a set with the given element count.
+ static inline unsigned
+ Capacity(unsigned count)
+ {
+ MOZ_ASSERT(count >= 2);
+ MOZ_ASSERT(count < SET_CAPACITY_OVERFLOW);
+
+ if (count <= SET_ARRAY_SIZE)
+ return SET_ARRAY_SIZE;
+
+ return 1u << (mozilla::FloorLog2(count) + 2);
+ }
+
+ // Compute the FNV hash for the low 32 bits of v.
+ template <class T, class KEY>
+ static inline uint32_t
+ HashKey(T v)
+ {
+ uint32_t nv = KEY::keyBits(v);
+
+ uint32_t hash = 84696351 ^ (nv & 0xff);
+ hash = (hash * 16777619) ^ ((nv >> 8) & 0xff);
+ hash = (hash * 16777619) ^ ((nv >> 16) & 0xff);
+ return (hash * 16777619) ^ ((nv >> 24) & 0xff);
+ }
+
+ // Insert space for an element into the specified set and grow its capacity
+ // if needed. returned value is an existing or new entry (nullptr if new).
+ template <class T, class U, class KEY>
+ static U**
+ InsertTry(LifoAlloc& alloc, U**& values, unsigned& count, T key)
+ {
+ unsigned capacity = Capacity(count);
+ unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
+
+ // Whether we are converting from a fixed array to hashtable.
+ bool converting = (count == SET_ARRAY_SIZE);
+
+ if (!converting) {
+ while (values[insertpos] != nullptr) {
+ if (KEY::getKey(values[insertpos]) == key)
+ return &values[insertpos];
+ insertpos = (insertpos + 1) & (capacity - 1);
+ }
+ }
+
+ if (count >= SET_CAPACITY_OVERFLOW)
+ return nullptr;
+
+ count++;
+ unsigned newCapacity = Capacity(count);
+
+ if (newCapacity == capacity) {
+ MOZ_ASSERT(!converting);
+ return &values[insertpos];
+ }
+
+ U** newValues = alloc.newArray<U*>(newCapacity);
+ if (!newValues)
+ return nullptr;
+ mozilla::PodZero(newValues, newCapacity);
+
+ for (unsigned i = 0; i < capacity; i++) {
+ if (values[i]) {
+ unsigned pos = HashKey<T,KEY>(KEY::getKey(values[i])) & (newCapacity - 1);
+ while (newValues[pos] != nullptr)
+ pos = (pos + 1) & (newCapacity - 1);
+ newValues[pos] = values[i];
+ }
+ }
+
+ values = newValues;
+
+ insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
+ while (values[insertpos] != nullptr)
+ insertpos = (insertpos + 1) & (newCapacity - 1);
+ return &values[insertpos];
+ }
+
+ // Insert an element into the specified set if it is not already there,
+ // returning an entry which is nullptr if the element was not there.
+ template <class T, class U, class KEY>
+ static inline U**
+ Insert(LifoAlloc& alloc, U**& values, unsigned& count, T key)
+ {
+ if (count == 0) {
+ MOZ_ASSERT(values == nullptr);
+ count++;
+ return (U**) &values;
+ }
+
+ if (count == 1) {
+ U* oldData = (U*) values;
+ if (KEY::getKey(oldData) == key)
+ return (U**) &values;
+
+ values = alloc.newArray<U*>(SET_ARRAY_SIZE);
+ if (!values) {
+ values = (U**) oldData;
+ return nullptr;
+ }
+ mozilla::PodZero(values, SET_ARRAY_SIZE);
+ count++;
+
+ values[0] = oldData;
+ return &values[1];
+ }
+
+ if (count <= SET_ARRAY_SIZE) {
+ for (unsigned i = 0; i < count; i++) {
+ if (KEY::getKey(values[i]) == key)
+ return &values[i];
+ }
+
+ if (count < SET_ARRAY_SIZE) {
+ count++;
+ return &values[count - 1];
+ }
+ }
+
+ return InsertTry<T,U,KEY>(alloc, values, count, key);
+ }
+
+ // Lookup an entry in a hash set, return nullptr if it does not exist.
+ template <class T, class U, class KEY>
+ static inline U*
+ Lookup(U** values, unsigned count, T key)
+ {
+ if (count == 0)
+ return nullptr;
+
+ if (count == 1)
+ return (KEY::getKey((U*) values) == key) ? (U*) values : nullptr;
+
+ if (count <= SET_ARRAY_SIZE) {
+ for (unsigned i = 0; i < count; i++) {
+ if (KEY::getKey(values[i]) == key)
+ return values[i];
+ }
+ return nullptr;
+ }
+
+ unsigned capacity = Capacity(count);
+ unsigned pos = HashKey<T,KEY>(key) & (capacity - 1);
+
+ while (values[pos] != nullptr) {
+ if (KEY::getKey(values[pos]) == key)
+ return values[pos];
+ pos = (pos + 1) & (capacity - 1);
+ }
+
+ return nullptr;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+// TypeSet
+/////////////////////////////////////////////////////////////////////
+
+inline TypeSet::ObjectKey*
+TypeSet::Type::objectKey() const
+{
+ MOZ_ASSERT(isObject());
+ return (ObjectKey*) data;
+}
+
+inline JSObject*
+TypeSet::Type::singleton() const
+{
+ return objectKey()->singleton();
+}
+
+inline ObjectGroup*
+TypeSet::Type::group() const
+{
+ return objectKey()->group();
+}
+
+inline JSObject*
+TypeSet::Type::singletonNoBarrier() const
+{
+ return objectKey()->singletonNoBarrier();
+}
+
+inline ObjectGroup*
+TypeSet::Type::groupNoBarrier() const
+{
+ return objectKey()->groupNoBarrier();
+}
+
+inline void
+TypeSet::Type::trace(JSTracer* trc)
+{
+ if (isSingletonUnchecked()) {
+ JSObject* obj = singletonNoBarrier();
+ TraceManuallyBarrieredEdge(trc, &obj, "TypeSet::Object");
+ *this = TypeSet::ObjectType(obj);
+ } else if (isGroupUnchecked()) {
+ ObjectGroup* group = groupNoBarrier();
+ TraceManuallyBarrieredEdge(trc, &group, "TypeSet::Group");
+ *this = TypeSet::ObjectType(group);
+ }
+}
+
+inline JSCompartment*
+TypeSet::Type::maybeCompartment()
+{
+ if (isSingletonUnchecked())
+ return singletonNoBarrier()->compartment();
+
+ if (isGroupUnchecked())
+ return groupNoBarrier()->compartment();
+
+ return nullptr;
+}
+
+inline bool
+TypeSet::hasType(Type type) const
+{
+ if (unknown())
+ return true;
+
+ if (type.isUnknown()) {
+ return false;
+ } else if (type.isPrimitive()) {
+ return !!(flags & PrimitiveTypeFlag(type.primitive()));
+ } else if (type.isAnyObject()) {
+ return !!(flags & TYPE_FLAG_ANYOBJECT);
+ } else {
+ return !!(flags & TYPE_FLAG_ANYOBJECT) ||
+ TypeHashSet::Lookup<ObjectKey*, ObjectKey, ObjectKey>
+ (objectSet, baseObjectCount(), type.objectKey()) != nullptr;
+ }
+}
+
+inline void
+TypeSet::setBaseObjectCount(uint32_t count)
+{
+ MOZ_ASSERT(count <= TYPE_FLAG_DOMOBJECT_COUNT_LIMIT);
+ flags = (flags & ~TYPE_FLAG_OBJECT_COUNT_MASK)
+ | (count << TYPE_FLAG_OBJECT_COUNT_SHIFT);
+}
+
+inline void
+HeapTypeSet::newPropertyState(ExclusiveContext* cxArg)
+{
+ /* Propagate the change to all constraints. */
+ if (JSContext* cx = cxArg->maybeJSContext()) {
+ TypeConstraint* constraint = constraintList;
+ while (constraint) {
+ constraint->newPropertyState(cx, this);
+ constraint = constraint->next;
+ }
+ } else {
+ MOZ_ASSERT(!constraintList);
+ }
+}
+
+inline void
+HeapTypeSet::setNonDataProperty(ExclusiveContext* cx)
+{
+ if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
+ return;
+
+ flags |= TYPE_FLAG_NON_DATA_PROPERTY;
+ newPropertyState(cx);
+}
+
+inline void
+HeapTypeSet::setNonWritableProperty(ExclusiveContext* cx)
+{
+ if (flags & TYPE_FLAG_NON_WRITABLE_PROPERTY)
+ return;
+
+ flags |= TYPE_FLAG_NON_WRITABLE_PROPERTY;
+ newPropertyState(cx);
+}
+
+inline void
+HeapTypeSet::setNonConstantProperty(ExclusiveContext* cx)
+{
+ if (flags & TYPE_FLAG_NON_CONSTANT_PROPERTY)
+ return;
+
+ flags |= TYPE_FLAG_NON_CONSTANT_PROPERTY;
+ newPropertyState(cx);
+}
+
+inline unsigned
+TypeSet::getObjectCount() const
+{
+ MOZ_ASSERT(!unknownObject());
+ uint32_t count = baseObjectCount();
+ if (count > TypeHashSet::SET_ARRAY_SIZE)
+ return TypeHashSet::Capacity(count);
+ return count;
+}
+
+inline TypeSet::ObjectKey*
+TypeSet::getObject(unsigned i) const
+{
+ MOZ_ASSERT(i < getObjectCount());
+ if (baseObjectCount() == 1) {
+ MOZ_ASSERT(i == 0);
+ return (ObjectKey*) objectSet;
+ }
+ return objectSet[i];
+}
+
+inline JSObject*
+TypeSet::getSingleton(unsigned i) const
+{
+ ObjectKey* key = getObject(i);
+ return (key && key->isSingleton()) ? key->singleton() : nullptr;
+}
+
+inline ObjectGroup*
+TypeSet::getGroup(unsigned i) const
+{
+ ObjectKey* key = getObject(i);
+ return (key && key->isGroup()) ? key->group() : nullptr;
+}
+
+inline JSObject*
+TypeSet::getSingletonNoBarrier(unsigned i) const
+{
+ ObjectKey* key = getObject(i);
+ return (key && key->isSingleton()) ? key->singletonNoBarrier() : nullptr;
+}
+
+inline ObjectGroup*
+TypeSet::getGroupNoBarrier(unsigned i) const
+{
+ ObjectKey* key = getObject(i);
+ return (key && key->isGroup()) ? key->groupNoBarrier() : nullptr;
+}
+
+inline const Class*
+TypeSet::getObjectClass(unsigned i) const
+{
+ if (JSObject* object = getSingleton(i))
+ return object->getClass();
+ if (ObjectGroup* group = getGroup(i))
+ return group->clasp();
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroup
+/////////////////////////////////////////////////////////////////////
+
+inline uint32_t
+ObjectGroup::basePropertyCount()
+{
+ return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
+}
+
+inline void
+ObjectGroup::setBasePropertyCount(uint32_t count)
+{
+ // Note: Callers must ensure they are performing threadsafe operations.
+ MOZ_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
+ flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
+ | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
+}
+
+inline HeapTypeSet*
+ObjectGroup::getProperty(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
+ MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
+ MOZ_ASSERT(!unknownProperties());
+ MOZ_ASSERT_IF(obj, obj->group() == this);
+ MOZ_ASSERT_IF(singleton(), obj);
+
+ if (HeapTypeSet* types = maybeGetProperty(id))
+ return types;
+
+ Property* base = cx->typeLifoAlloc().new_<Property>(id);
+ if (!base) {
+ markUnknown(cx);
+ return nullptr;
+ }
+
+ uint32_t propertyCount = basePropertyCount();
+ Property** pprop = TypeHashSet::Insert<jsid, Property, Property>
+ (cx->typeLifoAlloc(), propertySet, propertyCount, id);
+ if (!pprop) {
+ markUnknown(cx);
+ return nullptr;
+ }
+
+ MOZ_ASSERT(!*pprop);
+
+ setBasePropertyCount(propertyCount);
+ *pprop = base;
+
+ updateNewPropertyTypes(cx, obj, id, &base->types);
+
+ if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
+ // We hit the maximum number of properties the object can have, mark
+ // the object unknown so that new properties will not be added in the
+ // future.
+ markUnknown(cx);
+ }
+
+ return &base->types;
+}
+
+inline HeapTypeSet*
+ObjectGroup::maybeGetProperty(jsid id)
+{
+ MOZ_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
+ MOZ_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
+ MOZ_ASSERT(!unknownProperties());
+
+ Property* prop = TypeHashSet::Lookup<jsid, Property, Property>
+ (propertySet, basePropertyCount(), id);
+
+ return prop ? &prop->types : nullptr;
+}
+
+inline unsigned
+ObjectGroup::getPropertyCount()
+{
+ uint32_t count = basePropertyCount();
+ if (count > TypeHashSet::SET_ARRAY_SIZE)
+ return TypeHashSet::Capacity(count);
+ return count;
+}
+
+inline ObjectGroup::Property*
+ObjectGroup::getProperty(unsigned i)
+{
+ MOZ_ASSERT(i < getPropertyCount());
+ if (basePropertyCount() == 1) {
+ MOZ_ASSERT(i == 0);
+ return (Property*) propertySet;
+ }
+ return propertySet[i];
+}
+
+} // namespace js
+
+inline js::TypeScript*
+JSScript::types()
+{
+ maybeSweepTypes(nullptr);
+ return types_;
+}
+
+inline bool
+JSScript::ensureHasTypes(JSContext* cx)
+{
+ return types() || makeTypes(cx);
+}
+
+#endif /* vm_TypeInference_inl_h */
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
new file mode 100644
index 000000000..5b55ba947
--- /dev/null
+++ b/js/src/vm/TypeInference.cpp
@@ -0,0 +1,4600 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TypeInference-inl.h"
+
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/SizePrintfMacros.h"
+#include "mozilla/Sprintf.h"
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsgc.h"
+#include "jshashutil.h"
+#include "jsobj.h"
+#include "jsprf.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+#include "gc/Marking.h"
+#include "jit/BaselineJIT.h"
+#include "jit/CompileInfo.h"
+#include "jit/Ion.h"
+#include "jit/IonAnalysis.h"
+#include "jit/JitCompartment.h"
+#include "jit/OptimizationTracking.h"
+#include "js/MemoryMetrics.h"
+#include "vm/HelperThreads.h"
+#include "vm/Opcodes.h"
+#include "vm/Shape.h"
+#include "vm/Time.h"
+#include "vm/UnboxedObject.h"
+
+#include "jsatominlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::DebugOnly;
+using mozilla::Maybe;
+using mozilla::PodArrayZero;
+using mozilla::PodCopy;
+using mozilla::PodZero;
+
+#ifdef DEBUG
+
+static inline jsid
+id___proto__(JSContext* cx)
+{
+ return NameToId(cx->names().proto);
+}
+
+static inline jsid
+id_constructor(JSContext* cx)
+{
+ return NameToId(cx->names().constructor);
+}
+
+static inline jsid
+id_caller(JSContext* cx)
+{
+ return NameToId(cx->names().caller);
+}
+
+const char*
+js::TypeIdStringImpl(jsid id)
+{
+ if (JSID_IS_VOID(id))
+ return "(index)";
+ if (JSID_IS_EMPTY(id))
+ return "(new)";
+ if (JSID_IS_SYMBOL(id))
+ return "(symbol)";
+ static char bufs[4][100];
+ static unsigned which = 0;
+ which = (which + 1) & 3;
+ PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0);
+ return bufs[which];
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////////////
+// Logging
+/////////////////////////////////////////////////////////////////////
+
+/* static */ const char*
+TypeSet::NonObjectTypeString(TypeSet::Type type)
+{
+ if (type.isPrimitive()) {
+ switch (type.primitive()) {
+ case JSVAL_TYPE_UNDEFINED:
+ return "void";
+ case JSVAL_TYPE_NULL:
+ return "null";
+ case JSVAL_TYPE_BOOLEAN:
+ return "bool";
+ case JSVAL_TYPE_INT32:
+ return "int";
+ case JSVAL_TYPE_DOUBLE:
+ return "float";
+ case JSVAL_TYPE_STRING:
+ return "string";
+ case JSVAL_TYPE_SYMBOL:
+ return "symbol";
+ case JSVAL_TYPE_MAGIC:
+ return "lazyargs";
+ default:
+ MOZ_CRASH("Bad type");
+ }
+ }
+ if (type.isUnknown())
+ return "unknown";
+
+ MOZ_ASSERT(type.isAnyObject());
+ return "object";
+}
+
+/* static */ const char*
+TypeSet::TypeString(TypeSet::Type type)
+{
+ if (type.isPrimitive() || type.isUnknown() || type.isAnyObject())
+ return NonObjectTypeString(type);
+
+ static char bufs[4][40];
+ static unsigned which = 0;
+ which = (which + 1) & 3;
+
+ if (type.isSingleton()) {
+ JSObject* singleton = type.singletonNoBarrier();
+ snprintf(bufs[which], 40, "<%s %#" PRIxPTR ">",
+ singleton->getClass()->name, uintptr_t(singleton));
+ } else {
+ snprintf(bufs[which], 40, "[%s * %#" PRIxPTR "]", type.groupNoBarrier()->clasp()->name, uintptr_t(type.groupNoBarrier()));
+ }
+
+ return bufs[which];
+}
+
+/* static */ const char*
+TypeSet::ObjectGroupString(ObjectGroup* group)
+{
+ return TypeString(TypeSet::ObjectType(group));
+}
+
+#ifdef DEBUG
+
+bool
+js::InferSpewActive(SpewChannel channel)
+{
+ static bool active[SPEW_COUNT];
+ static bool checked = false;
+ if (!checked) {
+ checked = true;
+ PodArrayZero(active);
+ const char* env = getenv("INFERFLAGS");
+ if (!env)
+ return false;
+ if (strstr(env, "ops"))
+ active[ISpewOps] = true;
+ if (strstr(env, "result"))
+ active[ISpewResult] = true;
+ if (strstr(env, "full")) {
+ for (unsigned i = 0; i < SPEW_COUNT; i++)
+ active[i] = true;
+ }
+ }
+ return active[channel];
+}
+
+static bool InferSpewColorable()
+{
+ /* Only spew colors on xterm-color to not screw up emacs. */
+ static bool colorable = false;
+ static bool checked = false;
+ if (!checked) {
+ checked = true;
+ const char* env = getenv("TERM");
+ if (!env)
+ return false;
+ if (strcmp(env, "xterm-color") == 0 || strcmp(env, "xterm-256color") == 0)
+ colorable = true;
+ }
+ return colorable;
+}
+
+const char*
+js::InferSpewColorReset()
+{
+ if (!InferSpewColorable())
+ return "";
+ return "\x1b[0m";
+}
+
+const char*
+js::InferSpewColor(TypeConstraint* constraint)
+{
+ /* Type constraints are printed out using foreground colors. */
+ static const char * const colors[] = { "\x1b[31m", "\x1b[32m", "\x1b[33m",
+ "\x1b[34m", "\x1b[35m", "\x1b[36m",
+ "\x1b[37m" };
+ if (!InferSpewColorable())
+ return "";
+ return colors[DefaultHasher<TypeConstraint*>::hash(constraint) % 7];
+}
+
+const char*
+js::InferSpewColor(TypeSet* types)
+{
+ /* Type sets are printed out using bold colors. */
+ static const char * const colors[] = { "\x1b[1;31m", "\x1b[1;32m", "\x1b[1;33m",
+ "\x1b[1;34m", "\x1b[1;35m", "\x1b[1;36m",
+ "\x1b[1;37m" };
+ if (!InferSpewColorable())
+ return "";
+ return colors[DefaultHasher<TypeSet*>::hash(types) % 7];
+}
+
+#ifdef DEBUG
+void
+js::InferSpewImpl(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "[infer] ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+#endif
+
+MOZ_NORETURN MOZ_COLD static void
+MOZ_FORMAT_PRINTF(2, 3)
+TypeFailure(JSContext* cx, const char* fmt, ...)
+{
+ char msgbuf[1024]; /* Larger error messages will be truncated */
+ char errbuf[1024];
+
+ va_list ap;
+ va_start(ap, fmt);
+ VsprintfLiteral(errbuf, fmt, ap);
+ va_end(ap);
+
+ SprintfLiteral(msgbuf, "[infer failure] %s", errbuf);
+
+ /* Dump type state, even if INFERFLAGS is unset. */
+ PrintTypes(cx, cx->compartment(), true);
+
+ MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
+ MOZ_CRASH();
+}
+
+bool
+js::ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value)
+{
+ /*
+ * Check the correctness of the type information in the object's property
+ * against an actual value.
+ */
+ if (!group->unknownProperties() && !value.isUndefined()) {
+ id = IdToTypeId(id);
+
+ /* Watch for properties which inference does not monitor. */
+ if (id == id___proto__(cx) || id == id_constructor(cx) || id == id_caller(cx))
+ return true;
+
+ TypeSet::Type type = TypeSet::GetValueType(value);
+
+ AutoEnterAnalysis enter(cx);
+
+ /*
+ * We don't track types for properties inherited from prototypes which
+ * haven't yet been accessed during analysis of the inheriting object.
+ * Don't do the property instantiation now.
+ */
+ TypeSet* types = group->maybeGetProperty(id);
+ if (!types)
+ return true;
+
+ // Type set guards might miss when an object's group changes and its
+ // properties become unknown.
+ if (value.isObject()) {
+ if (types->unknownObject())
+ return true;
+ for (size_t i = 0; i < types->getObjectCount(); i++) {
+ if (TypeSet::ObjectKey* key = types->getObject(i)) {
+ if (key->unknownProperties())
+ return true;
+ }
+ }
+ JSObject* obj = &value.toObject();
+ if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup())
+ return true;
+ }
+
+ if (!types->hasType(type)) {
+ TypeFailure(cx, "Missing type in object %s %s: %s",
+ TypeSet::ObjectGroupString(group), TypeIdString(id),
+ TypeSet::TypeString(type));
+ }
+ }
+ return true;
+}
+
+#endif
+
+
+/////////////////////////////////////////////////////////////////////
+// TypeSet
+/////////////////////////////////////////////////////////////////////
+
+TemporaryTypeSet::TemporaryTypeSet(LifoAlloc* alloc, Type type)
+{
+ if (type.isUnknown()) {
+ flags |= TYPE_FLAG_BASE_MASK;
+ } else if (type.isPrimitive()) {
+ flags = PrimitiveTypeFlag(type.primitive());
+ if (flags == TYPE_FLAG_DOUBLE)
+ flags |= TYPE_FLAG_INT32;
+ } else if (type.isAnyObject()) {
+ flags |= TYPE_FLAG_ANYOBJECT;
+ } else if (type.isGroup() && type.group()->unknownProperties()) {
+ flags |= TYPE_FLAG_ANYOBJECT;
+ } else {
+ setBaseObjectCount(1);
+ objectSet = reinterpret_cast<ObjectKey**>(type.objectKey());
+
+ if (type.isGroup()) {
+ ObjectGroup* ngroup = type.group();
+ if (ngroup->newScript() && ngroup->newScript()->initializedGroup())
+ addType(ObjectType(ngroup->newScript()->initializedGroup()), alloc);
+ }
+ }
+}
+
+bool
+TypeSet::mightBeMIRType(jit::MIRType type) const
+{
+ if (unknown())
+ return true;
+
+ if (type == jit::MIRType::Object)
+ return unknownObject() || baseObjectCount() != 0;
+
+ switch (type) {
+ case jit::MIRType::Undefined:
+ return baseFlags() & TYPE_FLAG_UNDEFINED;
+ case jit::MIRType::Null:
+ return baseFlags() & TYPE_FLAG_NULL;
+ case jit::MIRType::Boolean:
+ return baseFlags() & TYPE_FLAG_BOOLEAN;
+ case jit::MIRType::Int32:
+ return baseFlags() & TYPE_FLAG_INT32;
+ case jit::MIRType::Float32: // Fall through, there's no JSVAL for Float32.
+ case jit::MIRType::Double:
+ return baseFlags() & TYPE_FLAG_DOUBLE;
+ case jit::MIRType::String:
+ return baseFlags() & TYPE_FLAG_STRING;
+ case jit::MIRType::Symbol:
+ return baseFlags() & TYPE_FLAG_SYMBOL;
+ case jit::MIRType::MagicOptimizedArguments:
+ return baseFlags() & TYPE_FLAG_LAZYARGS;
+ case jit::MIRType::MagicHole:
+ case jit::MIRType::MagicIsConstructing:
+ // These magic constants do not escape to script and are not observed
+ // in the type sets.
+ //
+ // The reason we can return false here is subtle: if Ion is asking the
+ // type set if it has seen such a magic constant, then the MIR in
+ // question is the most generic type, MIRType::Value. A magic constant
+ // could only be emitted by a MIR of MIRType::Value if that MIR is a
+ // phi, and we check that different magic constants do not flow to the
+ // same join point in GuessPhiType.
+ return false;
+ default:
+ MOZ_CRASH("Bad MIR type");
+ }
+}
+
+bool
+TypeSet::objectsAreSubset(TypeSet* other)
+{
+ if (other->unknownObject())
+ return true;
+
+ if (unknownObject())
+ return false;
+
+ for (unsigned i = 0; i < getObjectCount(); i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+ if (!other->hasType(ObjectType(key)))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+TypeSet::isSubset(const TypeSet* other) const
+{
+ if ((baseFlags() & other->baseFlags()) != baseFlags())
+ return false;
+
+ if (unknownObject()) {
+ MOZ_ASSERT(other->unknownObject());
+ } else {
+ for (unsigned i = 0; i < getObjectCount(); i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+ if (!other->hasType(ObjectType(key)))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+TypeSet::objectsIntersect(const TypeSet* other) const
+{
+ if (unknownObject() || other->unknownObject())
+ return true;
+
+ for (unsigned i = 0; i < getObjectCount(); i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+ if (other->hasType(ObjectType(key)))
+ return true;
+ }
+
+ return false;
+}
+
+template <class TypeListT>
+bool
+TypeSet::enumerateTypes(TypeListT* list) const
+{
+ /* If any type is possible, there's no need to worry about specifics. */
+ if (flags & TYPE_FLAG_UNKNOWN)
+ return list->append(UnknownType());
+
+ /* Enqueue type set members stored as bits. */
+ for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
+ if (flags & flag) {
+ Type type = PrimitiveType(TypeFlagPrimitive(flag));
+ if (!list->append(type))
+ return false;
+ }
+ }
+
+ /* If any object is possible, skip specifics. */
+ if (flags & TYPE_FLAG_ANYOBJECT)
+ return list->append(AnyObjectType());
+
+ /* Enqueue specific object types. */
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ ObjectKey* key = getObject(i);
+ if (key) {
+ if (!list->append(ObjectType(key)))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template bool TypeSet::enumerateTypes<TypeSet::TypeList>(TypeList* list) const;
+template bool TypeSet::enumerateTypes<jit::TempTypeList>(jit::TempTypeList* list) const;
+
+inline bool
+TypeSet::addTypesToConstraint(JSContext* cx, TypeConstraint* constraint)
+{
+ /*
+ * Build all types in the set into a vector before triggering the
+ * constraint, as doing so may modify this type set.
+ */
+ TypeList types;
+ if (!enumerateTypes(&types))
+ return false;
+
+ for (unsigned i = 0; i < types.length(); i++)
+ constraint->newType(cx, this, types[i]);
+
+ return true;
+}
+
+#ifdef DEBUG
+static inline bool
+CompartmentsMatch(JSCompartment* a, JSCompartment* b)
+{
+ return !a || !b || a == b;
+}
+#endif
+
+bool
+ConstraintTypeSet::addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting)
+{
+ if (!constraint) {
+ /* OOM failure while constructing the constraint. */
+ return false;
+ }
+
+ MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+ MOZ_ASSERT(CompartmentsMatch(maybeCompartment(), constraint->maybeCompartment()));
+
+ InferSpew(ISpewOps, "addConstraint: %sT%p%s %sC%p%s %s",
+ InferSpewColor(this), this, InferSpewColorReset(),
+ InferSpewColor(constraint), constraint, InferSpewColorReset(),
+ constraint->kind());
+
+ MOZ_ASSERT(constraint->next == nullptr);
+ constraint->next = constraintList;
+ constraintList = constraint;
+
+ if (callExisting)
+ return addTypesToConstraint(cx, constraint);
+ return true;
+}
+
+void
+TypeSet::clearObjects()
+{
+ setBaseObjectCount(0);
+ objectSet = nullptr;
+}
+
+JSCompartment*
+TypeSet::maybeCompartment()
+{
+ if (unknownObject())
+ return nullptr;
+
+ unsigned objectCount = getObjectCount();
+ for (unsigned i = 0; i < objectCount; i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+
+ JSCompartment* comp = key->maybeCompartment();
+ if (comp)
+ return comp;
+ }
+
+ return nullptr;
+}
+
+void
+TypeSet::addType(Type type, LifoAlloc* alloc)
+{
+ MOZ_ASSERT(CompartmentsMatch(maybeCompartment(), type.maybeCompartment()));
+
+ if (unknown())
+ return;
+
+ if (type.isUnknown()) {
+ flags |= TYPE_FLAG_BASE_MASK;
+ clearObjects();
+ MOZ_ASSERT(unknown());
+ return;
+ }
+
+ if (type.isPrimitive()) {
+ TypeFlags flag = PrimitiveTypeFlag(type.primitive());
+ if (flags & flag)
+ return;
+
+ /* If we add float to a type set it is also considered to contain int. */
+ if (flag == TYPE_FLAG_DOUBLE)
+ flag |= TYPE_FLAG_INT32;
+
+ flags |= flag;
+ return;
+ }
+
+ if (flags & TYPE_FLAG_ANYOBJECT)
+ return;
+ if (type.isAnyObject())
+ goto unknownObject;
+
+ {
+ uint32_t objectCount = baseObjectCount();
+ ObjectKey* key = type.objectKey();
+ ObjectKey** pentry = TypeHashSet::Insert<ObjectKey*, ObjectKey, ObjectKey>
+ (*alloc, objectSet, objectCount, key);
+ if (!pentry)
+ goto unknownObject;
+ if (*pentry)
+ return;
+ *pentry = key;
+
+ setBaseObjectCount(objectCount);
+
+ // Limit the number of objects we track. There is a different limit
+ // depending on whether the set only contains DOM objects, which can
+ // have many different classes and prototypes but are still optimizable
+ // by IonMonkey.
+ if (objectCount >= TYPE_FLAG_OBJECT_COUNT_LIMIT) {
+ JS_STATIC_ASSERT(TYPE_FLAG_DOMOBJECT_COUNT_LIMIT >= TYPE_FLAG_OBJECT_COUNT_LIMIT);
+ // Examining the entire type set is only required when we first hit
+ // the normal object limit.
+ if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT) {
+ for (unsigned i = 0; i < objectCount; i++) {
+ const Class* clasp = getObjectClass(i);
+ if (clasp && !clasp->isDOMClass())
+ goto unknownObject;
+ }
+ }
+
+ // Make sure the newly added object is also a DOM object.
+ if (!key->clasp()->isDOMClass())
+ goto unknownObject;
+
+ // Limit the number of DOM objects.
+ if (objectCount == TYPE_FLAG_DOMOBJECT_COUNT_LIMIT)
+ goto unknownObject;
+ }
+ }
+
+ if (type.isGroup()) {
+ ObjectGroup* ngroup = type.group();
+ MOZ_ASSERT(!ngroup->singleton());
+ if (ngroup->unknownProperties())
+ goto unknownObject;
+
+ // If we add a partially initialized group to a type set, add the
+ // corresponding fully initialized group, as an object's group may change
+ // from the former to the latter via the acquired properties analysis.
+ if (ngroup->newScript() && ngroup->newScript()->initializedGroup())
+ addType(ObjectType(ngroup->newScript()->initializedGroup()), alloc);
+ }
+
+ if (false) {
+ unknownObject:
+ flags |= TYPE_FLAG_ANYOBJECT;
+ clearObjects();
+ }
+}
+
+// This class is used for post barriers on type set contents. The only times
+// when type sets contain nursery references is when a nursery object has its
+// group dynamically changed to a singleton. In such cases the type set will
+// need to be traced at the next minor GC.
+//
+// There is no barrier used for TemporaryTypeSets. These type sets are only
+// used during Ion compilation, and if some ConstraintTypeSet contains nursery
+// pointers then any number of TemporaryTypeSets might as well. Thus, if there
+// are any such ConstraintTypeSets in existence, all off thread Ion
+// compilations are canceled by the next minor GC.
+class TypeSetRef : public BufferableRef
+{
+ Zone* zone;
+ ConstraintTypeSet* types;
+
+ public:
+ TypeSetRef(Zone* zone, ConstraintTypeSet* types)
+ : zone(zone), types(types)
+ {}
+
+ void trace(JSTracer* trc) override {
+ types->trace(zone, trc);
+ }
+};
+
+void
+ConstraintTypeSet::postWriteBarrier(ExclusiveContext* cx, Type type)
+{
+ if (type.isSingletonUnchecked() && IsInsideNursery(type.singletonNoBarrier())) {
+ JSRuntime* rt = cx->asJSContext()->runtime();
+ rt->gc.storeBuffer.putGeneric(TypeSetRef(cx->zone(), this));
+ rt->gc.storeBuffer.setShouldCancelIonCompilations();
+ }
+}
+
+void
+ConstraintTypeSet::addType(ExclusiveContext* cxArg, Type type)
+{
+ MOZ_ASSERT(cxArg->zone()->types.activeAnalysis);
+
+ if (hasType(type))
+ return;
+
+ TypeSet::addType(type, &cxArg->typeLifoAlloc());
+
+ if (type.isObjectUnchecked() && unknownObject())
+ type = AnyObjectType();
+
+ postWriteBarrier(cxArg, type);
+
+ InferSpew(ISpewOps, "addType: %sT%p%s %s",
+ InferSpewColor(this), this, InferSpewColorReset(),
+ TypeString(type));
+
+ /* Propagate the type to all constraints. */
+ if (JSContext* cx = cxArg->maybeJSContext()) {
+ TypeConstraint* constraint = constraintList;
+ while (constraint) {
+ constraint->newType(cx, this, type);
+ constraint = constraint->next;
+ }
+ } else {
+ MOZ_ASSERT(!constraintList);
+ }
+}
+
+void
+TypeSet::print(FILE* fp)
+{
+ bool fromDebugger = !fp;
+ if (!fp)
+ fp = stderr;
+
+ if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
+ fprintf(fp, " [non-data]");
+
+ if (flags & TYPE_FLAG_NON_WRITABLE_PROPERTY)
+ fprintf(fp, " [non-writable]");
+
+ if (definiteProperty())
+ fprintf(fp, " [definite:%d]", definiteSlot());
+
+ if (baseFlags() == 0 && !baseObjectCount()) {
+ fprintf(fp, " missing");
+ return;
+ }
+
+ if (flags & TYPE_FLAG_UNKNOWN)
+ fprintf(fp, " unknown");
+ if (flags & TYPE_FLAG_ANYOBJECT)
+ fprintf(fp, " object");
+
+ if (flags & TYPE_FLAG_UNDEFINED)
+ fprintf(fp, " void");
+ if (flags & TYPE_FLAG_NULL)
+ fprintf(fp, " null");
+ if (flags & TYPE_FLAG_BOOLEAN)
+ fprintf(fp, " bool");
+ if (flags & TYPE_FLAG_INT32)
+ fprintf(fp, " int");
+ if (flags & TYPE_FLAG_DOUBLE)
+ fprintf(fp, " float");
+ if (flags & TYPE_FLAG_STRING)
+ fprintf(fp, " string");
+ if (flags & TYPE_FLAG_SYMBOL)
+ fprintf(fp, " symbol");
+ if (flags & TYPE_FLAG_LAZYARGS)
+ fprintf(fp, " lazyargs");
+
+ uint32_t objectCount = baseObjectCount();
+ if (objectCount) {
+ fprintf(fp, " object[%u]", objectCount);
+
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ ObjectKey* key = getObject(i);
+ if (key)
+ fprintf(fp, " %s", TypeString(ObjectType(key)));
+ }
+ }
+
+ if (fromDebugger)
+ fprintf(fp, "\n");
+}
+
+/* static */ void
+TypeSet::readBarrier(const TypeSet* types)
+{
+ if (types->unknownObject())
+ return;
+
+ for (unsigned i = 0; i < types->getObjectCount(); i++) {
+ if (ObjectKey* key = types->getObject(i)) {
+ if (key->isSingleton())
+ (void) key->singleton();
+ else
+ (void) key->group();
+ }
+ }
+}
+
+/* static */ bool
+TypeSet::IsTypeMarked(JSRuntime* rt, TypeSet::Type* v)
+{
+ bool rv;
+ if (v->isSingletonUnchecked()) {
+ JSObject* obj = v->singletonNoBarrier();
+ rv = IsMarkedUnbarriered(rt, &obj);
+ *v = TypeSet::ObjectType(obj);
+ } else if (v->isGroupUnchecked()) {
+ ObjectGroup* group = v->groupNoBarrier();
+ rv = IsMarkedUnbarriered(rt, &group);
+ *v = TypeSet::ObjectType(group);
+ } else {
+ rv = true;
+ }
+ return rv;
+}
+
+/* static */ bool
+TypeSet::IsTypeAllocatedDuringIncremental(TypeSet::Type v)
+{
+ bool rv;
+ if (v.isSingletonUnchecked()) {
+ JSObject* obj = v.singletonNoBarrier();
+ rv = obj->isTenured() && obj->asTenured().arena()->allocatedDuringIncremental;
+ } else if (v.isGroupUnchecked()) {
+ ObjectGroup* group = v.groupNoBarrier();
+ rv = group->arena()->allocatedDuringIncremental;
+ } else {
+ rv = false;
+ }
+ return rv;
+}
+
+static inline bool
+IsObjectKeyAboutToBeFinalized(TypeSet::ObjectKey** keyp)
+{
+ TypeSet::ObjectKey* key = *keyp;
+ bool isAboutToBeFinalized;
+ if (key->isGroup()) {
+ ObjectGroup* group = key->groupNoBarrier();
+ isAboutToBeFinalized = IsAboutToBeFinalizedUnbarriered(&group);
+ if (!isAboutToBeFinalized)
+ *keyp = TypeSet::ObjectKey::get(group);
+ } else {
+ MOZ_ASSERT(key->isSingleton());
+ JSObject* singleton = key->singletonNoBarrier();
+ isAboutToBeFinalized = IsAboutToBeFinalizedUnbarriered(&singleton);
+ if (!isAboutToBeFinalized)
+ *keyp = TypeSet::ObjectKey::get(singleton);
+ }
+ return isAboutToBeFinalized;
+}
+
+bool
+TypeSet::IsTypeAboutToBeFinalized(TypeSet::Type* v)
+{
+ bool isAboutToBeFinalized;
+ if (v->isObjectUnchecked()) {
+ TypeSet::ObjectKey* key = v->objectKey();
+ isAboutToBeFinalized = IsObjectKeyAboutToBeFinalized(&key);
+ if (!isAboutToBeFinalized)
+ *v = TypeSet::ObjectType(key);
+ } else {
+ isAboutToBeFinalized = false;
+ }
+ return isAboutToBeFinalized;
+}
+
+bool
+TypeSet::clone(LifoAlloc* alloc, TemporaryTypeSet* result) const
+{
+ MOZ_ASSERT(result->empty());
+
+ unsigned objectCount = baseObjectCount();
+ unsigned capacity = (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0;
+
+ ObjectKey** newSet;
+ if (capacity) {
+ newSet = alloc->newArray<ObjectKey*>(capacity);
+ if (!newSet)
+ return false;
+ PodCopy(newSet, objectSet, capacity);
+ }
+
+ new(result) TemporaryTypeSet(flags, capacity ? newSet : objectSet);
+ return true;
+}
+
+TemporaryTypeSet*
+TypeSet::clone(LifoAlloc* alloc) const
+{
+ TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>();
+ if (!res || !clone(alloc, res))
+ return nullptr;
+ return res;
+}
+
+TemporaryTypeSet*
+TypeSet::cloneObjectsOnly(LifoAlloc* alloc)
+{
+ TemporaryTypeSet* res = clone(alloc);
+ if (!res)
+ return nullptr;
+
+ res->flags &= ~TYPE_FLAG_BASE_MASK | TYPE_FLAG_ANYOBJECT;
+
+ return res;
+}
+
+TemporaryTypeSet*
+TypeSet::cloneWithoutObjects(LifoAlloc* alloc)
+{
+ TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>();
+ if (!res)
+ return nullptr;
+
+ res->flags = flags & ~TYPE_FLAG_ANYOBJECT;
+ res->setBaseObjectCount(0);
+ return res;
+}
+
+/* static */ TemporaryTypeSet*
+TypeSet::unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc)
+{
+ TemporaryTypeSet* res = alloc->new_<TemporaryTypeSet>(a->baseFlags() | b->baseFlags(),
+ static_cast<ObjectKey**>(nullptr));
+ if (!res)
+ return nullptr;
+
+ if (!res->unknownObject()) {
+ for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
+ if (ObjectKey* key = a->getObject(i))
+ res->addType(ObjectType(key), alloc);
+ }
+ for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) {
+ if (ObjectKey* key = b->getObject(i))
+ res->addType(ObjectType(key), alloc);
+ }
+ }
+
+ return res;
+}
+
+/* static */ TemporaryTypeSet*
+TypeSet::removeSet(TemporaryTypeSet* input, TemporaryTypeSet* removal, LifoAlloc* alloc)
+{
+ // Only allow removal of primitives and the "AnyObject" flag.
+ MOZ_ASSERT(!removal->unknown());
+ MOZ_ASSERT_IF(!removal->unknownObject(), removal->getObjectCount() == 0);
+
+ uint32_t flags = input->baseFlags() & ~removal->baseFlags();
+ TemporaryTypeSet* res =
+ alloc->new_<TemporaryTypeSet>(flags, static_cast<ObjectKey**>(nullptr));
+ if (!res)
+ return nullptr;
+
+ res->setBaseObjectCount(0);
+ if (removal->unknownObject() || input->unknownObject())
+ return res;
+
+ for (size_t i = 0; i < input->getObjectCount(); i++) {
+ if (!input->getObject(i))
+ continue;
+
+ res->addType(TypeSet::ObjectType(input->getObject(i)), alloc);
+ }
+
+ return res;
+}
+
+/* static */ TemporaryTypeSet*
+TypeSet::intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc)
+{
+ TemporaryTypeSet* res;
+ res = alloc->new_<TemporaryTypeSet>(a->baseFlags() & b->baseFlags(),
+ static_cast<ObjectKey**>(nullptr));
+ if (!res)
+ return nullptr;
+
+ res->setBaseObjectCount(0);
+ if (res->unknownObject())
+ return res;
+
+ MOZ_ASSERT(!a->unknownObject() || !b->unknownObject());
+
+ if (a->unknownObject()) {
+ for (size_t i = 0; i < b->getObjectCount(); i++) {
+ if (b->getObject(i))
+ res->addType(ObjectType(b->getObject(i)), alloc);
+ }
+ return res;
+ }
+
+ if (b->unknownObject()) {
+ for (size_t i = 0; i < a->getObjectCount(); i++) {
+ if (a->getObject(i))
+ res->addType(ObjectType(a->getObject(i)), alloc);
+ }
+ return res;
+ }
+
+ MOZ_ASSERT(!a->unknownObject() && !b->unknownObject());
+
+ for (size_t i = 0; i < a->getObjectCount(); i++) {
+ for (size_t j = 0; j < b->getObjectCount(); j++) {
+ if (b->getObject(j) != a->getObject(i))
+ continue;
+ if (!b->getObject(j))
+ continue;
+ res->addType(ObjectType(b->getObject(j)), alloc);
+ break;
+ }
+ }
+
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Compiler constraints
+/////////////////////////////////////////////////////////////////////
+
+// Compiler constraints overview
+//
+// Constraints generated during Ion compilation capture assumptions made about
+// heap properties that will trigger invalidation of the resulting Ion code if
+// the constraint is violated. Constraints can only be attached to type sets on
+// the main thread, so to allow compilation to occur almost entirely off thread
+// the generation is split into two phases.
+//
+// During compilation, CompilerConstraint values are constructed in a list,
+// recording the heap property type set which was read from and its expected
+// contents, along with the assumption made about those contents.
+//
+// At the end of compilation, when linking the result on the main thread, the
+// list of compiler constraints are read and converted to type constraints and
+// attached to the type sets. If the property type sets have changed so that the
+// assumptions no longer hold then the compilation is aborted and its result
+// discarded.
+
+// Superclass of all constraints generated during Ion compilation. These may
+// be allocated off the main thread, using the current JIT context's allocator.
+class CompilerConstraint
+{
+ public:
+ // Property being queried by the compiler.
+ HeapTypeSetKey property;
+
+ // Contents of the property at the point when the query was performed. This
+ // may differ from the actual property types later in compilation as the
+ // main thread performs side effects.
+ TemporaryTypeSet* expected;
+
+ CompilerConstraint(LifoAlloc* alloc, const HeapTypeSetKey& property)
+ : property(property),
+ expected(property.maybeTypes() ? property.maybeTypes()->clone(alloc) : nullptr)
+ {}
+
+ // Generate the type constraint recording the assumption made by this
+ // compilation. Returns true if the assumption originally made still holds.
+ virtual bool generateTypeConstraint(JSContext* cx, RecompileInfo recompileInfo) = 0;
+};
+
+class js::CompilerConstraintList
+{
+ public:
+ struct FrozenScript
+ {
+ JSScript* script;
+ TemporaryTypeSet* thisTypes;
+ TemporaryTypeSet* argTypes;
+ TemporaryTypeSet* bytecodeTypes;
+ };
+
+ private:
+
+ // OOM during generation of some constraint.
+ bool failed_;
+
+ // Allocator used for constraints.
+ LifoAlloc* alloc_;
+
+ // Constraints generated on heap properties.
+ Vector<CompilerConstraint*, 0, jit::JitAllocPolicy> constraints;
+
+ // Scripts whose stack type sets were frozen for the compilation.
+ Vector<FrozenScript, 1, jit::JitAllocPolicy> frozenScripts;
+
+ public:
+ explicit CompilerConstraintList(jit::TempAllocator& alloc)
+ : failed_(false),
+ alloc_(alloc.lifoAlloc()),
+ constraints(alloc),
+ frozenScripts(alloc)
+ {}
+
+ void add(CompilerConstraint* constraint) {
+ if (!constraint || !constraints.append(constraint))
+ setFailed();
+ }
+
+ void freezeScript(JSScript* script,
+ TemporaryTypeSet* thisTypes,
+ TemporaryTypeSet* argTypes,
+ TemporaryTypeSet* bytecodeTypes)
+ {
+ FrozenScript entry;
+ entry.script = script;
+ entry.thisTypes = thisTypes;
+ entry.argTypes = argTypes;
+ entry.bytecodeTypes = bytecodeTypes;
+ if (!frozenScripts.append(entry))
+ setFailed();
+ }
+
+ size_t length() {
+ return constraints.length();
+ }
+
+ CompilerConstraint* get(size_t i) {
+ return constraints[i];
+ }
+
+ size_t numFrozenScripts() {
+ return frozenScripts.length();
+ }
+
+ const FrozenScript& frozenScript(size_t i) {
+ return frozenScripts[i];
+ }
+
+ bool failed() {
+ return failed_;
+ }
+ void setFailed() {
+ failed_ = true;
+ }
+ LifoAlloc* alloc() const {
+ return alloc_;
+ }
+};
+
+CompilerConstraintList*
+js::NewCompilerConstraintList(jit::TempAllocator& alloc)
+{
+ return alloc.lifoAlloc()->new_<CompilerConstraintList>(alloc);
+}
+
+/* static */ bool
+TypeScript::FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
+ TemporaryTypeSet** pThisTypes,
+ TemporaryTypeSet** pArgTypes,
+ TemporaryTypeSet** pBytecodeTypes)
+{
+ LifoAlloc* alloc = constraints->alloc();
+ StackTypeSet* existing = script->types()->typeArray();
+
+ size_t count = NumTypeSets(script);
+ TemporaryTypeSet* types = alloc->newArrayUninitialized<TemporaryTypeSet>(count);
+ if (!types)
+ return false;
+ PodZero(types, count);
+
+ for (size_t i = 0; i < count; i++) {
+ if (!existing[i].clone(alloc, &types[i]))
+ return false;
+ }
+
+ *pThisTypes = types + (ThisTypes(script) - existing);
+ *pArgTypes = (script->functionNonDelazifying() && script->functionNonDelazifying()->nargs())
+ ? (types + (ArgTypes(script, 0) - existing))
+ : nullptr;
+ *pBytecodeTypes = types;
+
+ constraints->freezeScript(script, *pThisTypes, *pArgTypes, *pBytecodeTypes);
+ return true;
+}
+
+namespace {
+
+template <typename T>
+class CompilerConstraintInstance : public CompilerConstraint
+{
+ T data;
+
+ public:
+ CompilerConstraintInstance<T>(LifoAlloc* alloc, const HeapTypeSetKey& property, const T& data)
+ : CompilerConstraint(alloc, property), data(data)
+ {}
+
+ bool generateTypeConstraint(JSContext* cx, RecompileInfo recompileInfo);
+};
+
+// Constraint generated from a CompilerConstraint when linking the compilation.
+template <typename T>
+class TypeCompilerConstraint : public TypeConstraint
+{
+ // Compilation which this constraint may invalidate.
+ RecompileInfo compilation;
+
+ T data;
+
+ public:
+ TypeCompilerConstraint<T>(RecompileInfo compilation, const T& data)
+ : compilation(compilation), data(data)
+ {}
+
+ const char* kind() { return data.kind(); }
+
+ void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) {
+ if (data.invalidateOnNewType(type))
+ cx->zone()->types.addPendingRecompile(cx, compilation);
+ }
+
+ void newPropertyState(JSContext* cx, TypeSet* source) {
+ if (data.invalidateOnNewPropertyState(source))
+ cx->zone()->types.addPendingRecompile(cx, compilation);
+ }
+
+ void newObjectState(JSContext* cx, ObjectGroup* group) {
+ // Note: Once the object has unknown properties, no more notifications
+ // will be sent on changes to its state, so always invalidate any
+ // associated compilations.
+ if (group->unknownProperties() || data.invalidateOnNewObjectState(group))
+ cx->zone()->types.addPendingRecompile(cx, compilation);
+ }
+
+ bool sweep(TypeZone& zone, TypeConstraint** res) {
+ if (data.shouldSweep() || compilation.shouldSweep(zone))
+ return false;
+ *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
+ return true;
+ }
+
+ JSCompartment* maybeCompartment() {
+ return data.maybeCompartment();
+ }
+};
+
+template <typename T>
+bool
+CompilerConstraintInstance<T>::generateTypeConstraint(JSContext* cx, RecompileInfo recompileInfo)
+{
+ if (property.object()->unknownProperties())
+ return false;
+
+ if (!property.instantiate(cx))
+ return false;
+
+ if (!data.constraintHolds(cx, property, expected))
+ return false;
+
+ return property.maybeTypes()->addConstraint(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
+ /* callExisting = */ false);
+}
+
+} /* anonymous namespace */
+
+const Class*
+TypeSet::ObjectKey::clasp()
+{
+ return isGroup() ? group()->clasp() : singleton()->getClass();
+}
+
+TaggedProto
+TypeSet::ObjectKey::proto()
+{
+ return isGroup() ? group()->proto() : singleton()->taggedProto();
+}
+
+TypeNewScript*
+TypeSet::ObjectKey::newScript()
+{
+ if (isGroup() && group()->newScript())
+ return group()->newScript();
+ return nullptr;
+}
+
+ObjectGroup*
+TypeSet::ObjectKey::maybeGroup()
+{
+ if (isGroup())
+ return group();
+ if (!singleton()->hasLazyGroup())
+ return singleton()->group();
+ return nullptr;
+}
+
+bool
+TypeSet::ObjectKey::unknownProperties()
+{
+ if (ObjectGroup* group = maybeGroup())
+ return group->unknownProperties();
+ return false;
+}
+
+HeapTypeSetKey
+TypeSet::ObjectKey::property(jsid id)
+{
+ MOZ_ASSERT(!unknownProperties());
+
+ HeapTypeSetKey property;
+ property.object_ = this;
+ property.id_ = id;
+ if (ObjectGroup* group = maybeGroup())
+ property.maybeTypes_ = group->maybeGetProperty(id);
+
+ return property;
+}
+
+void
+TypeSet::ObjectKey::ensureTrackedProperty(JSContext* cx, jsid id)
+{
+ // If we are accessing a lazily defined property which actually exists in
+ // the VM and has not been instantiated yet, instantiate it now if we are
+ // on the main thread and able to do so.
+ if (!JSID_IS_VOID(id) && !JSID_IS_EMPTY(id)) {
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
+ if (isSingleton()) {
+ JSObject* obj = singleton();
+ if (obj->isNative() && obj->as<NativeObject>().containsPure(id))
+ EnsureTrackPropertyTypes(cx, obj, id);
+ }
+ }
+}
+
+void
+js::EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id)
+{
+ id = IdToTypeId(id);
+
+ if (obj->isSingleton()) {
+ AutoEnterAnalysis enter(cx);
+ if (obj->hasLazyGroup()) {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!obj->getGroup(cx)) {
+ oomUnsafe.crash("Could not allocate ObjectGroup in EnsureTrackPropertyTypes");
+ return;
+ }
+ }
+ if (!obj->group()->unknownProperties() && !obj->group()->getProperty(cx, obj, id)) {
+ MOZ_ASSERT(obj->group()->unknownProperties());
+ return;
+ }
+ }
+
+ MOZ_ASSERT(obj->group()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
+}
+
+bool
+HeapTypeSetKey::instantiate(JSContext* cx)
+{
+ if (maybeTypes())
+ return true;
+ if (object()->isSingleton() && !object()->singleton()->getGroup(cx)) {
+ cx->clearPendingException();
+ return false;
+ }
+ JSObject* obj = object()->isSingleton() ? object()->singleton() : nullptr;
+ maybeTypes_ = object()->maybeGroup()->getProperty(cx, obj, id());
+ return maybeTypes_ != nullptr;
+}
+
+static bool
+CheckFrozenTypeSet(JSContext* cx, TemporaryTypeSet* frozen, StackTypeSet* actual)
+{
+ // Return whether the types frozen for a script during compilation are
+ // still valid. Also check for any new types added to the frozen set during
+ // compilation, and add them to the actual stack type sets. These new types
+ // indicate places where the compiler relaxed its possible inputs to be
+ // more tolerant of potential new types.
+
+ if (!actual->isSubset(frozen))
+ return false;
+
+ if (!frozen->isSubset(actual)) {
+ TypeSet::TypeList list;
+ frozen->enumerateTypes(&list);
+
+ for (size_t i = 0; i < list.length(); i++)
+ actual->addType(cx, list[i]);
+ }
+
+ return true;
+}
+
+namespace {
+
+/*
+ * As for TypeConstraintFreeze, but describes an implicit freeze constraint
+ * added for stack types within a script. Applies to all compilations of the
+ * script, not just a single one.
+ */
+class TypeConstraintFreezeStack : public TypeConstraint
+{
+ JSScript* script_;
+
+ public:
+ explicit TypeConstraintFreezeStack(JSScript* script)
+ : script_(script)
+ {}
+
+ const char* kind() { return "freezeStack"; }
+
+ void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) {
+ /*
+ * Unlike TypeConstraintFreeze, triggering this constraint once does
+ * not disable it on future changes to the type set.
+ */
+ cx->zone()->types.addPendingRecompile(cx, script_);
+ }
+
+ bool sweep(TypeZone& zone, TypeConstraint** res) {
+ if (IsAboutToBeFinalizedUnbarriered(&script_))
+ return false;
+ *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
+ return true;
+ }
+
+ JSCompartment* maybeCompartment() {
+ return script_->compartment();
+ }
+};
+
+} /* anonymous namespace */
+
+bool
+js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
+ RecompileInfo* precompileInfo, bool* isValidOut)
+{
+ if (constraints->failed())
+ return false;
+
+ CompilerOutput co(script);
+
+ TypeZone& types = cx->zone()->types;
+ if (!types.compilerOutputs) {
+ types.compilerOutputs = cx->new_<TypeZone::CompilerOutputVector>();
+ if (!types.compilerOutputs)
+ return false;
+ }
+
+#ifdef DEBUG
+ for (size_t i = 0; i < types.compilerOutputs->length(); i++) {
+ const CompilerOutput& co = (*types.compilerOutputs)[i];
+ MOZ_ASSERT_IF(co.isValid(), co.script() != script);
+ }
+#endif
+
+ uint32_t index = types.compilerOutputs->length();
+ if (!types.compilerOutputs->append(co)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ *precompileInfo = RecompileInfo(index, types.generation);
+
+ bool succeeded = true;
+
+ for (size_t i = 0; i < constraints->length(); i++) {
+ CompilerConstraint* constraint = constraints->get(i);
+ if (!constraint->generateTypeConstraint(cx, *precompileInfo))
+ succeeded = false;
+ }
+
+ for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
+ const CompilerConstraintList::FrozenScript& entry = constraints->frozenScript(i);
+ if (!entry.script->types()) {
+ succeeded = false;
+ break;
+ }
+
+ // It could happen that one of the compiled scripts was made a
+ // debuggee mid-compilation (e.g., via setting a breakpoint). If so,
+ // throw away the compilation.
+ if (entry.script->isDebuggee()) {
+ succeeded = false;
+ break;
+ }
+
+ if (!CheckFrozenTypeSet(cx, entry.thisTypes, TypeScript::ThisTypes(entry.script)))
+ succeeded = false;
+ unsigned nargs = entry.script->functionNonDelazifying()
+ ? entry.script->functionNonDelazifying()->nargs()
+ : 0;
+ for (size_t i = 0; i < nargs; i++) {
+ if (!CheckFrozenTypeSet(cx, &entry.argTypes[i], TypeScript::ArgTypes(entry.script, i)))
+ succeeded = false;
+ }
+ for (size_t i = 0; i < entry.script->nTypeSets(); i++) {
+ if (!CheckFrozenTypeSet(cx, &entry.bytecodeTypes[i], &entry.script->types()->typeArray()[i]))
+ succeeded = false;
+ }
+
+ // If necessary, add constraints to trigger invalidation on the script
+ // after any future changes to the stack type sets.
+ if (entry.script->hasFreezeConstraints())
+ continue;
+
+ size_t count = TypeScript::NumTypeSets(entry.script);
+
+ StackTypeSet* array = entry.script->types()->typeArray();
+ for (size_t i = 0; i < count; i++) {
+ if (!array[i].addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false))
+ succeeded = false;
+ }
+
+ if (succeeded)
+ entry.script->setHasFreezeConstraints();
+ }
+
+ if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
+ types.compilerOutputs->back().invalidate();
+ script->resetWarmUpCounter();
+ *isValidOut = false;
+ return true;
+ }
+
+ *isValidOut = true;
+ return true;
+}
+
+void
+js::InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script)
+{
+ TypeZone& types = cx->zone()->types;
+ if (types.compilerOutputs) {
+ for (auto& co : *types.compilerOutputs) {
+ if (co.script() == script)
+ co.invalidate();
+ }
+ }
+}
+
+static void
+CheckDefinitePropertiesTypeSet(JSContext* cx, TemporaryTypeSet* frozen, StackTypeSet* actual)
+{
+ // The definite properties analysis happens on the main thread, so no new
+ // types can have been added to actual. The analysis may have updated the
+ // contents of |frozen| though with new speculative types, and these need
+ // to be reflected in |actual| for AddClearDefiniteFunctionUsesInScript
+ // to work.
+ if (!frozen->isSubset(actual)) {
+ TypeSet::TypeList list;
+ frozen->enumerateTypes(&list);
+
+ for (size_t i = 0; i < list.length(); i++)
+ actual->addType(cx, list[i]);
+ }
+}
+
+void
+js::FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints)
+{
+#ifdef DEBUG
+ // Assert no new types have been added to the StackTypeSets. Do this before
+ // calling CheckDefinitePropertiesTypeSet, as it may add new types to the
+ // StackTypeSets and break these invariants if a script is inlined more
+ // than once. See also CheckDefinitePropertiesTypeSet.
+ for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
+ const CompilerConstraintList::FrozenScript& entry = constraints->frozenScript(i);
+ JSScript* script = entry.script;
+ MOZ_ASSERT(script->types());
+
+ MOZ_ASSERT(TypeScript::ThisTypes(script)->isSubset(entry.thisTypes));
+
+ unsigned nargs = entry.script->functionNonDelazifying()
+ ? entry.script->functionNonDelazifying()->nargs()
+ : 0;
+ for (size_t j = 0; j < nargs; j++)
+ MOZ_ASSERT(TypeScript::ArgTypes(script, j)->isSubset(&entry.argTypes[j]));
+
+ for (size_t j = 0; j < script->nTypeSets(); j++)
+ MOZ_ASSERT(script->types()->typeArray()[j].isSubset(&entry.bytecodeTypes[j]));
+ }
+#endif
+
+ for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
+ const CompilerConstraintList::FrozenScript& entry = constraints->frozenScript(i);
+ JSScript* script = entry.script;
+ if (!script->types())
+ MOZ_CRASH();
+
+ CheckDefinitePropertiesTypeSet(cx, entry.thisTypes, TypeScript::ThisTypes(script));
+
+ unsigned nargs = script->functionNonDelazifying()
+ ? script->functionNonDelazifying()->nargs()
+ : 0;
+ for (size_t j = 0; j < nargs; j++)
+ CheckDefinitePropertiesTypeSet(cx, &entry.argTypes[j], TypeScript::ArgTypes(script, j));
+
+ for (size_t j = 0; j < script->nTypeSets(); j++)
+ CheckDefinitePropertiesTypeSet(cx, &entry.bytecodeTypes[j], &script->types()->typeArray()[j]);
+ }
+}
+
+namespace {
+
+// Constraint which triggers recompilation of a script if any type is added to a type set. */
+class ConstraintDataFreeze
+{
+ public:
+ ConstraintDataFreeze() {}
+
+ const char* kind() { return "freeze"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return true; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return true; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) { return false; }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return expected
+ ? property.maybeTypes()->isSubset(expected)
+ : property.maybeTypes()->empty();
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+} /* anonymous namespace */
+
+void
+HeapTypeSetKey::freeze(CompilerConstraintList* constraints)
+{
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreeze> T;
+ constraints->add(alloc->new_<T>(alloc, *this, ConstraintDataFreeze()));
+}
+
+static inline jit::MIRType
+GetMIRTypeFromTypeFlags(TypeFlags flags)
+{
+ switch (flags) {
+ case TYPE_FLAG_UNDEFINED:
+ return jit::MIRType::Undefined;
+ case TYPE_FLAG_NULL:
+ return jit::MIRType::Null;
+ case TYPE_FLAG_BOOLEAN:
+ return jit::MIRType::Boolean;
+ case TYPE_FLAG_INT32:
+ return jit::MIRType::Int32;
+ case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE):
+ return jit::MIRType::Double;
+ case TYPE_FLAG_STRING:
+ return jit::MIRType::String;
+ case TYPE_FLAG_SYMBOL:
+ return jit::MIRType::Symbol;
+ case TYPE_FLAG_LAZYARGS:
+ return jit::MIRType::MagicOptimizedArguments;
+ case TYPE_FLAG_ANYOBJECT:
+ return jit::MIRType::Object;
+ default:
+ return jit::MIRType::Value;
+ }
+}
+
+jit::MIRType
+TemporaryTypeSet::getKnownMIRType()
+{
+ TypeFlags flags = baseFlags();
+ jit::MIRType type;
+
+ if (baseObjectCount())
+ type = flags ? jit::MIRType::Value : jit::MIRType::Object;
+ else
+ type = GetMIRTypeFromTypeFlags(flags);
+
+ /*
+ * If the type set is totally empty then it will be treated as unknown,
+ * but we still need to record the dependency as adding a new type can give
+ * it a definite type tag. This is not needed if there are enough types
+ * that the exact tag is unknown, as it will stay unknown as more types are
+ * added to the set.
+ */
+ DebugOnly<bool> empty = flags == 0 && baseObjectCount() == 0;
+ MOZ_ASSERT_IF(empty, type == jit::MIRType::Value);
+
+ return type;
+}
+
+jit::MIRType
+HeapTypeSetKey::knownMIRType(CompilerConstraintList* constraints)
+{
+ TypeSet* types = maybeTypes();
+
+ if (!types || types->unknown())
+ return jit::MIRType::Value;
+
+ TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
+ jit::MIRType type;
+
+ if (types->unknownObject() || types->getObjectCount())
+ type = flags ? jit::MIRType::Value : jit::MIRType::Object;
+ else
+ type = GetMIRTypeFromTypeFlags(flags);
+
+ if (type != jit::MIRType::Value)
+ freeze(constraints);
+
+ /*
+ * If the type set is totally empty then it will be treated as unknown,
+ * but we still need to record the dependency as adding a new type can give
+ * it a definite type tag. This is not needed if there are enough types
+ * that the exact tag is unknown, as it will stay unknown as more types are
+ * added to the set.
+ */
+ MOZ_ASSERT_IF(types->empty(), type == jit::MIRType::Value);
+
+ return type;
+}
+
+bool
+HeapTypeSetKey::isOwnProperty(CompilerConstraintList* constraints,
+ bool allowEmptyTypesForGlobal/* = false*/)
+{
+ if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
+ return true;
+ if (object()->isSingleton()) {
+ JSObject* obj = object()->singleton();
+ MOZ_ASSERT(CanHaveEmptyPropertyTypesForOwnProperty(obj) == obj->is<GlobalObject>());
+ if (!allowEmptyTypesForGlobal) {
+ if (CanHaveEmptyPropertyTypesForOwnProperty(obj))
+ return true;
+ }
+ }
+ freeze(constraints);
+ return false;
+}
+
+bool
+HeapTypeSetKey::knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other)
+{
+ if (!maybeTypes() || maybeTypes()->empty()) {
+ freeze(constraints);
+ return true;
+ }
+ if (!other.maybeTypes() || !maybeTypes()->isSubset(other.maybeTypes()))
+ return false;
+ freeze(constraints);
+ return true;
+}
+
+JSObject*
+TemporaryTypeSet::maybeSingleton()
+{
+ if (baseFlags() != 0 || baseObjectCount() != 1)
+ return nullptr;
+
+ return getSingleton(0);
+}
+
+JSObject*
+HeapTypeSetKey::singleton(CompilerConstraintList* constraints)
+{
+ HeapTypeSet* types = maybeTypes();
+
+ if (!types || types->nonDataProperty() || types->baseFlags() != 0 || types->getObjectCount() != 1)
+ return nullptr;
+
+ JSObject* obj = types->getSingleton(0);
+
+ if (obj)
+ freeze(constraints);
+
+ return obj;
+}
+
+bool
+HeapTypeSetKey::needsBarrier(CompilerConstraintList* constraints)
+{
+ TypeSet* types = maybeTypes();
+ if (!types)
+ return false;
+ bool result = types->unknownObject()
+ || types->getObjectCount() > 0
+ || types->hasAnyFlag(TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL);
+ if (!result)
+ freeze(constraints);
+ return result;
+}
+
+namespace {
+
+// Constraint which triggers recompilation if an object acquires particular flags.
+class ConstraintDataFreezeObjectFlags
+{
+ public:
+ // Flags we are watching for on this object.
+ ObjectGroupFlags flags;
+
+ explicit ConstraintDataFreezeObjectFlags(ObjectGroupFlags flags)
+ : flags(flags)
+ {
+ MOZ_ASSERT(flags);
+ }
+
+ const char* kind() { return "freezeObjectFlags"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) {
+ return group->hasAnyFlags(flags);
+ }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return !invalidateOnNewObjectState(property.object()->maybeGroup());
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+} /* anonymous namespace */
+
+bool
+TypeSet::ObjectKey::hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags)
+{
+ MOZ_ASSERT(flags);
+
+ if (ObjectGroup* group = maybeGroup()) {
+ if (group->hasAnyFlags(flags))
+ return true;
+ }
+
+ HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> T;
+ constraints->add(alloc->new_<T>(alloc, objectProperty, ConstraintDataFreezeObjectFlags(flags)));
+ return false;
+}
+
+bool
+TypeSet::ObjectKey::hasStableClassAndProto(CompilerConstraintList* constraints)
+{
+ return !hasFlags(constraints, OBJECT_FLAG_UNKNOWN_PROPERTIES);
+}
+
+bool
+TemporaryTypeSet::hasObjectFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags)
+{
+ if (unknownObject())
+ return true;
+
+ /*
+ * Treat type sets containing no objects as having all object flags,
+ * to spare callers from having to check this.
+ */
+ if (baseObjectCount() == 0)
+ return true;
+
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ ObjectKey* key = getObject(i);
+ if (key && key->hasFlags(constraints, flags))
+ return true;
+ }
+
+ return false;
+}
+
+gc::InitialHeap
+ObjectGroup::initialHeap(CompilerConstraintList* constraints)
+{
+ // If this object is not required to be pretenured but could be in the
+ // future, add a constraint to trigger recompilation if the requirement
+ // changes.
+
+ if (shouldPreTenure())
+ return gc::TenuredHeap;
+
+ if (!canPreTenure())
+ return gc::DefaultHeap;
+
+ HeapTypeSetKey objectProperty = TypeSet::ObjectKey::get(this)->property(JSID_EMPTY);
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> T;
+ constraints->add(alloc->new_<T>(alloc, objectProperty, ConstraintDataFreezeObjectFlags(OBJECT_FLAG_PRE_TENURE)));
+
+ return gc::DefaultHeap;
+}
+
+namespace {
+
+// Constraint which triggers recompilation on any type change in an inlined
+// script. The freeze constraints added to stack type sets will only directly
+// invalidate the script containing those stack type sets. To invalidate code
+// for scripts into which the base script was inlined, ObjectStateChange is used.
+class ConstraintDataFreezeObjectForInlinedCall
+{
+ public:
+ ConstraintDataFreezeObjectForInlinedCall()
+ {}
+
+ const char* kind() { return "freezeObjectForInlinedCall"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) {
+ // We don't keep track of the exact dependencies the caller has on its
+ // inlined scripts' type sets, so always invalidate the caller.
+ return true;
+ }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return true;
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+// Constraint which triggers recompilation when a typed array's data becomes
+// invalid.
+class ConstraintDataFreezeObjectForTypedArrayData
+{
+ NativeObject* obj;
+
+ uintptr_t viewData;
+ uint32_t length;
+
+ public:
+ explicit ConstraintDataFreezeObjectForTypedArrayData(TypedArrayObject& tarray)
+ : obj(&tarray),
+ viewData(tarray.viewDataEither().unwrapValue()),
+ length(tarray.length())
+ {
+ MOZ_ASSERT(tarray.isSingleton());
+ }
+
+ const char* kind() { return "freezeObjectForTypedArrayData"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) {
+ MOZ_ASSERT(obj->group() == group);
+ TypedArrayObject& tarr = obj->as<TypedArrayObject>();
+ return tarr.viewDataEither().unwrapValue() != viewData || tarr.length() != length;
+ }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return !invalidateOnNewObjectState(property.object()->maybeGroup());
+ }
+
+ bool shouldSweep() {
+ // Note: |viewData| is only used for equality testing.
+ return IsAboutToBeFinalizedUnbarriered(&obj);
+ }
+
+ JSCompartment* maybeCompartment() {
+ return obj->compartment();
+ }
+};
+
+// Constraint which triggers recompilation if an unboxed object in some group
+// is converted to a native object.
+class ConstraintDataFreezeObjectForUnboxedConvertedToNative
+{
+ public:
+ ConstraintDataFreezeObjectForUnboxedConvertedToNative()
+ {}
+
+ const char* kind() { return "freezeObjectForUnboxedConvertedToNative"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) {
+ return group->unboxedLayout().nativeGroup() != nullptr;
+ }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return !invalidateOnNewObjectState(property.object()->maybeGroup());
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+} /* anonymous namespace */
+
+void
+TypeSet::ObjectKey::watchStateChangeForInlinedCall(CompilerConstraintList* constraints)
+{
+ HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezeObjectForInlinedCall> T;
+ constraints->add(alloc->new_<T>(alloc, objectProperty, ConstraintDataFreezeObjectForInlinedCall()));
+}
+
+void
+TypeSet::ObjectKey::watchStateChangeForTypedArrayData(CompilerConstraintList* constraints)
+{
+ TypedArrayObject& tarray = singleton()->as<TypedArrayObject>();
+ HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezeObjectForTypedArrayData> T;
+ constraints->add(alloc->new_<T>(alloc, objectProperty,
+ ConstraintDataFreezeObjectForTypedArrayData(tarray)));
+}
+
+void
+TypeSet::ObjectKey::watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints)
+{
+ HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezeObjectForUnboxedConvertedToNative> T;
+ constraints->add(alloc->new_<T>(alloc, objectProperty,
+ ConstraintDataFreezeObjectForUnboxedConvertedToNative()));
+}
+
+static void
+ObjectStateChange(ExclusiveContext* cxArg, ObjectGroup* group, bool markingUnknown)
+{
+ if (group->unknownProperties())
+ return;
+
+ /* All constraints listening to state changes are on the empty id. */
+ HeapTypeSet* types = group->maybeGetProperty(JSID_EMPTY);
+
+ /* Mark as unknown after getting the types, to avoid assertion. */
+ if (markingUnknown)
+ group->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
+
+ if (types) {
+ if (JSContext* cx = cxArg->maybeJSContext()) {
+ TypeConstraint* constraint = types->constraintList;
+ while (constraint) {
+ constraint->newObjectState(cx, group);
+ constraint = constraint->next;
+ }
+ } else {
+ MOZ_ASSERT(!types->constraintList);
+ }
+ }
+}
+
+namespace {
+
+class ConstraintDataFreezePropertyState
+{
+ public:
+ enum Which {
+ NON_DATA,
+ NON_WRITABLE
+ } which;
+
+ explicit ConstraintDataFreezePropertyState(Which which)
+ : which(which)
+ {}
+
+ const char* kind() { return (which == NON_DATA) ? "freezeNonDataProperty" : "freezeNonWritableProperty"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) {
+ return (which == NON_DATA)
+ ? property->nonDataProperty()
+ : property->nonWritableProperty();
+ }
+ bool invalidateOnNewObjectState(ObjectGroup* group) { return false; }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return !invalidateOnNewPropertyState(property.maybeTypes());
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+} /* anonymous namespace */
+
+bool
+HeapTypeSetKey::nonData(CompilerConstraintList* constraints)
+{
+ if (maybeTypes() && maybeTypes()->nonDataProperty())
+ return true;
+
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezePropertyState> T;
+ constraints->add(alloc->new_<T>(alloc, *this,
+ ConstraintDataFreezePropertyState(ConstraintDataFreezePropertyState::NON_DATA)));
+ return false;
+}
+
+bool
+HeapTypeSetKey::nonWritable(CompilerConstraintList* constraints)
+{
+ if (maybeTypes() && maybeTypes()->nonWritableProperty())
+ return true;
+
+ LifoAlloc* alloc = constraints->alloc();
+
+ typedef CompilerConstraintInstance<ConstraintDataFreezePropertyState> T;
+ constraints->add(alloc->new_<T>(alloc, *this,
+ ConstraintDataFreezePropertyState(ConstraintDataFreezePropertyState::NON_WRITABLE)));
+ return false;
+}
+
+namespace {
+
+class ConstraintDataConstantProperty
+{
+ public:
+ explicit ConstraintDataConstantProperty() {}
+
+ const char* kind() { return "constantProperty"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) {
+ return property->nonConstantProperty();
+ }
+ bool invalidateOnNewObjectState(ObjectGroup* group) { return false; }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return !invalidateOnNewPropertyState(property.maybeTypes());
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+} /* anonymous namespace */
+
+bool
+HeapTypeSetKey::constant(CompilerConstraintList* constraints, Value* valOut)
+{
+ if (nonData(constraints))
+ return false;
+
+ // Only singleton object properties can be marked as constants.
+ JSObject* obj = object()->singleton();
+ if (!obj || !obj->isNative())
+ return false;
+
+ if (maybeTypes() && maybeTypes()->nonConstantProperty())
+ return false;
+
+ // Get the current value of the property.
+ Shape* shape = obj->as<NativeObject>().lookupPure(id());
+ if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot() || shape->hadOverwrite())
+ return false;
+
+ Value val = obj->as<NativeObject>().getSlot(shape->slot());
+
+ // If the value is a pointer to an object in the nursery, don't optimize.
+ if (val.isGCThing() && IsInsideNursery(val.toGCThing()))
+ return false;
+
+ // If the value is a string that's not atomic, don't optimize.
+ if (val.isString() && !val.toString()->isAtom())
+ return false;
+
+ *valOut = val;
+
+ LifoAlloc* alloc = constraints->alloc();
+ typedef CompilerConstraintInstance<ConstraintDataConstantProperty> T;
+ constraints->add(alloc->new_<T>(alloc, *this, ConstraintDataConstantProperty()));
+ return true;
+}
+
+// A constraint that never triggers recompilation.
+class ConstraintDataInert
+{
+ public:
+ explicit ConstraintDataInert() {}
+
+ const char* kind() { return "inert"; }
+
+ bool invalidateOnNewType(TypeSet::Type type) { return false; }
+ bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
+ bool invalidateOnNewObjectState(ObjectGroup* group) { return false; }
+
+ bool constraintHolds(JSContext* cx,
+ const HeapTypeSetKey& property, TemporaryTypeSet* expected)
+ {
+ return true;
+ }
+
+ bool shouldSweep() { return false; }
+
+ JSCompartment* maybeCompartment() { return nullptr; }
+};
+
+bool
+HeapTypeSetKey::couldBeConstant(CompilerConstraintList* constraints)
+{
+ // Only singleton object properties can be marked as constants.
+ if (!object()->isSingleton())
+ return false;
+
+ if (!maybeTypes() || !maybeTypes()->nonConstantProperty())
+ return true;
+
+ // It is possible for a property that was not marked as constant to
+ // 'become' one, if we throw away the type property during a GC and
+ // regenerate it with the constant flag set. ObjectGroup::sweep only removes
+ // type properties if they have no constraints attached to them, so add
+ // inert constraints to pin these properties in place.
+
+ LifoAlloc* alloc = constraints->alloc();
+ typedef CompilerConstraintInstance<ConstraintDataInert> T;
+ constraints->add(alloc->new_<T>(alloc, *this, ConstraintDataInert()));
+
+ return false;
+}
+
+bool
+TemporaryTypeSet::filtersType(const TemporaryTypeSet* other, Type filteredType) const
+{
+ if (other->unknown())
+ return unknown();
+
+ for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
+ Type type = PrimitiveType(TypeFlagPrimitive(flag));
+ if (type != filteredType && other->hasType(type) && !hasType(type))
+ return false;
+ }
+
+ if (other->unknownObject())
+ return unknownObject();
+
+ for (size_t i = 0; i < other->getObjectCount(); i++) {
+ ObjectKey* key = other->getObject(i);
+ if (key) {
+ Type type = ObjectType(key);
+ if (type != filteredType && !hasType(type))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TemporaryTypeSet::DoubleConversion
+TemporaryTypeSet::convertDoubleElements(CompilerConstraintList* constraints)
+{
+ if (unknownObject() || !getObjectCount())
+ return AmbiguousDoubleConversion;
+
+ bool alwaysConvert = true;
+ bool maybeConvert = false;
+ bool dontConvert = false;
+
+ for (unsigned i = 0; i < getObjectCount(); i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+
+ if (key->unknownProperties()) {
+ alwaysConvert = false;
+ continue;
+ }
+
+ HeapTypeSetKey property = key->property(JSID_VOID);
+ property.freeze(constraints);
+
+ // We can't convert to double elements for objects which do not have
+ // double in their element types (as the conversion may render the type
+ // information incorrect), nor for non-array objects (as their elements
+ // may point to emptyObjectElements or emptyObjectElementsShared, which
+ // cannot be converted).
+ if (!property.maybeTypes() ||
+ !property.maybeTypes()->hasType(DoubleType()) ||
+ key->clasp() != &ArrayObject::class_)
+ {
+ dontConvert = true;
+ alwaysConvert = false;
+ continue;
+ }
+
+ // Only bother with converting known packed arrays whose possible
+ // element types are int or double. Other arrays require type tests
+ // when elements are accessed regardless of the conversion.
+ if (property.knownMIRType(constraints) == jit::MIRType::Double &&
+ !key->hasFlags(constraints, OBJECT_FLAG_NON_PACKED))
+ {
+ maybeConvert = true;
+ } else {
+ alwaysConvert = false;
+ }
+ }
+
+ MOZ_ASSERT_IF(alwaysConvert, maybeConvert);
+
+ if (maybeConvert && dontConvert)
+ return AmbiguousDoubleConversion;
+ if (alwaysConvert)
+ return AlwaysConvertToDoubles;
+ if (maybeConvert)
+ return MaybeConvertToDoubles;
+ return DontConvertToDoubles;
+}
+
+const Class*
+TemporaryTypeSet::getKnownClass(CompilerConstraintList* constraints)
+{
+ if (unknownObject())
+ return nullptr;
+
+ const Class* clasp = nullptr;
+ unsigned count = getObjectCount();
+
+ for (unsigned i = 0; i < count; i++) {
+ const Class* nclasp = getObjectClass(i);
+ if (!nclasp)
+ continue;
+
+ if (getObject(i)->unknownProperties())
+ return nullptr;
+
+ if (clasp && clasp != nclasp)
+ return nullptr;
+ clasp = nclasp;
+ }
+
+ if (clasp) {
+ for (unsigned i = 0; i < count; i++) {
+ ObjectKey* key = getObject(i);
+ if (key && !key->hasStableClassAndProto(constraints))
+ return nullptr;
+ }
+ }
+
+ return clasp;
+}
+
+void
+TemporaryTypeSet::getTypedArraySharedness(CompilerConstraintList* constraints,
+ TypedArraySharedness* sharedness)
+{
+ // In the future this will inspect the object set.
+ *sharedness = UnknownSharedness;
+}
+
+TemporaryTypeSet::ForAllResult
+TemporaryTypeSet::forAllClasses(CompilerConstraintList* constraints,
+ bool (*func)(const Class* clasp))
+{
+ if (unknownObject())
+ return ForAllResult::MIXED;
+
+ unsigned count = getObjectCount();
+ if (count == 0)
+ return ForAllResult::EMPTY;
+
+ bool true_results = false;
+ bool false_results = false;
+ for (unsigned i = 0; i < count; i++) {
+ const Class* clasp = getObjectClass(i);
+ if (!clasp)
+ continue;
+ if (!getObject(i)->hasStableClassAndProto(constraints))
+ return ForAllResult::MIXED;
+ if (func(clasp)) {
+ true_results = true;
+ if (false_results)
+ return ForAllResult::MIXED;
+ } else {
+ false_results = true;
+ if (true_results)
+ return ForAllResult::MIXED;
+ }
+ }
+
+ MOZ_ASSERT(true_results != false_results);
+
+ return true_results ? ForAllResult::ALL_TRUE : ForAllResult::ALL_FALSE;
+}
+
+Scalar::Type
+TemporaryTypeSet::getTypedArrayType(CompilerConstraintList* constraints,
+ TypedArraySharedness* sharedness)
+{
+ const Class* clasp = getKnownClass(constraints);
+
+ if (clasp && IsTypedArrayClass(clasp)) {
+ if (sharedness)
+ getTypedArraySharedness(constraints, sharedness);
+ return (Scalar::Type) (clasp - &TypedArrayObject::classes[0]);
+ }
+ return Scalar::MaxTypedArrayViewType;
+}
+
+bool
+TemporaryTypeSet::isDOMClass(CompilerConstraintList* constraints)
+{
+ if (unknownObject())
+ return false;
+
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ const Class* clasp = getObjectClass(i);
+ if (!clasp)
+ continue;
+ if (!clasp->isDOMClass() || !getObject(i)->hasStableClassAndProto(constraints))
+ return false;
+ }
+
+ return count > 0;
+}
+
+bool
+TemporaryTypeSet::maybeCallable(CompilerConstraintList* constraints)
+{
+ if (!maybeObject())
+ return false;
+
+ if (unknownObject())
+ return true;
+
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ const Class* clasp = getObjectClass(i);
+ if (!clasp)
+ continue;
+ if (clasp->isProxy() || clasp->nonProxyCallable())
+ return true;
+ if (!getObject(i)->hasStableClassAndProto(constraints))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+TemporaryTypeSet::maybeEmulatesUndefined(CompilerConstraintList* constraints)
+{
+ if (!maybeObject())
+ return false;
+
+ if (unknownObject())
+ return true;
+
+ unsigned count = getObjectCount();
+ for (unsigned i = 0; i < count; i++) {
+ // The object emulates undefined if clasp->emulatesUndefined() or if
+ // it's a WrapperObject, see EmulatesUndefined. Since all wrappers are
+ // proxies, we can just check for that.
+ const Class* clasp = getObjectClass(i);
+ if (!clasp)
+ continue;
+ if (clasp->emulatesUndefined() || clasp->isProxy())
+ return true;
+ if (!getObject(i)->hasStableClassAndProto(constraints))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+TemporaryTypeSet::getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto)
+{
+ if (unknownObject())
+ return false;
+
+ *proto = nullptr;
+ bool isFirst = true;
+ unsigned count = getObjectCount();
+
+ for (unsigned i = 0; i < count; i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+
+ if (key->unknownProperties())
+ return false;
+
+ TaggedProto nproto = key->proto();
+ if (isFirst) {
+ if (nproto.isDynamic())
+ return false;
+ *proto = nproto.toObjectOrNull();
+ isFirst = false;
+ } else {
+ if (nproto != TaggedProto(*proto))
+ return false;
+ }
+ }
+
+ // Guard against mutating __proto__.
+ for (unsigned i = 0; i < count; i++) {
+ if (ObjectKey* key = getObject(i))
+ JS_ALWAYS_TRUE(key->hasStableClassAndProto(constraints));
+ }
+
+ return true;
+}
+
+bool
+TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id)
+{
+ if (unknownObject())
+ return true;
+
+ for (unsigned i = 0; i < getObjectCount(); i++) {
+ ObjectKey* key = getObject(i);
+ if (!key)
+ continue;
+
+ if (key->unknownProperties())
+ return true;
+
+ HeapTypeSetKey property = key->property(id);
+ if (property.needsBarrier(constraints))
+ return true;
+ }
+
+ return false;
+}
+
+bool
+js::ClassCanHaveExtraProperties(const Class* clasp)
+{
+ if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
+ return false;
+ return clasp->getResolve()
+ || clasp->getOpsLookupProperty()
+ || clasp->getOpsGetProperty()
+ || IsTypedArrayClass(clasp);
+}
+
+void
+TypeZone::processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles)
+{
+ MOZ_ASSERT(!recompiles.empty());
+
+ /*
+ * Steal the list of scripts to recompile, to make sure we don't try to
+ * recursively recompile them.
+ */
+ RecompileInfoVector pending;
+ for (size_t i = 0; i < recompiles.length(); i++) {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!pending.append(recompiles[i]))
+ oomUnsafe.crash("processPendingRecompiles");
+ }
+ recompiles.clear();
+
+ jit::Invalidate(*this, fop, pending);
+
+ MOZ_ASSERT(recompiles.empty());
+}
+
+void
+TypeZone::addPendingRecompile(JSContext* cx, const RecompileInfo& info)
+{
+ CompilerOutput* co = info.compilerOutput(cx);
+ if (!co || !co->isValid() || co->pendingInvalidation())
+ return;
+
+ InferSpew(ISpewOps, "addPendingRecompile: %p:%s:%" PRIuSIZE,
+ co->script(), co->script()->filename(), co->script()->lineno());
+
+ co->setPendingInvalidation();
+
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!cx->zone()->types.activeAnalysis->pendingRecompiles.append(info))
+ oomUnsafe.crash("Could not update pendingRecompiles");
+}
+
+void
+TypeZone::addPendingRecompile(JSContext* cx, JSScript* script)
+{
+ MOZ_ASSERT(script);
+
+ CancelOffThreadIonCompile(script);
+
+ // Let the script warm up again before attempting another compile.
+ if (jit::IsBaselineEnabled(cx))
+ script->resetWarmUpCounter();
+
+ if (script->hasIonScript())
+ addPendingRecompile(cx, script->ionScript()->recompileInfo());
+
+ // When one script is inlined into another the caller listens to state
+ // changes on the callee's script, so trigger these to force recompilation
+ // of any such callers.
+ if (script->functionNonDelazifying() && !script->functionNonDelazifying()->hasLazyGroup())
+ ObjectStateChange(cx, script->functionNonDelazifying()->group(), false);
+}
+
+void
+js::PrintTypes(JSContext* cx, JSCompartment* comp, bool force)
+{
+#ifdef DEBUG
+ gc::AutoSuppressGC suppressGC(cx);
+ JSAutoRequest request(cx);
+
+ Zone* zone = comp->zone();
+ AutoEnterAnalysis enter(nullptr, zone);
+
+ if (!force && !InferSpewActive(ISpewResult))
+ return;
+
+ RootedScript script(cx);
+ for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+ script = iter;
+ if (script->types())
+ script->types()->printTypes(cx, script);
+ }
+
+ for (auto group = zone->cellIter<ObjectGroup>(); !group.done(); group.next())
+ group->print();
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////
+// ObjectGroup
+/////////////////////////////////////////////////////////////////////
+
+static inline void
+UpdatePropertyType(ExclusiveContext* cx, HeapTypeSet* types, NativeObject* obj, Shape* shape,
+ bool indexed)
+{
+ MOZ_ASSERT(obj->isSingleton() && !obj->hasLazyGroup());
+
+ if (!shape->writable())
+ types->setNonWritableProperty(cx);
+
+ if (shape->hasGetterValue() || shape->hasSetterValue()) {
+ types->setNonDataProperty(cx);
+ types->TypeSet::addType(TypeSet::UnknownType(), &cx->typeLifoAlloc());
+ } else if (shape->hasDefaultGetter() && shape->hasSlot()) {
+ if (!indexed && types->canSetDefinite(shape->slot()))
+ types->setDefinite(shape->slot());
+
+ const Value& value = obj->getSlot(shape->slot());
+
+ /*
+ * Don't add initial undefined types for properties of global objects
+ * that are not collated into the JSID_VOID property (see propertySet
+ * comment).
+ *
+ * Also don't add untracked values (initial uninitialized lexical magic
+ * values and optimized out values) as appearing in CallObjects, module
+ * environments or the global lexical scope.
+ */
+ MOZ_ASSERT_IF(TypeSet::IsUntrackedValue(value),
+ obj->is<CallObject>() ||
+ obj->is<ModuleEnvironmentObject>() ||
+ IsExtensibleLexicalEnvironment(obj));
+ if ((indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) &&
+ !TypeSet::IsUntrackedValue(value))
+ {
+ TypeSet::Type type = TypeSet::GetValueType(value);
+ types->TypeSet::addType(type, &cx->typeLifoAlloc());
+ types->postWriteBarrier(cx, type);
+ }
+
+ if (indexed || shape->hadOverwrite()) {
+ types->setNonConstantProperty(cx);
+ } else {
+ InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s - setConstant",
+ InferSpewColor(types), types, InferSpewColorReset(),
+ TypeSet::ObjectGroupString(obj->group()), TypeIdString(shape->propid()));
+ }
+ }
+}
+
+void
+ObjectGroup::updateNewPropertyTypes(ExclusiveContext* cx, JSObject* objArg, jsid id, HeapTypeSet* types)
+{
+ InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s",
+ InferSpewColor(types), types, InferSpewColorReset(),
+ TypeSet::ObjectGroupString(this), TypeIdString(id));
+
+ MOZ_ASSERT_IF(objArg, objArg->group() == this);
+ MOZ_ASSERT_IF(singleton(), objArg);
+
+ if (!singleton() || !objArg->isNative()) {
+ types->setNonConstantProperty(cx);
+ return;
+ }
+
+ NativeObject* obj = &objArg->as<NativeObject>();
+
+ /*
+ * Fill the property in with any type the object already has in an own
+ * property. We are only interested in plain native properties and
+ * dense elements which don't go through a barrier when read by the VM
+ * or jitcode.
+ */
+
+ if (JSID_IS_VOID(id)) {
+ /* Go through all shapes on the object to get integer-valued properties. */
+ RootedShape shape(cx, obj->lastProperty());
+ while (!shape->isEmptyShape()) {
+ if (JSID_IS_VOID(IdToTypeId(shape->propid())))
+ UpdatePropertyType(cx, types, obj, shape, true);
+ shape = shape->previous();
+ }
+
+ /* Also get values of any dense elements in the object. */
+ for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
+ const Value& value = obj->getDenseElement(i);
+ if (!value.isMagic(JS_ELEMENTS_HOLE)) {
+ TypeSet::Type type = TypeSet::GetValueType(value);
+ types->TypeSet::addType(type, &cx->typeLifoAlloc());
+ types->postWriteBarrier(cx, type);
+ }
+ }
+ } else if (!JSID_IS_EMPTY(id)) {
+ RootedId rootedId(cx, id);
+ Shape* shape = obj->lookup(cx, rootedId);
+ if (shape)
+ UpdatePropertyType(cx, types, obj, shape, false);
+ }
+
+ if (obj->watched()) {
+ /*
+ * Mark the property as non-data, to inhibit optimizations on it
+ * and avoid bypassing the watchpoint handler.
+ */
+ types->setNonDataProperty(cx);
+ }
+}
+
+void
+ObjectGroup::addDefiniteProperties(ExclusiveContext* cx, Shape* shape)
+{
+ if (unknownProperties())
+ return;
+
+ // Mark all properties of shape as definite properties of this group.
+ AutoEnterAnalysis enter(cx);
+
+ while (!shape->isEmptyShape()) {
+ jsid id = IdToTypeId(shape->propid());
+ if (!JSID_IS_VOID(id)) {
+ MOZ_ASSERT_IF(shape->slot() >= shape->numFixedSlots(),
+ shape->numFixedSlots() == NativeObject::MAX_FIXED_SLOTS);
+ TypeSet* types = getProperty(cx, nullptr, id);
+ if (!types) {
+ MOZ_ASSERT(unknownProperties());
+ return;
+ }
+ if (types->canSetDefinite(shape->slot()))
+ types->setDefinite(shape->slot());
+ }
+
+ shape = shape->previous();
+ }
+}
+
+bool
+ObjectGroup::matchDefiniteProperties(HandleObject obj)
+{
+ unsigned count = getPropertyCount();
+ for (unsigned i = 0; i < count; i++) {
+ Property* prop = getProperty(i);
+ if (!prop)
+ continue;
+ if (prop->types.definiteProperty()) {
+ unsigned slot = prop->types.definiteSlot();
+
+ bool found = false;
+ Shape* shape = obj->as<NativeObject>().lastProperty();
+ while (!shape->isEmptyShape()) {
+ if (shape->slot() == slot && shape->propid() == prop->id) {
+ found = true;
+ break;
+ }
+ shape = shape->previous();
+ }
+ if (!found)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, jsid id, TypeSet::Type type)
+{
+ MOZ_ASSERT(id == IdToTypeId(id));
+
+ if (group->unknownProperties())
+ return;
+
+ AutoEnterAnalysis enter(cx);
+
+ HeapTypeSet* types = group->getProperty(cx, obj, id);
+ if (!types)
+ return;
+
+ // Clear any constant flag if it exists.
+ if (!types->empty() && !types->nonConstantProperty()) {
+ InferSpew(ISpewOps, "constantMutated: %sT%p%s %s",
+ InferSpewColor(types), types, InferSpewColorReset(), TypeSet::TypeString(type));
+ types->setNonConstantProperty(cx);
+ }
+
+ if (types->hasType(type))
+ return;
+
+ InferSpew(ISpewOps, "externalType: property %s %s: %s",
+ TypeSet::ObjectGroupString(group), TypeIdString(id), TypeSet::TypeString(type));
+ types->addType(cx, type);
+
+ // If this addType caused the type set to be marked as containing any
+ // object, make sure that is reflected in other type sets the addType is
+ // propagated to below.
+ if (type.isObjectUnchecked() && types->unknownObject())
+ type = TypeSet::AnyObjectType();
+
+ // Propagate new types from partially initialized groups to fully
+ // initialized groups for the acquired properties analysis. Note that we
+ // don't need to do this for other property changes, as these will also be
+ // reflected via shape changes on the object that will prevent the object
+ // from acquiring the fully initialized group.
+ if (group->newScript() && group->newScript()->initializedGroup())
+ AddTypePropertyId(cx, group->newScript()->initializedGroup(), nullptr, id, type);
+
+ // Maintain equivalent type information for unboxed object groups and their
+ // corresponding native group. Since type sets might contain the unboxed
+ // group but not the native group, this ensures optimizations based on the
+ // unboxed group are valid for the native group.
+ if (group->maybeUnboxedLayout() && group->maybeUnboxedLayout()->nativeGroup())
+ AddTypePropertyId(cx, group->maybeUnboxedLayout()->nativeGroup(), nullptr, id, type);
+ if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
+ AddTypePropertyId(cx, unboxedGroup, nullptr, id, type);
+}
+
+void
+js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, jsid id, const Value& value)
+{
+ AddTypePropertyId(cx, group, obj, id, TypeSet::GetValueType(value));
+}
+
+void
+ObjectGroup::markPropertyNonData(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ AutoEnterAnalysis enter(cx);
+
+ id = IdToTypeId(id);
+
+ HeapTypeSet* types = getProperty(cx, obj, id);
+ if (types)
+ types->setNonDataProperty(cx);
+}
+
+void
+ObjectGroup::markPropertyNonWritable(ExclusiveContext* cx, JSObject* obj, jsid id)
+{
+ AutoEnterAnalysis enter(cx);
+
+ id = IdToTypeId(id);
+
+ HeapTypeSet* types = getProperty(cx, obj, id);
+ if (types)
+ types->setNonWritableProperty(cx);
+}
+
+void
+ObjectGroup::markStateChange(ExclusiveContext* cxArg)
+{
+ if (unknownProperties())
+ return;
+
+ AutoEnterAnalysis enter(cxArg);
+ HeapTypeSet* types = maybeGetProperty(JSID_EMPTY);
+ if (types) {
+ if (JSContext* cx = cxArg->maybeJSContext()) {
+ TypeConstraint* constraint = types->constraintList;
+ while (constraint) {
+ constraint->newObjectState(cx, this);
+ constraint = constraint->next;
+ }
+ } else {
+ MOZ_ASSERT(!types->constraintList);
+ }
+ }
+}
+
+void
+ObjectGroup::setFlags(ExclusiveContext* cx, ObjectGroupFlags flags)
+{
+ if (hasAllFlags(flags))
+ return;
+
+ AutoEnterAnalysis enter(cx);
+
+ addFlags(flags);
+
+ InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeSet::ObjectGroupString(this), flags);
+
+ ObjectStateChange(cx, this, false);
+
+ // Propagate flag changes from partially to fully initialized groups for the
+ // acquired properties analysis.
+ if (newScript() && newScript()->initializedGroup())
+ newScript()->initializedGroup()->setFlags(cx, flags);
+
+ // Propagate flag changes between unboxed and corresponding native groups.
+ if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
+ maybeUnboxedLayout()->nativeGroup()->setFlags(cx, flags);
+ if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
+ unboxedGroup->setFlags(cx, flags);
+}
+
+void
+ObjectGroup::markUnknown(ExclusiveContext* cx)
+{
+ AutoEnterAnalysis enter(cx);
+
+ MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+ MOZ_ASSERT(!unknownProperties());
+
+ InferSpew(ISpewOps, "UnknownProperties: %s", TypeSet::ObjectGroupString(this));
+
+ clearNewScript(cx);
+ ObjectStateChange(cx, this, true);
+
+ /*
+ * Existing constraints may have already been added to this object, which we need
+ * to do the right thing for. We can't ensure that we will mark all unknown
+ * objects before they have been accessed, as the __proto__ of a known object
+ * could be dynamically set to an unknown object, and we can decide to ignore
+ * properties of an object during analysis (i.e. hashmaps). Adding unknown for
+ * any properties accessed already accounts for possible values read from them.
+ */
+
+ unsigned count = getPropertyCount();
+ for (unsigned i = 0; i < count; i++) {
+ Property* prop = getProperty(i);
+ if (prop) {
+ prop->types.addType(cx, TypeSet::UnknownType());
+ prop->types.setNonDataProperty(cx);
+ }
+ }
+
+ if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
+ MarkObjectGroupUnknownProperties(cx, unboxedGroup);
+ if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
+ MarkObjectGroupUnknownProperties(cx, maybeUnboxedLayout()->nativeGroup());
+ if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
+ MarkObjectGroupUnknownProperties(cx, unboxedGroup);
+}
+
+TypeNewScript*
+ObjectGroup::anyNewScript()
+{
+ if (newScript())
+ return newScript();
+ if (maybeUnboxedLayout())
+ return unboxedLayout().newScript();
+ return nullptr;
+}
+
+void
+ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement)
+{
+ // Clear the TypeNewScript from this ObjectGroup and, if it has been
+ // analyzed, remove it from the newObjectGroups table so that it will not be
+ // produced by calling 'new' on the associated function anymore.
+ // The TypeNewScript is not actually destroyed.
+ TypeNewScript* newScript = anyNewScript();
+ MOZ_ASSERT(newScript);
+
+ if (newScript->analyzed()) {
+ ObjectGroupCompartment& objectGroups = newScript->function()->compartment()->objectGroups;
+ TaggedProto proto = this->proto();
+ if (proto.isObject() && IsForwarded(proto.toObject()))
+ proto = TaggedProto(Forwarded(proto.toObject()));
+ JSObject* associated = MaybeForwarded(newScript->function());
+ if (replacement) {
+ MOZ_ASSERT(replacement->newScript()->function() == newScript->function());
+ objectGroups.replaceDefaultNewGroup(nullptr, proto, associated, replacement);
+ } else {
+ objectGroups.removeDefaultNewGroup(nullptr, proto, associated);
+ }
+ } else {
+ MOZ_ASSERT(!replacement);
+ }
+
+ if (this->newScript())
+ setAddendum(Addendum_None, nullptr, writeBarrier);
+ else
+ unboxedLayout().setNewScript(nullptr, writeBarrier);
+}
+
+void
+ObjectGroup::maybeClearNewScriptOnOOM()
+{
+ MOZ_ASSERT(zone()->isGCSweepingOrCompacting());
+
+ if (!isMarked())
+ return;
+
+ TypeNewScript* newScript = anyNewScript();
+ if (!newScript)
+ return;
+
+ addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
+
+ // This method is called during GC sweeping, so don't trigger pre barriers.
+ detachNewScript(/* writeBarrier = */ false, nullptr);
+
+ js_delete(newScript);
+}
+
+void
+ObjectGroup::clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement /* = nullptr*/)
+{
+ TypeNewScript* newScript = anyNewScript();
+ if (!newScript)
+ return;
+
+ AutoEnterAnalysis enter(cx);
+
+ if (!replacement) {
+ // Invalidate any Ion code constructing objects of this type.
+ setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
+
+ // Mark the constructing function as having its 'new' script cleared, so we
+ // will not try to construct another one later.
+ if (!newScript->function()->setNewScriptCleared(cx))
+ cx->recoverFromOutOfMemory();
+ }
+
+ detachNewScript(/* writeBarrier = */ true, replacement);
+
+ if (cx->isJSContext()) {
+ bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
+
+ // If we managed to rollback any partially initialized objects, then
+ // any definite properties we added due to analysis of the new script
+ // are now invalid, so remove them. If there weren't any partially
+ // initialized objects then we don't need to change type information,
+ // as no more objects of this type will be created and the 'new' script
+ // analysis was still valid when older objects were created.
+ if (found) {
+ for (unsigned i = 0; i < getPropertyCount(); i++) {
+ Property* prop = getProperty(i);
+ if (!prop)
+ continue;
+ if (prop->types.definiteProperty())
+ prop->types.setNonDataProperty(cx);
+ }
+ }
+ } else {
+ // Threads with an ExclusiveContext are not allowed to run scripts.
+ MOZ_ASSERT(!cx->perThreadData->runtimeIfOnOwnerThread() ||
+ !cx->perThreadData->runtimeIfOnOwnerThread()->activation());
+ }
+
+ js_delete(newScript);
+ markStateChange(cx);
+}
+
+void
+ObjectGroup::print()
+{
+ TaggedProto tagged(proto());
+ fprintf(stderr, "%s : %s",
+ TypeSet::ObjectGroupString(this),
+ tagged.isObject()
+ ? TypeSet::TypeString(TypeSet::ObjectType(tagged.toObject()))
+ : tagged.isDynamic()
+ ? "(dynamic)"
+ : "(null)");
+
+ if (unknownProperties()) {
+ fprintf(stderr, " unknown");
+ } else {
+ if (!hasAnyFlags(OBJECT_FLAG_SPARSE_INDEXES))
+ fprintf(stderr, " dense");
+ if (!hasAnyFlags(OBJECT_FLAG_NON_PACKED))
+ fprintf(stderr, " packed");
+ if (!hasAnyFlags(OBJECT_FLAG_LENGTH_OVERFLOW))
+ fprintf(stderr, " noLengthOverflow");
+ if (hasAnyFlags(OBJECT_FLAG_ITERATED))
+ fprintf(stderr, " iterated");
+ if (maybeInterpretedFunction())
+ fprintf(stderr, " ifun");
+ }
+
+ unsigned count = getPropertyCount();
+
+ if (count == 0) {
+ fprintf(stderr, " {}\n");
+ return;
+ }
+
+ fprintf(stderr, " {");
+
+ if (newScript()) {
+ if (newScript()->analyzed()) {
+ fprintf(stderr, "\n newScript %d properties",
+ (int) newScript()->templateObject()->slotSpan());
+ if (newScript()->initializedGroup()) {
+ fprintf(stderr, " initializedGroup %#" PRIxPTR " with %d properties",
+ uintptr_t(newScript()->initializedGroup()), int(newScript()->initializedShape()->slotSpan()));
+ }
+ } else {
+ fprintf(stderr, "\n newScript unanalyzed");
+ }
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ Property* prop = getProperty(i);
+ if (prop) {
+ fprintf(stderr, "\n %s:", TypeIdString(prop->id));
+ prop->types.print();
+ }
+ }
+
+ fprintf(stderr, "\n}\n");
+}
+
+/////////////////////////////////////////////////////////////////////
+// Type Analysis
+/////////////////////////////////////////////////////////////////////
+
+/*
+ * Persistent constraint clearing out newScript and definite properties from
+ * an object should a property on another object get a getter or setter.
+ */
+class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
+{
+ public:
+ ObjectGroup* group;
+
+ explicit TypeConstraintClearDefiniteGetterSetter(ObjectGroup* group)
+ : group(group)
+ {}
+
+ const char* kind() { return "clearDefiniteGetterSetter"; }
+
+ void newPropertyState(JSContext* cx, TypeSet* source) {
+ /*
+ * Clear out the newScript shape and definite property information from
+ * an object if the source type set could be a setter or could be
+ * non-writable.
+ */
+ if (source->nonDataProperty() || source->nonWritableProperty())
+ group->clearNewScript(cx);
+ }
+
+ void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) {}
+
+ bool sweep(TypeZone& zone, TypeConstraint** res) {
+ if (IsAboutToBeFinalizedUnbarriered(&group))
+ return false;
+ *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(group);
+ return true;
+ }
+
+ JSCompartment* maybeCompartment() {
+ return group->compartment();
+ }
+};
+
+bool
+js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id)
+{
+ /*
+ * Ensure that if the properties named here could have a getter, setter or
+ * a permanent property in any transitive prototype, the definite
+ * properties get cleared from the group.
+ */
+ RootedObject proto(cx, group->proto().toObjectOrNull());
+ while (proto) {
+ ObjectGroup* protoGroup = proto->getGroup(cx);
+ if (!protoGroup) {
+ cx->recoverFromOutOfMemory();
+ return false;
+ }
+ if (protoGroup->unknownProperties())
+ return false;
+ HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id);
+ if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
+ return false;
+ if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(group)))
+ return false;
+ proto = proto->staticPrototype();
+ }
+ return true;
+}
+
+/*
+ * Constraint which clears definite properties on a group should a type set
+ * contain any types other than a single object.
+ */
+class TypeConstraintClearDefiniteSingle : public TypeConstraint
+{
+ public:
+ ObjectGroup* group;
+
+ explicit TypeConstraintClearDefiniteSingle(ObjectGroup* group)
+ : group(group)
+ {}
+
+ const char* kind() { return "clearDefiniteSingle"; }
+
+ void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) {
+ if (source->baseFlags() || source->getObjectCount() > 1)
+ group->clearNewScript(cx);
+ }
+
+ bool sweep(TypeZone& zone, TypeConstraint** res) {
+ if (IsAboutToBeFinalizedUnbarriered(&group))
+ return false;
+ *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(group);
+ return true;
+ }
+
+ JSCompartment* maybeCompartment() {
+ return group->compartment();
+ }
+};
+
+bool
+js::AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
+ JSScript* script, JSScript* calleeScript)
+{
+ // Look for any uses of the specified calleeScript in type sets for
+ // |script|, and add constraints to ensure that if the type sets' contents
+ // change then the definite properties are cleared from the type.
+ // This ensures that the inlining performed when the definite properties
+ // analysis was done is stable. We only need to look at type sets which
+ // contain a single object, as IonBuilder does not inline polymorphic sites
+ // during the definite properties analysis.
+
+ TypeSet::ObjectKey* calleeKey =
+ TypeSet::ObjectType(calleeScript->functionNonDelazifying()).objectKey();
+
+ unsigned count = TypeScript::NumTypeSets(script);
+ StackTypeSet* typeArray = script->types()->typeArray();
+
+ for (unsigned i = 0; i < count; i++) {
+ StackTypeSet* types = &typeArray[i];
+ if (!types->unknownObject() && types->getObjectCount() == 1) {
+ if (calleeKey != types->getObject(0)) {
+ // Also check if the object is the Function.call or
+ // Function.apply native. IonBuilder uses the presence of these
+ // functions during inlining.
+ JSObject* singleton = types->getSingleton(0);
+ if (!singleton || !singleton->is<JSFunction>())
+ continue;
+ JSFunction* fun = &singleton->as<JSFunction>();
+ if (!fun->isNative())
+ continue;
+ if (fun->native() != fun_call && fun->native() != fun_apply)
+ continue;
+ }
+ // This is a type set that might have been used when inlining
+ // |calleeScript| into |script|.
+ if (!types->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(group)))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Interface functions
+/////////////////////////////////////////////////////////////////////
+
+void
+js::TypeMonitorCallSlow(JSContext* cx, JSObject* callee, const CallArgs& args, bool constructing)
+{
+ unsigned nargs = callee->as<JSFunction>().nargs();
+ JSScript* script = callee->as<JSFunction>().nonLazyScript();
+
+ if (!constructing)
+ TypeScript::SetThis(cx, script, args.thisv());
+
+ /*
+ * Add constraints going up to the minimum of the actual and formal count.
+ * If there are more actuals than formals the later values can only be
+ * accessed through the arguments object, which is monitored.
+ */
+ unsigned arg = 0;
+ for (; arg < args.length() && arg < nargs; arg++)
+ TypeScript::SetArgument(cx, script, arg, args[arg]);
+
+ /* Watch for fewer actuals than formals to the call. */
+ for (; arg < nargs; arg++)
+ TypeScript::SetArgument(cx, script, arg, UndefinedValue());
+}
+
+void
+js::FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap)
+{
+ uint32_t added = 0;
+ for (jsbytecode* pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
+ JSOp op = JSOp(*pc);
+ if (CodeSpec[op].format & JOF_TYPESET) {
+ bytecodeMap[added++] = script->pcToOffset(pc);
+ if (added == script->nTypeSets())
+ break;
+ }
+ }
+ MOZ_ASSERT(added == script->nTypeSets());
+}
+
+void
+js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, TypeSet::Type type)
+{
+ assertSameCompartment(cx, script, type);
+
+ AutoEnterAnalysis enter(cx);
+
+ StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+ if (types->hasType(type))
+ return;
+
+ InferSpew(ISpewOps, "bytecodeType: %p %05" PRIuSIZE ": %s",
+ script, script->pcToOffset(pc), TypeSet::TypeString(type));
+ types->addType(cx, type);
+}
+
+void
+js::TypeMonitorResult(JSContext* cx, JSScript* script, jsbytecode* pc, const js::Value& rval)
+{
+ /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
+ if (!(CodeSpec[*pc].format & JOF_TYPESET))
+ return;
+
+ if (!script->hasBaselineScript())
+ return;
+
+ TypeMonitorResult(cx, script, pc, TypeSet::GetValueType(rval));
+}
+
+/////////////////////////////////////////////////////////////////////
+// TypeScript
+/////////////////////////////////////////////////////////////////////
+
+bool
+JSScript::makeTypes(JSContext* cx)
+{
+ MOZ_ASSERT(!types_);
+
+ AutoEnterAnalysis enter(cx);
+
+ unsigned count = TypeScript::NumTypeSets(this);
+
+ TypeScript* typeScript = (TypeScript*)
+ zone()->pod_calloc<uint8_t>(TypeScript::SizeIncludingTypeArray(count));
+ if (!typeScript) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ types_ = typeScript;
+ setTypesGeneration(cx->zone()->types.generation);
+
+#ifdef DEBUG
+ StackTypeSet* typeArray = typeScript->typeArray();
+ for (unsigned i = 0; i < nTypeSets(); i++) {
+ InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p",
+ InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
+ i, this);
+ }
+ TypeSet* thisTypes = TypeScript::ThisTypes(this);
+ InferSpew(ISpewOps, "typeSet: %sT%p%s this %p",
+ InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
+ this);
+ unsigned nargs = functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0;
+ for (unsigned i = 0; i < nargs; i++) {
+ TypeSet* types = TypeScript::ArgTypes(this, i);
+ InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u %p",
+ InferSpewColor(types), types, InferSpewColorReset(),
+ i, this);
+ }
+#endif
+
+ return true;
+}
+
+/* static */ bool
+JSFunction::setTypeForScriptedFunction(ExclusiveContext* cx, HandleFunction fun,
+ bool singleton /* = false */)
+{
+ if (singleton) {
+ if (!setSingleton(cx, fun))
+ return false;
+ } else {
+ RootedObject funProto(cx, fun->staticPrototype());
+ Rooted<TaggedProto> taggedProto(cx, TaggedProto(funProto));
+ ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_,
+ taggedProto);
+ if (!group)
+ return false;
+
+ fun->setGroup(group);
+ group->setInterpretedFunction(fun);
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// PreliminaryObjectArray
+/////////////////////////////////////////////////////////////////////
+
+void
+PreliminaryObjectArray::registerNewObject(JSObject* res)
+{
+ // The preliminary object pointers are weak, and won't be swept properly
+ // during nursery collections, so the preliminary objects need to be
+ // initially tenured.
+ MOZ_ASSERT(!IsInsideNursery(res));
+
+ for (size_t i = 0; i < COUNT; i++) {
+ if (!objects[i]) {
+ objects[i] = res;
+ return;
+ }
+ }
+
+ MOZ_CRASH("There should be room for registering the new object");
+}
+
+void
+PreliminaryObjectArray::unregisterObject(JSObject* obj)
+{
+ for (size_t i = 0; i < COUNT; i++) {
+ if (objects[i] == obj) {
+ objects[i] = nullptr;
+ return;
+ }
+ }
+
+ MOZ_CRASH("The object should be in the array");
+}
+
+bool
+PreliminaryObjectArray::full() const
+{
+ for (size_t i = 0; i < COUNT; i++) {
+ if (!objects[i])
+ return false;
+ }
+ return true;
+}
+
+bool
+PreliminaryObjectArray::empty() const
+{
+ for (size_t i = 0; i < COUNT; i++) {
+ if (objects[i])
+ return false;
+ }
+ return true;
+}
+
+void
+PreliminaryObjectArray::sweep()
+{
+ // All objects in the array are weak, so clear any that are about to be
+ // destroyed.
+ for (size_t i = 0; i < COUNT; i++) {
+ JSObject** ptr = &objects[i];
+ if (*ptr && IsAboutToBeFinalizedUnbarriered(ptr)) {
+ // Before we clear this reference, change the object's group to the
+ // Object.prototype group. This is done to ensure JSObject::finalize
+ // sees a NativeObject Class even if we change the current group's
+ // Class to one of the unboxed object classes in the meantime. If
+ // the compartment's global is dead, we don't do anything as the
+ // group's Class is not going to change in that case.
+ JSObject* obj = *ptr;
+ GlobalObject* global = obj->compartment()->unsafeUnbarrieredMaybeGlobal();
+ if (global && !obj->isSingleton()) {
+ JSObject* objectProto = GetBuiltinPrototypePure(global, JSProto_Object);
+ obj->setGroup(objectProto->groupRaw());
+ MOZ_ASSERT(obj->is<NativeObject>());
+ MOZ_ASSERT(obj->getClass() == objectProto->getClass());
+ MOZ_ASSERT(!obj->getClass()->hasFinalize());
+ }
+
+ *ptr = nullptr;
+ }
+ }
+}
+
+void
+PreliminaryObjectArrayWithTemplate::trace(JSTracer* trc)
+{
+ TraceNullableEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
+}
+
+/* static */ void
+PreliminaryObjectArrayWithTemplate::writeBarrierPre(PreliminaryObjectArrayWithTemplate* objects)
+{
+ Shape* shape = objects->shape();
+
+ if (!shape)
+ return;
+
+ JS::Zone* zone = shape->zoneFromAnyThread();
+ if (zone->needsIncrementalBarrier())
+ objects->trace(zone->barrierTracer());
+}
+
+// Return whether shape consists entirely of plain data properties.
+static bool
+OnlyHasDataProperties(Shape* shape)
+{
+ MOZ_ASSERT(!shape->inDictionary());
+
+ while (!shape->isEmptyShape()) {
+ if (!shape->isDataDescriptor() ||
+ !shape->configurable() ||
+ !shape->enumerable() ||
+ !shape->writable() ||
+ !shape->hasSlot())
+ {
+ return false;
+ }
+ shape = shape->previous();
+ }
+
+ return true;
+}
+
+// Find the most recent common ancestor of two shapes, or an empty shape if
+// the two shapes have no common ancestor.
+static Shape*
+CommonPrefix(Shape* first, Shape* second)
+{
+ MOZ_ASSERT(OnlyHasDataProperties(first));
+ MOZ_ASSERT(OnlyHasDataProperties(second));
+
+ while (first->slotSpan() > second->slotSpan())
+ first = first->previous();
+ while (second->slotSpan() > first->slotSpan())
+ second = second->previous();
+
+ while (first != second && !first->isEmptyShape()) {
+ first = first->previous();
+ second = second->previous();
+ }
+
+ return first;
+}
+
+void
+PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGroup* group, bool force)
+{
+ // Don't perform the analyses until sufficient preliminary objects have
+ // been allocated.
+ if (!force && !full())
+ return;
+
+ AutoEnterAnalysis enter(cx);
+
+ ScopedJSDeletePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
+ group->detachPreliminaryObjects();
+
+ if (shape()) {
+ MOZ_ASSERT(shape()->slotSpan() != 0);
+ MOZ_ASSERT(OnlyHasDataProperties(shape()));
+
+ // Make sure all the preliminary objects reflect the properties originally
+ // in the template object.
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* objBase = preliminaryObjects->get(i);
+ if (!objBase)
+ continue;
+ PlainObject* obj = &objBase->as<PlainObject>();
+
+ if (obj->inDictionaryMode() || !OnlyHasDataProperties(obj->lastProperty()))
+ return;
+
+ if (CommonPrefix(obj->lastProperty(), shape()) != shape())
+ return;
+ }
+ }
+
+ TryConvertToUnboxedLayout(cx, enter, shape(), group, preliminaryObjects);
+ if (group->maybeUnboxedLayout())
+ return;
+
+ if (shape()) {
+ // We weren't able to use an unboxed layout, but since the preliminary
+ // objects still reflect the template object's properties, and all
+ // objects in the future will be created with those properties, the
+ // properties can be marked as definite for objects in the group.
+ group->addDefiniteProperties(cx, shape());
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// TypeNewScript
+/////////////////////////////////////////////////////////////////////
+
+// Make a TypeNewScript for |group|, and set it up to hold the preliminary
+// objects created with the group.
+/* static */ bool
+TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun)
+{
+ MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+ MOZ_ASSERT(!group->newScript());
+ MOZ_ASSERT(!group->maybeUnboxedLayout());
+
+ if (group->unknownProperties())
+ return true;
+
+ ScopedJSDeletePtr<TypeNewScript> newScript(cx->new_<TypeNewScript>());
+ if (!newScript)
+ return false;
+
+ newScript->function_ = fun;
+
+ newScript->preliminaryObjects = group->zone()->new_<PreliminaryObjectArray>();
+ if (!newScript->preliminaryObjects)
+ return true;
+
+ group->setNewScript(newScript.forget());
+
+ gc::TraceTypeNewScript(group);
+ return true;
+}
+
+// Make a TypeNewScript with the same initializer list as |newScript| but with
+// a new template object.
+/* static */ TypeNewScript*
+TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
+ PlainObject* templateObject)
+{
+ MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+
+ ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
+ if (!nativeNewScript)
+ return nullptr;
+
+ nativeNewScript->function_ = newScript->function();
+ nativeNewScript->templateObject_ = templateObject;
+
+ Initializer* cursor = newScript->initializerList;
+ while (cursor->kind != Initializer::DONE) { cursor++; }
+ size_t initializerLength = cursor - newScript->initializerList + 1;
+
+ nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
+ if (!nativeNewScript->initializerList) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+ PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
+
+ return nativeNewScript.forget();
+}
+
+size_t
+TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ size_t n = mallocSizeOf(this);
+ n += mallocSizeOf(preliminaryObjects);
+ n += mallocSizeOf(initializerList);
+ return n;
+}
+
+void
+TypeNewScript::registerNewObject(PlainObject* res)
+{
+ MOZ_ASSERT(!analyzed());
+
+ // New script objects must have the maximum number of fixed slots, so that
+ // we can adjust their shape later to match the number of fixed slots used
+ // by the template object we eventually create.
+ MOZ_ASSERT(res->numFixedSlots() == NativeObject::MAX_FIXED_SLOTS);
+
+ preliminaryObjects->registerNewObject(res);
+}
+
+static bool
+ChangeObjectFixedSlotCount(JSContext* cx, PlainObject* obj, gc::AllocKind allocKind)
+{
+ MOZ_ASSERT(OnlyHasDataProperties(obj->lastProperty()));
+
+ Shape* newShape = ReshapeForAllocKind(cx, obj->lastProperty(), obj->taggedProto(), allocKind);
+ if (!newShape)
+ return false;
+
+ obj->setLastPropertyShrinkFixedSlots(newShape);
+ return true;
+}
+
+namespace {
+
+struct DestroyTypeNewScript
+{
+ JSContext* cx;
+ ObjectGroup* group;
+
+ DestroyTypeNewScript(JSContext* cx, ObjectGroup* group)
+ : cx(cx), group(group)
+ {}
+
+ ~DestroyTypeNewScript() {
+ if (group)
+ group->clearNewScript(cx);
+ }
+};
+
+} // namespace
+
+bool
+TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force)
+{
+ // Perform the new script properties analysis if necessary, returning
+ // whether the new group table was updated and group needs to be refreshed.
+ MOZ_ASSERT(this == group->newScript());
+
+ // Make sure there aren't dead references in preliminaryObjects. This can
+ // clear out the new script information on OOM.
+ group->maybeSweep(nullptr);
+ if (!group->newScript())
+ return true;
+
+ if (regenerate)
+ *regenerate = false;
+
+ if (analyzed()) {
+ // The analyses have already been performed.
+ return true;
+ }
+
+ // Don't perform the analyses until sufficient preliminary objects have
+ // been allocated.
+ if (!force && !preliminaryObjects->full())
+ return true;
+
+ AutoEnterAnalysis enter(cx);
+
+ // Any failures after this point will clear out this TypeNewScript.
+ DestroyTypeNewScript destroyNewScript(cx, group);
+
+ // Compute the greatest common shape prefix and the largest slot span of
+ // the preliminary objects.
+ Shape* prefixShape = nullptr;
+ size_t maxSlotSpan = 0;
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* objBase = preliminaryObjects->get(i);
+ if (!objBase)
+ continue;
+ PlainObject* obj = &objBase->as<PlainObject>();
+
+ // For now, we require all preliminary objects to have only simple
+ // lineages of plain data properties.
+ Shape* shape = obj->lastProperty();
+ if (shape->inDictionary() ||
+ !OnlyHasDataProperties(shape) ||
+ shape->getObjectFlags() != 0)
+ {
+ return true;
+ }
+
+ maxSlotSpan = Max<size_t>(maxSlotSpan, obj->slotSpan());
+
+ if (prefixShape) {
+ MOZ_ASSERT(shape->numFixedSlots() == prefixShape->numFixedSlots());
+ prefixShape = CommonPrefix(prefixShape, shape);
+ } else {
+ prefixShape = shape;
+ }
+ if (prefixShape->isEmptyShape()) {
+ // The preliminary objects don't have any common properties.
+ return true;
+ }
+ }
+ if (!prefixShape)
+ return true;
+
+ gc::AllocKind kind = gc::GetGCObjectKind(maxSlotSpan);
+
+ if (kind != gc::GetGCObjectKind(NativeObject::MAX_FIXED_SLOTS)) {
+ // The template object will have a different allocation kind from the
+ // preliminary objects that have already been constructed. Optimizing
+ // definite property accesses requires both that the property is
+ // definitely in a particular slot and that the object has a specific
+ // number of fixed slots. So, adjust the shape and slot layout of all
+ // the preliminary objects so that their structure matches that of the
+ // template object. Also recompute the prefix shape, as it reflects the
+ // old number of fixed slots.
+ Shape* newPrefixShape = nullptr;
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* objBase = preliminaryObjects->get(i);
+ if (!objBase)
+ continue;
+ PlainObject* obj = &objBase->as<PlainObject>();
+ if (!ChangeObjectFixedSlotCount(cx, obj, kind))
+ return false;
+ if (newPrefixShape) {
+ MOZ_ASSERT(CommonPrefix(obj->lastProperty(), newPrefixShape) == newPrefixShape);
+ } else {
+ newPrefixShape = obj->lastProperty();
+ while (newPrefixShape->slotSpan() > prefixShape->slotSpan())
+ newPrefixShape = newPrefixShape->previous();
+ }
+ }
+ prefixShape = newPrefixShape;
+ }
+
+ RootedObjectGroup groupRoot(cx, group);
+ templateObject_ = NewObjectWithGroup<PlainObject>(cx, groupRoot, kind, TenuredObject);
+ if (!templateObject_)
+ return false;
+
+ Vector<Initializer> initializerVector(cx);
+
+ RootedPlainObject templateRoot(cx, templateObject());
+ if (!jit::AnalyzeNewScriptDefiniteProperties(cx, function(), group, templateRoot, &initializerVector))
+ return false;
+
+ if (!group->newScript())
+ return true;
+
+ MOZ_ASSERT(OnlyHasDataProperties(templateObject()->lastProperty()));
+
+ if (templateObject()->slotSpan() != 0) {
+ // Make sure that all definite properties found are reflected in the
+ // prefix shape. Otherwise, the constructor behaved differently before
+ // we baseline compiled it and started observing types. Compare
+ // property names rather than looking at the shapes directly, as the
+ // allocation kind and other non-property parts of the template and
+ // existing objects may differ.
+ if (templateObject()->slotSpan() > prefixShape->slotSpan())
+ return true;
+ {
+ Shape* shape = prefixShape;
+ while (shape->slotSpan() != templateObject()->slotSpan())
+ shape = shape->previous();
+ Shape* templateShape = templateObject()->lastProperty();
+ while (!shape->isEmptyShape()) {
+ if (shape->slot() != templateShape->slot())
+ return true;
+ if (shape->propid() != templateShape->propid())
+ return true;
+ shape = shape->previous();
+ templateShape = templateShape->previous();
+ }
+ if (!templateShape->isEmptyShape())
+ return true;
+ }
+
+ Initializer done(Initializer::DONE, 0);
+
+ if (!initializerVector.append(done))
+ return false;
+
+ initializerList = group->zone()->pod_calloc<Initializer>(initializerVector.length());
+ if (!initializerList) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ PodCopy(initializerList, initializerVector.begin(), initializerVector.length());
+ }
+
+ // Try to use an unboxed representation for the group.
+ if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(), group, preliminaryObjects))
+ return false;
+
+ js_delete(preliminaryObjects);
+ preliminaryObjects = nullptr;
+
+ if (group->maybeUnboxedLayout()) {
+ // An unboxed layout was constructed for the group, and this has already
+ // been hooked into it.
+ MOZ_ASSERT(group->unboxedLayout().newScript() == this);
+ destroyNewScript.group = nullptr;
+
+ // Clear out the template object, which is not used for TypeNewScripts
+ // with an unboxed layout. Currently it is a mutant object with a
+ // non-native group and native shape, so make it safe for GC by changing
+ // its group to the default for its prototype.
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ ObjectGroup* plainGroup = ObjectGroup::defaultNewGroup(cx, &PlainObject::class_,
+ group->proto());
+ if (!plainGroup)
+ oomUnsafe.crash("TypeNewScript::maybeAnalyze");
+ templateObject_->setGroup(plainGroup);
+ templateObject_ = nullptr;
+
+ return true;
+ }
+
+ if (prefixShape->slotSpan() == templateObject()->slotSpan()) {
+ // The definite properties analysis found exactly the properties that
+ // are held in common by the preliminary objects. No further analysis
+ // is needed.
+ group->addDefiniteProperties(cx, templateObject()->lastProperty());
+
+ destroyNewScript.group = nullptr;
+ return true;
+ }
+
+ // There are more properties consistently added to objects of this group
+ // than were discovered by the definite properties analysis. Use the
+ // existing group to represent fully initialized objects with all
+ // definite properties in the prefix shape, and make a new group to
+ // represent partially initialized objects.
+ MOZ_ASSERT(prefixShape->slotSpan() > templateObject()->slotSpan());
+
+ ObjectGroupFlags initialFlags = group->flags() & OBJECT_FLAG_DYNAMIC_MASK;
+
+ Rooted<TaggedProto> protoRoot(cx, group->proto());
+ ObjectGroup* initialGroup = ObjectGroupCompartment::makeGroup(cx, group->clasp(), protoRoot,
+ initialFlags);
+ if (!initialGroup)
+ return false;
+
+ initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
+ group->addDefiniteProperties(cx, prefixShape);
+
+ cx->compartment()->objectGroups.replaceDefaultNewGroup(nullptr, group->proto(), function(),
+ initialGroup);
+
+ templateObject()->setGroup(initialGroup);
+
+ // Transfer this TypeNewScript from the fully initialized group to the
+ // partially initialized group.
+ group->setNewScript(nullptr);
+ initialGroup->setNewScript(this);
+
+ initializedShape_ = prefixShape;
+ initializedGroup_ = group;
+
+ destroyNewScript.group = nullptr;
+
+ if (regenerate)
+ *regenerate = true;
+ return true;
+}
+
+bool
+TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group)
+{
+ // If we cleared this new script while in the middle of initializing an
+ // object, it will still have the new script's shape and reflect the no
+ // longer correct state of the object once its initialization is completed.
+ // We can't detect the possibility of this statically while remaining
+ // robust, but the new script keeps track of where each property is
+ // initialized so we can walk the stack and fix up any such objects.
+ // Return whether any objects were modified.
+
+ if (!initializerList)
+ return false;
+
+ bool found = false;
+
+ RootedFunction function(cx, this->function());
+ Vector<uint32_t, 32> pcOffsets(cx);
+ for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
+ {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!pcOffsets.append(iter.script()->pcToOffset(iter.pc())))
+ oomUnsafe.crash("rollbackPartiallyInitializedObjects");
+ }
+
+ if (!iter.isConstructing() || !iter.matchCallee(cx, function))
+ continue;
+
+ // Derived class constructors initialize their this-binding later and
+ // we shouldn't run the definite properties analysis on them.
+ MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
+
+ Value thisv = iter.thisArgument(cx);
+ if (!thisv.isObject() ||
+ thisv.toObject().hasLazyGroup() ||
+ thisv.toObject().group() != group)
+ {
+ continue;
+ }
+
+ if (thisv.toObject().is<UnboxedPlainObject>()) {
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject()))
+ oomUnsafe.crash("rollbackPartiallyInitializedObjects");
+ }
+
+ // Found a matching frame.
+ RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
+
+ // Whether all identified 'new' properties have been initialized.
+ bool finished = false;
+
+ // If not finished, number of properties that have been added.
+ uint32_t numProperties = 0;
+
+ // Whether the current SETPROP is within an inner frame which has
+ // finished entirely.
+ bool pastProperty = false;
+
+ // Index in pcOffsets of the outermost frame.
+ int callDepth = pcOffsets.length() - 1;
+
+ // Index in pcOffsets of the frame currently being checked for a SETPROP.
+ int setpropDepth = callDepth;
+
+ for (Initializer* init = initializerList;; init++) {
+ if (init->kind == Initializer::SETPROP) {
+ if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
+ // Have not yet reached this setprop.
+ break;
+ }
+ // This setprop has executed, reset state for the next one.
+ numProperties++;
+ pastProperty = false;
+ setpropDepth = callDepth;
+ } else if (init->kind == Initializer::SETPROP_FRAME) {
+ if (!pastProperty) {
+ if (pcOffsets[setpropDepth] < init->offset) {
+ // Have not yet reached this inner call.
+ break;
+ } else if (pcOffsets[setpropDepth] > init->offset) {
+ // Have advanced past this inner call.
+ pastProperty = true;
+ } else if (setpropDepth == 0) {
+ // Have reached this call but not yet in it.
+ break;
+ } else {
+ // Somewhere inside this inner call.
+ setpropDepth--;
+ }
+ }
+ } else {
+ MOZ_ASSERT(init->kind == Initializer::DONE);
+ finished = true;
+ break;
+ }
+ }
+
+ if (!finished) {
+ (void) NativeObject::rollbackProperties(cx, obj, numProperties);
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+void
+TypeNewScript::trace(JSTracer* trc)
+{
+ TraceEdge(trc, &function_, "TypeNewScript_function");
+ TraceNullableEdge(trc, &templateObject_, "TypeNewScript_templateObject");
+ TraceNullableEdge(trc, &initializedShape_, "TypeNewScript_initializedShape");
+ TraceNullableEdge(trc, &initializedGroup_, "TypeNewScript_initializedGroup");
+}
+
+/* static */ void
+TypeNewScript::writeBarrierPre(TypeNewScript* newScript)
+{
+ if (newScript->function()->runtimeFromAnyThread()->isHeapCollecting())
+ return;
+
+ JS::Zone* zone = newScript->function()->zoneFromAnyThread();
+ if (zone->needsIncrementalBarrier())
+ newScript->trace(zone->barrierTracer());
+}
+
+void
+TypeNewScript::sweep()
+{
+ if (preliminaryObjects)
+ preliminaryObjects->sweep();
+}
+
+/////////////////////////////////////////////////////////////////////
+// Tracing
+/////////////////////////////////////////////////////////////////////
+
+static inline void
+TraceObjectKey(JSTracer* trc, TypeSet::ObjectKey** keyp)
+{
+ TypeSet::ObjectKey* key = *keyp;
+ if (key->isGroup()) {
+ ObjectGroup* group = key->groupNoBarrier();
+ TraceManuallyBarrieredEdge(trc, &group, "objectKey_group");
+ *keyp = TypeSet::ObjectKey::get(group);
+ } else {
+ JSObject* singleton = key->singletonNoBarrier();
+ TraceManuallyBarrieredEdge(trc, &singleton, "objectKey_singleton");
+ *keyp = TypeSet::ObjectKey::get(singleton);
+ }
+}
+
+void
+ConstraintTypeSet::trace(Zone* zone, JSTracer* trc)
+{
+ // ConstraintTypeSets only hold strong references during minor collections.
+ MOZ_ASSERT(zone->runtimeFromMainThread()->isHeapMinorCollecting());
+
+ unsigned objectCount = baseObjectCount();
+ if (objectCount >= 2) {
+ unsigned oldCapacity = TypeHashSet::Capacity(objectCount);
+ ObjectKey** oldArray = objectSet;
+
+ clearObjects();
+ objectCount = 0;
+ for (unsigned i = 0; i < oldCapacity; i++) {
+ ObjectKey* key = oldArray[i];
+ if (!key)
+ continue;
+ TraceObjectKey(trc, &key);
+
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ ObjectKey** pentry =
+ TypeHashSet::Insert<ObjectKey*, ObjectKey, ObjectKey>
+ (zone->types.typeLifoAlloc, objectSet, objectCount, key);
+ if (!pentry)
+ oomUnsafe.crash("ConstraintTypeSet::trace");
+
+ *pentry = key;
+ }
+ setBaseObjectCount(objectCount);
+ } else if (objectCount == 1) {
+ ObjectKey* key = (ObjectKey*) objectSet;
+ TraceObjectKey(trc, &key);
+ objectSet = reinterpret_cast<ObjectKey**>(key);
+ }
+}
+
+static inline void
+AssertGCStateForSweep(Zone* zone)
+{
+ MOZ_ASSERT(zone->isGCSweepingOrCompacting());
+
+ // IsAboutToBeFinalized doesn't work right on tenured objects when called
+ // during a minor collection.
+ MOZ_ASSERT(!zone->runtimeFromMainThread()->isHeapMinorCollecting());
+}
+
+void
+ConstraintTypeSet::sweep(Zone* zone, AutoClearTypeInferenceStateOnOOM& oom)
+{
+ AssertGCStateForSweep(zone);
+
+ /*
+ * Purge references to objects that are no longer live. Type sets hold
+ * only weak references. For type sets containing more than one object,
+ * live entries in the object hash need to be copied to the zone's
+ * new arena.
+ */
+ unsigned objectCount = baseObjectCount();
+ if (objectCount >= 2) {
+ unsigned oldCapacity = TypeHashSet::Capacity(objectCount);
+ ObjectKey** oldArray = objectSet;
+
+ clearObjects();
+ objectCount = 0;
+ for (unsigned i = 0; i < oldCapacity; i++) {
+ ObjectKey* key = oldArray[i];
+ if (!key)
+ continue;
+ if (!IsObjectKeyAboutToBeFinalized(&key)) {
+ ObjectKey** pentry =
+ TypeHashSet::Insert<ObjectKey*, ObjectKey, ObjectKey>
+ (zone->types.typeLifoAlloc, objectSet, objectCount, key);
+ if (pentry) {
+ *pentry = key;
+ } else {
+ oom.setOOM();
+ flags |= TYPE_FLAG_ANYOBJECT;
+ clearObjects();
+ objectCount = 0;
+ break;
+ }
+ } else if (key->isGroup() &&
+ key->groupNoBarrier()->unknownPropertiesDontCheckGeneration()) {
+ // Object sets containing objects with unknown properties might
+ // not be complete. Mark the type set as unknown, which it will
+ // be treated as during Ion compilation.
+ //
+ // Note that we don't have to do this when the type set might
+ // be missing the native group corresponding to an unboxed
+ // object group. In this case, the native group points to the
+ // unboxed object group via its addendum, so as long as objects
+ // with either group exist, neither group will be finalized.
+ flags |= TYPE_FLAG_ANYOBJECT;
+ clearObjects();
+ objectCount = 0;
+ break;
+ }
+ }
+ setBaseObjectCount(objectCount);
+ } else if (objectCount == 1) {
+ ObjectKey* key = (ObjectKey*) objectSet;
+ if (!IsObjectKeyAboutToBeFinalized(&key)) {
+ objectSet = reinterpret_cast<ObjectKey**>(key);
+ } else {
+ // As above, mark type sets containing objects with unknown
+ // properties as unknown.
+ if (key->isGroup() && key->groupNoBarrier()->unknownPropertiesDontCheckGeneration())
+ flags |= TYPE_FLAG_ANYOBJECT;
+ objectSet = nullptr;
+ setBaseObjectCount(0);
+ }
+ }
+
+ /*
+ * Type constraints only hold weak references. Copy constraints referring
+ * to data that is still live into the zone's new arena.
+ */
+ TypeConstraint* constraint = constraintList;
+ constraintList = nullptr;
+ while (constraint) {
+ MOZ_ASSERT(zone->types.sweepTypeLifoAlloc.contains(constraint));
+ TypeConstraint* copy;
+ if (constraint->sweep(zone->types, &copy)) {
+ if (copy) {
+ MOZ_ASSERT(zone->types.typeLifoAlloc.contains(copy));
+ copy->next = constraintList;
+ constraintList = copy;
+ } else {
+ oom.setOOM();
+ }
+ }
+ constraint = constraint->next;
+ }
+}
+
+inline void
+ObjectGroup::clearProperties()
+{
+ setBasePropertyCount(0);
+ propertySet = nullptr;
+}
+
+static void
+EnsureHasAutoClearTypeInferenceStateOnOOM(AutoClearTypeInferenceStateOnOOM*& oom, Zone* zone,
+ Maybe<AutoClearTypeInferenceStateOnOOM>& fallback)
+{
+ if (!oom) {
+ if (zone->types.activeAnalysis) {
+ oom = &zone->types.activeAnalysis->oom;
+ } else {
+ fallback.emplace(zone);
+ oom = &fallback.ref();
+ }
+ }
+}
+
+/*
+ * Before sweeping the arenas themselves, scan all groups in a compartment to
+ * fixup weak references: property type sets referencing dead JS and type
+ * objects, and singleton JS objects whose type is not referenced elsewhere.
+ * This is done either incrementally as part of the sweep, or on demand as type
+ * objects are accessed before their contents have been swept.
+ */
+void
+ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom)
+{
+ MOZ_ASSERT(generation() != zoneFromAnyThread()->types.generation);
+
+ setGeneration(zone()->types.generation);
+
+ AssertGCStateForSweep(zone());
+
+ Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
+ EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM);
+
+ if (maybeUnboxedLayout()) {
+ // Remove unboxed layouts that are about to be finalized from the
+ // compartment wide list while we are still on the main thread.
+ ObjectGroup* group = this;
+ if (IsAboutToBeFinalizedUnbarriered(&group))
+ unboxedLayout().detachFromCompartment();
+
+ if (unboxedLayout().newScript())
+ unboxedLayout().newScript()->sweep();
+
+ // Discard constructor code to avoid holding onto ExecutablePools.
+ if (zone()->isGCCompacting())
+ unboxedLayout().setConstructorCode(nullptr);
+ }
+
+ if (maybePreliminaryObjects())
+ maybePreliminaryObjects()->sweep();
+
+ if (newScript())
+ newScript()->sweep();
+
+ LifoAlloc& typeLifoAlloc = zone()->types.typeLifoAlloc;
+
+ /*
+ * Properties were allocated from the old arena, and need to be copied over
+ * to the new one.
+ */
+ unsigned propertyCount = basePropertyCount();
+ if (propertyCount >= 2) {
+ unsigned oldCapacity = TypeHashSet::Capacity(propertyCount);
+ Property** oldArray = propertySet;
+
+ clearProperties();
+ propertyCount = 0;
+ for (unsigned i = 0; i < oldCapacity; i++) {
+ Property* prop = oldArray[i];
+ if (prop) {
+ if (singleton() && !prop->types.constraintList && !zone()->isPreservingCode()) {
+ /*
+ * Don't copy over properties of singleton objects when their
+ * presence will not be required by jitcode or type constraints
+ * (i.e. for the definite properties analysis). The contents of
+ * these type sets will be regenerated as necessary.
+ */
+ continue;
+ }
+
+ Property* newProp = typeLifoAlloc.new_<Property>(*prop);
+ if (newProp) {
+ Property** pentry = TypeHashSet::Insert<jsid, Property, Property>
+ (typeLifoAlloc, propertySet, propertyCount, prop->id);
+ if (pentry) {
+ *pentry = newProp;
+ newProp->types.sweep(zone(), *oom);
+ continue;
+ }
+ }
+
+ oom->setOOM();
+ addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
+ clearProperties();
+ return;
+ }
+ }
+ setBasePropertyCount(propertyCount);
+ } else if (propertyCount == 1) {
+ Property* prop = (Property*) propertySet;
+ if (singleton() && !prop->types.constraintList && !zone()->isPreservingCode()) {
+ // Skip, as above.
+ clearProperties();
+ } else {
+ Property* newProp = typeLifoAlloc.new_<Property>(*prop);
+ if (newProp) {
+ propertySet = (Property**) newProp;
+ newProp->types.sweep(zone(), *oom);
+ } else {
+ oom->setOOM();
+ addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
+ clearProperties();
+ return;
+ }
+ }
+ }
+}
+
+/* static */ void
+JSScript::maybeSweepTypes(AutoClearTypeInferenceStateOnOOM* oom)
+{
+ if (!types_ || typesGeneration() == zone()->types.generation)
+ return;
+
+ setTypesGeneration(zone()->types.generation);
+
+ AssertGCStateForSweep(zone());
+
+ Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
+ EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM);
+
+ TypeZone& types = zone()->types;
+
+ // Destroy all type information attached to the script if desired. We can
+ // only do this if nothing has been compiled for the script, which will be
+ // the case unless the script has been compiled since we started sweeping.
+ if (types.sweepReleaseTypes &&
+ !hasBaselineScript() &&
+ !hasIonScript())
+ {
+ types_->destroy();
+ types_ = nullptr;
+
+ // Freeze constraints on stack type sets need to be regenerated the
+ // next time the script is analyzed.
+ hasFreezeConstraints_ = false;
+
+ return;
+ }
+
+ unsigned num = TypeScript::NumTypeSets(this);
+ StackTypeSet* typeArray = types_->typeArray();
+
+ // Remove constraints and references to dead objects from stack type sets.
+ for (unsigned i = 0; i < num; i++)
+ typeArray[i].sweep(zone(), *oom);
+
+ if (oom->hadOOM()) {
+ // It's possible we OOM'd while copying freeze constraints, so they
+ // need to be regenerated.
+ hasFreezeConstraints_ = false;
+ }
+
+ // Update the recompile indexes in any IonScripts still on the script.
+ if (hasIonScript())
+ ionScript()->recompileInfoRef().shouldSweep(types);
+}
+
+void
+TypeScript::destroy()
+{
+ js_free(this);
+}
+
+void
+Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ size_t* typePool,
+ size_t* baselineStubsOptimized,
+ size_t* uniqueIdMap,
+ size_t* shapeTables)
+{
+ *typePool += types.typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
+ if (jitZone()) {
+ *baselineStubsOptimized +=
+ jitZone()->optimizedStubSpace()->sizeOfExcludingThis(mallocSizeOf);
+ }
+ *uniqueIdMap += uniqueIds_.sizeOfExcludingThis(mallocSizeOf);
+ *shapeTables += baseShapes.sizeOfExcludingThis(mallocSizeOf)
+ + initialShapes.sizeOfExcludingThis(mallocSizeOf);
+}
+
+TypeZone::TypeZone(Zone* zone)
+ : zone_(zone),
+ typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+ generation(0),
+ compilerOutputs(nullptr),
+ sweepTypeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+ sweepCompilerOutputs(nullptr),
+ sweepReleaseTypes(false),
+ activeAnalysis(nullptr)
+{
+}
+
+TypeZone::~TypeZone()
+{
+ js_delete(compilerOutputs);
+ js_delete(sweepCompilerOutputs);
+}
+
+void
+TypeZone::beginSweep(FreeOp* fop, bool releaseTypes, AutoClearTypeInferenceStateOnOOM& oom)
+{
+ MOZ_ASSERT(zone()->isGCSweepingOrCompacting());
+ MOZ_ASSERT(!sweepCompilerOutputs);
+ MOZ_ASSERT(!sweepReleaseTypes);
+
+ sweepReleaseTypes = releaseTypes;
+
+ // Clear the analysis pool, but don't release its data yet. While sweeping
+ // types any live data will be allocated into the pool.
+ sweepTypeLifoAlloc.steal(&typeLifoAlloc);
+
+ // Sweep any invalid or dead compiler outputs, and keep track of the new
+ // index for remaining live outputs.
+ if (compilerOutputs) {
+ CompilerOutputVector* newCompilerOutputs = nullptr;
+ for (size_t i = 0; i < compilerOutputs->length(); i++) {
+ CompilerOutput& output = (*compilerOutputs)[i];
+ if (output.isValid()) {
+ JSScript* script = output.script();
+ if (IsAboutToBeFinalizedUnbarriered(&script)) {
+ if (script->hasIonScript())
+ script->ionScript()->recompileInfoRef() = RecompileInfo();
+ output.invalidate();
+ } else {
+ CompilerOutput newOutput(script);
+
+ if (!newCompilerOutputs)
+ newCompilerOutputs = js_new<CompilerOutputVector>();
+ if (newCompilerOutputs && newCompilerOutputs->append(newOutput)) {
+ output.setSweepIndex(newCompilerOutputs->length() - 1);
+ } else {
+ oom.setOOM();
+ script->ionScript()->recompileInfoRef() = RecompileInfo();
+ output.invalidate();
+ }
+ }
+ }
+ }
+ sweepCompilerOutputs = compilerOutputs;
+ compilerOutputs = newCompilerOutputs;
+ }
+
+ // All existing RecompileInfos are stale and will be updated to the new
+ // compiler outputs list later during the sweep. Don't worry about overflow
+ // here, since stale indexes will persist only until the sweep finishes.
+ generation++;
+}
+
+void
+TypeZone::endSweep(JSRuntime* rt)
+{
+ js_delete(sweepCompilerOutputs);
+ sweepCompilerOutputs = nullptr;
+
+ sweepReleaseTypes = false;
+
+ rt->gc.freeAllLifoBlocksAfterSweeping(&sweepTypeLifoAlloc);
+}
+
+void
+TypeZone::clearAllNewScriptsOnOOM()
+{
+ for (auto iter = zone()->cellIter<ObjectGroup>(); !iter.done(); iter.next()) {
+ ObjectGroup* group = iter;
+ if (!IsAboutToBeFinalizedUnbarriered(&group))
+ group->maybeClearNewScriptOnOOM();
+ }
+}
+
+AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM()
+{
+ if (oom) {
+ JSRuntime* rt = zone->runtimeFromMainThread();
+ js::CancelOffThreadIonCompile(rt);
+ zone->setPreservingCode(false);
+ zone->discardJitCode(rt->defaultFreeOp(), /* discardBaselineCode = */ false);
+ zone->types.clearAllNewScriptsOnOOM();
+ }
+}
+
+#ifdef DEBUG
+void
+TypeScript::printTypes(JSContext* cx, HandleScript script) const
+{
+ MOZ_ASSERT(script->types() == this);
+
+ if (!script->hasBaselineScript())
+ return;
+
+ AutoEnterAnalysis enter(nullptr, script->zone());
+
+ if (script->functionNonDelazifying())
+ fprintf(stderr, "Function");
+ else if (script->isForEval())
+ fprintf(stderr, "Eval");
+ else
+ fprintf(stderr, "Main");
+ fprintf(stderr, " %#" PRIxPTR " %s:%" PRIuSIZE " ",
+ uintptr_t(script.get()), script->filename(), script->lineno());
+
+ if (script->functionNonDelazifying()) {
+ if (JSAtom* name = script->functionNonDelazifying()->name())
+ name->dumpCharsNoNewline();
+ }
+
+ fprintf(stderr, "\n this:");
+ TypeScript::ThisTypes(script)->print();
+
+ for (unsigned i = 0;
+ script->functionNonDelazifying() && i < script->functionNonDelazifying()->nargs();
+ i++)
+ {
+ fprintf(stderr, "\n arg%u:", i);
+ TypeScript::ArgTypes(script, i)->print();
+ }
+ fprintf(stderr, "\n");
+
+ for (jsbytecode* pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
+ {
+ fprintf(stderr, "%p:", script.get());
+ Sprinter sprinter(cx);
+ if (!sprinter.init())
+ return;
+ Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter);
+ fprintf(stderr, "%s", sprinter.string());
+ }
+
+ if (CodeSpec[*pc].format & JOF_TYPESET) {
+ StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
+ fprintf(stderr, " typeset %u:", unsigned(types - typeArray()));
+ types->print();
+ fprintf(stderr, "\n");
+ }
+ }
+
+ fprintf(stderr, "\n");
+}
+#endif /* DEBUG */
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<js::ObjectGroup>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+ size += get().sizeOfExcludingThis(mallocSizeOf);
+ return size;
+}
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
new file mode 100644
index 000000000..45b2711e2
--- /dev/null
+++ b/js/src/vm/TypeInference.h
@@ -0,0 +1,1345 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Definitions related to javascript type inference. */
+
+#ifndef vm_TypeInference_h
+#define vm_TypeInference_h
+
+#include "mozilla/MemoryReporting.h"
+
+#include "jsalloc.h"
+#include "jsfriendapi.h"
+#include "jstypes.h"
+
+#include "ds/IdValuePair.h"
+#include "ds/LifoAlloc.h"
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "jit/IonTypes.h"
+#include "js/UbiNode.h"
+#include "js/Utility.h"
+#include "js/Vector.h"
+#include "vm/TaggedProto.h"
+
+namespace js {
+
+namespace jit {
+ struct IonScript;
+ class JitAllocPolicy;
+ class TempAllocator;
+} // namespace jit
+
+struct TypeZone;
+class TypeConstraint;
+class TypeNewScript;
+class CompilerConstraintList;
+class HeapTypeSetKey;
+
+/*
+ * Type inference memory management overview.
+ *
+ * Type information about the values observed within scripts and about the
+ * contents of the heap is accumulated as the program executes. Compilation
+ * accumulates constraints relating type information on the heap with the
+ * compilations that should be invalidated when those types change. Type
+ * information and constraints are allocated in the zone's typeLifoAlloc,
+ * and on GC all data referring to live things is copied into a new allocator.
+ * Thus, type set and constraints only hold weak references.
+ */
+
+/* Flags and other state stored in TypeSet::flags */
+enum : uint32_t {
+ TYPE_FLAG_UNDEFINED = 0x1,
+ TYPE_FLAG_NULL = 0x2,
+ TYPE_FLAG_BOOLEAN = 0x4,
+ TYPE_FLAG_INT32 = 0x8,
+ TYPE_FLAG_DOUBLE = 0x10,
+ TYPE_FLAG_STRING = 0x20,
+ TYPE_FLAG_SYMBOL = 0x40,
+ TYPE_FLAG_LAZYARGS = 0x80,
+ TYPE_FLAG_ANYOBJECT = 0x100,
+
+ /* Mask containing all primitives */
+ TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
+ TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
+ TYPE_FLAG_SYMBOL,
+
+ /* Mask/shift for the number of objects in objectSet */
+ TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
+ TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
+ TYPE_FLAG_OBJECT_COUNT_LIMIT = 7,
+ TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
+ TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
+
+ /* Whether the contents of this type set are totally unknown. */
+ TYPE_FLAG_UNKNOWN = 0x00004000,
+
+ /* Mask of normal type flags on a type set. */
+ TYPE_FLAG_BASE_MASK = 0x000041ff,
+
+ /* Additional flags for HeapTypeSet sets. */
+
+ /*
+ * Whether the property has ever been deleted or reconfigured to behave
+ * differently from a plain data property, other than making the property
+ * non-writable.
+ */
+ TYPE_FLAG_NON_DATA_PROPERTY = 0x00008000,
+
+ /* Whether the property has ever been made non-writable. */
+ TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
+
+ /* Whether the property might not be constant. */
+ TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
+
+ /*
+ * Whether the property is definitely in a particular slot on all objects
+ * from which it has not been deleted or reconfigured. For singletons
+ * this may be a fixed or dynamic slot, and for other objects this will be
+ * a fixed slot.
+ *
+ * If the property is definite, mask and shift storing the slot + 1.
+ * Otherwise these bits are clear.
+ */
+ TYPE_FLAG_DEFINITE_MASK = 0xfffc0000,
+ TYPE_FLAG_DEFINITE_SHIFT = 18
+};
+typedef uint32_t TypeFlags;
+
+/* Flags and other state stored in ObjectGroup::Flags */
+enum : uint32_t {
+ /* Whether this group is associated with some allocation site. */
+ OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1,
+
+ /* Whether this group is associated with a single object. */
+ OBJECT_FLAG_SINGLETON = 0x2,
+
+ /*
+ * Whether this group is used by objects whose singleton groups have not
+ * been created yet.
+ */
+ OBJECT_FLAG_LAZY_SINGLETON = 0x4,
+
+ /* Mask/shift for the number of properties in propertySet */
+ OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8,
+ OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3,
+ OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
+ OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
+
+ /* Whether any objects this represents may have sparse indexes. */
+ OBJECT_FLAG_SPARSE_INDEXES = 0x00010000,
+
+ /* Whether any objects this represents may not have packed dense elements. */
+ OBJECT_FLAG_NON_PACKED = 0x00020000,
+
+ /*
+ * Whether any objects this represents may be arrays whose length does not
+ * fit in an int32.
+ */
+ OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000,
+
+ /* Whether any objects have been iterated over. */
+ OBJECT_FLAG_ITERATED = 0x00080000,
+
+ /* Whether any object this represents may be frozen. */
+ OBJECT_FLAG_FROZEN = 0x00100000,
+
+ /*
+ * For the function on a run-once script, whether the function has actually
+ * run multiple times.
+ */
+ OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000,
+
+ /*
+ * For a global object, whether any array buffers in this compartment with
+ * typed object views have ever been detached.
+ */
+ OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER = 0x00400000,
+
+ /*
+ * Whether objects with this type should be allocated directly in the
+ * tenured heap.
+ */
+ OBJECT_FLAG_PRE_TENURE = 0x00800000,
+
+ /* Whether objects with this type might have copy on write elements. */
+ OBJECT_FLAG_COPY_ON_WRITE = 0x01000000,
+
+ /* Whether this type has had its 'new' script cleared in the past. */
+ OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x02000000,
+
+ /*
+ * Whether all properties of this object are considered unknown.
+ * If set, all other flags in DYNAMIC_MASK will also be set.
+ */
+ OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x04000000,
+
+ /* Flags which indicate dynamic properties of represented objects. */
+ OBJECT_FLAG_DYNAMIC_MASK = 0x07ff0000,
+
+ // Mask/shift for the kind of addendum attached to this group.
+ OBJECT_FLAG_ADDENDUM_MASK = 0x38000000,
+ OBJECT_FLAG_ADDENDUM_SHIFT = 27,
+
+ // Mask/shift for this group's generation. If out of sync with the
+ // TypeZone's generation, this group hasn't been swept yet.
+ OBJECT_FLAG_GENERATION_MASK = 0x40000000,
+ OBJECT_FLAG_GENERATION_SHIFT = 30,
+};
+typedef uint32_t ObjectGroupFlags;
+
+class StackTypeSet;
+class HeapTypeSet;
+class TemporaryTypeSet;
+
+/*
+ * Information about the set of types associated with an lvalue. There are
+ * three kinds of type sets:
+ *
+ * - StackTypeSet are associated with TypeScripts, for arguments and values
+ * observed at property reads. These are implicitly frozen on compilation
+ * and only have constraints added to them which can trigger invalidation of
+ * TypeNewScript information.
+ *
+ * - HeapTypeSet are associated with the properties of ObjectGroups. These
+ * may have constraints added to them to trigger invalidation of either
+ * compiled code or TypeNewScript information.
+ *
+ * - TemporaryTypeSet are created during compilation and do not outlive
+ * that compilation.
+ *
+ * The contents of a type set completely describe the values that a particular
+ * lvalue might have, except for the following cases:
+ *
+ * - If an object's prototype or class is dynamically mutated, its group will
+ * change. Type sets containing the old group will not necessarily contain
+ * the new group. When this occurs, the properties of the old and new group
+ * will both be marked as unknown, which will prevent Ion from optimizing
+ * based on the object's type information.
+ *
+ * - If an unboxed object is converted to a native object, its group will also
+ * change and type sets containing the old group will not necessarily contain
+ * the new group. Unlike the above case, this will not degrade property type
+ * information, but Ion will no longer optimize unboxed objects with the old
+ * group.
+ */
+class TypeSet
+{
+ public:
+ // Type set entry for either a JSObject with singleton type or a
+ // non-singleton ObjectGroup.
+ class ObjectKey {
+ public:
+ static intptr_t keyBits(ObjectKey* obj) { return (intptr_t) obj; }
+ static ObjectKey* getKey(ObjectKey* obj) { return obj; }
+
+ static inline ObjectKey* get(JSObject* obj);
+ static inline ObjectKey* get(ObjectGroup* group);
+
+ bool isGroup() {
+ return (uintptr_t(this) & 1) == 0;
+ }
+ bool isSingleton() {
+ return (uintptr_t(this) & 1) != 0;
+ }
+
+ inline ObjectGroup* group();
+ inline JSObject* singleton();
+
+ inline ObjectGroup* groupNoBarrier();
+ inline JSObject* singletonNoBarrier();
+
+ const Class* clasp();
+ TaggedProto proto();
+ TypeNewScript* newScript();
+
+ bool unknownProperties();
+ bool hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
+ bool hasStableClassAndProto(CompilerConstraintList* constraints);
+ void watchStateChangeForInlinedCall(CompilerConstraintList* constraints);
+ void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
+ void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
+ HeapTypeSetKey property(jsid id);
+ void ensureTrackedProperty(JSContext* cx, jsid id);
+
+ ObjectGroup* maybeGroup();
+
+ JSCompartment* maybeCompartment();
+ } JS_HAZ_GC_POINTER;
+
+ // Information about a single concrete type. We pack this into one word,
+ // where small values are particular primitive or other singleton types and
+ // larger values are either specific JS objects or object groups.
+ class Type
+ {
+ friend class TypeSet;
+
+ uintptr_t data;
+ explicit Type(uintptr_t data) : data(data) {}
+
+ public:
+
+ uintptr_t raw() const { return data; }
+
+ bool isPrimitive() const {
+ return data < JSVAL_TYPE_OBJECT;
+ }
+
+ bool isPrimitive(JSValueType type) const {
+ MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
+ return (uintptr_t) type == data;
+ }
+
+ JSValueType primitive() const {
+ MOZ_ASSERT(isPrimitive());
+ return (JSValueType) data;
+ }
+
+ bool isMagicArguments() const {
+ return primitive() == JSVAL_TYPE_MAGIC;
+ }
+
+ bool isSomeObject() const {
+ return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
+ }
+
+ bool isAnyObject() const {
+ return data == JSVAL_TYPE_OBJECT;
+ }
+
+ bool isUnknown() const {
+ return data == JSVAL_TYPE_UNKNOWN;
+ }
+
+ /* Accessors for types that are either JSObject or ObjectGroup. */
+
+ bool isObject() const {
+ MOZ_ASSERT(!isAnyObject() && !isUnknown());
+ return data > JSVAL_TYPE_UNKNOWN;
+ }
+
+ bool isObjectUnchecked() const {
+ return data > JSVAL_TYPE_UNKNOWN;
+ }
+
+ inline ObjectKey* objectKey() const;
+
+ /* Accessors for JSObject types */
+
+ bool isSingleton() const {
+ return isObject() && !!(data & 1);
+ }
+ bool isSingletonUnchecked() const {
+ return isObjectUnchecked() && !!(data & 1);
+ }
+
+ inline JSObject* singleton() const;
+ inline JSObject* singletonNoBarrier() const;
+
+ /* Accessors for ObjectGroup types */
+
+ bool isGroup() const {
+ return isObject() && !(data & 1);
+ }
+ bool isGroupUnchecked() const {
+ return isObjectUnchecked() && !(data & 1);
+ }
+
+ inline ObjectGroup* group() const;
+ inline ObjectGroup* groupNoBarrier() const;
+
+ inline void trace(JSTracer* trc);
+
+ JSCompartment* maybeCompartment();
+
+ bool operator == (Type o) const { return data == o.data; }
+ bool operator != (Type o) const { return data != o.data; }
+ } JS_HAZ_GC_POINTER;
+
+ static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
+ static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
+ static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
+ static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
+ static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
+ static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
+ static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
+ static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
+ static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
+ static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
+
+ static inline Type PrimitiveType(JSValueType type) {
+ MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
+ return Type(type);
+ }
+
+ static inline Type ObjectType(JSObject* obj);
+ static inline Type ObjectType(ObjectGroup* group);
+ static inline Type ObjectType(ObjectKey* key);
+
+ static const char* NonObjectTypeString(Type type);
+
+ static const char* TypeString(Type type);
+ static const char* ObjectGroupString(ObjectGroup* group);
+
+ protected:
+ /* Flags for this type set. */
+ TypeFlags flags;
+
+ /* Possible objects this type set can represent. */
+ ObjectKey** objectSet;
+
+ public:
+
+ TypeSet()
+ : flags(0), objectSet(nullptr)
+ {}
+
+ void print(FILE* fp = stderr);
+
+ /* Whether this set contains a specific type. */
+ inline bool hasType(Type type) const;
+
+ TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
+ bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
+ bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
+ bool empty() const { return !baseFlags() && !baseObjectCount(); }
+
+ bool hasAnyFlag(TypeFlags flags) const {
+ MOZ_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
+ return !!(baseFlags() & flags);
+ }
+
+ bool nonDataProperty() const {
+ return flags & TYPE_FLAG_NON_DATA_PROPERTY;
+ }
+ bool nonWritableProperty() const {
+ return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
+ }
+ bool nonConstantProperty() const {
+ return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
+ }
+ bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
+ unsigned definiteSlot() const {
+ MOZ_ASSERT(definiteProperty());
+ return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
+ }
+
+ /* Join two type sets into a new set. The result should not be modified further. */
+ static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
+ /* Return the intersection of the 2 TypeSets. The result should not be modified further */
+ static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
+ /*
+ * Returns a copy of TypeSet a excluding/removing the types in TypeSet b.
+ * TypeSet b can only contain primitives or be any object. No support for
+ * specific objects. The result should not be modified further.
+ */
+ static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
+
+ /* Add a type to this set using the specified allocator. */
+ void addType(Type type, LifoAlloc* alloc);
+
+ /* Get a list of all types in this set. */
+ typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
+ template <class TypeListT> bool enumerateTypes(TypeListT* list) const;
+
+ /*
+ * Iterate through the objects in this set. getObjectCount overapproximates
+ * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
+ * getObject may return nullptr.
+ */
+ inline unsigned getObjectCount() const;
+ inline ObjectKey* getObject(unsigned i) const;
+ inline JSObject* getSingleton(unsigned i) const;
+ inline ObjectGroup* getGroup(unsigned i) const;
+ inline JSObject* getSingletonNoBarrier(unsigned i) const;
+ inline ObjectGroup* getGroupNoBarrier(unsigned i) const;
+
+ /* The Class of an object in this set. */
+ inline const Class* getObjectClass(unsigned i) const;
+
+ bool canSetDefinite(unsigned slot) {
+ // Note: the cast is required to work around an MSVC issue.
+ return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
+ }
+ void setDefinite(unsigned slot) {
+ MOZ_ASSERT(canSetDefinite(slot));
+ flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
+ MOZ_ASSERT(definiteSlot() == slot);
+ }
+
+ /* Whether any values in this set might have the specified type. */
+ bool mightBeMIRType(jit::MIRType type) const;
+
+ /*
+ * Get whether this type set is known to be a subset of other.
+ * This variant doesn't freeze constraints. That variant is called knownSubset
+ */
+ bool isSubset(const TypeSet* other) const;
+
+ /*
+ * Get whether the objects in this TypeSet are a subset of the objects
+ * in other.
+ */
+ bool objectsAreSubset(TypeSet* other);
+
+ /* Whether this TypeSet contains exactly the same types as other. */
+ bool equals(const TypeSet* other) const {
+ return this->isSubset(other) && other->isSubset(this);
+ }
+
+ bool objectsIntersect(const TypeSet* other) const;
+
+ /* Forward all types in this set to the specified constraint. */
+ bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
+
+ // Clone a type set into an arbitrary allocator.
+ TemporaryTypeSet* clone(LifoAlloc* alloc) const;
+ bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
+
+ // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
+ TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
+ // Create a new TemporaryTypeSet where the type has been set to object.
+ TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
+ TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
+
+ JSCompartment* maybeCompartment();
+
+ // Trigger a read barrier on all the contents of a type set.
+ static void readBarrier(const TypeSet* types);
+
+ protected:
+ uint32_t baseObjectCount() const {
+ return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
+ }
+ inline void setBaseObjectCount(uint32_t count);
+
+ void clearObjects();
+
+ public:
+ static inline Type GetValueType(const Value& val);
+
+ static inline bool IsUntrackedValue(const Value& val);
+
+ // Get the type of a possibly optimized out or uninitialized let value.
+ // This generally only happens on unconditional type monitors on bailing
+ // out of Ion, such as for argument and local types.
+ static inline Type GetMaybeUntrackedValueType(const Value& val);
+
+ static bool IsTypeMarked(JSRuntime* rt, Type* v);
+ static bool IsTypeAllocatedDuringIncremental(Type v);
+ static bool IsTypeAboutToBeFinalized(Type* v);
+} JS_HAZ_GC_POINTER;
+
+/*
+ * A constraint which listens to additions to a type set and propagates those
+ * changes to other type sets.
+ */
+class TypeConstraint
+{
+public:
+ /* Next constraint listening to the same type set. */
+ TypeConstraint* next;
+
+ TypeConstraint()
+ : next(nullptr)
+ {}
+
+ /* Debugging name for this kind of constraint. */
+ virtual const char* kind() = 0;
+
+ /* Register a new type for the set this constraint is listening to. */
+ virtual void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) = 0;
+
+ /*
+ * For constraints attached to an object property's type set, mark the
+ * property as having changed somehow.
+ */
+ virtual void newPropertyState(JSContext* cx, TypeSet* source) {}
+
+ /*
+ * For constraints attached to the JSID_EMPTY type set on an object,
+ * indicate a change in one of the object's dynamic property flags or other
+ * state.
+ */
+ virtual void newObjectState(JSContext* cx, ObjectGroup* group) {}
+
+ /*
+ * If the data this constraint refers to is still live, copy it into the
+ * zone's new allocator. Type constraints only hold weak references.
+ */
+ virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
+
+ /* The associated compartment, if any. */
+ virtual JSCompartment* maybeCompartment() = 0;
+};
+
+// If there is an OOM while sweeping types, the type information is deoptimized
+// so that it stays correct (i.e. overapproximates the possible types in the
+// zone), but constraints might not have been triggered on the deoptimization
+// or even copied over completely. In this case, destroy all JIT code and new
+// script information in the zone, the only things whose correctness depends on
+// the type constraints.
+class AutoClearTypeInferenceStateOnOOM
+{
+ Zone* zone;
+ bool oom;
+
+ public:
+ explicit AutoClearTypeInferenceStateOnOOM(Zone* zone)
+ : zone(zone), oom(false)
+ {}
+
+ ~AutoClearTypeInferenceStateOnOOM();
+
+ void setOOM() {
+ oom = true;
+ }
+ bool hadOOM() const {
+ return oom;
+ }
+};
+
+/* Superclass common to stack and heap type sets. */
+class ConstraintTypeSet : public TypeSet
+{
+ public:
+ /* Chain of constraints which propagate changes out from this type set. */
+ TypeConstraint* constraintList;
+
+ ConstraintTypeSet() : constraintList(nullptr) {}
+
+ /*
+ * Add a type to this set, calling any constraint handlers if this is a new
+ * possible type.
+ */
+ void addType(ExclusiveContext* cx, Type type);
+
+ // Trigger a post barrier when writing to this set, if necessary.
+ // addType(cx, type) takes care of this automatically.
+ void postWriteBarrier(ExclusiveContext* cx, Type type);
+
+ /* Add a new constraint to this set. */
+ bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
+
+ inline void sweep(JS::Zone* zone, AutoClearTypeInferenceStateOnOOM& oom);
+ inline void trace(JS::Zone* zone, JSTracer* trc);
+};
+
+class StackTypeSet : public ConstraintTypeSet
+{
+ public:
+};
+
+class HeapTypeSet : public ConstraintTypeSet
+{
+ inline void newPropertyState(ExclusiveContext* cx);
+
+ public:
+ /* Mark this type set as representing a non-data property. */
+ inline void setNonDataProperty(ExclusiveContext* cx);
+
+ /* Mark this type set as representing a non-writable property. */
+ inline void setNonWritableProperty(ExclusiveContext* cx);
+
+ // Mark this type set as being non-constant.
+ inline void setNonConstantProperty(ExclusiveContext* cx);
+};
+
+CompilerConstraintList*
+NewCompilerConstraintList(jit::TempAllocator& alloc);
+
+class TemporaryTypeSet : public TypeSet
+{
+ public:
+ TemporaryTypeSet() {}
+ TemporaryTypeSet(LifoAlloc* alloc, Type type);
+
+ TemporaryTypeSet(uint32_t flags, ObjectKey** objectSet) {
+ this->flags = flags;
+ this->objectSet = objectSet;
+ }
+
+ TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type)
+ : TemporaryTypeSet(alloc, PrimitiveType(ValueTypeFromMIRType(type)))
+ {
+ MOZ_ASSERT(type != jit::MIRType::Value);
+ }
+
+ /*
+ * Constraints for JIT compilation.
+ *
+ * Methods for JIT compilation. These must be used when a script is
+ * currently being compiled (see AutoEnterCompilation) and will add
+ * constraints ensuring that if the return value change in the future due
+ * to new type information, the script's jitcode will be discarded.
+ */
+
+ /* Get any type tag which all values in this set must have. */
+ jit::MIRType getKnownMIRType();
+
+ bool isMagicArguments() { return getKnownMIRType() == jit::MIRType::MagicOptimizedArguments; }
+
+ /* Whether this value may be an object. */
+ bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
+
+ /*
+ * Whether this typeset represents a potentially sentineled object value:
+ * the value may be an object or null or undefined.
+ * Returns false if the value cannot ever be an object.
+ */
+ bool objectOrSentinel() {
+ TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
+ if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
+ return false;
+
+ return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
+ }
+
+ /* Whether the type set contains objects with any of a set of flags. */
+ bool hasObjectFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
+
+ /* Get the class shared by all objects in this set, or nullptr. */
+ const Class* getKnownClass(CompilerConstraintList* constraints);
+
+ /* Result returned from forAllClasses */
+ enum ForAllResult {
+ EMPTY=1, // Set empty
+ ALL_TRUE, // Set not empty and predicate returned true for all classes
+ ALL_FALSE, // Set not empty and predicate returned false for all classes
+ MIXED, // Set not empty and predicate returned false for some classes
+ // and true for others, or set contains an unknown or non-object
+ // type
+ };
+
+ /* Apply func to the members of the set and return an appropriate result.
+ * The iteration may end early if the result becomes known early.
+ */
+ ForAllResult forAllClasses(CompilerConstraintList* constraints,
+ bool (*func)(const Class* clasp));
+
+ /*
+ * Returns true if all objects in this set have the same prototype, and
+ * assigns this object to *proto. The proto can be nullptr.
+ */
+ bool getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto);
+
+ /* Whether the buffer mapped by a TypedArray is shared memory or not */
+ enum TypedArraySharedness {
+ UnknownSharedness=1, // We can't determine sharedness
+ KnownShared, // We know for sure the buffer is shared
+ KnownUnshared // We know for sure the buffer is unshared
+ };
+
+ /* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
+ * If there is such a common type and sharedness is not nullptr then
+ * *sharedness is set to what we know about the sharedness of the memory.
+ */
+ Scalar::Type getTypedArrayType(CompilerConstraintList* constraints,
+ TypedArraySharedness* sharedness = nullptr);
+
+ /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
+ bool isDOMClass(CompilerConstraintList* constraints);
+
+ /* Whether clasp->isCallable() is true for one or more objects in this set. */
+ bool maybeCallable(CompilerConstraintList* constraints);
+
+ /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
+ bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
+
+ /* Get the single value which can appear in this type set, otherwise nullptr. */
+ JSObject* maybeSingleton();
+
+ /* Whether any objects in the type set needs a barrier on id. */
+ bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
+
+ /*
+ * Whether this set contains all types in other, except (possibly) the
+ * specified type.
+ */
+ bool filtersType(const TemporaryTypeSet* other, Type type) const;
+
+ enum DoubleConversion {
+ /* All types in the set should use eager double conversion. */
+ AlwaysConvertToDoubles,
+
+ /* Some types in the set should use eager double conversion. */
+ MaybeConvertToDoubles,
+
+ /* No types should use eager double conversion. */
+ DontConvertToDoubles,
+
+ /* Some types should use eager double conversion, others cannot. */
+ AmbiguousDoubleConversion
+ };
+
+ /*
+ * Whether known double optimizations are possible for element accesses on
+ * objects in this type set.
+ */
+ DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
+
+ private:
+ void getTypedArraySharedness(CompilerConstraintList* constraints,
+ TypedArraySharedness* sharedness);
+};
+
+bool
+AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
+
+bool
+AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
+ JSScript* script, JSScript* calleeScript);
+
+// For groups where only a small number of objects have been allocated, this
+// structure keeps track of all objects in the group. Once COUNT objects have
+// been allocated, this structure is cleared and the objects are analyzed, to
+// perform the new script properties analyses or determine if an unboxed
+// representation can be used.
+class PreliminaryObjectArray
+{
+ public:
+ static const uint32_t COUNT = 20;
+
+ private:
+ // All objects with the type which have been allocated. The pointers in
+ // this array are weak.
+ JSObject* objects[COUNT];
+
+ public:
+ PreliminaryObjectArray() {
+ mozilla::PodZero(this);
+ }
+
+ void registerNewObject(JSObject* res);
+ void unregisterObject(JSObject* obj);
+
+ JSObject* get(size_t i) const {
+ MOZ_ASSERT(i < COUNT);
+ return objects[i];
+ }
+
+ bool full() const;
+ bool empty() const;
+ void sweep();
+};
+
+class PreliminaryObjectArrayWithTemplate : public PreliminaryObjectArray
+{
+ HeapPtr<Shape*> shape_;
+
+ public:
+ explicit PreliminaryObjectArrayWithTemplate(Shape* shape)
+ : shape_(shape)
+ {}
+
+ void clear() {
+ shape_.init(nullptr);
+ }
+
+ Shape* shape() {
+ return shape_;
+ }
+
+ void maybeAnalyze(ExclusiveContext* cx, ObjectGroup* group, bool force = false);
+
+ void trace(JSTracer* trc);
+
+ static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects);
+};
+
+// New script properties analyses overview.
+//
+// When constructing objects using 'new' on a script, we attempt to determine
+// the properties which that object will eventually have. This is done via two
+// analyses. One of these, the definite properties analysis, is static, and the
+// other, the acquired properties analysis, is dynamic. As objects are
+// constructed using 'new' on some script to create objects of group G, our
+// analysis strategy is as follows:
+//
+// - When the first objects are created, no analysis is immediately performed.
+// Instead, all objects of group G are accumulated in an array.
+//
+// - After a certain number of such objects have been created, the definite
+// properties analysis is performed. This analyzes the body of the
+// constructor script and any other functions it calls to look for properties
+// which will definitely be added by the constructor in a particular order,
+// creating an object with shape S.
+//
+// - The properties in S are compared with the greatest common prefix P of the
+// shapes of the objects that have been created. If P has more properties
+// than S, the acquired properties analysis is performed.
+//
+// - The acquired properties analysis marks all properties in P as definite
+// in G, and creates a new group IG for objects which are partially
+// initialized. Objects of group IG are initially created with shape S, and if
+// they are later given shape P, their group can be changed to G.
+//
+// For objects which are rarely created, the definite properties analysis can
+// be triggered after only one or a few objects have been allocated, when code
+// being Ion compiled might access them. In this case type information in the
+// constructor might not be good enough for the definite properties analysis to
+// compute useful information, but the acquired properties analysis will still
+// be able to identify definite properties in this case.
+//
+// This layered approach is designed to maximize performance on easily
+// analyzable code, while still allowing us to determine definite properties
+// robustly when code consistently adds the same properties to objects, but in
+// complex ways which can't be understood statically.
+class TypeNewScript
+{
+ public:
+ struct Initializer {
+ enum Kind {
+ SETPROP,
+ SETPROP_FRAME,
+ DONE
+ } kind;
+ uint32_t offset;
+ Initializer(Kind kind, uint32_t offset)
+ : kind(kind), offset(offset)
+ {}
+ };
+
+ private:
+ // Scripted function which this information was computed for.
+ HeapPtr<JSFunction*> function_;
+
+ // Any preliminary objects with the type. The analyses are not performed
+ // until this array is cleared.
+ PreliminaryObjectArray* preliminaryObjects;
+
+ // After the new script properties analyses have been performed, a template
+ // object to use for newly constructed objects. The shape of this object
+ // reflects all definite properties the object will have, and the
+ // allocation kind to use. This is null if the new objects have an unboxed
+ // layout, in which case the UnboxedLayout provides the initial structure
+ // of the object.
+ HeapPtr<PlainObject*> templateObject_;
+
+ // Order in which definite properties become initialized. We need this in
+ // case the definite properties are invalidated (such as by adding a setter
+ // to an object on the prototype chain) while an object is in the middle of
+ // being initialized, so we can walk the stack and fixup any objects which
+ // look for in-progress objects which were prematurely set with an incorrect
+ // shape. Property assignments in inner frames are preceded by a series of
+ // SETPROP_FRAME entries specifying the stack down to the frame containing
+ // the write.
+ Initializer* initializerList;
+
+ // If there are additional properties found by the acquired properties
+ // analysis which were not found by the definite properties analysis, this
+ // shape contains all such additional properties (plus the definite
+ // properties). When an object of this group acquires this shape, it is
+ // fully initialized and its group can be changed to initializedGroup.
+ HeapPtr<Shape*> initializedShape_;
+
+ // Group with definite properties set for all properties found by
+ // both the definite and acquired properties analyses.
+ HeapPtr<ObjectGroup*> initializedGroup_;
+
+ public:
+ TypeNewScript() { mozilla::PodZero(this); }
+ ~TypeNewScript() {
+ js_delete(preliminaryObjects);
+ js_free(initializerList);
+ }
+
+ void clear() {
+ function_.init(nullptr);
+ templateObject_.init(nullptr);
+ initializedShape_.init(nullptr);
+ initializedGroup_.init(nullptr);
+ }
+
+ static void writeBarrierPre(TypeNewScript* newScript);
+
+ bool analyzed() const {
+ return preliminaryObjects == nullptr;
+ }
+
+ PlainObject* templateObject() const {
+ return templateObject_;
+ }
+
+ Shape* initializedShape() const {
+ return initializedShape_;
+ }
+
+ ObjectGroup* initializedGroup() const {
+ return initializedGroup_;
+ }
+
+ JSFunction* function() const {
+ return function_;
+ }
+
+ void trace(JSTracer* trc);
+ void sweep();
+
+ void registerNewObject(PlainObject* res);
+ bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
+
+ bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
+
+ static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
+ static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
+ PlainObject* templateObject);
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+};
+
+/* Is this a reasonable PC to be doing inlining on? */
+inline bool isInlinableCall(jsbytecode* pc);
+
+bool
+ClassCanHaveExtraProperties(const Class* clasp);
+
+/* Persistent type information for a script, retained across GCs. */
+class TypeScript
+{
+ friend class ::JSScript;
+
+ // Variable-size array
+ StackTypeSet typeArray_[1];
+
+ public:
+ /* Array of type sets for variables and JOF_TYPESET ops. */
+ StackTypeSet* typeArray() const {
+ // Ensure typeArray_ is the last data member of TypeScript.
+ JS_STATIC_ASSERT(sizeof(TypeScript) ==
+ sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
+ return const_cast<StackTypeSet*>(typeArray_);
+ }
+
+ static inline size_t SizeIncludingTypeArray(size_t arraySize) {
+ // Ensure typeArray_ is the last data member of TypeScript.
+ JS_STATIC_ASSERT(sizeof(TypeScript) ==
+ sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
+ return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
+ }
+
+ static inline unsigned NumTypeSets(JSScript* script);
+
+ static inline StackTypeSet* ThisTypes(JSScript* script);
+ static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i);
+
+ /* Get the type set for values observed at an opcode. */
+ static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc);
+
+ template <typename TYPESET>
+ static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
+ uint32_t* hint, TYPESET* typeArray);
+
+ /*
+ * Monitor a bytecode pushing any value. This must be called for any opcode
+ * which is JOF_TYPESET, and where either the script has not been analyzed
+ * by type inference or where the pc has type barriers. For simplicity, we
+ * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
+ * and only look at barriers when generating JIT code for the script.
+ */
+ static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
+ const js::Value& val);
+ static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
+ TypeSet::Type type);
+ static inline void Monitor(JSContext* cx, const js::Value& rval);
+
+ /* Monitor an assignment at a SETELEM on a non-integer identifier. */
+ static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
+
+ /* Add a type for a variable in a script. */
+ static inline void SetThis(JSContext* cx, JSScript* script, TypeSet::Type type);
+ static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
+ static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
+ TypeSet::Type type);
+ static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
+ const js::Value& value);
+
+ /*
+ * Freeze all the stack type sets in a script, for a compilation. Returns
+ * copies of the type sets which will be checked against the actual ones
+ * under FinishCompilation, to detect any type changes.
+ */
+ static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
+ TemporaryTypeSet** pThisTypes,
+ TemporaryTypeSet** pArgTypes,
+ TemporaryTypeSet** pBytecodeTypes);
+
+ static void Purge(JSContext* cx, HandleScript script);
+
+ void destroy();
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(this);
+ }
+
+#ifdef DEBUG
+ void printTypes(JSContext* cx, HandleScript script) const;
+#endif
+};
+
+void
+FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
+
+class RecompileInfo;
+
+// Allocate a CompilerOutput for a finished compilation and generate the type
+// constraints for the compilation. Sets |isValidOut| based on whether the type
+// constraints still hold.
+bool
+FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
+ RecompileInfo* precompileInfo, bool* isValidOut);
+
+// Reset any CompilerOutput present for a script.
+void
+InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
+
+// Update the actual types in any scripts queried by constraints with any
+// speculative types added during the definite properties analysis.
+void
+FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
+
+// Representation of a heap type property which may or may not be instantiated.
+// Heap properties for singleton types are instantiated lazily as they are used
+// by the compiler, but this is only done on the main thread. If we are
+// compiling off thread and use a property which has not yet been instantiated,
+// it will be treated as empty and non-configured and will be instantiated when
+// rejoining to the main thread. If it is in fact not empty, the compilation
+// will fail; to avoid this, we try to instantiate singleton property types
+// during generation of baseline caches.
+class HeapTypeSetKey
+{
+ friend class TypeSet::ObjectKey;
+
+ // Object and property being accessed.
+ TypeSet::ObjectKey* object_;
+ jsid id_;
+
+ // If instantiated, the underlying heap type set.
+ HeapTypeSet* maybeTypes_;
+
+ public:
+ HeapTypeSetKey()
+ : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
+ {}
+
+ TypeSet::ObjectKey* object() const { return object_; }
+ jsid id() const { return id_; }
+ HeapTypeSet* maybeTypes() const { return maybeTypes_; }
+
+ bool instantiate(JSContext* cx);
+
+ void freeze(CompilerConstraintList* constraints);
+ jit::MIRType knownMIRType(CompilerConstraintList* constraints);
+ bool nonData(CompilerConstraintList* constraints);
+ bool nonWritable(CompilerConstraintList* constraints);
+ bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
+ bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
+ JSObject* singleton(CompilerConstraintList* constraints);
+ bool needsBarrier(CompilerConstraintList* constraints);
+ bool constant(CompilerConstraintList* constraints, Value* valOut);
+ bool couldBeConstant(CompilerConstraintList* constraints);
+};
+
+/*
+ * Information about the result of the compilation of a script. This structure
+ * stored in the TypeCompartment is indexed by the RecompileInfo. This
+ * indirection enables the invalidation of all constraints related to the same
+ * compilation.
+ */
+class CompilerOutput
+{
+ // If this compilation has not been invalidated, the associated script and
+ // kind of compilation being performed.
+ JSScript* script_;
+
+ // Whether this compilation is about to be invalidated.
+ bool pendingInvalidation_ : 1;
+
+ // During sweeping, the list of compiler outputs is compacted and invalidated
+ // outputs are removed. This gives the new index for a valid compiler output.
+ uint32_t sweepIndex_ : 31;
+
+ public:
+ static const uint32_t INVALID_SWEEP_INDEX = static_cast<uint32_t>(1 << 31) - 1;
+
+ CompilerOutput()
+ : script_(nullptr),
+ pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
+ {}
+
+ explicit CompilerOutput(JSScript* script)
+ : script_(script),
+ pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
+ {}
+
+ JSScript* script() const { return script_; }
+
+ inline jit::IonScript* ion() const;
+
+ bool isValid() const {
+ return script_ != nullptr;
+ }
+ void invalidate() {
+ script_ = nullptr;
+ }
+
+ void setPendingInvalidation() {
+ pendingInvalidation_ = true;
+ }
+ bool pendingInvalidation() {
+ return pendingInvalidation_;
+ }
+
+ void setSweepIndex(uint32_t index) {
+ if (index >= INVALID_SWEEP_INDEX)
+ MOZ_CRASH();
+ sweepIndex_ = index;
+ }
+ uint32_t sweepIndex() {
+ MOZ_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
+ return sweepIndex_;
+ }
+};
+
+class RecompileInfo
+{
+ // Index in the TypeZone's compilerOutputs or sweepCompilerOutputs arrays,
+ // depending on the generation value.
+ uint32_t outputIndex : 31;
+
+ // If out of sync with the TypeZone's generation, this index is for the
+ // zone's sweepCompilerOutputs rather than compilerOutputs.
+ uint32_t generation : 1;
+
+ public:
+ RecompileInfo(uint32_t outputIndex, uint32_t generation)
+ : outputIndex(outputIndex), generation(generation)
+ {}
+
+ RecompileInfo()
+ : outputIndex(JS_BITMASK(31)), generation(0)
+ {}
+
+ CompilerOutput* compilerOutput(TypeZone& types) const;
+ CompilerOutput* compilerOutput(JSContext* cx) const;
+ bool shouldSweep(TypeZone& types);
+};
+
+// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a
+// single IonScript doesn't require an allocation.
+typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector;
+
+struct AutoEnterAnalysis;
+
+struct TypeZone
+{
+ JS::Zone* zone_;
+
+ /* Pool for type information in this zone. */
+ static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
+ LifoAlloc typeLifoAlloc;
+
+ // Current generation for sweeping.
+ uint32_t generation : 1;
+
+ /*
+ * All Ion compilations that have occured in this zone, for indexing via
+ * RecompileInfo. This includes both valid and invalid compilations, though
+ * invalidated compilations are swept on GC.
+ */
+ typedef Vector<CompilerOutput, 4, SystemAllocPolicy> CompilerOutputVector;
+ CompilerOutputVector* compilerOutputs;
+
+ // During incremental sweeping, allocator holding the old type information
+ // for the zone.
+ LifoAlloc sweepTypeLifoAlloc;
+
+ // During incremental sweeping, the old compiler outputs for use by
+ // recompile indexes with a stale generation.
+ CompilerOutputVector* sweepCompilerOutputs;
+
+ // During incremental sweeping, whether to try to destroy all type
+ // information attached to scripts.
+ bool sweepReleaseTypes;
+
+ // The topmost AutoEnterAnalysis on the stack, if there is one.
+ AutoEnterAnalysis* activeAnalysis;
+
+ explicit TypeZone(JS::Zone* zone);
+ ~TypeZone();
+
+ JS::Zone* zone() const { return zone_; }
+
+ void beginSweep(FreeOp* fop, bool releaseTypes, AutoClearTypeInferenceStateOnOOM& oom);
+ void endSweep(JSRuntime* rt);
+ void clearAllNewScriptsOnOOM();
+
+ /* Mark a script as needing recompilation once inference has finished. */
+ void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
+ void addPendingRecompile(JSContext* cx, JSScript* script);
+
+ void processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles);
+};
+
+enum SpewChannel {
+ ISpewOps, /* ops: New constraints and types. */
+ ISpewResult, /* result: Final type sets. */
+ SPEW_COUNT
+};
+
+#ifdef DEBUG
+
+bool InferSpewActive(SpewChannel channel);
+const char * InferSpewColorReset();
+const char * InferSpewColor(TypeConstraint* constraint);
+const char * InferSpewColor(TypeSet* types);
+
+#define InferSpew(channel, ...) if (InferSpewActive(channel)) { InferSpewImpl(__VA_ARGS__); } else {}
+void InferSpewImpl(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2);
+
+/* Check that the type property for id in group contains value. */
+bool ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value);
+
+#else
+
+inline const char * InferSpewColorReset() { return nullptr; }
+inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
+inline const char * InferSpewColor(TypeSet* types) { return nullptr; }
+
+#define InferSpew(channel, ...) do {} while (0)
+
+#endif
+
+// Prints type information for a context if spew is enabled or force is set.
+void
+PrintTypes(JSContext* cx, JSCompartment* comp, bool force);
+
+} /* namespace js */
+
+// JS::ubi::Nodes can point to object groups; they're js::gc::Cell instances
+// with no associated compartment.
+namespace JS {
+namespace ubi {
+
+template<>
+class Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> {
+ protected:
+ explicit Concrete(js::ObjectGroup *ptr) : TracerConcrete<js::ObjectGroup>(ptr) { }
+
+ public:
+ static void construct(void *storage, js::ObjectGroup *ptr) { new (storage) Concrete(ptr); }
+
+ Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+ const char16_t* typeName() const override { return concreteTypeName; }
+ static const char16_t concreteTypeName[];
+};
+
+} // namespace ubi
+} // namespace JS
+
+#endif /* vm_TypeInference_h */
diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h
new file mode 100644
index 000000000..d29c93a65
--- /dev/null
+++ b/js/src/vm/TypedArrayCommon.h
@@ -0,0 +1,887 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_TypedArrayCommon_h
+#define vm_TypedArrayCommon_h
+
+/* Utilities and common inline code for TypedArray */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/PodOperations.h"
+
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jsnum.h"
+
+#include "jit/AtomicOperations.h"
+
+#include "js/Conversions.h"
+#include "js/Value.h"
+
+#include "vm/NativeObject.h"
+#include "vm/TypedArrayObject.h"
+
+namespace js {
+
+// ValueIsLength happens not to be according to ES6, which mandates
+// the use of ToLength, which in turn includes ToNumber, ToInteger,
+// and clamping. ValueIsLength is used in the current TypedArray code
+// but will disappear when that code is made spec-compliant.
+
+inline bool
+ValueIsLength(const Value& v, uint32_t* len)
+{
+ if (v.isInt32()) {
+ int32_t i = v.toInt32();
+ if (i < 0)
+ return false;
+ *len = i;
+ return true;
+ }
+
+ if (v.isDouble()) {
+ double d = v.toDouble();
+ if (mozilla::IsNaN(d))
+ return false;
+
+ uint32_t length = uint32_t(d);
+ if (d != double(length))
+ return false;
+
+ *len = length;
+ return true;
+ }
+
+ return false;
+}
+
+template<typename To, typename From>
+inline To
+ConvertNumber(From src);
+
+template<>
+inline int8_t
+ConvertNumber<int8_t, float>(float src)
+{
+ return JS::ToInt8(src);
+}
+
+template<>
+inline uint8_t
+ConvertNumber<uint8_t, float>(float src)
+{
+ return JS::ToUint8(src);
+}
+
+template<>
+inline uint8_clamped
+ConvertNumber<uint8_clamped, float>(float src)
+{
+ return uint8_clamped(src);
+}
+
+template<>
+inline int16_t
+ConvertNumber<int16_t, float>(float src)
+{
+ return JS::ToInt16(src);
+}
+
+template<>
+inline uint16_t
+ConvertNumber<uint16_t, float>(float src)
+{
+ return JS::ToUint16(src);
+}
+
+template<>
+inline int32_t
+ConvertNumber<int32_t, float>(float src)
+{
+ return JS::ToInt32(src);
+}
+
+template<>
+inline uint32_t
+ConvertNumber<uint32_t, float>(float src)
+{
+ return JS::ToUint32(src);
+}
+
+template<> inline int8_t
+ConvertNumber<int8_t, double>(double src)
+{
+ return JS::ToInt8(src);
+}
+
+template<>
+inline uint8_t
+ConvertNumber<uint8_t, double>(double src)
+{
+ return JS::ToUint8(src);
+}
+
+template<>
+inline uint8_clamped
+ConvertNumber<uint8_clamped, double>(double src)
+{
+ return uint8_clamped(src);
+}
+
+template<>
+inline int16_t
+ConvertNumber<int16_t, double>(double src)
+{
+ return JS::ToInt16(src);
+}
+
+template<>
+inline uint16_t
+ConvertNumber<uint16_t, double>(double src)
+{
+ return JS::ToUint16(src);
+}
+
+template<>
+inline int32_t
+ConvertNumber<int32_t, double>(double src)
+{
+ return JS::ToInt32(src);
+}
+
+template<>
+inline uint32_t
+ConvertNumber<uint32_t, double>(double src)
+{
+ return JS::ToUint32(src);
+}
+
+template<typename To, typename From>
+inline To
+ConvertNumber(From src)
+{
+ static_assert(!mozilla::IsFloatingPoint<From>::value ||
+ (mozilla::IsFloatingPoint<From>::value && mozilla::IsFloatingPoint<To>::value),
+ "conversion from floating point to int should have been handled by "
+ "specializations above");
+ return To(src);
+}
+
+template<typename NativeType> struct TypeIDOfType;
+template<> struct TypeIDOfType<int8_t> { static const Scalar::Type id = Scalar::Int8; };
+template<> struct TypeIDOfType<uint8_t> { static const Scalar::Type id = Scalar::Uint8; };
+template<> struct TypeIDOfType<int16_t> { static const Scalar::Type id = Scalar::Int16; };
+template<> struct TypeIDOfType<uint16_t> { static const Scalar::Type id = Scalar::Uint16; };
+template<> struct TypeIDOfType<int32_t> { static const Scalar::Type id = Scalar::Int32; };
+template<> struct TypeIDOfType<uint32_t> { static const Scalar::Type id = Scalar::Uint32; };
+template<> struct TypeIDOfType<float> { static const Scalar::Type id = Scalar::Float32; };
+template<> struct TypeIDOfType<double> { static const Scalar::Type id = Scalar::Float64; };
+template<> struct TypeIDOfType<uint8_clamped> { static const Scalar::Type id = Scalar::Uint8Clamped; };
+
+class SharedOps
+{
+ public:
+ template<typename T>
+ static T load(SharedMem<T*> addr) {
+ return js::jit::AtomicOperations::loadSafeWhenRacy(addr);
+ }
+
+ template<typename T>
+ static void store(SharedMem<T*> addr, T value) {
+ js::jit::AtomicOperations::storeSafeWhenRacy(addr, value);
+ }
+
+ template<typename T>
+ static void memcpy(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
+ js::jit::AtomicOperations::memcpySafeWhenRacy(dest, src, size);
+ }
+
+ template<typename T>
+ static void memmove(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
+ js::jit::AtomicOperations::memmoveSafeWhenRacy(dest, src, size);
+ }
+
+ template<typename T>
+ static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
+ js::jit::AtomicOperations::podCopySafeWhenRacy(dest, src, nelem);
+ }
+
+ template<typename T>
+ static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
+ js::jit::AtomicOperations::podMoveSafeWhenRacy(dest, src, nelem);
+ }
+
+ static SharedMem<void*> extract(TypedArrayObject* obj) {
+ return obj->viewDataEither();
+ }
+};
+
+class UnsharedOps
+{
+ public:
+ template<typename T>
+ static T load(SharedMem<T*> addr) {
+ return *addr.unwrapUnshared();
+ }
+
+ template<typename T>
+ static void store(SharedMem<T*> addr, T value) {
+ *addr.unwrapUnshared() = value;
+ }
+
+ template<typename T>
+ static void memcpy(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
+ ::memcpy(dest.unwrapUnshared(), src.unwrapUnshared(), size);
+ }
+
+ template<typename T>
+ static void memmove(SharedMem<T*> dest, SharedMem<T*> src, size_t size) {
+ ::memmove(dest.unwrapUnshared(), src.unwrapUnshared(), size);
+ }
+
+ template<typename T>
+ static void podCopy(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
+ mozilla::PodCopy(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
+ }
+
+ template<typename T>
+ static void podMove(SharedMem<T*> dest, SharedMem<T*> src, size_t nelem) {
+ mozilla::PodMove(dest.unwrapUnshared(), src.unwrapUnshared(), nelem);
+ }
+
+ static SharedMem<void*> extract(TypedArrayObject* obj) {
+ return SharedMem<void*>::unshared(obj->viewDataUnshared());
+ }
+};
+
+template<class SpecificArray, typename Ops>
+class ElementSpecific
+{
+ typedef typename SpecificArray::ElementType T;
+ typedef typename SpecificArray::SomeTypedArray SomeTypedArray;
+
+ public:
+ /*
+ * Copy |source|'s elements into |target|, starting at |target[offset]|.
+ * Act as if the assignments occurred from a fresh copy of |source|, in
+ * case the two memory ranges overlap.
+ */
+ static bool
+ setFromTypedArray(JSContext* cx,
+ Handle<SomeTypedArray*> target, HandleObject source,
+ uint32_t offset)
+ {
+ MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
+ "calling wrong setFromTypedArray specialization");
+
+ MOZ_ASSERT(offset <= target->length());
+ MOZ_ASSERT(source->as<TypedArrayObject>().length() <= target->length() - offset);
+
+ if (source->is<SomeTypedArray>()) {
+ Rooted<SomeTypedArray*> src(cx, source.as<SomeTypedArray>());
+ if (SomeTypedArray::sameBuffer(target, src))
+ return setFromOverlappingTypedArray(cx, target, src, offset);
+ }
+
+ SharedMem<T*> dest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
+ uint32_t count = source->as<TypedArrayObject>().length();
+
+ if (source->as<TypedArrayObject>().type() == target->type()) {
+ Ops::podCopy(dest, source->as<TypedArrayObject>().viewDataEither().template cast<T*>(),
+ count);
+ return true;
+ }
+
+ // Inhibit unaligned accesses on ARM (bug 1097253, a compiler bug).
+#ifdef __arm__
+# define JS_VOLATILE_ARM volatile
+#else
+# define JS_VOLATILE_ARM
+#endif
+
+ SharedMem<void*> data = Ops::extract(source.as<TypedArrayObject>());
+ switch (source->as<TypedArrayObject>().type()) {
+ case Scalar::Int8: {
+ SharedMem<JS_VOLATILE_ARM int8_t*> src = data.cast<JS_VOLATILE_ARM int8_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Uint8:
+ case Scalar::Uint8Clamped: {
+ SharedMem<JS_VOLATILE_ARM uint8_t*> src = data.cast<JS_VOLATILE_ARM uint8_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Int16: {
+ SharedMem<JS_VOLATILE_ARM int16_t*> src = data.cast<JS_VOLATILE_ARM int16_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Uint16: {
+ SharedMem<JS_VOLATILE_ARM uint16_t*> src = data.cast<JS_VOLATILE_ARM uint16_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Int32: {
+ SharedMem<JS_VOLATILE_ARM int32_t*> src = data.cast<JS_VOLATILE_ARM int32_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Uint32: {
+ SharedMem<JS_VOLATILE_ARM uint32_t*> src = data.cast<JS_VOLATILE_ARM uint32_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Float32: {
+ SharedMem<JS_VOLATILE_ARM float*> src = data.cast<JS_VOLATILE_ARM float*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::Float64: {
+ SharedMem<JS_VOLATILE_ARM double*> src = data.cast<JS_VOLATILE_ARM double*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ default:
+ MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
+ }
+
+#undef JS_VOLATILE_ARM
+
+ return true;
+ }
+
+ /*
+ * Copy |source[0]| to |source[len]| (exclusive) elements into the typed
+ * array |target|, starting at index |offset|. |source| must not be a
+ * typed array.
+ */
+ static bool
+ setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
+ uint32_t len, uint32_t offset = 0)
+ {
+ MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
+ "target type and NativeType must match");
+ MOZ_ASSERT(!source->is<TypedArrayObject>(),
+ "use setFromTypedArray instead of this method");
+
+ uint32_t i = 0;
+ if (source->isNative()) {
+ // Attempt fast-path infallible conversion of dense elements up to
+ // the first potentially side-effectful lookup or conversion.
+ uint32_t bound = Min(source->as<NativeObject>().getDenseInitializedLength(), len);
+
+ SharedMem<T*> dest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
+
+ MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE)),
+ "the following loop must abort on holes");
+
+ const Value* srcValues = source->as<NativeObject>().getDenseElements();
+ for (; i < bound; i++) {
+ if (!canConvertInfallibly(srcValues[i]))
+ break;
+ Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
+ }
+ if (i == len)
+ return true;
+ }
+
+ // Convert and copy any remaining elements generically.
+ RootedValue v(cx);
+ for (; i < len; i++) {
+ if (!GetElement(cx, source, source, i, &v))
+ return false;
+
+ T n;
+ if (!valueToNative(cx, v, &n))
+ return false;
+
+ len = Min(len, target->length());
+ if (i >= len)
+ break;
+
+ // Compute every iteration in case getElement/valueToNative is wacky.
+ SharedMem<T*> dest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() +
+ offset + i;
+ Ops::store(dest, n);
+ }
+
+ return true;
+ }
+
+ /*
+ * Copy |source| into the typed array |target|.
+ */
+ static bool
+ initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
+ HandleArrayObject source)
+ {
+ MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
+ "target type and NativeType must match");
+ MOZ_ASSERT(IsPackedArray(source), "source array must be packed");
+ MOZ_ASSERT(source->getDenseInitializedLength() <= target->length());
+
+ uint32_t len = source->getDenseInitializedLength();
+ uint32_t i = 0;
+
+ // Attempt fast-path infallible conversion of dense elements up to the
+ // first potentially side-effectful conversion.
+
+ SharedMem<T*> dest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
+
+ const Value* srcValues = source->getDenseElements();
+ for (; i < len; i++) {
+ if (!canConvertInfallibly(srcValues[i]))
+ break;
+ Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
+ }
+ if (i == len)
+ return true;
+
+ // Convert any remaining elements by first collecting them into a
+ // temporary list, and then copying them into the typed array.
+ AutoValueVector values(cx);
+ if (!values.append(srcValues + i, len - i))
+ return false;
+
+ RootedValue v(cx);
+ for (uint32_t j = 0; j < values.length(); i++, j++) {
+ v = values[j];
+
+ T n;
+ if (!valueToNative(cx, v, &n))
+ return false;
+
+ // |target| is a newly allocated typed array and not yet visible to
+ // content script, so valueToNative can't detach the underlying
+ // buffer.
+ MOZ_ASSERT(i < target->length());
+
+ // Compute every iteration in case GC moves the data.
+ SharedMem<T*> newDest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
+ Ops::store(newDest + i, n);
+ }
+
+ return true;
+ }
+
+ private:
+ static bool
+ setFromOverlappingTypedArray(JSContext* cx,
+ Handle<SomeTypedArray*> target,
+ Handle<SomeTypedArray*> source,
+ uint32_t offset)
+ {
+ MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
+ "calling wrong setFromTypedArray specialization");
+ MOZ_ASSERT(SomeTypedArray::sameBuffer(target, source),
+ "the provided arrays don't actually overlap, so it's "
+ "undesirable to use this method");
+
+ MOZ_ASSERT(offset <= target->length());
+ MOZ_ASSERT(source->length() <= target->length() - offset);
+
+ SharedMem<T*> dest =
+ target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
+ uint32_t len = source->length();
+
+ if (source->type() == target->type()) {
+ SharedMem<T*> src =
+ source->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
+ Ops::podMove(dest, src, len);
+ return true;
+ }
+
+ // Copy |source| in case it overlaps the target elements being set.
+ size_t sourceByteLen = len * source->bytesPerElement();
+ void* data = target->zone()->template pod_malloc<uint8_t>(sourceByteLen);
+ if (!data)
+ return false;
+ Ops::memcpy(SharedMem<void*>::unshared(data),
+ source->template as<TypedArrayObject>().viewDataEither(),
+ sourceByteLen);
+
+ switch (source->type()) {
+ case Scalar::Int8: {
+ int8_t* src = static_cast<int8_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Uint8:
+ case Scalar::Uint8Clamped: {
+ uint8_t* src = static_cast<uint8_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Int16: {
+ int16_t* src = static_cast<int16_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Uint16: {
+ uint16_t* src = static_cast<uint16_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Int32: {
+ int32_t* src = static_cast<int32_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Uint32: {
+ uint32_t* src = static_cast<uint32_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Float32: {
+ float* src = static_cast<float*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::Float64: {
+ double* src = static_cast<double*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ default:
+ MOZ_CRASH("setFromOverlappingTypedArray with a typed array with bogus type");
+ }
+
+ js_free(data);
+ return true;
+ }
+
+ static bool
+ canConvertInfallibly(const Value& v)
+ {
+ return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined();
+ }
+
+ static T
+ infallibleValueToNative(const Value& v)
+ {
+ if (v.isInt32())
+ return T(v.toInt32());
+ if (v.isDouble())
+ return doubleToNative(v.toDouble());
+ if (v.isBoolean())
+ return T(v.toBoolean());
+ if (v.isNull())
+ return T(0);
+
+ MOZ_ASSERT(v.isUndefined());
+ return TypeIsFloatingPoint<T>() ? T(JS::GenericNaN()) : T(0);
+ }
+
+ static bool
+ valueToNative(JSContext* cx, HandleValue v, T* result)
+ {
+ MOZ_ASSERT(!v.isMagic());
+
+ if (MOZ_LIKELY(canConvertInfallibly(v))) {
+ *result = infallibleValueToNative(v);
+ return true;
+ }
+
+ double d;
+ MOZ_ASSERT(v.isString() || v.isObject() || v.isSymbol());
+ if (!(v.isString() ? StringToNumber(cx, v.toString(), &d) : ToNumber(cx, v, &d)))
+ return false;
+
+ *result = doubleToNative(d);
+ return true;
+ }
+
+ static T
+ doubleToNative(double d)
+ {
+ if (TypeIsFloatingPoint<T>()) {
+#ifdef JS_MORE_DETERMINISTIC
+ // The JS spec doesn't distinguish among different NaN values, and
+ // it deliberately doesn't specify the bit pattern written to a
+ // typed array when NaN is written into it. This bit-pattern
+ // inconsistency could confuse deterministic testing, so always
+ // canonicalize NaN values in more-deterministic builds.
+ d = JS::CanonicalizeNaN(d);
+#endif
+ return T(d);
+ }
+ if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
+ return T(0);
+ if (SpecificArray::ArrayTypeID() == Scalar::Uint8Clamped)
+ return T(d);
+ if (TypeIsUnsigned<T>())
+ return T(JS::ToUint32(d));
+ return T(JS::ToInt32(d));
+ }
+};
+
+template<typename SomeTypedArray>
+class TypedArrayMethods
+{
+ static_assert(mozilla::IsSame<SomeTypedArray, TypedArrayObject>::value,
+ "methods must be shared/unshared-specific, not "
+ "element-type-specific");
+
+ typedef typename SomeTypedArray::BufferType BufferType;
+
+ typedef typename SomeTypedArray::template OfType<int8_t>::Type Int8ArrayType;
+ typedef typename SomeTypedArray::template OfType<uint8_t>::Type Uint8ArrayType;
+ typedef typename SomeTypedArray::template OfType<int16_t>::Type Int16ArrayType;
+ typedef typename SomeTypedArray::template OfType<uint16_t>::Type Uint16ArrayType;
+ typedef typename SomeTypedArray::template OfType<int32_t>::Type Int32ArrayType;
+ typedef typename SomeTypedArray::template OfType<uint32_t>::Type Uint32ArrayType;
+ typedef typename SomeTypedArray::template OfType<float>::Type Float32ArrayType;
+ typedef typename SomeTypedArray::template OfType<double>::Type Float64ArrayType;
+ typedef typename SomeTypedArray::template OfType<uint8_clamped>::Type Uint8ClampedArrayType;
+
+ public:
+ /* set(array[, offset]) */
+ static bool
+ set(JSContext* cx, const CallArgs& args)
+ {
+ MOZ_ASSERT(SomeTypedArray::is(args.thisv()));
+
+ Rooted<SomeTypedArray*> target(cx, &args.thisv().toObject().as<SomeTypedArray>());
+
+ // The first argument must be either a typed array or arraylike.
+ if (args.length() == 0 || !args[0].isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return false;
+ }
+
+ int32_t offset = 0;
+ if (args.length() > 1) {
+ if (!ToInt32(cx, args[1], &offset))
+ return false;
+
+ if (offset < 0 || uint32_t(offset) > target->length()) {
+ // the given offset is bogus
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+ return false;
+ }
+ }
+
+ RootedObject arg0(cx, &args[0].toObject());
+ if (arg0->is<TypedArrayObject>()) {
+ if (arg0->as<TypedArrayObject>().length() > target->length() - offset) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+ return false;
+ }
+
+ if (!setFromTypedArray(cx, target, arg0, offset))
+ return false;
+ } else {
+ uint32_t len;
+ if (!GetLengthProperty(cx, arg0, &len))
+ return false;
+
+ if (uint32_t(offset) > target->length() || len > target->length() - offset) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+ return false;
+ }
+
+ if (!setFromNonTypedArray(cx, target, arg0, len, offset))
+ return false;
+ }
+
+ args.rval().setUndefined();
+ return true;
+ }
+
+ static bool
+ setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
+ uint32_t offset = 0)
+ {
+ MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
+
+ bool isShared = target->isSharedMemory() || source->as<TypedArrayObject>().isSharedMemory();
+
+ switch (target->type()) {
+ case Scalar::Int8:
+ if (isShared)
+ return ElementSpecific<Int8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Uint8:
+ if (isShared)
+ return ElementSpecific<Uint8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Int16:
+ if (isShared)
+ return ElementSpecific<Int16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Uint16:
+ if (isShared)
+ return ElementSpecific<Uint16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Int32:
+ if (isShared)
+ return ElementSpecific<Int32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Uint32:
+ if (isShared)
+ return ElementSpecific<Uint32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Float32:
+ if (isShared)
+ return ElementSpecific<Float32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Float64:
+ if (isShared)
+ return ElementSpecific<Float64ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Uint8Clamped:
+ if (isShared)
+ return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+
+ MOZ_CRASH("nonsense target element type");
+ }
+
+ static bool
+ setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
+ uint32_t len, uint32_t offset = 0)
+ {
+ MOZ_ASSERT(!source->is<TypedArrayObject>(), "use setFromTypedArray");
+
+ bool isShared = target->isSharedMemory();
+
+ switch (target->type()) {
+ case Scalar::Int8:
+ if (isShared)
+ return ElementSpecific<Int8ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Uint8:
+ if (isShared)
+ return ElementSpecific<Uint8ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Int16:
+ if (isShared)
+ return ElementSpecific<Int16ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Uint16:
+ if (isShared)
+ return ElementSpecific<Uint16ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Int32:
+ if (isShared)
+ return ElementSpecific<Int32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Uint32:
+ if (isShared)
+ return ElementSpecific<Uint32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Float32:
+ if (isShared)
+ return ElementSpecific<Float32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Float64:
+ if (isShared)
+ return ElementSpecific<Float64ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Uint8Clamped:
+ if (isShared)
+ return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+ MOZ_CRASH("bad target array type");
+ }
+
+ static bool
+ initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
+ HandleArrayObject source)
+ {
+ bool isShared = target->isSharedMemory();
+
+ switch (target->type()) {
+ case Scalar::Int8:
+ if (isShared)
+ return ElementSpecific<Int8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Int8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Uint8:
+ if (isShared)
+ return ElementSpecific<Uint8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Uint8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Int16:
+ if (isShared)
+ return ElementSpecific<Int16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Int16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Uint16:
+ if (isShared)
+ return ElementSpecific<Uint16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Uint16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Int32:
+ if (isShared)
+ return ElementSpecific<Int32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Int32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Uint32:
+ if (isShared)
+ return ElementSpecific<Uint32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Uint32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Float32:
+ if (isShared)
+ return ElementSpecific<Float32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Float32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Float64:
+ if (isShared)
+ return ElementSpecific<Float64ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Float64ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Uint8Clamped:
+ if (isShared)
+ return ElementSpecific<Uint8ClampedArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+ MOZ_CRASH("bad target array type");
+ }
+};
+
+} // namespace js
+
+#endif // vm_TypedArrayCommon_h
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
new file mode 100644
index 000000000..9d4ee94c6
--- /dev/null
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -0,0 +1,3315 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/TypedArrayObject.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/Casting.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/PodOperations.h"
+
+#include <string.h>
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jscpucfg.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jstypes.h"
+#include "jsutil.h"
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+#include "jswrapper.h"
+
+#include "builtin/TypedObjectConstants.h"
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "jit/InlinableNatives.h"
+#include "js/Conversions.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/PIC.h"
+#include "vm/SelfHosting.h"
+#include "vm/TypedArrayCommon.h"
+#include "vm/WrapperObject.h"
+
+#include "jsatominlines.h"
+
+#include "gc/Nursery-inl.h"
+#include "gc/StoreBuffer-inl.h"
+#include "vm/ArrayBufferObject-inl.h"
+#include "vm/NativeObject-inl.h"
+#include "vm/Shape-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+using mozilla::AssertedCast;
+using JS::CanonicalizeNaN;
+using JS::ToInt32;
+using JS::ToUint32;
+
+/*
+ * TypedArrayObject
+ *
+ * The non-templated base class for the specific typed implementations.
+ * This class holds all the member variables that are used by
+ * the subclasses.
+ */
+
+/* static */ int
+TypedArrayObject::lengthOffset()
+{
+ return NativeObject::getFixedSlotOffset(LENGTH_SLOT);
+}
+
+/* static */ int
+TypedArrayObject::dataOffset()
+{
+ return NativeObject::getPrivateDataOffset(DATA_SLOT);
+}
+
+void
+TypedArrayObject::notifyBufferDetached(JSContext* cx, void* newData)
+{
+ MOZ_ASSERT(!isSharedMemory());
+ setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
+ setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
+
+ // If the object is in the nursery, the buffer will be freed by the next
+ // nursery GC. Free the data slot pointer if the object has no inline data.
+ Nursery& nursery = cx->runtime()->gc.nursery;
+ if (isTenured() && !hasBuffer() && !hasInlineElements() &&
+ !nursery.isInside(elements()))
+ {
+ js_free(elements());
+ }
+
+ setPrivate(newData);
+}
+
+/* static */ bool
+TypedArrayObject::is(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<TypedArrayObject>();
+}
+
+/* static */ bool
+TypedArrayObject::ensureHasBuffer(JSContext* cx, Handle<TypedArrayObject*> tarray)
+{
+ if (tarray->hasBuffer())
+ return true;
+
+ Rooted<ArrayBufferObject*> buffer(cx, ArrayBufferObject::create(cx, tarray->byteLength()));
+ if (!buffer)
+ return false;
+
+ if (!buffer->addView(cx, tarray))
+ return false;
+
+ // tarray is not shared, because if it were it would have a buffer.
+ memcpy(buffer->dataPointer(), tarray->viewDataUnshared(), tarray->byteLength());
+
+ // If the object is in the nursery, the buffer will be freed by the next
+ // nursery GC. Free the data slot pointer if the object has no inline data.
+ Nursery& nursery = cx->runtime()->gc.nursery;
+ if (tarray->isTenured() && !tarray->hasInlineElements() &&
+ !nursery.isInside(tarray->elements()))
+ {
+ js_free(tarray->elements());
+ }
+
+ tarray->setPrivate(buffer->dataPointer());
+
+ tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*buffer));
+
+ // Notify compiled jit code that the base pointer has moved.
+ MarkObjectStateChange(cx, tarray);
+
+ return true;
+}
+
+#ifdef DEBUG
+void
+TypedArrayObject::assertZeroLengthArrayData() const
+{
+ if (length() == 0 && !hasBuffer()) {
+ uint8_t* end = fixedData(TypedArrayObject::FIXED_DATA_START);
+ MOZ_ASSERT(end[0] == ZeroLengthArrayData);
+ }
+}
+#endif
+
+/* static */ void
+TypedArrayObject::trace(JSTracer* trc, JSObject* objArg)
+{
+ // Handle all tracing required when the object has a buffer.
+ ArrayBufferViewObject::trace(trc, objArg);
+}
+
+void
+TypedArrayObject::finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(!IsInsideNursery(obj));
+ TypedArrayObject* curObj = &obj->as<TypedArrayObject>();
+
+ // Template objects or discarded objects (which didn't have enough room
+ // for inner elements). Don't have anything to free.
+ if (!curObj->elementsRaw())
+ return;
+
+ curObj->assertZeroLengthArrayData();
+
+ // Typed arrays with a buffer object do not need to be free'd
+ if (curObj->hasBuffer())
+ return;
+
+ // Free the data slot pointer if it does not point into the old JSObject.
+ if (!curObj->hasInlineElements())
+ js_free(curObj->elements());
+}
+
+/* static */ void
+TypedArrayObject::objectMoved(JSObject* obj, const JSObject* old)
+{
+ TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
+ const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
+
+ // Typed arrays with a buffer object do not need an update.
+ if (oldObj->hasBuffer())
+ return;
+
+ // Update the data slot pointer if it points to the old JSObject.
+ if (oldObj->hasInlineElements())
+ newObj->setInlineElements();
+}
+
+/* static */ size_t
+TypedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
+ gc::AllocKind newAllocKind)
+{
+ TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
+ const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
+ MOZ_ASSERT(newObj->elementsRaw() == oldObj->elementsRaw());
+ MOZ_ASSERT(obj->isTenured());
+
+ // Typed arrays with a buffer object do not need an update.
+ if (oldObj->hasBuffer())
+ return 0;
+
+ Nursery& nursery = trc->runtime()->gc.nursery;
+ void* buf = oldObj->elements();
+
+ if (!nursery.isInside(buf)) {
+ nursery.removeMallocedBuffer(buf);
+ return 0;
+ }
+
+ // Determine if we can use inline data for the target array. If this is
+ // possible, the nursery will have picked an allocation size that is large
+ // enough.
+ size_t nbytes = 0;
+ switch (oldObj->type()) {
+#define OBJECT_MOVED_TYPED_ARRAY(T, N) \
+ case Scalar::N: \
+ nbytes = oldObj->length() * sizeof(T); \
+ break;
+JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY)
+#undef OBJECT_MOVED_TYPED_ARRAY
+ default:
+ MOZ_CRASH("Unsupported TypedArray type");
+ }
+
+ size_t headerSize = dataOffset() + sizeof(HeapSlot);
+
+ // See AllocKindForLazyBuffer.
+ MOZ_ASSERT_IF(nbytes == 0, headerSize + sizeof(uint8_t) <= GetGCKindBytes(newAllocKind));
+
+ if (headerSize + nbytes <= GetGCKindBytes(newAllocKind)) {
+ MOZ_ASSERT(oldObj->hasInlineElements());
+#ifdef DEBUG
+ if (nbytes == 0) {
+ uint8_t* output = newObj->fixedData(TypedArrayObject::FIXED_DATA_START);
+ output[0] = ZeroLengthArrayData;
+ }
+#endif
+ newObj->setInlineElements();
+ } else {
+ MOZ_ASSERT(!oldObj->hasInlineElements());
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ nbytes = JS_ROUNDUP(nbytes, sizeof(Value));
+ void* data = newObj->zone()->pod_malloc<uint8_t>(nbytes);
+ if (!data)
+ oomUnsafe.crash("Failed to allocate typed array elements while tenuring.");
+ MOZ_ASSERT(!nursery.isInside(data));
+ newObj->initPrivate(data);
+ }
+
+ mozilla::PodCopy(newObj->elements(), oldObj->elements(), nbytes);
+
+ // Set a forwarding pointer for the element buffers in case they were
+ // preserved on the stack by Ion.
+ nursery.maybeSetForwardingPointer(trc, oldObj->elements(), newObj->elements(),
+ /* direct = */nbytes >= sizeof(uintptr_t));
+
+ return newObj->hasInlineElements() ? 0 : nbytes;
+}
+
+bool
+TypedArrayObject::hasInlineElements() const
+{
+ return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START) &&
+ byteLength() <= TypedArrayObject::INLINE_BUFFER_LIMIT;
+}
+
+void
+TypedArrayObject::setInlineElements()
+{
+ char* dataSlot = reinterpret_cast<char*>(this) + this->dataOffset();
+ *reinterpret_cast<void**>(dataSlot) = this->fixedData(TypedArrayObject::FIXED_DATA_START);
+}
+
+/* Helper clamped uint8_t type */
+
+uint32_t JS_FASTCALL
+js::ClampDoubleToUint8(const double x)
+{
+ // Not < so that NaN coerces to 0
+ if (!(x >= 0))
+ return 0;
+
+ if (x > 255)
+ return 255;
+
+ double toTruncate = x + 0.5;
+ uint8_t y = uint8_t(toTruncate);
+
+ /*
+ * now val is rounded to nearest, ties rounded up. We want
+ * rounded to nearest ties to even, so check whether we had a
+ * tie.
+ */
+ if (y == toTruncate) {
+ /*
+ * It was a tie (since adding 0.5 gave us the exact integer
+ * we want). Since we rounded up, we either already have an
+ * even number or we have an odd number but the number we
+ * want is one less. So just unconditionally masking out the
+ * ones bit should do the trick to get us the value we
+ * want.
+ */
+ return y & ~1;
+ }
+
+ return y;
+}
+
+template<typename ElementType>
+static inline JSObject*
+NewArray(JSContext* cx, uint32_t nelements);
+
+namespace {
+
+// We allow nullptr for newTarget for all the creation methods, to allow for
+// JSFriendAPI functions that don't care about subclassing
+static bool
+GetPrototypeForInstance(JSContext* cx, HandleObject newTarget, MutableHandleObject proto)
+{
+ if (newTarget) {
+ if (!GetPrototypeFromConstructor(cx, newTarget, proto))
+ return false;
+ } else {
+ proto.set(nullptr);
+ }
+ return true;
+}
+
+enum class SpeciesConstructorOverride {
+ None,
+ ArrayBuffer
+};
+
+template<typename NativeType>
+class TypedArrayObjectTemplate : public TypedArrayObject
+{
+ friend class TypedArrayObject;
+
+ public:
+ typedef NativeType ElementType;
+
+ static constexpr Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>::id; }
+ static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
+ static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
+
+ static const size_t BYTES_PER_ELEMENT = sizeof(NativeType);
+
+ static JSObject*
+ createPrototype(JSContext* cx, JSProtoKey key)
+ {
+ Handle<GlobalObject*> global = cx->global();
+ RootedObject typedArrayProto(cx, GlobalObject::getOrCreateTypedArrayPrototype(cx, global));
+ if (!typedArrayProto)
+ return nullptr;
+
+ const Class* clasp = TypedArrayObject::protoClassForType(ArrayTypeID());
+ return global->createBlankPrototypeInheriting(cx, clasp, typedArrayProto);
+ }
+
+ static JSObject*
+ createConstructor(JSContext* cx, JSProtoKey key)
+ {
+ Handle<GlobalObject*> global = cx->global();
+ RootedFunction ctorProto(cx, GlobalObject::getOrCreateTypedArrayConstructor(cx, global));
+ if (!ctorProto)
+ return nullptr;
+
+ JSFunction* fun = NewFunctionWithProto(cx, class_constructor, 3,
+ JSFunction::NATIVE_CTOR, nullptr,
+ ClassName(key, cx),
+ ctorProto, gc::AllocKind::FUNCTION,
+ SingletonObject);
+
+ if (fun)
+ fun->setJitInfo(&jit::JitInfo_TypedArrayConstructor);
+
+ return fun;
+ }
+
+ static bool
+ getOrCreateCreateArrayFromBufferFunction(JSContext* cx, MutableHandleValue fval)
+ {
+ RootedValue cache(cx, cx->global()->createArrayFromBuffer<NativeType>());
+ if (cache.isObject()) {
+ MOZ_ASSERT(cache.toObject().is<JSFunction>());
+ fval.set(cache);
+ return true;
+ }
+
+ RootedFunction fun(cx);
+ fun = NewNativeFunction(cx, ArrayBufferObject::createTypedArrayFromBuffer<NativeType>,
+ 0, nullptr);
+ if (!fun)
+ return false;
+
+ cx->global()->setCreateArrayFromBuffer<NativeType>(fun);
+
+ fval.setObject(*fun);
+ return true;
+ }
+
+ static inline const Class* instanceClass()
+ {
+ return TypedArrayObject::classForType(ArrayTypeID());
+ }
+
+ static bool is(HandleValue v) {
+ return v.isObject() && v.toObject().hasClass(instanceClass());
+ }
+
+ static void
+ setIndexValue(TypedArrayObject& tarray, uint32_t index, double d)
+ {
+ // If the array is an integer array, we only handle up to
+ // 32-bit ints from this point on. if we want to handle
+ // 64-bit ints, we'll need some changes.
+
+ // Assign based on characteristics of the destination type
+ if (ArrayTypeIsFloatingPoint()) {
+ setIndex(tarray, index, NativeType(d));
+ } else if (ArrayTypeIsUnsigned()) {
+ MOZ_ASSERT(sizeof(NativeType) <= 4);
+ uint32_t n = ToUint32(d);
+ setIndex(tarray, index, NativeType(n));
+ } else if (ArrayTypeID() == Scalar::Uint8Clamped) {
+ // The uint8_clamped type has a special rounding converter
+ // for doubles.
+ setIndex(tarray, index, NativeType(d));
+ } else {
+ MOZ_ASSERT(sizeof(NativeType) <= 4);
+ int32_t n = ToInt32(d);
+ setIndex(tarray, index, NativeType(n));
+ }
+ }
+
+ static TypedArrayObject*
+ makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
+ {
+ MOZ_ASSERT(proto);
+
+ JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
+ return obj ? &obj->as<TypedArrayObject>() : nullptr;
+ }
+
+ static TypedArrayObject*
+ makeTypedInstance(JSContext* cx, uint32_t len, gc::AllocKind allocKind)
+ {
+ const Class* clasp = instanceClass();
+ if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
+ JSObject* obj = NewBuiltinClassInstance(cx, clasp, allocKind, SingletonObject);
+ if (!obj)
+ return nullptr;
+ return &obj->as<TypedArrayObject>();
+ }
+
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ NewObjectKind newKind = GenericObject;
+ if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp))
+ newKind = SingletonObject;
+ RootedObject obj(cx, NewBuiltinClassInstance(cx, clasp, allocKind, newKind));
+ if (!obj)
+ return nullptr;
+
+ if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
+ newKind == SingletonObject))
+ {
+ return nullptr;
+ }
+
+ return &obj->as<TypedArrayObject>();
+ }
+
+ static TypedArrayObject*
+ makeInstance(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer, uint32_t byteOffset, uint32_t len,
+ HandleObject proto)
+ {
+ MOZ_ASSERT_IF(!buffer, byteOffset == 0);
+
+ gc::AllocKind allocKind = buffer
+ ? GetGCObjectKind(instanceClass())
+ : AllocKindForLazyBuffer(len * sizeof(NativeType));
+
+ // Subclassing mandates that we hand in the proto every time. Most of
+ // the time, though, that [[Prototype]] will not be interesting. If
+ // it isn't, we can do some more TI optimizations.
+ RootedObject checkProto(cx);
+ if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &checkProto))
+ return nullptr;
+
+ AutoSetNewObjectMetadata metadata(cx);
+ Rooted<TypedArrayObject*> obj(cx);
+ if (proto && proto != checkProto)
+ obj = makeProtoInstance(cx, proto, allocKind);
+ else
+ obj = makeTypedInstance(cx, len, allocKind);
+ if (!obj)
+ return nullptr;
+
+ bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
+
+ obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
+ // This is invariant. Self-hosting code that sets BUFFER_SLOT
+ // (if it does) must maintain it, should it need to.
+ if (isSharedMemory)
+ obj->setIsSharedMemory();
+
+ if (buffer) {
+ obj->initViewData(buffer->dataPointerEither() + byteOffset);
+
+ // If the buffer is for an inline typed object, the data pointer
+ // may be in the nursery, so include a barrier to make sure this
+ // object is updated if that typed object moves.
+ auto ptr = buffer->dataPointerEither();
+ if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(ptr)) {
+ // Shared buffer data should never be nursery-allocated, so we
+ // need to fail here if isSharedMemory. However, mmap() can
+ // place a SharedArrayRawBuffer up against the bottom end of a
+ // nursery chunk, and a zero-length buffer will erroneously be
+ // perceived as being inside the nursery; sidestep that.
+ if (isSharedMemory) {
+ MOZ_ASSERT(buffer->byteLength() == 0 &&
+ (uintptr_t(ptr.unwrapValue()) & gc::ChunkMask) == 0);
+ } else {
+ cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+ }
+ }
+ } else {
+ void* data = obj->fixedData(FIXED_DATA_START);
+ obj->initPrivate(data);
+ memset(data, 0, len * sizeof(NativeType));
+#ifdef DEBUG
+ if (len == 0) {
+ uint8_t* elements = static_cast<uint8_t*>(data);
+ elements[0] = ZeroLengthArrayData;
+ }
+#endif
+ }
+
+ obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(len));
+ obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
+
+#ifdef DEBUG
+ if (buffer) {
+ uint32_t arrayByteLength = obj->byteLength();
+ uint32_t arrayByteOffset = obj->byteOffset();
+ uint32_t bufferByteLength = buffer->byteLength();
+ // Unwraps are safe: both are for the pointer value.
+ if (IsArrayBuffer(buffer.get())) {
+ MOZ_ASSERT_IF(!AsArrayBuffer(buffer.get()).isDetached(),
+ buffer->dataPointerEither().unwrap(/*safe*/) <= obj->viewDataEither().unwrap(/*safe*/));
+ }
+ MOZ_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
+ MOZ_ASSERT(arrayByteOffset <= bufferByteLength);
+ }
+
+ // Verify that the private slot is at the expected place
+ MOZ_ASSERT(obj->numFixedSlots() == TypedArrayObject::DATA_SLOT);
+#endif
+
+ // ArrayBufferObjects track their views to support detaching.
+ if (buffer && buffer->is<ArrayBufferObject>()) {
+ if (!buffer->as<ArrayBufferObject>().addView(cx, obj))
+ return nullptr;
+ }
+
+ return obj;
+ }
+
+ static TypedArrayObject*
+ makeInstance(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer,
+ uint32_t byteOffset, uint32_t len)
+ {
+ RootedObject proto(cx, nullptr);
+ return makeInstance(cx, buffer, byteOffset, len, proto);
+ }
+
+ static TypedArrayObject*
+ makeTemplateObject(JSContext* cx, int32_t len)
+ {
+ MOZ_ASSERT(len >= 0);
+ size_t nbytes;
+ MOZ_ALWAYS_TRUE(CalculateAllocSize<NativeType>(len, &nbytes));
+ MOZ_ASSERT(nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH);
+ NewObjectKind newKind = TenuredObject;
+ bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
+ const Class* clasp = instanceClass();
+ gc::AllocKind allocKind = !fitsInline
+ ? GetGCObjectKind(clasp)
+ : AllocKindForLazyBuffer(nbytes);
+ MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
+ allocKind = GetBackgroundAllocKind(allocKind);
+
+ AutoSetNewObjectMetadata metadata(cx);
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp))
+ newKind = SingletonObject;
+ JSObject* tmp = NewBuiltinClassInstance(cx, clasp, allocKind, newKind);
+ if (!tmp)
+ return nullptr;
+
+ Rooted<TypedArrayObject*> tarray(cx, &tmp->as<TypedArrayObject>());
+ initTypedArraySlots(cx, tarray, len);
+
+ // Template objects do not need memory for its elements, since there
+ // won't be any elements to store. Therefore, we set the pointer to
+ // nullptr and avoid allocating memory that will never be used.
+ tarray->initPrivate(nullptr);
+
+ if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, tarray,
+ newKind == SingletonObject))
+ {
+ return nullptr;
+ }
+
+ return tarray;
+ }
+
+ static void
+ initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len)
+ {
+ MOZ_ASSERT(len >= 0);
+ tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, NullValue());
+ tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(AssertedCast<int32_t>(len)));
+ tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
+
+ // Verify that the private slot is at the expected place.
+ MOZ_ASSERT(tarray->numFixedSlots() == TypedArrayObject::DATA_SLOT);
+
+#ifdef DEBUG
+ if (len == 0) {
+ uint8_t* output = tarray->fixedData(TypedArrayObject::FIXED_DATA_START);
+ output[0] = TypedArrayObject::ZeroLengthArrayData;
+ }
+#endif
+ }
+
+ static void
+ initTypedArrayData(JSContext* cx, TypedArrayObject* tarray, int32_t len,
+ void* buf, AllocKind allocKind)
+ {
+ if (buf) {
+#ifdef DEBUG
+ Nursery& nursery = cx->runtime()->gc.nursery;
+ MOZ_ASSERT_IF(!nursery.isInside(buf) && !tarray->hasInlineElements(),
+ tarray->isTenured());
+#endif
+ tarray->initPrivate(buf);
+ } else {
+ size_t nbytes = len * sizeof(NativeType);
+#ifdef DEBUG
+ size_t dataOffset = TypedArrayObject::dataOffset();
+ size_t offset = dataOffset + sizeof(HeapSlot);
+ MOZ_ASSERT(offset + nbytes <= GetGCKindBytes(allocKind));
+#endif
+
+ void* data = tarray->fixedData(FIXED_DATA_START);
+ tarray->initPrivate(data);
+ memset(data, 0, nbytes);
+ }
+ }
+
+ static TypedArrayObject*
+ makeTypedArrayWithTemplate(JSContext* cx, TypedArrayObject* templateObj, int32_t len)
+ {
+ if (len < 0 || uint32_t(len) >= INT32_MAX / sizeof(NativeType)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr;
+ }
+
+ size_t nbytes;
+ MOZ_ALWAYS_TRUE(js::CalculateAllocSize<NativeType>(len, &nbytes));
+
+ bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
+
+ AutoSetNewObjectMetadata metadata(cx);
+
+ const Class* clasp = templateObj->group()->clasp();
+ gc::AllocKind allocKind = !fitsInline
+ ? GetGCObjectKind(clasp)
+ : AllocKindForLazyBuffer(nbytes);
+ MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
+ allocKind = GetBackgroundAllocKind(allocKind);
+ RootedObjectGroup group(cx, templateObj->group());
+
+ NewObjectKind newKind = TenuredObject;
+
+ ScopedJSFreePtr<void> buf;
+ if (!fitsInline && len > 0) {
+ buf = cx->zone()->pod_malloc<uint8_t>(nbytes);
+ if (!buf) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ memset(buf, 0, nbytes);
+ }
+
+ RootedObject tmp(cx, NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind));
+ if (!tmp)
+ return nullptr;
+
+ TypedArrayObject* obj = &tmp->as<TypedArrayObject>();
+ initTypedArraySlots(cx, obj, len);
+ initTypedArrayData(cx, obj, len, buf.forget(), allocKind);
+
+ return obj;
+ }
+
+ /*
+ * new [Type]Array(length)
+ * new [Type]Array(otherTypedArray)
+ * new [Type]Array(JSArray)
+ * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
+ */
+ static bool
+ class_constructor(JSContext* cx, unsigned argc, Value* vp)
+ {
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "typed array"))
+ return false;
+
+ JSObject* obj = create(cx, args);
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ static JSObject*
+ create(JSContext* cx, const CallArgs& args)
+ {
+ MOZ_ASSERT(args.isConstructing());
+ RootedObject newTarget(cx, &args.newTarget().toObject());
+
+ /* () or (number) */
+ uint32_t len = 0;
+ if (args.length() == 0 || ValueIsLength(args[0], &len))
+ return fromLength(cx, len, newTarget);
+
+ /* (not an object) */
+ if (!args[0].isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr;
+ }
+
+ RootedObject dataObj(cx, &args.get(0).toObject());
+
+ /*
+ * (typedArray)
+ * (sharedTypedArray)
+ * (type[] array)
+ *
+ * Otherwise create a new typed array and copy elements 0..len-1
+ * properties from the object, treating it as some sort of array.
+ * Note that offset and length will be ignored. Note that a
+ * shared array's values are copied here.
+ */
+ if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObjectMaybeShared>())
+ return fromArray(cx, dataObj, newTarget);
+
+ /* (ArrayBuffer, [byteOffset, [length]]) */
+ RootedObject proto(cx);
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return nullptr;
+
+ int32_t byteOffset = 0;
+ if (args.hasDefined(1)) {
+ if (!ToInt32(cx, args[1], &byteOffset))
+ return nullptr;
+ if (byteOffset < 0) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_NEGATIVE_ARG,
+ "1");
+ return nullptr;
+ }
+ }
+
+ int32_t length = -1;
+ if (args.hasDefined(2)) {
+ if (!ToInt32(cx, args[2], &length))
+ return nullptr;
+ if (length < 0) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_NEGATIVE_ARG,
+ "2");
+ return nullptr;
+ }
+ }
+
+ return fromBufferWithProto(cx, dataObj, byteOffset, length, proto);
+ }
+
+ public:
+ static JSObject*
+ fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt) {
+ return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, nullptr);
+ }
+
+ static JSObject*
+ fromBufferWithProto(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt,
+ HandleObject proto)
+ {
+ if (bufobj->is<ProxyObject>()) {
+ /*
+ * Normally, NonGenericMethodGuard handles the case of transparent
+ * wrappers. However, we have a peculiar situation: we want to
+ * construct the new typed array in the compartment of the buffer,
+ * so that the typed array can point directly at their buffer's
+ * data without crossing compartment boundaries. So we use the
+ * machinery underlying NonGenericMethodGuard directly to proxy the
+ * native call. We will end up with a wrapper in the origin
+ * compartment for a view in the target compartment referencing the
+ * ArrayBufferObject in that same compartment.
+ */
+ JSObject* wrapped = CheckedUnwrap(bufobj);
+ if (!wrapped) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return nullptr;
+ }
+
+ if (!IsAnyArrayBuffer(wrapped)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr; // must be arrayBuffer
+ }
+
+ /*
+ * And for even more fun, the new view's prototype should be
+ * set to the origin compartment's prototype object, not the
+ * target's (specifically, the actual view in the target
+ * compartment will use as its prototype a wrapper around the
+ * origin compartment's view.prototype object).
+ *
+ * Rather than hack some crazy solution together, implement
+ * this all using a private helper function, created when
+ * ArrayBufferObject was initialized and cached in the global.
+ * This reuses all the existing cross-compartment crazy so we
+ * don't have to do anything *uniquely* crazy here.
+ */
+
+ RootedObject protoRoot(cx, proto);
+ if (!protoRoot) {
+ if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &protoRoot))
+ return nullptr;
+ }
+
+ FixedInvokeArgs<3> args(cx);
+
+ args[0].setNumber(byteOffset);
+ args[1].setInt32(lengthInt);
+ args[2].setObject(*protoRoot);
+
+ RootedValue fval(cx);
+ if (!getOrCreateCreateArrayFromBufferFunction(cx, &fval))
+ return nullptr;
+
+ RootedValue thisv(cx, ObjectValue(*bufobj));
+ RootedValue rval(cx);
+ if (!js::Call(cx, fval, thisv, args, &rval))
+ return nullptr;
+
+ return &rval.toObject();
+ }
+
+ if (!IsAnyArrayBuffer(bufobj)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return nullptr; // must be arrayBuffer
+ }
+
+ Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
+ if (IsArrayBuffer(bufobj)) {
+ ArrayBufferObject& buf = AsArrayBuffer(bufobj);
+ if (buf.isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+
+ buffer = static_cast<ArrayBufferObjectMaybeShared*>(&buf);
+ } else {
+ buffer = static_cast<ArrayBufferObjectMaybeShared*>(&AsSharedArrayBuffer(bufobj));
+ }
+
+ if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
+ return nullptr; // invalid byteOffset
+ }
+
+ uint32_t len;
+ if (lengthInt == -1) {
+ len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
+ if (len * sizeof(NativeType) != buffer->byteLength() - byteOffset) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
+ return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N
+ }
+ } else {
+ len = uint32_t(lengthInt);
+ }
+
+ // Go slowly and check for overflow.
+ uint32_t arrayByteLength = len * sizeof(NativeType);
+ if (len >= INT32_MAX / sizeof(NativeType) || byteOffset >= INT32_MAX - arrayByteLength) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
+ return nullptr; // overflow when calculating byteOffset + len * sizeof(NativeType)
+ }
+
+ if (arrayByteLength + byteOffset > buffer->byteLength()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
+ return nullptr; // byteOffset + len is too big for the arraybuffer
+ }
+
+ return makeInstance(cx, buffer, byteOffset, len, proto);
+ }
+
+ static bool
+ maybeCreateArrayBuffer(JSContext* cx, uint32_t count, uint32_t unit,
+ HandleObject nonDefaultProto,
+ MutableHandle<ArrayBufferObject*> buffer)
+ {
+ if (count >= INT32_MAX / unit) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NEED_DIET,
+ "size and count");
+ return false;
+ }
+ uint32_t byteLength = count * unit;
+
+ MOZ_ASSERT(byteLength < INT32_MAX);
+ static_assert(INLINE_BUFFER_LIMIT % sizeof(NativeType) == 0,
+ "ArrayBuffer inline storage shouldn't waste any space");
+
+ if (!nonDefaultProto && byteLength <= INLINE_BUFFER_LIMIT) {
+ // The array's data can be inline, and the buffer created lazily.
+ return true;
+ }
+
+ ArrayBufferObject* buf = ArrayBufferObject::create(cx, byteLength, nonDefaultProto);
+ if (!buf)
+ return false;
+
+ buffer.set(buf);
+ return true;
+ }
+
+ static JSObject*
+ fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr)
+ {
+ RootedObject proto(cx);
+ if (!GetPrototypeForInstance(cx, newTarget, &proto))
+ return nullptr;
+
+ Rooted<ArrayBufferObject*> buffer(cx);
+ if (!maybeCreateArrayBuffer(cx, nelements, BYTES_PER_ELEMENT, nullptr, &buffer))
+ return nullptr;
+
+ return makeInstance(cx, buffer, 0, nelements, proto);
+ }
+
+ static bool
+ AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
+ uint32_t count, uint32_t unit,
+ MutableHandle<ArrayBufferObject*> buffer);
+
+ static bool
+ CloneArrayBufferNoCopy(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
+ bool isWrapped, uint32_t srcByteOffset, uint32_t srcLength,
+ SpeciesConstructorOverride override,
+ MutableHandle<ArrayBufferObject*> buffer);
+
+ static JSObject*
+ fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr);
+
+ static JSObject*
+ fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped, HandleObject newTarget);
+
+ static JSObject*
+ fromObject(JSContext* cx, HandleObject other, HandleObject newTarget);
+
+ static const NativeType
+ getIndex(JSObject* obj, uint32_t index)
+ {
+ TypedArrayObject& tarray = obj->as<TypedArrayObject>();
+ MOZ_ASSERT(index < tarray.length());
+ return jit::AtomicOperations::loadSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index);
+ }
+
+ static void
+ setIndex(TypedArrayObject& tarray, uint32_t index, NativeType val)
+ {
+ MOZ_ASSERT(index < tarray.length());
+ jit::AtomicOperations::storeSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index, val);
+ }
+
+ static Value getIndexValue(JSObject* tarray, uint32_t index);
+};
+
+#define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \
+ typedef TypedArrayObjectTemplate<T> N##Array;
+JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPE_FOR_TYPED_ARRAY)
+#undef CREATE_TYPE_FOR_TYPED_ARRAY
+
+} /* anonymous namespace */
+
+TypedArrayObject*
+js::TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj, int32_t len)
+{
+ MOZ_ASSERT(templateObj->is<TypedArrayObject>());
+ TypedArrayObject* tobj = &templateObj->as<TypedArrayObject>();
+
+ switch (tobj->type()) {
+#define CREATE_TYPED_ARRAY(T, N) \
+ case Scalar::N: \
+ return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, len);
+JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
+#undef CREATE_TYPED_ARRAY
+ default:
+ MOZ_CRASH("Unsupported TypedArray type");
+ }
+}
+
+template<typename T>
+struct TypedArrayObject::OfType
+{
+ typedef TypedArrayObjectTemplate<T> Type;
+};
+
+// ES 2016 draft Mar 25, 2016 24.1.1.1.
+// byteLength = count * unit
+template<typename T>
+/* static */ bool
+TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
+ uint32_t count, uint32_t unit,
+ MutableHandle<ArrayBufferObject*> buffer)
+{
+ // ES 2016 draft Mar 25, 2016 24.1.1.1 step 1 (partially).
+ // ES 2016 draft Mar 25, 2016 9.1.14 steps 1-2.
+ MOZ_ASSERT(ctor.isObject());
+ RootedObject proto(cx);
+ RootedObject ctorObj(cx, &ctor.toObject());
+ if (!GetPrototypeFromConstructor(cx, ctorObj, &proto))
+ return false;
+ JSObject* arrayBufferProto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
+ if (!arrayBufferProto)
+ return false;
+ if (proto == arrayBufferProto)
+ proto = nullptr;
+
+ // ES 2016 draft Mar 25, 2016 24.1.1.1 steps 1 (remaining part), 2-6.
+ if (!maybeCreateArrayBuffer(cx, count, unit, proto, buffer))
+ return false;
+
+ return true;
+}
+
+static bool
+IsArrayBufferConstructor(const Value& v)
+{
+ return v.isObject() &&
+ v.toObject().is<JSFunction>() &&
+ v.toObject().as<JSFunction>().isNative() &&
+ v.toObject().as<JSFunction>().native() == ArrayBufferObject::class_constructor;
+}
+
+static bool
+IsArrayBufferSpecies(JSContext* cx, HandleObject origBuffer)
+{
+ RootedValue ctor(cx);
+ if (!GetPropertyPure(cx, origBuffer, NameToId(cx->names().constructor), ctor.address()))
+ return false;
+
+ if (!IsArrayBufferConstructor(ctor))
+ return false;
+
+ RootedObject ctorObj(cx, &ctor.toObject());
+ RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
+ JSFunction* getter;
+ if (!GetGetterPure(cx, ctorObj, speciesId, &getter))
+ return false;
+
+ if (!getter)
+ return false;
+
+ return IsSelfHostedFunctionWithName(getter, cx->names().ArrayBufferSpecies);
+}
+
+static bool
+GetSpeciesConstructor(JSContext* cx, HandleObject obj, bool isWrapped,
+ SpeciesConstructorOverride override, MutableHandleValue ctor)
+{
+ if (!isWrapped) {
+ if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
+ return false;
+ RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
+ // The second disjunct is an optimization.
+ if (override == SpeciesConstructorOverride::ArrayBuffer || IsArrayBufferSpecies(cx, obj))
+ ctor.set(defaultCtor);
+ else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
+ return false;
+
+ return true;
+ }
+
+ {
+ JSAutoCompartment ac(cx, obj);
+ if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
+ return false;
+ RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
+ if (override == SpeciesConstructorOverride::ArrayBuffer)
+ ctor.set(defaultCtor);
+ else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
+ return false;
+ }
+
+ return JS_WrapValue(cx, ctor);
+}
+
+// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
+template<typename T>
+/* static */ bool
+TypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext* cx,
+ Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
+ bool isWrapped, uint32_t srcByteOffset,
+ uint32_t srcLength,
+ SpeciesConstructorOverride override,
+ MutableHandle<ArrayBufferObject*> buffer)
+{
+ // Step 1 (skipped).
+
+ // Step 2.a.
+ RootedValue cloneCtor(cx);
+ if (!GetSpeciesConstructor(cx, srcBuffer, isWrapped, override, &cloneCtor))
+ return false;
+
+ // Step 2.b.
+ if (srcBuffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Steps 3-4 (skipped).
+
+ // Steps 5.
+ if (!AllocateArrayBuffer(cx, cloneCtor, srcLength, 1, buffer))
+ return false;
+
+ // Step 6.
+ if (srcBuffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Steps 7-8 (done in caller).
+
+ // Step 9.
+ return true;
+}
+
+template<typename T>
+/* static */ JSObject*
+TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
+ HandleObject newTarget /* = nullptr */)
+{
+ // Allow nullptr newTarget for FriendAPI methods, which don't care about
+ // subclassing.
+ if (other->is<TypedArrayObject>())
+ return fromTypedArray(cx, other, /* wrapped= */ false, newTarget);
+
+ if (other->is<WrapperObject>() && UncheckedUnwrap(other)->is<TypedArrayObject>())
+ return fromTypedArray(cx, other, /* wrapped= */ true, newTarget);
+
+ return fromObject(cx, other, newTarget);
+}
+
+// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 22.2.4.3.
+template<typename T>
+/* static */ JSObject*
+TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped,
+ HandleObject newTarget)
+{
+ // Step 1.
+ MOZ_ASSERT_IF(!isWrapped, other->is<TypedArrayObject>());
+ MOZ_ASSERT_IF(isWrapped,
+ other->is<WrapperObject>() &&
+ UncheckedUnwrap(other)->is<TypedArrayObject>());
+
+ // Step 2 (done in caller).
+
+ // Step 4 (partially).
+ RootedObject proto(cx);
+ if (!GetPrototypeForInstance(cx, newTarget, &proto))
+ return nullptr;
+
+ // Step 5.
+ Rooted<TypedArrayObject*> srcArray(cx);
+ if (!isWrapped) {
+ srcArray = &other->as<TypedArrayObject>();
+ if (!TypedArrayObject::ensureHasBuffer(cx, srcArray))
+ return nullptr;
+ } else {
+ RootedObject unwrapped(cx, CheckedUnwrap(other));
+ if (!unwrapped) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return nullptr;
+ }
+
+ JSAutoCompartment ac(cx, unwrapped);
+
+ srcArray = &unwrapped->as<TypedArrayObject>();
+ if (!TypedArrayObject::ensureHasBuffer(cx, srcArray))
+ return nullptr;
+ }
+
+ // Step 6.
+ Rooted<ArrayBufferObjectMaybeShared*> srcData(cx, srcArray->bufferEither());
+
+ // Step 7.
+ if (srcData->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+
+ // Steps 10.
+ uint32_t elementLength = srcArray->length();
+
+ // Steps 11-12.
+ Scalar::Type srcType = srcArray->type();
+
+ // Step 13 (skipped).
+
+ // Step 14.
+ uint32_t srcByteOffset = srcArray->byteOffset();
+
+ // Step 17, modified for SharedArrayBuffer.
+ bool isShared = srcArray->isSharedMemory();
+ SpeciesConstructorOverride override = isShared ? SpeciesConstructorOverride::ArrayBuffer
+ : SpeciesConstructorOverride::None;
+
+ // Steps 8-9, 17.
+ Rooted<ArrayBufferObject*> buffer(cx);
+ if (ArrayTypeID() == srcType) {
+ // Step 17.a.
+ uint32_t srcLength = srcArray->byteLength();
+
+ // Step 17.b, modified for SharedArrayBuffer
+ if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, srcLength, override,
+ &buffer))
+ {
+ return nullptr;
+ }
+ } else {
+ // Step 18.a, modified for SharedArrayBuffer
+ RootedValue bufferCtor(cx);
+ if (!GetSpeciesConstructor(cx, srcData, isWrapped, override, &bufferCtor))
+ return nullptr;
+
+ // Step 15-16, 18.b.
+ if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, BYTES_PER_ELEMENT, &buffer))
+ return nullptr;
+
+ // Step 18.c.
+ if (srcArray->hasDetachedBuffer()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+ }
+
+ // Steps 3, 4 (remaining part), 19-22.
+ Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, elementLength, proto));
+ if (!obj)
+ return nullptr;
+
+ // Step 18.d-g or 24.1.1.4 step 11.
+ if (!TypedArrayMethods<TypedArrayObject>::setFromTypedArray(cx, obj, srcArray))
+ return nullptr;
+
+ // Step 23.
+ return obj;
+}
+
+static MOZ_ALWAYS_INLINE bool
+IsOptimizableInit(JSContext* cx, HandleObject iterable, bool* optimized)
+{
+ MOZ_ASSERT(!*optimized);
+
+ if (!IsPackedArray(iterable))
+ return true;
+
+ ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
+ if (!stubChain)
+ return false;
+
+ return stubChain->tryOptimizeArray(cx, iterable.as<ArrayObject>(), optimized);
+}
+
+// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
+// 22.2.4.4 TypedArray ( object )
+template<typename T>
+/* static */ JSObject*
+TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, HandleObject newTarget)
+{
+ // Steps 1-2 (Already performed in caller).
+
+ // Steps 3-4 (Allocation deferred until later).
+ RootedObject proto(cx);
+ if (!GetPrototypeForInstance(cx, newTarget, &proto))
+ return nullptr;
+
+ bool optimized = false;
+ if (!IsOptimizableInit(cx, other, &optimized))
+ return nullptr;
+
+ // Fast path when iterable is a packed array using the default iterator.
+ if (optimized) {
+ // Step 6.a (We don't need to call IterableToList for the fast path).
+ RootedArrayObject array(cx, &other->as<ArrayObject>());
+
+ // Step 6.b.
+ uint32_t len = array->getDenseInitializedLength();
+
+ // Step 6.c.
+ Rooted<ArrayBufferObject*> buffer(cx);
+ if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
+ return nullptr;
+
+ Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
+ if (!obj)
+ return nullptr;
+
+ // Steps 6.d-e.
+ if (!TypedArrayMethods<TypedArrayObject>::initFromIterablePackedArray(cx, obj, array))
+ return nullptr;
+
+ // Step 6.f (The assertion isn't applicable for the fast path).
+
+ // Step 6.g.
+ return obj;
+ }
+
+ // Step 5.
+ RootedValue callee(cx);
+ RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
+ if (!GetProperty(cx, other, other, iteratorId, &callee))
+ return nullptr;
+
+ // Steps 6-8.
+ RootedObject arrayLike(cx);
+ if (!callee.isNullOrUndefined()) {
+ // Throw if other[Symbol.iterator] isn't callable.
+ if (!callee.isObject() || !callee.toObject().isCallable()) {
+ RootedValue otherVal(cx, ObjectValue(*other));
+ UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, otherVal, nullptr);
+ if (!bytes)
+ return nullptr;
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
+ bytes.get());
+ return nullptr;
+ }
+
+ FixedInvokeArgs<2> args2(cx);
+ args2[0].setObject(*other);
+ args2[1].set(callee);
+
+ // Step 6.a.
+ RootedValue rval(cx);
+ if (!CallSelfHostedFunction(cx, cx->names().IterableToList, UndefinedHandleValue, args2,
+ &rval))
+ {
+ return nullptr;
+ }
+
+ // Steps 6.b-g (Implemented in steps 9-13 below).
+ arrayLike = &rval.toObject();
+ } else {
+ // Step 7 is an assertion: object is not an Iterator. Testing this is
+ // literally the very last thing we did, so we don't assert here.
+
+ // Step 8.
+ arrayLike = other;
+ }
+
+ // Step 9.
+ uint32_t len;
+ if (!GetLengthProperty(cx, arrayLike, &len))
+ return nullptr;
+
+ // Step 10.
+ Rooted<ArrayBufferObject*> buffer(cx);
+ if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
+ return nullptr;
+
+ Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
+ if (!obj)
+ return nullptr;
+
+ // Steps 11-12.
+ if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, arrayLike, len))
+ return nullptr;
+
+ // Step 13.
+ return obj;
+}
+
+bool
+TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT,
+ args.isConstructing() ? "construct" : "call");
+ return false;
+}
+
+/* static */ bool
+TypedArrayObject::GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
+ MutableHandleObject res)
+{
+#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
+ if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
+ size_t nbytes; \
+ if (!js::CalculateAllocSize<T>(len, &nbytes)) \
+ return true; \
+ \
+ if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \
+ res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \
+ return !!res; \
+ } \
+ }
+JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
+#undef CHECK_TYPED_ARRAY_CONSTRUCTOR
+ return true;
+}
+
+/*
+ * These next 3 functions are brought to you by the buggy GCC we use to build
+ * B2G ICS. Older GCC versions have a bug in which they fail to compile
+ * reinterpret_casts of templated functions with the message: "insufficient
+ * contextual information to determine type". JS_PSG needs to
+ * reinterpret_cast<JSGetterOp>, so this causes problems for us here.
+ *
+ * We could restructure all this code to make this nicer, but since ICS isn't
+ * going to be around forever (and since this bug is fixed with the newer GCC
+ * versions we use on JB and KK), the workaround here is designed for ease of
+ * removal. When you stop seeing ICS Emulator builds on TBPL, remove these 3
+ * JSNatives and insert the templated callee directly into the JS_PSG below.
+ */
+static bool
+TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp); \
+}
+
+static bool
+TypedArray_byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ return TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>(cx, argc, vp);
+}
+
+static bool
+TypedArray_byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ return TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx, argc, vp);
+}
+
+bool
+BufferGetterImpl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
+ Rooted<TypedArrayObject*> tarray(cx, &args.thisv().toObject().as<TypedArrayObject>());
+ if (!TypedArrayObject::ensureHasBuffer(cx, tarray))
+ return false;
+ args.rval().set(TypedArrayObject::bufferValue(tarray));
+ return true;
+}
+
+/*static*/ bool
+js::TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<TypedArrayObject::is, BufferGetterImpl>(cx, args);
+}
+
+/* static */ const JSPropertySpec
+TypedArrayObject::protoAccessors[] = {
+ JS_PSG("length", TypedArray_lengthGetter, 0),
+ JS_PSG("buffer", TypedArray_bufferGetter, 0),
+ JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
+ JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
+ JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
+ JS_PS_END
+};
+
+/* static */ bool
+TypedArrayObject::set(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<TypedArrayObject::is,
+ TypedArrayMethods<TypedArrayObject>::set>(cx, args);
+}
+
+/* static */ const JSFunctionSpec
+TypedArrayObject::protoFunctions[] = {
+ JS_SELF_HOSTED_FN("subarray", "TypedArraySubarray", 2, 0),
+#if 0 /* disabled until perf-testing is completed */
+ JS_SELF_HOSTED_FN("set", "TypedArraySet", 2, 0),
+#else
+ JS_FN("set", TypedArrayObject::set, 1, 0),
+#endif
+ JS_SELF_HOSTED_FN("copyWithin", "TypedArrayCopyWithin", 3, 0),
+ JS_SELF_HOSTED_FN("every", "TypedArrayEvery", 1, 0),
+ JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
+ JS_SELF_HOSTED_FN("filter", "TypedArrayFilter", 1, 0),
+ JS_SELF_HOSTED_FN("find", "TypedArrayFind", 1, 0),
+ JS_SELF_HOSTED_FN("findIndex", "TypedArrayFindIndex", 1, 0),
+ JS_SELF_HOSTED_FN("forEach", "TypedArrayForEach", 1, 0),
+ JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
+ JS_SELF_HOSTED_FN("join", "TypedArrayJoin", 1, 0),
+ JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 2, 0),
+ JS_SELF_HOSTED_FN("map", "TypedArrayMap", 1, 0),
+ JS_SELF_HOSTED_FN("reduce", "TypedArrayReduce", 1, 0),
+ JS_SELF_HOSTED_FN("reduceRight", "TypedArrayReduceRight", 1, 0),
+ JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
+ JS_SELF_HOSTED_FN("slice", "TypedArraySlice", 2, 0),
+ JS_SELF_HOSTED_FN("some", "TypedArraySome", 1, 0),
+ JS_SELF_HOSTED_FN("sort", "TypedArraySort", 1, 0),
+ JS_SELF_HOSTED_FN("entries", "TypedArrayEntries", 0, 0),
+ JS_SELF_HOSTED_FN("keys", "TypedArrayKeys", 0, 0),
+ JS_SELF_HOSTED_FN("values", "TypedArrayValues", 0, 0),
+ JS_SELF_HOSTED_SYM_FN(iterator, "TypedArrayValues", 0, 0),
+ JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
+ JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0),
+ JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0),
+ JS_FS_END
+};
+
+/* static */ const JSFunctionSpec
+TypedArrayObject::staticFunctions[] = {
+ JS_SELF_HOSTED_FN("from", "TypedArrayStaticFrom", 3, 0),
+ JS_SELF_HOSTED_FN("of", "TypedArrayStaticOf", 0, 0),
+ JS_FS_END
+};
+
+/* static */ const JSPropertySpec
+TypedArrayObject::staticProperties[] = {
+ JS_SELF_HOSTED_SYM_GET(species, "TypedArraySpecies", 0),
+ JS_PS_END
+};
+
+static const ClassSpec
+TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
+ GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
+ GenericCreatePrototype,
+ TypedArrayObject::staticFunctions,
+ TypedArrayObject::staticProperties,
+ TypedArrayObject::protoFunctions,
+ TypedArrayObject::protoAccessors,
+ nullptr,
+ ClassSpec::DontDefineConstructor
+};
+
+/* static */ const Class
+TypedArrayObject::sharedTypedArrayPrototypeClass = {
+ // Actually ({}).toString.call(%TypedArray%.prototype) should throw,
+ // because %TypedArray%.prototype lacks the the typed array internal
+ // slots. (It's not clear this is desirable -- particularly applied to
+ // the actual typed array prototypes, see below -- but it's what ES6
+ // draft 20140824 requires.) But this is about as much as we can do
+ // until we implement @@toStringTag.
+ "???",
+ JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray),
+ JS_NULL_CLASS_OPS,
+ &TypedArrayObjectSharedTypedArrayPrototypeClassSpec
+};
+
+template<typename T>
+bool
+ArrayBufferObject::createTypedArrayFromBufferImpl(JSContext* cx, const CallArgs& args)
+{
+ typedef TypedArrayObjectTemplate<T> ArrayType;
+ MOZ_ASSERT(IsAnyArrayBuffer(args.thisv()));
+ MOZ_ASSERT(args.length() == 3);
+
+ Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
+ Rooted<JSObject*> proto(cx, &args[2].toObject());
+
+ Rooted<JSObject*> obj(cx);
+ double byteOffset = args[0].toNumber();
+ MOZ_ASSERT(0 <= byteOffset);
+ MOZ_ASSERT(byteOffset <= UINT32_MAX);
+ MOZ_ASSERT(byteOffset == uint32_t(byteOffset));
+ obj = ArrayType::fromBufferWithProto(cx, buffer, uint32_t(byteOffset), args[1].toInt32(),
+ proto);
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+}
+
+template<typename T>
+bool
+ArrayBufferObject::createTypedArrayFromBuffer(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsAnyArrayBuffer, createTypedArrayFromBufferImpl<T> >(cx, args);
+}
+
+// this default implementation is only valid for integer types
+// less than 32-bits in size.
+template<typename NativeType>
+Value
+TypedArrayObjectTemplate<NativeType>::getIndexValue(JSObject* tarray, uint32_t index)
+{
+ static_assert(sizeof(NativeType) < 4,
+ "this method must only handle NativeType values that are "
+ "always exact int32_t values");
+
+ return Int32Value(getIndex(tarray, index));
+}
+
+namespace {
+
+// and we need to specialize for 32-bit integers and floats
+template<>
+Value
+TypedArrayObjectTemplate<int32_t>::getIndexValue(JSObject* tarray, uint32_t index)
+{
+ return Int32Value(getIndex(tarray, index));
+}
+
+template<>
+Value
+TypedArrayObjectTemplate<uint32_t>::getIndexValue(JSObject* tarray, uint32_t index)
+{
+ uint32_t val = getIndex(tarray, index);
+ return NumberValue(val);
+}
+
+template<>
+Value
+TypedArrayObjectTemplate<float>::getIndexValue(JSObject* tarray, uint32_t index)
+{
+ float val = getIndex(tarray, index);
+ double dval = val;
+
+ /*
+ * Doubles in typed arrays could be typed-punned arrays of integers. This
+ * could allow user code to break the engine-wide invariant that only
+ * canonical nans are stored into jsvals, which means user code could
+ * confuse the engine into interpreting a double-typed jsval as an
+ * object-typed jsval.
+ *
+ * This could be removed for platforms/compilers known to convert a 32-bit
+ * non-canonical nan to a 64-bit canonical nan.
+ */
+ return DoubleValue(CanonicalizeNaN(dval));
+}
+
+template<>
+Value
+TypedArrayObjectTemplate<double>::getIndexValue(JSObject* tarray, uint32_t index)
+{
+ double val = getIndex(tarray, index);
+
+ /*
+ * Doubles in typed arrays could be typed-punned arrays of integers. This
+ * could allow user code to break the engine-wide invariant that only
+ * canonical nans are stored into jsvals, which means user code could
+ * confuse the engine into interpreting a double-typed jsval as an
+ * object-typed jsval.
+ */
+ return DoubleValue(CanonicalizeNaN(val));
+}
+
+} /* anonymous namespace */
+
+static NewObjectKind
+DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
+{
+ if (!proto && byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH)
+ return SingletonObject;
+ jsbytecode* pc;
+ JSScript* script = cx->currentScript(&pc);
+ if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &DataViewObject::class_))
+ return SingletonObject;
+ return GenericObject;
+}
+
+DataViewObject*
+DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
+ Handle<ArrayBufferObject*> arrayBuffer, JSObject* protoArg)
+{
+ if (arrayBuffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return nullptr;
+ }
+
+ MOZ_ASSERT(byteOffset <= INT32_MAX);
+ MOZ_ASSERT(byteLength <= INT32_MAX);
+ MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
+ MOZ_ASSERT(!arrayBuffer || !arrayBuffer->is<SharedArrayBufferObject>());
+
+ RootedObject proto(cx, protoArg);
+ RootedObject obj(cx);
+
+ NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
+ obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+ if (!obj)
+ return nullptr;
+
+ if (!proto) {
+ if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
+ MOZ_ASSERT(obj->isSingleton());
+ } else {
+ jsbytecode* pc;
+ RootedScript script(cx, cx->currentScript(&pc));
+ if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
+ newKind == SingletonObject))
+ {
+ return nullptr;
+ }
+ }
+ }
+
+ // Caller should have established these preconditions, and no
+ // (non-self-hosted) JS code has had an opportunity to run so nothing can
+ // have invalidated them.
+ MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
+ MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
+
+ DataViewObject& dvobj = obj->as<DataViewObject>();
+ dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
+ dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength));
+ dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
+ dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset);
+
+ // Include a barrier if the data view's data pointer is in the nursery, as
+ // is done for typed arrays.
+ if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer()))
+ cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+
+ // Verify that the private slot is at the expected place
+ MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
+
+ if (!arrayBuffer->addView(cx, &dvobj))
+ return nullptr;
+
+ return &dvobj;
+}
+
+bool
+DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
+ uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
+{
+ if (!IsArrayBuffer(bufobj)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
+ "DataView", "ArrayBuffer", bufobj->getClass()->name);
+ return false;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
+ uint32_t byteOffset = 0;
+ uint32_t byteLength = buffer->byteLength();
+
+ if (args.length() > 1) {
+ if (!ToUint32(cx, args[1], &byteOffset))
+ return false;
+ if (byteOffset > INT32_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
+ "1");
+ return false;
+ }
+ }
+
+ if (buffer->isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ if (args.length() > 1) {
+ if (byteOffset > byteLength) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
+ "1");
+ return false;
+ }
+
+ if (args.get(2).isUndefined()) {
+ byteLength -= byteOffset;
+ } else {
+ if (!ToUint32(cx, args[2], &byteLength))
+ return false;
+ if (byteLength > INT32_MAX) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
+ return false;
+ }
+
+ MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
+ "can't overflow: both numbers are less than INT32_MAX");
+ if (byteOffset + byteLength > buffer->byteLength()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+ return false;
+ }
+ }
+ }
+
+ /* The sum of these cannot overflow a uint32_t */
+ MOZ_ASSERT(byteOffset <= INT32_MAX);
+ MOZ_ASSERT(byteLength <= INT32_MAX);
+
+
+ *byteOffsetPtr = byteOffset;
+ *byteLengthPtr = byteLength;
+
+ return true;
+}
+
+bool
+DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args)
+{
+ MOZ_ASSERT(args.isConstructing());
+ assertSameCompartment(cx, bufobj);
+
+ uint32_t byteOffset, byteLength;
+ if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
+ return false;
+
+ RootedObject proto(cx);
+ RootedObject newTarget(cx, &args.newTarget().toObject());
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
+ JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+}
+
+// Create a DataView object in another compartment.
+//
+// ES6 supports creating a DataView in global A (using global A's DataView
+// constructor) backed by an ArrayBuffer created in global B.
+//
+// Our DataViewObject implementation doesn't support a DataView in
+// compartment A backed by an ArrayBuffer in compartment B. So in this case,
+// we create the DataView in B (!) and return a cross-compartment wrapper.
+//
+// Extra twist: the spec says the new DataView's [[Prototype]] must be
+// A's DataView.prototype. So even though we're creating the DataView in B,
+// its [[Prototype]] must be (a cross-compartment wrapper for) the
+// DataView.prototype in A.
+//
+// As if this were not confusing enough, the way we actually do this is also
+// tricky. We call compartment A's createDataViewForThis method, passing it
+// bufobj as `this`. That calls ArrayBufferObject::createDataViewForThis(),
+// which uses CallNonGenericMethod to switch to compartment B so that
+// the new DataView is created there.
+bool
+DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args)
+{
+ MOZ_ASSERT(args.isConstructing());
+ MOZ_ASSERT(bufobj->is<WrapperObject>());
+
+ JSObject* unwrapped = CheckedUnwrap(bufobj);
+ if (!unwrapped) {
+ JS_ReportErrorASCII(cx, "Permission denied to access object");
+ return false;
+ }
+
+ // NB: This entails the IsArrayBuffer check
+ uint32_t byteOffset, byteLength;
+ if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength))
+ return false;
+
+ // Make sure to get the [[Prototype]] for the created view from this
+ // compartment.
+ RootedObject proto(cx);
+ RootedObject newTarget(cx, &args.newTarget().toObject());
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+ return false;
+
+ Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+ if (!proto) {
+ proto = global->getOrCreateDataViewPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
+ FixedInvokeArgs<3> args2(cx);
+
+ args2[0].set(PrivateUint32Value(byteOffset));
+ args2[1].set(PrivateUint32Value(byteLength));
+ args2[2].setObject(*proto);
+
+ RootedValue fval(cx, global->createDataViewForThis());
+ RootedValue thisv(cx, ObjectValue(*bufobj));
+ return js::Call(cx, fval, thisv, args2, args.rval());
+}
+
+bool
+DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "DataView"))
+ return false;
+
+ RootedObject bufobj(cx);
+ if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
+ return false;
+
+ if (bufobj->is<WrapperObject>())
+ return constructWrapped(cx, bufobj, args);
+ return constructSameCompartment(cx, bufobj, args);
+}
+
+template <typename NativeType>
+/* static */ uint8_t*
+DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, double offset)
+{
+ MOZ_ASSERT(offset >= 0);
+
+ const size_t TypeSize = sizeof(NativeType);
+ if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
+ "1");
+ return nullptr;
+ }
+
+ MOZ_ASSERT(offset < UINT32_MAX);
+ return static_cast<uint8_t*>(obj->dataPointer()) + uint32_t(offset);
+}
+
+static inline bool
+needToSwapBytes(bool littleEndian)
+{
+#if MOZ_LITTLE_ENDIAN
+ return !littleEndian;
+#else
+ return littleEndian;
+#endif
+}
+
+static inline uint8_t
+swapBytes(uint8_t x)
+{
+ return x;
+}
+
+static inline uint16_t
+swapBytes(uint16_t x)
+{
+ return ((x & 0xff) << 8) | (x >> 8);
+}
+
+static inline uint32_t
+swapBytes(uint32_t x)
+{
+ return ((x & 0xff) << 24) |
+ ((x & 0xff00) << 8) |
+ ((x & 0xff0000) >> 8) |
+ ((x & 0xff000000) >> 24);
+}
+
+static inline uint64_t
+swapBytes(uint64_t x)
+{
+ uint32_t a = x & UINT32_MAX;
+ uint32_t b = x >> 32;
+ return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
+}
+
+template <typename DataType> struct DataToRepType { typedef DataType result; };
+template <> struct DataToRepType<int8_t> { typedef uint8_t result; };
+template <> struct DataToRepType<uint8_t> { typedef uint8_t result; };
+template <> struct DataToRepType<int16_t> { typedef uint16_t result; };
+template <> struct DataToRepType<uint16_t> { typedef uint16_t result; };
+template <> struct DataToRepType<int32_t> { typedef uint32_t result; };
+template <> struct DataToRepType<uint32_t> { typedef uint32_t result; };
+template <> struct DataToRepType<float> { typedef uint32_t result; };
+template <> struct DataToRepType<double> { typedef uint64_t result; };
+
+template <typename DataType>
+struct DataViewIO
+{
+ typedef typename DataToRepType<DataType>::result ReadWriteType;
+
+ static void fromBuffer(DataType* dest, const uint8_t* unalignedBuffer, bool wantSwap)
+ {
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
+ memcpy((void*) dest, unalignedBuffer, sizeof(ReadWriteType));
+ if (wantSwap) {
+ ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
+ *rwDest = swapBytes(*rwDest);
+ }
+ }
+
+ static void toBuffer(uint8_t* unalignedBuffer, const DataType* src, bool wantSwap)
+ {
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
+ ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
+ if (wantSwap)
+ temp = swapBytes(temp);
+ memcpy(unalignedBuffer, (void*) &temp, sizeof(ReadWriteType));
+ }
+};
+
+static bool
+ToIndex(JSContext* cx, HandleValue v, double* index)
+{
+ if (v.isUndefined()) {
+ *index = 0.0;
+ return true;
+ }
+
+ double integerIndex;
+ if (!ToInteger(cx, v, &integerIndex))
+ return false;
+
+ // Inlined version of ToLength.
+ // 1. Already an integer
+ // 2. Step eliminates < 0, +0 == -0 with SameValueZero
+ // 3/4. Limit to <= 2^53-1, so everything above should fail.
+ if (integerIndex < 0 || integerIndex > 9007199254740991) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
+ return false;
+ }
+
+ *index = integerIndex;
+ return true;
+}
+
+template<typename NativeType>
+/* static */ bool
+DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, NativeType* val, const char* method)
+{
+ // Steps 1-2. done by the caller
+ // Step 3. unnecessary assert
+
+ // Step 4.
+ double getIndex;
+ if (!ToIndex(cx, args.get(0), &getIndex))
+ return false;
+
+ // Step 5.
+ bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
+
+ // Steps 6-7.
+ if (obj->arrayBuffer().isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Steps 8-12.
+ uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex);
+ if (!data)
+ return false;
+
+ // Step 13.
+ DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(isLittleEndian));
+ return true;
+}
+
+template <typename NativeType>
+static inline bool
+WebIDLCast(JSContext* cx, HandleValue value, NativeType* out)
+{
+ int32_t temp;
+ if (!ToInt32(cx, value, &temp))
+ return false;
+ // Technically, the behavior of assigning an out of range value to a signed
+ // variable is undefined. In practice, compilers seem to do what we want
+ // without issuing any warnings.
+ *out = static_cast<NativeType>(temp);
+ return true;
+}
+
+template <>
+inline bool
+WebIDLCast<float>(JSContext* cx, HandleValue value, float* out)
+{
+ double temp;
+ if (!ToNumber(cx, value, &temp))
+ return false;
+ *out = static_cast<float>(temp);
+ return true;
+}
+
+template <>
+inline bool
+WebIDLCast<double>(JSContext* cx, HandleValue value, double* out)
+{
+ return ToNumber(cx, value, out);
+}
+
+template<typename NativeType>
+/* static */ bool
+DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, const char* method)
+{
+ // Steps 1-2. done by the caller
+ // Step 3. unnecessary assert
+
+ // Step 4.
+ double getIndex;
+ if (!ToIndex(cx, args.get(0), &getIndex))
+ return false;
+
+ // Step 5. Should just call ToNumber (unobservable)
+ NativeType value;
+ if (!WebIDLCast(cx, args.get(1), &value))
+ return false;
+
+#ifdef JS_MORE_DETERMINISTIC
+ // See the comment in ElementSpecific::doubleToNative.
+ if (TypeIsFloatingPoint<NativeType>())
+ value = JS::CanonicalizeNaN(value);
+#endif
+
+ // Step 6.
+ bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
+
+ // Steps 7-8.
+ if (obj->arrayBuffer().isDetached()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+ return false;
+ }
+
+ // Steps 9-13.
+ uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex);
+ if (!data)
+ return false;
+
+ // Step 14.
+ DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(isLittleEndian));
+ return true;
+}
+
+bool
+DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ int8_t val;
+ if (!read(cx, thisView, args, &val, "getInt8"))
+ return false;
+ args.rval().setInt32(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getInt8Impl>(cx, args);
+}
+
+bool
+DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ uint8_t val;
+ if (!read(cx, thisView, args, &val, "getUint8"))
+ return false;
+ args.rval().setInt32(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getUint8Impl>(cx, args);
+}
+
+bool
+DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ int16_t val;
+ if (!read(cx, thisView, args, &val, "getInt16"))
+ return false;
+ args.rval().setInt32(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getInt16Impl>(cx, args);
+}
+
+bool
+DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ uint16_t val;
+ if (!read(cx, thisView, args, &val, "getUint16"))
+ return false;
+ args.rval().setInt32(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getUint16Impl>(cx, args);
+}
+
+bool
+DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ int32_t val;
+ if (!read(cx, thisView, args, &val, "getInt32"))
+ return false;
+ args.rval().setInt32(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getInt32Impl>(cx, args);
+}
+
+bool
+DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ uint32_t val;
+ if (!read(cx, thisView, args, &val, "getUint32"))
+ return false;
+ args.rval().setNumber(val);
+ return true;
+}
+
+bool
+DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getUint32Impl>(cx, args);
+}
+
+bool
+DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ float val;
+ if (!read(cx, thisView, args, &val, "getFloat32"))
+ return false;
+
+ args.rval().setDouble(CanonicalizeNaN(val));
+ return true;
+}
+
+bool
+DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getFloat32Impl>(cx, args);
+}
+
+bool
+DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ double val;
+ if (!read(cx, thisView, args, &val, "getFloat64"))
+ return false;
+
+ args.rval().setDouble(CanonicalizeNaN(val));
+ return true;
+}
+
+bool
+DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getFloat64Impl>(cx, args);
+}
+
+bool
+DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<int8_t>(cx, thisView, args, "setInt8"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setInt8Impl>(cx, args);
+}
+
+bool
+DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<uint8_t>(cx, thisView, args, "setUint8"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setUint8Impl>(cx, args);
+}
+
+bool
+DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<int16_t>(cx, thisView, args, "setInt16"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setInt16Impl>(cx, args);
+}
+
+bool
+DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<uint16_t>(cx, thisView, args, "setUint16"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setUint16Impl>(cx, args);
+}
+
+bool
+DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<int32_t>(cx, thisView, args, "setInt32"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setInt32Impl>(cx, args);
+}
+
+bool
+DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<uint32_t>(cx, thisView, args, "setUint32"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setUint32Impl>(cx, args);
+}
+
+bool
+DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<float>(cx, thisView, args, "setFloat32"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setFloat32Impl>(cx, args);
+}
+
+bool
+DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args)
+{
+ MOZ_ASSERT(is(args.thisv()));
+
+ Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
+
+ if (!write<double>(cx, thisView, args, "setFloat64"))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, setFloat64Impl>(cx, args);
+}
+
+Value
+TypedArrayObject::getElement(uint32_t index)
+{
+ switch (type()) {
+ case Scalar::Int8:
+ return Int8Array::getIndexValue(this, index);
+ case Scalar::Uint8:
+ return Uint8Array::getIndexValue(this, index);
+ case Scalar::Int16:
+ return Int16Array::getIndexValue(this, index);
+ case Scalar::Uint16:
+ return Uint16Array::getIndexValue(this, index);
+ case Scalar::Int32:
+ return Int32Array::getIndexValue(this, index);
+ case Scalar::Uint32:
+ return Uint32Array::getIndexValue(this, index);
+ case Scalar::Float32:
+ return Float32Array::getIndexValue(this, index);
+ case Scalar::Float64:
+ return Float64Array::getIndexValue(this, index);
+ case Scalar::Uint8Clamped:
+ return Uint8ClampedArray::getIndexValue(this, index);
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+
+ MOZ_CRASH("Unknown TypedArray type");
+}
+
+void
+TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
+{
+ MOZ_ASSERT(index < obj.length());
+
+#ifdef JS_MORE_DETERMINISTIC
+ // See the comment in ElementSpecific::doubleToNative.
+ d = JS::CanonicalizeNaN(d);
+#endif
+
+ switch (obj.type()) {
+ case Scalar::Int8:
+ Int8Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Uint8:
+ Uint8Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Uint8Clamped:
+ Uint8ClampedArray::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Int16:
+ Int16Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Uint16:
+ Uint16Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Int32:
+ Int32Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Uint32:
+ Uint32Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Float32:
+ Float32Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Float64:
+ Float64Array::setIndexValue(obj, index, d);
+ return;
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+
+ MOZ_CRASH("Unknown TypedArray type");
+}
+
+/***
+ *** JS impl
+ ***/
+
+/*
+ * TypedArrayObject boilerplate
+ */
+
+#define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \
+ JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \
+ { \
+ return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements); \
+ } \
+ JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \
+ { \
+ return TypedArrayObjectTemplate<NativeType>::fromArray(cx, other); \
+ } \
+ JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \
+ HandleObject arrayBuffer, uint32_t byteOffset, int32_t length) \
+ { \
+ return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset, \
+ length); \
+ } \
+ JS_FRIEND_API(bool) JS_Is ## Name ## Array(JSObject* obj) \
+ { \
+ if (!(obj = CheckedUnwrap(obj))) \
+ return false; \
+ const Class* clasp = obj->getClass(); \
+ return clasp == TypedArrayObjectTemplate<NativeType>::instanceClass(); \
+ } \
+ JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \
+ { \
+ obj = CheckedUnwrap(obj); \
+ if (!obj) \
+ return nullptr; \
+ const Class* clasp = obj->getClass(); \
+ if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass()) \
+ return obj; \
+ return nullptr; \
+ } \
+ const js::Class* const js::detail::Name ## ArrayClassPtr = \
+ &js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];
+
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32, uint32_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
+
+#define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType) \
+ JS_FRIEND_API(JSObject*) JS_GetObjectAs ## Name ## Array(JSObject* obj, \
+ uint32_t* length, \
+ bool* isShared, \
+ ExternalType** data) \
+ { \
+ if (!(obj = CheckedUnwrap(obj))) \
+ return nullptr; \
+ \
+ const Class* clasp = obj->getClass(); \
+ if (clasp != TypedArrayObjectTemplate<InternalType>::instanceClass()) \
+ return nullptr; \
+ \
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>(); \
+ *length = tarr->length(); \
+ *isShared = tarr->isSharedMemory(); \
+ *data = static_cast<ExternalType*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared flag*/)); \
+ \
+ return obj; \
+ }
+
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int8, int8_t, int8_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8, uint8_t, uint8_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped, uint8_t, uint8_clamped)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16, int16_t, int16_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16, uint16_t, uint16_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
+
+static const ClassOps TypedArrayClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ TypedArrayObject::finalize, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ TypedArrayObject::trace, /* trace */
+};
+
+static const ClassExtension TypedArrayClassExtension = {
+ nullptr,
+ TypedArrayObject::objectMoved,
+};
+
+#define IMPL_TYPED_ARRAY_PROPERTIES(_type) \
+{ \
+JS_INT32_PS("BYTES_PER_ELEMENT", _type##Array::BYTES_PER_ELEMENT, \
+ JSPROP_READONLY | JSPROP_PERMANENT), \
+JS_PS_END \
+}
+
+static const JSPropertySpec static_prototype_properties[Scalar::MaxTypedArrayViewType][2] = {
+ IMPL_TYPED_ARRAY_PROPERTIES(Int8),
+ IMPL_TYPED_ARRAY_PROPERTIES(Uint8),
+ IMPL_TYPED_ARRAY_PROPERTIES(Int16),
+ IMPL_TYPED_ARRAY_PROPERTIES(Uint16),
+ IMPL_TYPED_ARRAY_PROPERTIES(Int32),
+ IMPL_TYPED_ARRAY_PROPERTIES(Uint32),
+ IMPL_TYPED_ARRAY_PROPERTIES(Float32),
+ IMPL_TYPED_ARRAY_PROPERTIES(Float64),
+ IMPL_TYPED_ARRAY_PROPERTIES(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \
+{ \
+ _type##Array::createConstructor, \
+ _type##Array::createPrototype, \
+ nullptr, \
+ static_prototype_properties[Scalar::Type::_type], \
+ nullptr, \
+ static_prototype_properties[Scalar::Type::_type], \
+ nullptr, \
+ JSProto_TypedArray \
+}
+
+static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_CLASS(_type) \
+{ \
+ #_type "Array", \
+ JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | \
+ JSCLASS_HAS_PRIVATE | \
+ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \
+ JSCLASS_DELAY_METADATA_BUILDER | \
+ JSCLASS_SKIP_NURSERY_FINALIZE | \
+ JSCLASS_BACKGROUND_FINALIZE, \
+ &TypedArrayClassOps, \
+ &TypedArrayObjectClassSpecs[Scalar::Type::_type], \
+ &TypedArrayClassExtension \
+}
+
+const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_CLASS(Int8),
+ IMPL_TYPED_ARRAY_CLASS(Uint8),
+ IMPL_TYPED_ARRAY_CLASS(Int16),
+ IMPL_TYPED_ARRAY_CLASS(Uint16),
+ IMPL_TYPED_ARRAY_CLASS(Int32),
+ IMPL_TYPED_ARRAY_CLASS(Uint32),
+ IMPL_TYPED_ARRAY_CLASS(Float32),
+ IMPL_TYPED_ARRAY_CLASS(Float64),
+ IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(_type) \
+{ \
+ DELEGATED_CLASSSPEC(TypedArrayObject::classes[Scalar::Type::_type].spec), \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ nullptr, \
+ JSProto_TypedArray | ClassSpec::IsDelegated \
+}
+
+static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped)
+};
+
+// The various typed array prototypes are supposed to 1) be normal objects,
+// 2) stringify to "[object <name of constructor>]", and 3) (Gecko-specific)
+// be xrayable. The first and second requirements mandate (in the absence of
+// @@toStringTag) a custom class. The third requirement mandates that each
+// prototype's class have the relevant typed array's cached JSProtoKey in them.
+// Thus we need one class with cached prototype per kind of typed array, with a
+// delegated ClassSpec.
+#define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \
+{ \
+ /*
+ * Actually ({}).toString.call(Uint8Array.prototype) should throw, because
+ * Uint8Array.prototype lacks the the typed array internal slots. (Same as
+ * with %TypedArray%.prototype.) It's not clear this is desirable (see
+ * above), but it's what we've always done, so keep doing it till we
+ * implement @@toStringTag or ES6 changes.
+ */ \
+ #_type "ArrayPrototype", \
+ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
+ JS_NULL_CLASS_OPS, \
+ &TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \
+}
+
+const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
+};
+
+/* static */ bool
+TypedArrayObject::isOriginalLengthGetter(Native native)
+{
+ return native == TypedArray_lengthGetter;
+}
+
+const Class DataViewObject::protoClass = {
+ "DataViewPrototype",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_DataView)
+};
+
+static const ClassOps DataViewObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ArrayBufferViewObject::trace
+};
+
+const Class DataViewObject::class_ = {
+ "DataView",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
+ &DataViewObjectClassOps
+};
+
+const JSFunctionSpec DataViewObject::jsfuncs[] = {
+ JS_FN("getInt8", DataViewObject::fun_getInt8, 1,0),
+ JS_FN("getUint8", DataViewObject::fun_getUint8, 1,0),
+ JS_FN("getInt16", DataViewObject::fun_getInt16, 1,0),
+ JS_FN("getUint16", DataViewObject::fun_getUint16, 1,0),
+ JS_FN("getInt32", DataViewObject::fun_getInt32, 1,0),
+ JS_FN("getUint32", DataViewObject::fun_getUint32, 1,0),
+ JS_FN("getFloat32", DataViewObject::fun_getFloat32, 1,0),
+ JS_FN("getFloat64", DataViewObject::fun_getFloat64, 1,0),
+ JS_FN("setInt8", DataViewObject::fun_setInt8, 2,0),
+ JS_FN("setUint8", DataViewObject::fun_setUint8, 2,0),
+ JS_FN("setInt16", DataViewObject::fun_setInt16, 2,0),
+ JS_FN("setUint16", DataViewObject::fun_setUint16, 2,0),
+ JS_FN("setInt32", DataViewObject::fun_setInt32, 2,0),
+ JS_FN("setUint32", DataViewObject::fun_setUint32, 2,0),
+ JS_FN("setFloat32", DataViewObject::fun_setFloat32, 2,0),
+ JS_FN("setFloat64", DataViewObject::fun_setFloat64, 2,0),
+ JS_FS_END
+};
+
+template<Value ValueGetter(DataViewObject* view)>
+bool
+DataViewObject::getterImpl(JSContext* cx, const CallArgs& args)
+{
+ args.rval().set(ValueGetter(&args.thisv().toObject().as<DataViewObject>()));
+ return true;
+}
+
+template<Value ValueGetter(DataViewObject* view)>
+bool
+DataViewObject::getter(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, getterImpl<ValueGetter> >(cx, args);
+}
+
+template<Value ValueGetter(DataViewObject* view)>
+bool
+DataViewObject::defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto)
+{
+ RootedId id(cx, NameToId(name));
+ RootedAtom atom(cx, IdToFunctionName(cx, id, "get"));
+ if (!atom)
+ return false;
+ unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
+
+ Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+ JSObject* getter =
+ NewNativeFunction(cx, DataViewObject::getter<ValueGetter>, 0, atom);
+ if (!getter)
+ return false;
+
+ return NativeDefineProperty(cx, proto, id, UndefinedHandleValue,
+ JS_DATA_TO_FUNC_PTR(GetterOp, getter), nullptr, attrs);
+}
+
+/* static */ bool
+DataViewObject::initClass(JSContext* cx)
+{
+ Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+ if (global->isStandardClassResolved(JSProto_DataView))
+ return true;
+
+ RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass));
+ if (!proto)
+ return false;
+
+ RootedFunction ctor(cx, global->createConstructor(cx, DataViewObject::class_constructor,
+ cx->names().DataView, 3));
+ if (!ctor)
+ return false;
+
+ if (!LinkConstructorAndPrototype(cx, ctor, proto))
+ return false;
+
+ if (!defineGetter<bufferValue>(cx, cx->names().buffer, proto))
+ return false;
+
+ if (!defineGetter<byteLengthValue>(cx, cx->names().byteLength, proto))
+ return false;
+
+ if (!defineGetter<byteOffsetValue>(cx, cx->names().byteOffset, proto))
+ return false;
+
+ if (!JS_DefineFunctions(cx, proto, DataViewObject::jsfuncs))
+ return false;
+
+ if (!DefineToStringTag(cx, proto, cx->names().DataView))
+ return false;
+
+ /*
+ * Create a helper function to implement the craziness of
+ * |new DataView(new otherWindow.ArrayBuffer())|, and install it in the
+ * global for use by the DataViewObject constructor.
+ */
+ RootedFunction fun(cx, NewNativeFunction(cx, ArrayBufferObject::createDataViewForThis,
+ 0, nullptr));
+ if (!fun)
+ return false;
+
+ if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_DataView, ctor, proto))
+ return false;
+
+ global->setCreateDataViewForThis(fun);
+
+ return true;
+}
+
+void
+DataViewObject::notifyBufferDetached(void* newData)
+{
+ setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
+ setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
+ setPrivate(newData);
+}
+
+JSObject*
+js::InitDataViewClass(JSContext* cx, HandleObject obj)
+{
+ if (!DataViewObject::initClass(cx))
+ return nullptr;
+ return &cx->global()->getPrototype(JSProto_DataView).toObject();
+}
+
+bool
+js::IsTypedArrayConstructor(HandleValue v, uint32_t type)
+{
+ switch (type) {
+ case Scalar::Int8:
+ return IsNativeFunction(v, Int8Array::class_constructor);
+ case Scalar::Uint8:
+ return IsNativeFunction(v, Uint8Array::class_constructor);
+ case Scalar::Int16:
+ return IsNativeFunction(v, Int16Array::class_constructor);
+ case Scalar::Uint16:
+ return IsNativeFunction(v, Uint16Array::class_constructor);
+ case Scalar::Int32:
+ return IsNativeFunction(v, Int32Array::class_constructor);
+ case Scalar::Uint32:
+ return IsNativeFunction(v, Uint32Array::class_constructor);
+ case Scalar::Float32:
+ return IsNativeFunction(v, Float32Array::class_constructor);
+ case Scalar::Float64:
+ return IsNativeFunction(v, Float64Array::class_constructor);
+ case Scalar::Uint8Clamped:
+ return IsNativeFunction(v, Uint8ClampedArray::class_constructor);
+ case Scalar::MaxTypedArrayViewType:
+ break;
+ }
+ MOZ_CRASH("unexpected typed array type");
+}
+
+template <typename CharT>
+bool
+js::StringIsTypedArrayIndex(const CharT* s, size_t length, uint64_t* indexp)
+{
+ const CharT* end = s + length;
+
+ if (s == end)
+ return false;
+
+ bool negative = false;
+ if (*s == '-') {
+ negative = true;
+ if (++s == end)
+ return false;
+ }
+
+ if (!JS7_ISDEC(*s))
+ return false;
+
+ uint64_t index = 0;
+ uint32_t digit = JS7_UNDEC(*s++);
+
+ /* Don't allow leading zeros. */
+ if (digit == 0 && s != end)
+ return false;
+
+ index = digit;
+
+ for (; s < end; s++) {
+ if (!JS7_ISDEC(*s))
+ return false;
+
+ digit = JS7_UNDEC(*s);
+
+ /* Watch for overflows. */
+ if ((UINT64_MAX - digit) / 10 < index)
+ index = UINT64_MAX;
+ else
+ index = 10 * index + digit;
+ }
+
+ if (negative)
+ *indexp = UINT64_MAX;
+ else
+ *indexp = index;
+ return true;
+}
+
+template bool
+js::StringIsTypedArrayIndex(const char16_t* s, size_t length, uint64_t* indexp);
+
+template bool
+js::StringIsTypedArrayIndex(const Latin1Char* s, size_t length, uint64_t* indexp);
+
+/* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */
+bool
+js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
+ Handle<PropertyDescriptor> desc, ObjectOpResult& result)
+{
+ MOZ_ASSERT(obj->is<TypedArrayObject>());
+
+ // These are all substeps of 3.b.
+
+ // Steps i-iii are handled by the caller.
+
+ // Steps iv-v.
+ // We (wrongly) ignore out of range defines with a value.
+ uint32_t length = obj->as<TypedArrayObject>().length();
+ if (index >= length)
+ return result.succeed();
+
+ // Step vi.
+ if (desc.isAccessorDescriptor())
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ // Step vii.
+ if (desc.hasConfigurable() && desc.configurable())
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ // Step viii.
+ if (desc.hasEnumerable() && !desc.enumerable())
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ // Step ix.
+ if (desc.hasWritable() && !desc.writable())
+ return result.fail(JSMSG_CANT_REDEFINE_PROP);
+
+ // Step x.
+ if (desc.hasValue()) {
+ // The following step numbers refer to 9.4.5.9
+ // IntegerIndexedElementSet.
+
+ // Steps 1-2 are enforced by the caller.
+
+ // Step 3.
+ double numValue;
+ if (!ToNumber(cx, desc.value(), &numValue))
+ return false;
+
+ // Steps 4-5, 8-9.
+ if (obj->as<TypedArrayObject>().hasDetachedBuffer())
+ return result.fail(JSMSG_TYPED_ARRAY_DETACHED);
+
+ // Steps 10-16.
+ TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, numValue);
+ }
+
+ // Step xii.
+ return result.succeed();
+}
+
+/* JS Friend API */
+
+JS_FRIEND_API(bool)
+JS_IsTypedArrayObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->is<TypedArrayObject>() : false;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetTypedArrayLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->as<TypedArrayObject>().length();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetTypedArrayByteOffset(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->as<TypedArrayObject>().byteOffset();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetTypedArrayByteLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->as<TypedArrayObject>().byteLength();
+}
+
+JS_FRIEND_API(bool)
+JS_GetTypedArraySharedness(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return false;
+ return obj->as<TypedArrayObject>().isSharedMemory();
+}
+
+JS_FRIEND_API(js::Scalar::Type)
+JS_GetArrayBufferViewType(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return Scalar::MaxTypedArrayViewType;
+
+ if (obj->is<TypedArrayObject>())
+ return obj->as<TypedArrayObject>().type();
+ if (obj->is<DataViewObject>())
+ return Scalar::MaxTypedArrayViewType;
+ MOZ_CRASH("invalid ArrayBufferView type");
+}
+
+JS_FRIEND_API(int8_t*)
+JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int8);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<int8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared*/));
+}
+
+JS_FRIEND_API(uint8_t*)
+JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(uint8_t*)
+JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8Clamped);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(int16_t*)
+JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int16);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<int16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(uint16_t*)
+JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint16);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<uint16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(int32_t*)
+JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int32);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<int32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(uint32_t*)
+JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint32);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<uint32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(float*)
+JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float32);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<float*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(double*)
+JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
+ MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float64);
+ *isSharedMemory = tarr->isSharedMemory();
+ return static_cast<double*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
+}
+
+JS_FRIEND_API(bool)
+JS_IsDataViewObject(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->is<DataViewObject>() : false;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetDataViewByteOffset(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->as<DataViewObject>().byteOffset();
+}
+
+JS_FRIEND_API(void*)
+JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ return obj->as<DataViewObject>().dataPointer();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetDataViewByteLength(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->as<DataViewObject>().byteLength();
+}
+
+JS_FRIEND_API(JSObject*)
+JS_NewDataView(JSContext* cx, HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength)
+{
+ RootedObject constructor(cx);
+ JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewObject::class_);
+ if (!GetBuiltinConstructor(cx, key, &constructor))
+ return nullptr;
+
+ FixedConstructArgs<3> cargs(cx);
+
+ cargs[0].setObject(*arrayBuffer);
+ cargs[1].setNumber(byteOffset);
+ cargs[2].setInt32(byteLength);
+
+ RootedValue fun(cx, ObjectValue(*constructor));
+ RootedObject obj(cx);
+ if (!Construct(cx, fun, cargs, fun, &obj))
+ return nullptr;
+ return obj;
+}
diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h
new file mode 100644
index 000000000..775a9a0af
--- /dev/null
+++ b/js/src/vm/TypedArrayObject.h
@@ -0,0 +1,607 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_TypedArrayObject_h
+#define vm_TypedArrayObject_h
+
+#include "mozilla/Attributes.h"
+
+#include "jsobj.h"
+
+#include "gc/Barrier.h"
+#include "js/Class.h"
+#include "vm/ArrayBufferObject.h"
+#include "vm/SharedArrayObject.h"
+
+#define JS_FOR_EACH_TYPED_ARRAY(macro) \
+ macro(int8_t, Int8) \
+ macro(uint8_t, Uint8) \
+ macro(int16_t, Int16) \
+ macro(uint16_t, Uint16) \
+ macro(int32_t, Int32) \
+ macro(uint32_t, Uint32) \
+ macro(float, Float32) \
+ macro(double, Float64) \
+ macro(uint8_clamped, Uint8Clamped)
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+enum class TypedArrayLength { Fixed, Dynamic };
+
+/*
+ * TypedArrayObject
+ *
+ * The non-templated base class for the specific typed implementations.
+ * This class holds all the member variables that are used by
+ * the subclasses.
+ */
+
+class TypedArrayObject : public NativeObject
+{
+ public:
+ // Underlying (Shared)ArrayBufferObject.
+ static const size_t BUFFER_SLOT = 0;
+ static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right buffer slot");
+
+ // Slot containing length of the view in number of typed elements.
+ static const size_t LENGTH_SLOT = 1;
+ static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right length slot");
+
+ // Offset of view within underlying (Shared)ArrayBufferObject.
+ static const size_t BYTEOFFSET_SLOT = 2;
+ static_assert(BYTEOFFSET_SLOT == JS_TYPEDARRAYLAYOUT_BYTEOFFSET_SLOT,
+ "self-hosted code with burned-in constants must get the "
+ "right byteOffset slot");
+
+ static const size_t RESERVED_SLOTS = 3;
+
+#ifdef DEBUG
+ static const uint8_t ZeroLengthArrayData = 0x4A;
+#endif
+
+ static int lengthOffset();
+ static int dataOffset();
+
+ // The raw pointer to the buffer memory, the "private" value.
+ //
+ // This offset is exposed for performance reasons - so that it
+ // need not be looked up on accesses.
+ static const size_t DATA_SLOT = 3;
+
+ static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
+ "bad inlined constant in jsfriendapi.h");
+
+ typedef TypedArrayObject SomeTypedArray;
+ typedef ArrayBufferObject BufferType;
+
+ template<typename T> struct OfType;
+
+ static bool sameBuffer(Handle<TypedArrayObject*> a, Handle<TypedArrayObject*> b) {
+ // Inline buffers.
+ if (!a->hasBuffer() || !b->hasBuffer())
+ return a.get() == b.get();
+
+ // Shared buffers.
+ if (a->isSharedMemory() && b->isSharedMemory()) {
+ return (a->bufferObject()->as<SharedArrayBufferObject>().globalID() ==
+ b->bufferObject()->as<SharedArrayBufferObject>().globalID());
+ }
+
+ return a->bufferObject() == b->bufferObject();
+ }
+
+ static const Class classes[Scalar::MaxTypedArrayViewType];
+ static const Class protoClasses[Scalar::MaxTypedArrayViewType];
+ static const Class sharedTypedArrayPrototypeClass;
+
+ static const Class* classForType(Scalar::Type type) {
+ MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
+ return &classes[type];
+ }
+
+ static const Class* protoClassForType(Scalar::Type type) {
+ MOZ_ASSERT(type < Scalar::MaxTypedArrayViewType);
+ return &protoClasses[type];
+ }
+
+ static const size_t FIXED_DATA_START = DATA_SLOT + 1;
+
+ // For typed arrays which can store their data inline, the array buffer
+ // object is created lazily.
+ static const uint32_t INLINE_BUFFER_LIMIT =
+ (NativeObject::MAX_FIXED_SLOTS - FIXED_DATA_START) * sizeof(Value);
+
+ static gc::AllocKind
+ AllocKindForLazyBuffer(size_t nbytes)
+ {
+ MOZ_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
+ if (nbytes == 0)
+ nbytes += sizeof(uint8_t);
+ size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
+ MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
+ return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
+ }
+
+ inline Scalar::Type type() const;
+ inline size_t bytesPerElement() const;
+
+ static Value bufferValue(TypedArrayObject* tarr) {
+ return tarr->getFixedSlot(BUFFER_SLOT);
+ }
+ static Value byteOffsetValue(TypedArrayObject* tarr) {
+ Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+ static Value byteLengthValue(TypedArrayObject* tarr) {
+ return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement());
+ }
+ static Value lengthValue(TypedArrayObject* tarr) {
+ return tarr->getFixedSlot(LENGTH_SLOT);
+ }
+
+ static bool
+ ensureHasBuffer(JSContext* cx, Handle<TypedArrayObject*> tarray);
+
+ bool hasBuffer() const {
+ return bufferValue(const_cast<TypedArrayObject*>(this)).isObject();
+ }
+ JSObject* bufferObject() const {
+ return bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ }
+ uint32_t byteOffset() const {
+ return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+ uint32_t byteLength() const {
+ return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+ uint32_t length() const {
+ return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
+ }
+
+ bool hasInlineElements() const;
+ void setInlineElements();
+ uint8_t* elementsRaw() const {
+ return *(uint8_t **)((((char *)this) + this->dataOffset()));
+ }
+ uint8_t* elements() const {
+ assertZeroLengthArrayData();
+ return elementsRaw();
+ }
+
+#ifdef DEBUG
+ void assertZeroLengthArrayData() const;
+#else
+ void assertZeroLengthArrayData() const {};
+#endif
+
+ Value getElement(uint32_t index);
+ static void setElement(TypedArrayObject& obj, uint32_t index, double d);
+
+ void notifyBufferDetached(JSContext* cx, void* newData);
+
+ static bool
+ GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
+ MutableHandleObject res);
+
+ /*
+ * Byte length above which created typed arrays and data views will have
+ * singleton types regardless of the context in which they are created.
+ */
+ static const uint32_t SINGLETON_BYTE_LENGTH = 1024 * 1024 * 10;
+
+ static bool isOriginalLengthGetter(Native native);
+
+ ArrayBufferObject* bufferUnshared() const {
+ MOZ_ASSERT(!isSharedMemory());
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ return &obj->as<ArrayBufferObject>();
+ }
+ SharedArrayBufferObject* bufferShared() const {
+ MOZ_ASSERT(isSharedMemory());
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ return &obj->as<SharedArrayBufferObject>();
+ }
+ ArrayBufferObjectMaybeShared* bufferEither() const {
+ JSObject* obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObjectOrNull();
+ if (!obj)
+ return nullptr;
+ if (isSharedMemory())
+ return &obj->as<SharedArrayBufferObject>();
+ return &obj->as<ArrayBufferObject>();
+ }
+
+ SharedMem<void*> viewDataShared() const {
+ return SharedMem<void*>::shared(viewDataEither_());
+ }
+ SharedMem<void*> viewDataEither() const {
+ if (isSharedMemory())
+ return SharedMem<void*>::shared(viewDataEither_());
+ return SharedMem<void*>::unshared(viewDataEither_());
+ }
+ void initViewData(SharedMem<uint8_t*> viewData) {
+ // Install a pointer to the buffer location that corresponds
+ // to offset zero within the typed array.
+ //
+ // The following unwrap is safe because the DATA_SLOT is
+ // accessed only from jitted code and from the
+ // viewDataEither_() accessor below; in neither case does the
+ // raw pointer escape untagged into C++ code.
+ initPrivate(viewData.unwrap(/*safe - see above*/));
+ }
+ void* viewDataUnshared() const {
+ MOZ_ASSERT(!isSharedMemory());
+ return viewDataEither_();
+ }
+
+ bool hasDetachedBuffer() const {
+ // Shared buffers can't be detached.
+ if (isSharedMemory())
+ return false;
+
+ // A typed array with a null buffer has never had its buffer exposed to
+ // become detached.
+ ArrayBufferObject* buffer = bufferUnshared();
+ if (!buffer)
+ return false;
+
+ return buffer->isDetached();
+ }
+
+ private:
+ void* viewDataEither_() const {
+ // Note, do not check whether shared or not
+ // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
+ return static_cast<void*>(getPrivate(DATA_SLOT));
+ }
+
+ public:
+ static void trace(JSTracer* trc, JSObject* obj);
+ static void finalize(FreeOp* fop, JSObject* obj);
+ static void objectMoved(JSObject* obj, const JSObject* old);
+ static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
+ gc::AllocKind allocKind);
+
+ /* Initialization bits */
+
+ template<Value ValueGetter(TypedArrayObject* tarr)>
+ static bool
+ GetterImpl(JSContext* cx, const CallArgs& args)
+ {
+ MOZ_ASSERT(is(args.thisv()));
+ args.rval().set(ValueGetter(&args.thisv().toObject().as<TypedArrayObject>()));
+ return true;
+ }
+
+ // ValueGetter is a function that takes an unwrapped typed array object and
+ // returns a Value. Given such a function, Getter<> is a native that
+ // retrieves a given Value, probably from a slot on the object.
+ template<Value ValueGetter(TypedArrayObject* tarr)>
+ static bool
+ Getter(JSContext* cx, unsigned argc, Value* vp)
+ {
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<is, GetterImpl<ValueGetter>>(cx, args);
+ }
+
+ static const JSFunctionSpec protoFunctions[];
+ static const JSPropertySpec protoAccessors[];
+ static const JSFunctionSpec staticFunctions[];
+ static const JSPropertySpec staticProperties[];
+
+ /* Accessors and functions */
+
+ static bool is(HandleValue v);
+
+ static bool set(JSContext* cx, unsigned argc, Value* vp);
+};
+
+MOZ_MUST_USE bool TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp);
+
+extern TypedArrayObject*
+TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj, int32_t len);
+
+inline bool
+IsTypedArrayClass(const Class* clasp)
+{
+ return &TypedArrayObject::classes[0] <= clasp &&
+ clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
+}
+
+bool
+IsTypedArrayConstructor(HandleValue v, uint32_t type);
+
+inline Scalar::Type
+TypedArrayObject::type() const
+{
+ MOZ_ASSERT(IsTypedArrayClass(getClass()));
+ return static_cast<Scalar::Type>(getClass() - &classes[0]);
+}
+
+inline size_t
+TypedArrayObject::bytesPerElement() const
+{
+ return Scalar::byteSize(type());
+}
+
+// Return value is whether the string is some integer. If the string is an
+// integer which is not representable as a uint64_t, the return value is true
+// and the resulting index is UINT64_MAX.
+template <typename CharT>
+bool
+StringIsTypedArrayIndex(const CharT* s, size_t length, uint64_t* indexp);
+
+inline bool
+IsTypedArrayIndex(jsid id, uint64_t* indexp)
+{
+ if (JSID_IS_INT(id)) {
+ int32_t i = JSID_TO_INT(id);
+ MOZ_ASSERT(i >= 0);
+ *indexp = (double)i;
+ return true;
+ }
+
+ if (MOZ_UNLIKELY(!JSID_IS_STRING(id)))
+ return false;
+
+ JS::AutoCheckCannotGC nogc;
+ JSAtom* atom = JSID_TO_ATOM(id);
+ size_t length = atom->length();
+
+ if (atom->hasLatin1Chars()) {
+ const Latin1Char* s = atom->latin1Chars(nogc);
+ if (!JS7_ISDEC(*s) && *s != '-')
+ return false;
+ return StringIsTypedArrayIndex(s, length, indexp);
+ }
+
+ const char16_t* s = atom->twoByteChars(nogc);
+ if (!JS7_ISDEC(*s) && *s != '-')
+ return false;
+ return StringIsTypedArrayIndex(s, length, indexp);
+}
+
+/*
+ * Implements [[DefineOwnProperty]] for TypedArrays when the property
+ * key is a TypedArray index.
+ */
+bool
+DefineTypedArrayElement(JSContext* cx, HandleObject arr, uint64_t index,
+ Handle<PropertyDescriptor> desc, ObjectOpResult& result);
+
+static inline unsigned
+TypedArrayShift(Scalar::Type viewType)
+{
+ switch (viewType) {
+ case Scalar::Int8:
+ case Scalar::Uint8:
+ case Scalar::Uint8Clamped:
+ return 0;
+ case Scalar::Int16:
+ case Scalar::Uint16:
+ return 1;
+ case Scalar::Int32:
+ case Scalar::Uint32:
+ case Scalar::Float32:
+ return 2;
+ case Scalar::Int64:
+ case Scalar::Float64:
+ return 3;
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ return 4;
+ default:;
+ }
+ MOZ_CRASH("Unexpected array type");
+}
+
+static inline unsigned
+TypedArrayElemSize(Scalar::Type viewType)
+{
+ return 1u << TypedArrayShift(viewType);
+}
+
+// Assign
+//
+// target[targetOffset] = unsafeSrcCrossCompartment[0]
+// ...
+// target[targetOffset + unsafeSrcCrossCompartment.length - 1] =
+// unsafeSrcCrossCompartment[unsafeSrcCrossCompartment.length - 1]
+//
+// where the source element range doesn't overlap the target element range in
+// memory.
+extern void
+SetDisjointTypedElements(TypedArrayObject* target, uint32_t targetOffset,
+ TypedArrayObject* unsafeSrcCrossCompartment);
+
+extern JSObject*
+InitDataViewClass(JSContext* cx, HandleObject obj);
+
+class DataViewObject : public NativeObject
+{
+ private:
+ static const Class protoClass;
+
+ static bool is(HandleValue v) {
+ return v.isObject() && v.toObject().hasClass(&class_);
+ }
+
+ template <typename NativeType>
+ static uint8_t*
+ getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, double offset);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ getterImpl(JSContext* cx, const CallArgs& args);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ getter(JSContext* cx, unsigned argc, Value* vp);
+
+ template<Value ValueGetter(DataViewObject* view)>
+ static bool
+ defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
+
+ static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
+ uint32_t *byteOffset, uint32_t* byteLength);
+ static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
+ static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
+
+ friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
+ static DataViewObject*
+ create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
+ Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto);
+
+ public:
+ static const Class class_;
+
+ static Value byteOffsetValue(DataViewObject* view) {
+ Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+
+ static Value byteLengthValue(DataViewObject* view) {
+ Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
+ MOZ_ASSERT(v.toInt32() >= 0);
+ return v;
+ }
+
+ static Value bufferValue(DataViewObject* view) {
+ return view->getFixedSlot(TypedArrayObject::BUFFER_SLOT);
+ }
+
+ uint32_t byteOffset() const {
+ return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
+ }
+
+ uint32_t byteLength() const {
+ return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
+ }
+
+ ArrayBufferObject& arrayBuffer() const {
+ return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
+ }
+
+ void* dataPointer() const {
+ return getPrivate();
+ }
+
+ static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getInt32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getInt32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getUint32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getUint32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getFloat32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getFloat32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool getFloat64Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_getFloat64(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint8Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint8(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint16Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint16(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setInt32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setInt32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setUint32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setUint32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setFloat32Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setFloat32(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool setFloat64Impl(JSContext* cx, const CallArgs& args);
+ static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);
+
+ static bool initClass(JSContext* cx);
+ static void notifyBufferDetached(JSObject* view);
+ template<typename NativeType>
+ static bool read(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, NativeType* val, const char* method);
+ template<typename NativeType>
+ static bool write(JSContext* cx, Handle<DataViewObject*> obj,
+ const CallArgs& args, const char* method);
+
+ void notifyBufferDetached(void* newData);
+
+ private:
+ static const JSFunctionSpec jsfuncs[];
+};
+
+static inline int32_t
+ClampIntForUint8Array(int32_t x)
+{
+ if (x < 0)
+ return 0;
+ if (x > 255)
+ return 255;
+ return x;
+}
+
+static inline bool
+IsAnyArrayBuffer(HandleObject obj)
+{
+ return IsArrayBuffer(obj) || IsSharedArrayBuffer(obj);
+}
+
+static inline bool
+IsAnyArrayBuffer(JSObject* obj)
+{
+ return IsArrayBuffer(obj) || IsSharedArrayBuffer(obj);
+}
+
+static inline bool
+IsAnyArrayBuffer(HandleValue v)
+{
+ return v.isObject() && IsAnyArrayBuffer(&v.toObject());
+}
+
+} // namespace js
+
+template <>
+inline bool
+JSObject::is<js::TypedArrayObject>() const
+{
+ return js::IsTypedArrayClass(getClass());
+}
+
+#endif /* vm_TypedArrayObject_h */
diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp
new file mode 100644
index 000000000..538011bff
--- /dev/null
+++ b/js/src/vm/UbiNode.cpp
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/UbiNode.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Range.h"
+#include "mozilla/Scoped.h"
+
+#include <algorithm>
+
+#include "jscntxt.h"
+#include "jsobj.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+#include "jit/IonCode.h"
+#include "js/Debug.h"
+#include "js/TracingAPI.h"
+#include "js/TypeDecls.h"
+#include "js/Utility.h"
+#include "js/Vector.h"
+#include "vm/Debugger.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/GlobalObject.h"
+#include "vm/Scope.h"
+#include "vm/Shape.h"
+#include "vm/String.h"
+#include "vm/Symbol.h"
+
+#include "jsobjinlines.h"
+#include "vm/Debugger-inl.h"
+
+using namespace js;
+
+using mozilla::Some;
+using mozilla::RangedPtr;
+using JS::DispatchTyped;
+using JS::HandleValue;
+using JS::Value;
+using JS::ZoneSet;
+using JS::ubi::AtomOrTwoByteChars;
+using JS::ubi::CoarseType;
+using JS::ubi::Concrete;
+using JS::ubi::Edge;
+using JS::ubi::EdgeRange;
+using JS::ubi::Node;
+using JS::ubi::EdgeVector;
+using JS::ubi::StackFrame;
+using JS::ubi::TracerConcrete;
+using JS::ubi::TracerConcreteWithCompartment;
+
+struct CopyToBufferMatcher
+{
+ RangedPtr<char16_t> destination;
+ size_t maxLength;
+
+ CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
+ : destination(destination)
+ , maxLength(maxLength)
+ { }
+
+ template<typename CharT>
+ static size_t
+ copyToBufferHelper(const CharT* src, RangedPtr<char16_t> dest, size_t length)
+ {
+ size_t i = 0;
+ for ( ; i < length; i++)
+ dest[i] = src[i];
+ return i;
+ }
+
+ size_t
+ match(JSAtom* atom)
+ {
+ if (!atom)
+ return 0;
+
+ size_t length = std::min(atom->length(), maxLength);
+ JS::AutoCheckCannotGC noGC;
+ return atom->hasTwoByteChars()
+ ? copyToBufferHelper(atom->twoByteChars(noGC), destination, length)
+ : copyToBufferHelper(atom->latin1Chars(noGC), destination, length);
+ }
+
+ size_t
+ match(const char16_t* chars)
+ {
+ if (!chars)
+ return 0;
+
+ size_t length = std::min(js_strlen(chars), maxLength);
+ return copyToBufferHelper(chars, destination, length);
+ }
+};
+
+size_t
+JS::ubi::AtomOrTwoByteChars::copyToBuffer(RangedPtr<char16_t> destination, size_t length)
+{
+ CopyToBufferMatcher m(destination, length);
+ return match(m);
+}
+
+struct LengthMatcher
+{
+ size_t
+ match(JSAtom* atom)
+ {
+ return atom ? atom->length() : 0;
+ }
+
+ size_t
+ match(const char16_t* chars)
+ {
+ return chars ? js_strlen(chars) : 0;
+ }
+};
+
+size_t
+JS::ubi::AtomOrTwoByteChars::length()
+{
+ LengthMatcher m;
+ return match(m);
+}
+
+size_t
+StackFrame::source(RangedPtr<char16_t> destination, size_t length) const
+{
+ auto s = source();
+ return s.copyToBuffer(destination, length);
+}
+
+size_t
+StackFrame::functionDisplayName(RangedPtr<char16_t> destination, size_t length) const
+{
+ auto name = functionDisplayName();
+ return name.copyToBuffer(destination, length);
+}
+
+size_t
+StackFrame::sourceLength()
+{
+ return source().length();
+}
+
+size_t
+StackFrame::functionDisplayNameLength()
+{
+ return functionDisplayName().length();
+}
+
+// All operations on null ubi::Nodes crash.
+CoarseType Concrete<void>::coarseType() const { MOZ_CRASH("null ubi::Node"); }
+const char16_t* Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
+JS::Zone* Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
+JSCompartment* Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
+
+UniquePtr<EdgeRange>
+Concrete<void>::edges(JSContext*, bool) const {
+ MOZ_CRASH("null ubi::Node");
+}
+
+Node::Size
+Concrete<void>::size(mozilla::MallocSizeOf mallocSizeof) const
+{
+ MOZ_CRASH("null ubi::Node");
+}
+
+struct Node::ConstructFunctor : public js::BoolDefaultAdaptor<Value, false> {
+ template <typename T> bool operator()(T* t, Node* node) { node->construct(t); return true; }
+};
+
+Node::Node(const JS::GCCellPtr &thing)
+{
+ DispatchTyped(ConstructFunctor(), thing, this);
+}
+
+Node::Node(HandleValue value)
+{
+ if (!DispatchTyped(ConstructFunctor(), value, this))
+ construct<void>(nullptr);
+}
+
+Value
+Node::exposeToJS() const
+{
+ Value v;
+
+ if (is<JSObject>()) {
+ JSObject& obj = *as<JSObject>();
+ if (obj.is<js::EnvironmentObject>()) {
+ v.setUndefined();
+ } else if (obj.is<JSFunction>() && js::IsInternalFunctionObject(obj)) {
+ v.setUndefined();
+ } else {
+ v.setObject(obj);
+ }
+ } else if (is<JSString>()) {
+ v.setString(as<JSString>());
+ } else if (is<JS::Symbol>()) {
+ v.setSymbol(as<JS::Symbol>());
+ } else {
+ v.setUndefined();
+ }
+
+ ExposeValueToActiveJS(v);
+
+ return v;
+}
+
+
+// A JS::CallbackTracer subclass that adds a Edge to a Vector for each
+// edge on which it is invoked.
+class EdgeVectorTracer : public JS::CallbackTracer {
+ // The vector to which we add Edges.
+ EdgeVector* vec;
+
+ // True if we should populate the edge's names.
+ bool wantNames;
+
+ void onChild(const JS::GCCellPtr& thing) override {
+ if (!okay)
+ return;
+
+ // Don't trace permanent atoms and well-known symbols that are owned by
+ // a parent JSRuntime.
+ if (thing.is<JSString>() && thing.as<JSString>().isPermanentAtom())
+ return;
+ if (thing.is<JS::Symbol>() && thing.as<JS::Symbol>().isWellKnownSymbol())
+ return;
+
+ char16_t* name16 = nullptr;
+ if (wantNames) {
+ // Ask the tracer to compute an edge name for us.
+ char buffer[1024];
+ getTracingEdgeName(buffer, sizeof(buffer));
+ const char* name = buffer;
+
+ // Convert the name to char16_t characters.
+ name16 = js_pod_malloc<char16_t>(strlen(name) + 1);
+ if (!name16) {
+ okay = false;
+ return;
+ }
+
+ size_t i;
+ for (i = 0; name[i]; i++)
+ name16[i] = name[i];
+ name16[i] = '\0';
+ }
+
+ // The simplest code is correct! The temporary Edge takes
+ // ownership of name; if the append succeeds, the vector element
+ // then takes ownership; if the append fails, then the temporary
+ // retains it, and its destructor will free it.
+ if (!vec->append(mozilla::Move(Edge(name16, Node(thing))))) {
+ okay = false;
+ return;
+ }
+ }
+
+ public:
+ // True if no errors (OOM, say) have yet occurred.
+ bool okay;
+
+ EdgeVectorTracer(JSRuntime* rt, EdgeVector* vec, bool wantNames)
+ : JS::CallbackTracer(rt),
+ vec(vec),
+ wantNames(wantNames),
+ okay(true)
+ { }
+};
+
+
+// An EdgeRange concrete class that simply holds a vector of Edges,
+// populated by the init method.
+class SimpleEdgeRange : public EdgeRange {
+ EdgeVector edges;
+ size_t i;
+
+ void settle() {
+ front_ = i < edges.length() ? &edges[i] : nullptr;
+ }
+
+ public:
+ explicit SimpleEdgeRange() : edges(), i(0) { }
+
+ bool init(JSRuntime* rt, void* thing, JS::TraceKind kind, bool wantNames = true) {
+ EdgeVectorTracer tracer(rt, &edges, wantNames);
+ js::TraceChildren(&tracer, thing, kind);
+ settle();
+ return tracer.okay;
+ }
+
+ void popFront() override { i++; settle(); }
+};
+
+
+template<typename Referent>
+JS::Zone*
+TracerConcrete<Referent>::zone() const
+{
+ return get().zoneFromAnyThread();
+}
+
+template JS::Zone* TracerConcrete<JSScript>::zone() const;
+template JS::Zone* TracerConcrete<js::LazyScript>::zone() const;
+template JS::Zone* TracerConcrete<js::Shape>::zone() const;
+template JS::Zone* TracerConcrete<js::BaseShape>::zone() const;
+template JS::Zone* TracerConcrete<js::ObjectGroup>::zone() const;
+template JS::Zone* TracerConcrete<js::Scope>::zone() const;
+template JS::Zone* TracerConcrete<JS::Symbol>::zone() const;
+template JS::Zone* TracerConcrete<JSString>::zone() const;
+
+template<typename Referent>
+UniquePtr<EdgeRange>
+TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
+ UniquePtr<SimpleEdgeRange, JS::DeletePolicy<SimpleEdgeRange>> range(js_new<SimpleEdgeRange>());
+ if (!range)
+ return nullptr;
+
+ if (!range->init(cx, ptr, JS::MapTypeToTraceKind<Referent>::kind, wantNames))
+ return nullptr;
+
+ return UniquePtr<EdgeRange>(range.release());
+}
+
+template UniquePtr<EdgeRange> TracerConcrete<JSScript>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<js::LazyScript>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<js::Scope>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<JS::Symbol>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(JSContext* cx, bool wantNames) const;
+
+template<typename Referent>
+JSCompartment*
+TracerConcreteWithCompartment<Referent>::compartment() const
+{
+ return TracerBase::get().compartment();
+}
+
+template JSCompartment* TracerConcreteWithCompartment<JSScript>::compartment() const;
+
+bool
+Concrete<JSObject>::hasAllocationStack() const
+{
+ return !!js::Debugger::getObjectAllocationSite(get());
+}
+
+StackFrame
+Concrete<JSObject>::allocationStack() const
+{
+ MOZ_ASSERT(hasAllocationStack());
+ return StackFrame(js::Debugger::getObjectAllocationSite(get()));
+}
+
+const char*
+Concrete<JSObject>::jsObjectClassName() const
+{
+ return Concrete::get().getClass()->name;
+}
+
+bool
+Concrete<JSObject>::jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const
+{
+ JSAtom* name = Concrete::get().maybeConstructorDisplayAtom();
+ if (!name) {
+ outName.reset(nullptr);
+ return true;
+ }
+
+ auto len = JS_GetStringLength(name);
+ auto size = len + 1;
+
+ outName.reset(cx->pod_malloc<char16_t>(size * sizeof(char16_t)));
+ if (!outName)
+ return false;
+
+ mozilla::Range<char16_t> chars(outName.get(), size);
+ if (!JS_CopyStringChars(cx, chars, name))
+ return false;
+
+ outName[len] = '\0';
+ return true;
+}
+
+const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
+const char16_t Concrete<JSScript>::concreteTypeName[] = u"JSScript";
+const char16_t Concrete<js::LazyScript>::concreteTypeName[] = u"js::LazyScript";
+const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] = u"js::jit::JitCode";
+const char16_t Concrete<js::Shape>::concreteTypeName[] = u"js::Shape";
+const char16_t Concrete<js::BaseShape>::concreteTypeName[] = u"js::BaseShape";
+const char16_t Concrete<js::ObjectGroup>::concreteTypeName[] = u"js::ObjectGroup";
+const char16_t Concrete<js::Scope>::concreteTypeName[] = u"js::Scope";
+
+namespace JS {
+namespace ubi {
+
+RootList::RootList(JSContext* cx, Maybe<AutoCheckCannotGC>& noGC, bool wantNames /* = false */)
+ : noGC(noGC),
+ cx(cx),
+ edges(),
+ wantNames(wantNames)
+{ }
+
+
+bool
+RootList::init()
+{
+ EdgeVectorTracer tracer(cx, &edges, wantNames);
+ js::TraceRuntime(&tracer);
+ if (!tracer.okay)
+ return false;
+ noGC.emplace(cx);
+ return true;
+}
+
+bool
+RootList::init(CompartmentSet& debuggees)
+{
+ EdgeVector allRootEdges;
+ EdgeVectorTracer tracer(cx, &allRootEdges, wantNames);
+
+ ZoneSet debuggeeZones;
+ if (!debuggeeZones.init())
+ return false;
+ for (auto range = debuggees.all(); !range.empty(); range.popFront()) {
+ if (!debuggeeZones.put(range.front()->zone()))
+ return false;
+ }
+
+ js::TraceRuntime(&tracer);
+ if (!tracer.okay)
+ return false;
+ TraceIncomingCCWs(&tracer, debuggees);
+ if (!tracer.okay)
+ return false;
+
+ for (EdgeVector::Range r = allRootEdges.all(); !r.empty(); r.popFront()) {
+ Edge& edge = r.front();
+
+ JSCompartment* compartment = edge.referent.compartment();
+ if (compartment && !debuggees.has(compartment))
+ continue;
+
+ Zone* zone = edge.referent.zone();
+ if (zone && !debuggeeZones.has(zone))
+ continue;
+
+ if (!edges.append(mozilla::Move(edge)))
+ return false;
+ }
+
+ noGC.emplace(cx);
+ return true;
+}
+
+bool
+RootList::init(HandleObject debuggees)
+{
+ MOZ_ASSERT(debuggees && JS::dbg::IsDebugger(*debuggees));
+ js::Debugger* dbg = js::Debugger::fromJSObject(debuggees.get());
+
+ CompartmentSet debuggeeCompartments;
+ if (!debuggeeCompartments.init())
+ return false;
+
+ for (js::WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) {
+ if (!debuggeeCompartments.put(r.front()->compartment()))
+ return false;
+ }
+
+ if (!init(debuggeeCompartments))
+ return false;
+
+ // Ensure that each of our debuggee globals are in the root list.
+ for (js::WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) {
+ if (!addRoot(JS::ubi::Node(static_cast<JSObject*>(r.front())),
+ u"debuggee global"))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+RootList::addRoot(Node node, const char16_t* edgeName)
+{
+ MOZ_ASSERT(noGC.isSome());
+ MOZ_ASSERT_IF(wantNames, edgeName);
+
+ UniqueTwoByteChars name;
+ if (edgeName) {
+ name = js::DuplicateString(edgeName);
+ if (!name)
+ return false;
+ }
+
+ return edges.append(mozilla::Move(Edge(name.release(), node)));
+}
+
+const char16_t Concrete<RootList>::concreteTypeName[] = u"JS::ubi::RootList";
+
+UniquePtr<EdgeRange>
+Concrete<RootList>::edges(JSContext* cx, bool wantNames) const {
+ MOZ_ASSERT_IF(wantNames, get().wantNames);
+ return UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
+}
+
+} // namespace ubi
+} // namespace JS
diff --git a/js/src/vm/UbiNodeCensus.cpp b/js/src/vm/UbiNodeCensus.cpp
new file mode 100644
index 000000000..e2c56c666
--- /dev/null
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -0,0 +1,1167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/UbiNodeCensus.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+namespace JS {
+namespace ubi {
+
+JS_PUBLIC_API(void)
+CountDeleter::operator()(CountBase* ptr)
+{
+ if (!ptr)
+ return;
+
+ // Downcast to our true type and destruct, as guided by our CountType
+ // pointer.
+ ptr->destruct();
+ js_free(ptr);
+}
+
+JS_PUBLIC_API(bool)
+Census::init() {
+ AutoLockForExclusiveAccess lock(cx);
+ atomsZone = cx->runtime()->atomsCompartment(lock)->zone();
+ return targetZones.init();
+}
+
+
+/*** Count Types ***********************************************************************************/
+
+// The simplest type: just count everything.
+class SimpleCount : public CountType {
+
+ struct Count : CountBase {
+ size_t totalBytes_;
+
+ explicit Count(SimpleCount& count)
+ : CountBase(count),
+ totalBytes_(0)
+ { }
+ };
+
+ UniqueTwoByteChars label;
+ bool reportCount : 1;
+ bool reportBytes : 1;
+
+ public:
+ explicit SimpleCount(UniqueTwoByteChars& label,
+ bool reportCount=true,
+ bool reportBytes=true)
+ : CountType(),
+ label(Move(label)),
+ reportCount(reportCount),
+ reportBytes(reportBytes)
+ { }
+
+ explicit SimpleCount()
+ : CountType(),
+ label(nullptr),
+ reportCount(true),
+ reportBytes(true)
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override { return CountBasePtr(js_new<Count>(*this)); }
+ void traceCount(CountBase& countBase, JSTracer* trc) 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, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+ if (reportBytes)
+ count.totalBytes_ += node.size(mallocSizeOf);
+ return true;
+}
+
+bool
+SimpleCount::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj)
+ return false;
+
+ RootedValue countValue(cx, NumberValue(count.total_));
+ if (reportCount && !DefineProperty(cx, obj, cx->names().count, countValue))
+ return false;
+
+ RootedValue bytesValue(cx, NumberValue(count.totalBytes_));
+ if (reportBytes && !DefineProperty(cx, obj, cx->names().bytes, bytesValue))
+ return false;
+
+ if (label) {
+ JSString* labelString = JS_NewUCStringCopyZ(cx, label.get());
+ if (!labelString)
+ return false;
+ RootedValue labelValue(cx, StringValue(labelString));
+ if (!DefineProperty(cx, obj, cx->names().label, labelValue))
+ return false;
+ }
+
+ report.setObject(*obj);
+ return true;
+}
+
+
+// A count type that collects all matching nodes in a bucket.
+class BucketCount : public CountType {
+
+ struct Count : CountBase {
+ JS::ubi::Vector<JS::ubi::Node::Id> ids_;
+
+ explicit Count(BucketCount& count)
+ : CountBase(count),
+ ids_()
+ { }
+ };
+
+ public:
+ explicit BucketCount()
+ : CountType()
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override { return CountBasePtr(js_new<Count>(*this)); }
+ void traceCount(CountBase& countBase, JSTracer* trc) final { }
+ bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+ bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+};
+
+bool
+BucketCount::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+ return count.ids_.append(node.identifier());
+}
+
+bool
+BucketCount::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ size_t length = count.ids_.length();
+ RootedArrayObject arr(cx, NewDenseFullyAllocatedArray(cx, length));
+ if (!arr)
+ return false;
+ arr->ensureDenseInitializedLength(cx, 0, length);
+
+ for (size_t i = 0; i < length; i++)
+ arr->setDenseElement(i, NumberValue(count.ids_[i]));
+
+ report.setObject(*arr);
+ return true;
+}
+
+
+// A type that categorizes nodes by their JavaScript type -- 'objects',
+// 'strings', 'scripts', and 'other' -- and then passes the nodes to child
+// types.
+//
+// Implementation details of scripts like jitted code are counted under
+// 'scripts'.
+class ByCoarseType : public CountType {
+ CountTypePtr objects;
+ CountTypePtr scripts;
+ CountTypePtr strings;
+ CountTypePtr other;
+
+ struct Count : CountBase {
+ Count(CountType& type,
+ CountBasePtr& objects,
+ CountBasePtr& scripts,
+ CountBasePtr& strings,
+ CountBasePtr& other)
+ : CountBase(type),
+ objects(Move(objects)),
+ scripts(Move(scripts)),
+ strings(Move(strings)),
+ other(Move(other))
+ { }
+
+ CountBasePtr objects;
+ CountBasePtr scripts;
+ CountBasePtr strings;
+ CountBasePtr other;
+ };
+
+ public:
+ ByCoarseType(CountTypePtr& objects,
+ CountTypePtr& scripts,
+ CountTypePtr& strings,
+ CountTypePtr& other)
+ : CountType(),
+ objects(Move(objects)),
+ scripts(Move(scripts)),
+ strings(Move(strings)),
+ other(Move(other))
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override;
+ void traceCount(CountBase& countBase, JSTracer* trc) override;
+ bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+ bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+};
+
+CountBasePtr
+ByCoarseType::makeCount()
+{
+ CountBasePtr objectsCount(objects->makeCount());
+ CountBasePtr scriptsCount(scripts->makeCount());
+ CountBasePtr stringsCount(strings->makeCount());
+ CountBasePtr otherCount(other->makeCount());
+
+ if (!objectsCount || !scriptsCount || !stringsCount || !otherCount)
+ return CountBasePtr(nullptr);
+
+ return CountBasePtr(js_new<Count>(*this,
+ objectsCount,
+ scriptsCount,
+ stringsCount,
+ otherCount));
+}
+
+void
+ByCoarseType::traceCount(CountBase& countBase, JSTracer* trc)
+{
+ Count& count = static_cast<Count&>(countBase);
+ count.objects->trace(trc);
+ count.scripts->trace(trc);
+ count.strings->trace(trc);
+ count.other->trace(trc);
+}
+
+bool
+ByCoarseType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ switch (node.coarseType()) {
+ case JS::ubi::CoarseType::Object:
+ return count.objects->count(mallocSizeOf, node);
+ case JS::ubi::CoarseType::Script:
+ return count.scripts->count(mallocSizeOf, node);
+ case JS::ubi::CoarseType::String:
+ return count.strings->count(mallocSizeOf, node);
+ case JS::ubi::CoarseType::Other:
+ return count.other->count(mallocSizeOf, node);
+ default:
+ MOZ_CRASH("bad JS::ubi::CoarseType in JS::ubi::ByCoarseType::count");
+ return false;
+ }
+}
+
+bool
+ByCoarseType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj)
+ return false;
+
+ RootedValue objectsReport(cx);
+ if (!count.objects->report(cx, &objectsReport) ||
+ !DefineProperty(cx, obj, cx->names().objects, objectsReport))
+ return false;
+
+ RootedValue scriptsReport(cx);
+ if (!count.scripts->report(cx, &scriptsReport) ||
+ !DefineProperty(cx, obj, cx->names().scripts, scriptsReport))
+ return false;
+
+ RootedValue stringsReport(cx);
+ if (!count.strings->report(cx, &stringsReport) ||
+ !DefineProperty(cx, obj, cx->names().strings, stringsReport))
+ return false;
+
+ RootedValue otherReport(cx);
+ if (!count.other->report(cx, &otherReport) ||
+ !DefineProperty(cx, obj, cx->names().other, otherReport))
+ return false;
+
+ report.setObject(*obj);
+ return true;
+}
+
+
+// Comparison function for sorting hash table entries by the smallest node ID
+// they counted. Node IDs are stable and unique, which ensures ordering of
+// results never depends on hash table placement or sort algorithm vagaries. The
+// arguments are doubly indirect: they're pointers to elements in an array of
+// pointers to table entries.
+template<typename Entry>
+static int compareEntries(const void* lhsVoid, const void* rhsVoid) {
+ auto lhs = (*static_cast<const Entry* const*>(lhsVoid))->value()->smallestNodeIdCounted_;
+ auto rhs = (*static_cast<const Entry* const*>(rhsVoid))->value()->smallestNodeIdCounted_;
+
+ // We don't want to just subtract the values, as they're unsigned.
+ if (lhs < rhs)
+ return 1;
+ if (lhs > rhs)
+ return -1;
+ return 0;
+}
+
+// A hash map mapping from C strings to counts.
+using CStringCountMap = HashMap<const char*, CountBasePtr, CStringHasher, SystemAllocPolicy>;
+
+// Convert a HashMap into an object with each key one of the entries from the
+// map and each value the associated count's report. For use during census
+// reporting.
+//
+// `Map` must be a `HashMap` from some key type to a `CountBasePtr`.
+//
+// `GetName` must be a callable type which takes `const Map::Key&` and returns
+// `const char*`.
+template <class Map, class GetName>
+static PlainObject*
+countMapToObject(JSContext* cx, Map& map, GetName getName) {
+ // 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
+ // more interesting, and a little less non-deterministic.
+
+ JS::ubi::Vector<typename Map::Entry*> entries;
+ if (!entries.reserve(map.count())) {
+ ReportOutOfMemory(cx);
+ return nullptr;
+ }
+
+ for (auto r = map.all(); !r.empty(); r.popFront())
+ entries.infallibleAppend(&r.front());
+
+ qsort(entries.begin(), entries.length(), sizeof(*entries.begin()),
+ compareEntries<typename Map::Entry>);
+
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj)
+ return nullptr;
+
+ for (auto& entry : entries) {
+ CountBasePtr& thenCount = entry->value();
+ RootedValue thenReport(cx);
+ if (!thenCount->report(cx, &thenReport))
+ return nullptr;
+
+ const char* name = getName(entry->key());
+ MOZ_ASSERT(name);
+ JSAtom* atom = Atomize(cx, name, strlen(name));
+ if (!atom)
+ return nullptr;
+
+ RootedId entryId(cx, AtomToId(atom));
+ if (!DefineProperty(cx, obj, entryId, thenReport))
+ return nullptr;
+ }
+
+ return obj;
+}
+
+
+// A type that categorizes nodes that are JSObjects by their class name,
+// and places all other nodes in an 'other' category.
+class ByObjectClass : public CountType {
+ // A table mapping class names to their counts. Note that we treat js::Class
+ // instances with the same name as equal keys. If you have several
+ // js::Classes with equal names (and we do; as of this writing there were
+ // six named "Object"), you will get several different js::Classes being
+ // counted in the same table entry.
+ using Table = CStringCountMap;
+ using Entry = Table::Entry;
+
+ struct Count : public CountBase {
+ Table table;
+ CountBasePtr other;
+
+ Count(CountType& type, CountBasePtr& other)
+ : CountBase(type),
+ other(Move(other))
+ { }
+
+ bool init() { return table.init(); }
+ };
+
+ CountTypePtr classesType;
+ CountTypePtr otherType;
+
+ public:
+ ByObjectClass(CountTypePtr& classesType, CountTypePtr& otherType)
+ : CountType(),
+ classesType(Move(classesType)),
+ otherType(Move(otherType))
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override;
+ void traceCount(CountBase& countBase, JSTracer* trc) override;
+ bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+ bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+};
+
+CountBasePtr
+ByObjectClass::makeCount()
+{
+ CountBasePtr otherCount(otherType->makeCount());
+ if (!otherCount)
+ return nullptr;
+
+ UniquePtr<Count> count(js_new<Count>(*this, otherCount));
+ if (!count || !count->init())
+ return nullptr;
+
+ return CountBasePtr(count.release());
+}
+
+void
+ByObjectClass::traceCount(CountBase& countBase, JSTracer* trc)
+{
+ Count& count = static_cast<Count&>(countBase);
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
+ r.front().value()->trace(trc);
+ count.other->trace(trc);
+}
+
+bool
+ByObjectClass::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ const char* className = node.jsObjectClassName();
+ if (!className)
+ return count.other->count(mallocSizeOf, node);
+
+ Table::AddPtr p = count.table.lookupForAdd(className);
+ if (!p) {
+ CountBasePtr classCount(classesType->makeCount());
+ if (!classCount || !count.table.add(p, className, Move(classCount)))
+ return false;
+ }
+ return p->value()->count(mallocSizeOf, node);
+}
+
+bool
+ByObjectClass::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ RootedPlainObject obj(cx, countMapToObject(cx, count.table, [](const char* key) {
+ return key;
+ }));
+ if (!obj)
+ return false;
+
+ RootedValue otherReport(cx);
+ if (!count.other->report(cx, &otherReport) ||
+ !DefineProperty(cx, obj, cx->names().other, otherReport))
+ return false;
+
+ report.setObject(*obj);
+ return true;
+}
+
+
+// A count type that categorizes nodes by their ubi::Node::typeName.
+class ByUbinodeType : public CountType {
+ // Note that, because ubi::Node::typeName promises to return a specific
+ // pointer, not just any string whose contents are correct, we can use their
+ // addresses as hash table keys.
+ using Table = HashMap<const char16_t*, CountBasePtr, DefaultHasher<const char16_t*>,
+ SystemAllocPolicy>;
+ using Entry = Table::Entry;
+
+ struct Count: public CountBase {
+ Table table;
+
+ explicit Count(CountType& type) : CountBase(type) { }
+
+ bool init() { return table.init(); }
+ };
+
+ CountTypePtr entryType;
+
+ public:
+ explicit ByUbinodeType(CountTypePtr& entryType)
+ : CountType(),
+ entryType(Move(entryType))
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override;
+ void traceCount(CountBase& countBase, JSTracer* trc) 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> count(js_new<Count>(*this));
+ if (!count || !count->init())
+ return nullptr;
+
+ return CountBasePtr(count.release());
+}
+
+void
+ByUbinodeType::traceCount(CountBase& countBase, JSTracer* trc)
+{
+ Count& count = static_cast<Count&>(countBase);
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
+ r.front().value()->trace(trc);
+}
+
+bool
+ByUbinodeType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ const char16_t* key = node.typeName();
+ MOZ_ASSERT(key);
+ Table::AddPtr p = count.table.lookupForAdd(key);
+ if (!p) {
+ CountBasePtr typesCount(entryType->makeCount());
+ if (!typesCount || !count.table.add(p, key, Move(typesCount)))
+ return false;
+ }
+ return p->value()->count(mallocSizeOf, node);
+}
+
+bool
+ByUbinodeType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ // 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
+ // more interesting, and a little less non-deterministic.
+ JS::ubi::Vector<Entry*> entries;
+ if (!entries.reserve(count.table.count()))
+ return false;
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
+ entries.infallibleAppend(&r.front());
+ qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries<Entry>);
+
+ // Now build the result by iterating over the sorted vector.
+ RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!obj)
+ return false;
+ for (Entry** entryPtr = entries.begin(); entryPtr < entries.end(); entryPtr++) {
+ Entry& entry = **entryPtr;
+ CountBasePtr& typeCount = entry.value();
+ RootedValue typeReport(cx);
+ if (!typeCount->report(cx, &typeReport))
+ return false;
+
+ const char16_t* name = entry.key();
+ MOZ_ASSERT(name);
+ JSAtom* atom = AtomizeChars(cx, name, js_strlen(name));
+ if (!atom)
+ return false;
+ RootedId entryId(cx, AtomToId(atom));
+
+ if (!DefineProperty(cx, obj, entryId, typeReport))
+ return false;
+ }
+
+ report.setObject(*obj);
+ return true;
+}
+
+
+// A count type that categorizes nodes by the JS stack under which they were
+// allocated.
+class ByAllocationStack : public CountType {
+ using Table = HashMap<StackFrame, CountBasePtr, DefaultHasher<StackFrame>,
+ SystemAllocPolicy>;
+ using Entry = Table::Entry;
+
+ struct Count : public CountBase {
+ // NOTE: You may look up entries in this table by JS::ubi::StackFrame
+ // key only during traversal, NOT ONCE TRAVERSAL IS COMPLETE. Once
+ // traversal is complete, you may only iterate over it.
+ //
+ // In this hash table, keys are JSObjects (with some indirection), and
+ // we use JSObject identity (that is, address identity) as key
+ // identity. The normal way to support such a table is to make the trace
+ // function notice keys that have moved and re-key them in the
+ // table. However, our trace function does *not* rehash; the first GC
+ // may render the hash table unsearchable.
+ //
+ // This is as it should be:
+ //
+ // First, the heap traversal phase needs lookups by key to work. But no
+ // GC may ever occur during a traversal; this is enforced by the
+ // JS::ubi::BreadthFirst template. So the traceCount function doesn't
+ // need to do anything to help traversal; it never even runs then.
+ //
+ // Second, the report phase needs iteration over the table to work, but
+ // never looks up entries by key. GC may well occur during this phase:
+ // we allocate a Map object, and probably cross-compartment wrappers for
+ // SavedFrame instances as well. If a GC were to occur, it would call
+ // our traceCount function; if traceCount were to re-key, that would
+ // ruin the traversal in progress.
+ //
+ // So depending on the phase, we either don't need re-keying, or
+ // can't abide it.
+ Table table;
+ CountBasePtr noStack;
+
+ Count(CountType& type, CountBasePtr& noStack)
+ : CountBase(type),
+ noStack(Move(noStack))
+ { }
+ bool init() { return table.init(); }
+ };
+
+ CountTypePtr entryType;
+ CountTypePtr noStackType;
+
+ public:
+ ByAllocationStack(CountTypePtr& entryType, CountTypePtr& noStackType)
+ : CountType(),
+ entryType(Move(entryType)),
+ noStackType(Move(noStackType))
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override;
+ void traceCount(CountBase& countBase, JSTracer* trc) override;
+ bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+ bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+};
+
+CountBasePtr
+ByAllocationStack::makeCount()
+{
+ CountBasePtr noStackCount(noStackType->makeCount());
+ if (!noStackCount)
+ return nullptr;
+
+ UniquePtr<Count> count(js_new<Count>(*this, noStackCount));
+ if (!count || !count->init())
+ return nullptr;
+ return CountBasePtr(count.release());
+}
+
+void
+ByAllocationStack::traceCount(CountBase& countBase, JSTracer* trc)
+{
+ Count& count = static_cast<Count&>(countBase);
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront()) {
+ // Trace our child Counts.
+ r.front().value()->trace(trc);
+
+ // Trace the StackFrame that is this entry's key. Do not re-key if
+ // it has moved; see comments for ByAllocationStack::Count::table.
+ const StackFrame* key = &r.front().key();
+ auto& k = *const_cast<StackFrame*>(key);
+ k.trace(trc);
+ }
+ count.noStack->trace(trc);
+}
+
+bool
+ByAllocationStack::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ // If we do have an allocation stack for this node, include it in the
+ // count for that stack.
+ if (node.hasAllocationStack()) {
+ auto allocationStack = node.allocationStack();
+ auto p = count.table.lookupForAdd(allocationStack);
+ if (!p) {
+ CountBasePtr stackCount(entryType->makeCount());
+ if (!stackCount || !count.table.add(p, allocationStack, Move(stackCount)))
+ return false;
+ }
+ MOZ_ASSERT(p);
+ return p->value()->count(mallocSizeOf, node);
+ }
+
+ // Otherwise, count it in the "no stack" category.
+ return count.noStack->count(mallocSizeOf, node);
+}
+
+bool
+ByAllocationStack::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+#ifdef DEBUG
+ // Check that nothing rehashes our table while we hold pointers into it.
+ Generation generation = count.table.generation();
+#endif
+
+ // 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
+ // more interesting, and a little less non-deterministic.
+ JS::ubi::Vector<Entry*> entries;
+ if (!entries.reserve(count.table.count()))
+ return false;
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
+ entries.infallibleAppend(&r.front());
+ qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries<Entry>);
+
+ // Now build the result by iterating over the sorted vector.
+ Rooted<MapObject*> map(cx, MapObject::create(cx));
+ if (!map)
+ return false;
+ for (Entry** entryPtr = entries.begin(); entryPtr < entries.end(); entryPtr++) {
+ Entry& entry = **entryPtr;
+ MOZ_ASSERT(entry.key());
+
+ RootedObject stack(cx);
+ if (!entry.key().constructSavedFrameStack(cx, &stack) ||
+ !cx->compartment()->wrap(cx, &stack))
+ {
+ return false;
+ }
+ RootedValue stackVal(cx, ObjectValue(*stack));
+
+ CountBasePtr& stackCount = entry.value();
+ RootedValue stackReport(cx);
+ if (!stackCount->report(cx, &stackReport))
+ return false;
+
+ if (!MapObject::set(cx, map, stackVal, stackReport))
+ return false;
+ }
+
+ if (count.noStack->total_ > 0) {
+ RootedValue noStackReport(cx);
+ if (!count.noStack->report(cx, &noStackReport))
+ return false;
+ RootedValue noStack(cx, StringValue(cx->names().noStack));
+ if (!MapObject::set(cx, map, noStack, noStackReport))
+ return false;
+ }
+
+ MOZ_ASSERT(generation == count.table.generation());
+
+ report.setObject(*map);
+ return true;
+}
+
+// A count type that categorizes nodes by their script's filename.
+class ByFilename : public CountType {
+ using UniqueCString = UniquePtr<char, JS::FreePolicy>;
+
+ struct UniqueCStringHasher {
+ using Lookup = UniqueCString;
+
+ static js::HashNumber hash(const Lookup& lookup) {
+ return CStringHasher::hash(lookup.get());
+ }
+
+ static bool match(const UniqueCString& key, const Lookup& lookup) {
+ return CStringHasher::match(key.get(), lookup.get());
+ }
+ };
+
+ // A table mapping filenames to their counts. Note that we treat scripts
+ // with the same filename as equivalent. If you have several sources with
+ // the same filename, then all their scripts will get bucketed together.
+ using Table = HashMap<UniqueCString, CountBasePtr, UniqueCStringHasher,
+ SystemAllocPolicy>;
+ using Entry = Table::Entry;
+
+ struct Count : public CountBase {
+ Table table;
+ CountBasePtr then;
+ CountBasePtr noFilename;
+
+ Count(CountType& type, CountBasePtr&& then, CountBasePtr&& noFilename)
+ : CountBase(type)
+ , then(Move(then))
+ , noFilename(Move(noFilename))
+ { }
+
+ bool init() { return table.init(); }
+ };
+
+ CountTypePtr thenType;
+ CountTypePtr noFilenameType;
+
+ public:
+ ByFilename(CountTypePtr&& thenType, CountTypePtr&& noFilenameType)
+ : CountType(),
+ thenType(Move(thenType)),
+ noFilenameType(Move(noFilenameType))
+ { }
+
+ void destructCount(CountBase& countBase) override {
+ Count& count = static_cast<Count&>(countBase);
+ count.~Count();
+ }
+
+ CountBasePtr makeCount() override;
+ void traceCount(CountBase& countBase, JSTracer* trc) override;
+ bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
+ bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
+};
+
+CountBasePtr
+ByFilename::makeCount()
+{
+ CountBasePtr thenCount(thenType->makeCount());
+ if (!thenCount)
+ return nullptr;
+
+ CountBasePtr noFilenameCount(noFilenameType->makeCount());
+ if (!noFilenameCount)
+ return nullptr;
+
+ UniquePtr<Count> count(js_new<Count>(*this, Move(thenCount), Move(noFilenameCount)));
+ if (!count || !count->init())
+ return nullptr;
+
+ return CountBasePtr(count.release());
+}
+
+void
+ByFilename::traceCount(CountBase& countBase, JSTracer* trc)
+{
+ Count& count = static_cast<Count&>(countBase);
+ for (Table::Range r = count.table.all(); !r.empty(); r.popFront())
+ r.front().value()->trace(trc);
+ count.noFilename->trace(trc);
+}
+
+bool
+ByFilename::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ const char* filename = node.scriptFilename();
+ if (!filename)
+ return count.noFilename->count(mallocSizeOf, node);
+
+ UniqueCString myFilename(js_strdup(filename));
+ if (!myFilename)
+ return false;
+
+ Table::AddPtr p = count.table.lookupForAdd(myFilename);
+ if (!p) {
+ CountBasePtr thenCount(thenType->makeCount());
+ if (!thenCount || !count.table.add(p, Move(myFilename), Move(thenCount)))
+ return false;
+ }
+ return p->value()->count(mallocSizeOf, node);
+}
+
+bool
+ByFilename::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
+{
+ Count& count = static_cast<Count&>(countBase);
+
+ RootedPlainObject obj(cx, countMapToObject(cx, count.table, [](const UniqueCString& key) {
+ return key.get();
+ }));
+ if (!obj)
+ return false;
+
+ RootedValue noFilenameReport(cx);
+ if (!count.noFilename->report(cx, &noFilenameReport) ||
+ !DefineProperty(cx, obj, cx->names().noFilename, noFilenameReport))
+ {
+ return false;
+ }
+
+ report.setObject(*obj);
+ return true;
+}
+
+
+/*** Census Handler *******************************************************************************/
+
+JS_PUBLIC_API(bool)
+CensusHandler::operator() (BreadthFirst<CensusHandler>& traversal,
+ Node origin, const Edge& edge,
+ NodeData* referentData, bool first)
+{
+ // We're only interested in the first time we reach edge.referent, not
+ // in every edge arriving at that node.
+ if (!first)
+ return true;
+
+ // Don't count nodes outside the debuggee zones. Do count things in the
+ // special atoms zone, but don't traverse their outgoing edges, on the
+ // assumption that they are shared resources that debuggee is using.
+ // Symbols are always allocated in the atoms zone, even if they were
+ // created for exactly one compartment and never shared; this rule will
+ // include such nodes in the count.
+ const Node& referent = edge.referent;
+ Zone* zone = referent.zone();
+
+ if (census.targetZones.count() == 0 || census.targetZones.has(zone))
+ return rootCount->count(mallocSizeOf, referent);
+
+ if (zone == census.atomsZone) {
+ traversal.abandonReferent();
+ return rootCount->count(mallocSizeOf, referent);
+ }
+
+ traversal.abandonReferent();
+ return true;
+}
+
+
+/*** Parsing Breakdowns ***************************************************************************/
+
+static CountTypePtr
+ParseChildBreakdown(JSContext* cx, HandleObject breakdown, PropertyName* prop)
+{
+ RootedValue v(cx);
+ if (!GetProperty(cx, breakdown, breakdown, prop, &v))
+ return nullptr;
+ return ParseBreakdown(cx, v);
+}
+
+JS_PUBLIC_API(CountTypePtr)
+ParseBreakdown(JSContext* cx, HandleValue breakdownValue)
+{
+ if (breakdownValue.isUndefined()) {
+ // Construct the default type, { by: 'count' }
+ CountTypePtr simple(cx->new_<SimpleCount>());
+ return simple;
+ }
+
+ RootedObject breakdown(cx, ToObject(cx, breakdownValue));
+ if (!breakdown)
+ return nullptr;
+
+ RootedValue byValue(cx);
+ if (!GetProperty(cx, breakdown, breakdown, cx->names().by, &byValue))
+ return nullptr;
+ RootedString byString(cx, ToString(cx, byValue));
+ if (!byString)
+ return nullptr;
+ RootedLinearString by(cx, byString->ensureLinear(cx));
+ if (!by)
+ return nullptr;
+
+ if (StringEqualsAscii(by, "count")) {
+ RootedValue countValue(cx), bytesValue(cx);
+ if (!GetProperty(cx, breakdown, breakdown, cx->names().count, &countValue) ||
+ !GetProperty(cx, breakdown, breakdown, cx->names().bytes, &bytesValue))
+ return nullptr;
+
+ // Both 'count' and 'bytes' default to true if omitted, but ToBoolean
+ // naturally treats 'undefined' as false; fix this up.
+ if (countValue.isUndefined()) countValue.setBoolean(true);
+ if (bytesValue.isUndefined()) bytesValue.setBoolean(true);
+
+ // Undocumented feature, for testing: { by: 'count' } breakdowns can have
+ // a 'label' property whose value is converted to a string and included as
+ // a 'label' property on the report object.
+ RootedValue label(cx);
+ if (!GetProperty(cx, breakdown, breakdown, cx->names().label, &label))
+ return nullptr;
+
+ UniqueTwoByteChars labelUnique(nullptr);
+ if (!label.isUndefined()) {
+ RootedString labelString(cx, ToString(cx, label));
+ if (!labelString)
+ return nullptr;
+
+ JSFlatString* flat = labelString->ensureFlat(cx);
+ if (!flat)
+ return nullptr;
+
+ AutoStableStringChars chars(cx);
+ if (!chars.initTwoByte(cx, flat))
+ return nullptr;
+
+ // Since flat strings are null-terminated, and AutoStableStringChars
+ // null- terminates if it needs to make a copy, we know that
+ // chars.twoByteChars() is null-terminated.
+ labelUnique = DuplicateString(cx, chars.twoByteChars());
+ if (!labelUnique)
+ return nullptr;
+ }
+
+ CountTypePtr simple(cx->new_<SimpleCount>(labelUnique,
+ ToBoolean(countValue),
+ ToBoolean(bytesValue)));
+ return simple;
+ }
+
+ if (StringEqualsAscii(by, "bucket"))
+ return CountTypePtr(cx->new_<BucketCount>());
+
+ if (StringEqualsAscii(by, "objectClass")) {
+ CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
+ if (!thenType)
+ return nullptr;
+
+ CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
+ if (!otherType)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByObjectClass>(thenType, otherType));
+ }
+
+ if (StringEqualsAscii(by, "coarseType")) {
+ CountTypePtr objectsType(ParseChildBreakdown(cx, breakdown, cx->names().objects));
+ if (!objectsType)
+ return nullptr;
+ CountTypePtr scriptsType(ParseChildBreakdown(cx, breakdown, cx->names().scripts));
+ if (!scriptsType)
+ return nullptr;
+ CountTypePtr stringsType(ParseChildBreakdown(cx, breakdown, cx->names().strings));
+ if (!stringsType)
+ return nullptr;
+ CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
+ if (!otherType)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByCoarseType>(objectsType,
+ scriptsType,
+ stringsType,
+ otherType));
+ }
+
+ if (StringEqualsAscii(by, "internalType")) {
+ CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
+ if (!thenType)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByUbinodeType>(thenType));
+ }
+
+ if (StringEqualsAscii(by, "allocationStack")) {
+ CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
+ if (!thenType)
+ return nullptr;
+ CountTypePtr noStackType(ParseChildBreakdown(cx, breakdown, cx->names().noStack));
+ if (!noStackType)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByAllocationStack>(thenType, noStackType));
+ }
+
+ if (StringEqualsAscii(by, "filename")) {
+ CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
+ if (!thenType)
+ return nullptr;
+
+ CountTypePtr noFilenameType(ParseChildBreakdown(cx, breakdown, cx->names().noFilename));
+ if (!noFilenameType)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByFilename>(Move(thenType), Move(noFilenameType)));
+ }
+
+ // We didn't recognize the breakdown type; complain.
+ RootedString bySource(cx, ValueToSource(cx, byValue));
+ if (!bySource)
+ return nullptr;
+
+ JSAutoByteString byBytes(cx, bySource);
+ if (!byBytes)
+ return nullptr;
+
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_CENSUS_BREAKDOWN,
+ byBytes.ptr());
+ return nullptr;
+}
+
+// Get the default census breakdown:
+//
+// { by: "coarseType",
+// objects: { by: "objectClass" },
+// other: { by: "internalType" }
+// }
+static CountTypePtr
+GetDefaultBreakdown(JSContext* cx)
+{
+ CountTypePtr byClass(cx->new_<SimpleCount>());
+ if (!byClass)
+ return nullptr;
+
+ CountTypePtr byClassElse(cx->new_<SimpleCount>());
+ if (!byClassElse)
+ return nullptr;
+
+ CountTypePtr objects(cx->new_<ByObjectClass>(byClass, byClassElse));
+ if (!objects)
+ return nullptr;
+
+ CountTypePtr scripts(cx->new_<SimpleCount>());
+ if (!scripts)
+ return nullptr;
+
+ CountTypePtr strings(cx->new_<SimpleCount>());
+ if (!strings)
+ return nullptr;
+
+ CountTypePtr byType(cx->new_<SimpleCount>());
+ if (!byType)
+ return nullptr;
+
+ CountTypePtr other(cx->new_<ByUbinodeType>(byType));
+ if (!other)
+ return nullptr;
+
+ return CountTypePtr(cx->new_<ByCoarseType>(objects,
+ scripts,
+ strings,
+ other));
+}
+
+JS_PUBLIC_API(bool)
+ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTypePtr& outResult)
+{
+ RootedValue breakdown(cx, UndefinedValue());
+ if (options && !GetProperty(cx, options, options, cx->names().breakdown, &breakdown))
+ return false;
+
+ outResult = breakdown.isUndefined()
+ ? GetDefaultBreakdown(cx)
+ : ParseBreakdown(cx, breakdown);
+ return !!outResult;
+}
+
+} // namespace ubi
+} // namespace JS
diff --git a/js/src/vm/UbiNodeShortestPaths.cpp b/js/src/vm/UbiNodeShortestPaths.cpp
new file mode 100644
index 000000000..a1a293997
--- /dev/null
+++ b/js/src/vm/UbiNodeShortestPaths.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/UbiNodeShortestPaths.h"
+
+#include "mozilla/Maybe.h"
+#include "mozilla/Move.h"
+
+#include "jsstr.h"
+
+namespace JS {
+namespace ubi {
+
+JS_PUBLIC_API(BackEdge::Ptr)
+BackEdge::clone() const
+{
+ BackEdge::Ptr clone(js_new<BackEdge>());
+ if (!clone)
+ return nullptr;
+
+ clone->predecessor_ = predecessor();
+ if (name()) {
+ clone->name_ = js::DuplicateString(name().get());
+ if (!clone->name_)
+ return nullptr;
+ }
+ return mozilla::Move(clone);
+}
+
+#ifdef DEBUG
+
+static void
+dumpNode(const JS::ubi::Node& node)
+{
+ fprintf(stderr, " %p ", (void*) node.identifier());
+ js_fputs(node.typeName(), stderr);
+ if (node.coarseType() == JS::ubi::CoarseType::Object) {
+ if (const char* clsName = node.jsObjectClassName())
+ fprintf(stderr, " [object %s]", clsName);
+ }
+ fputc('\n', stderr);
+}
+
+JS_PUBLIC_API(void)
+dumpPaths(JSContext* cx, Node node, uint32_t maxNumPaths /* = 10 */)
+{
+ mozilla::Maybe<AutoCheckCannotGC> nogc;
+
+ JS::ubi::RootList rootList(cx, nogc, true);
+ MOZ_ASSERT(rootList.init());
+
+ NodeSet targets;
+ bool ok = targets.init() && targets.putNew(node);
+ MOZ_ASSERT(ok);
+
+ auto paths = ShortestPaths::Create(cx, nogc.ref(), maxNumPaths, &rootList, mozilla::Move(targets));
+ MOZ_ASSERT(paths.isSome());
+
+ int i = 0;
+ ok = paths->forEachPath(node, [&](Path& path) {
+ fprintf(stderr, "Path %d:\n", i++);
+ for (auto backEdge : path) {
+ dumpNode(backEdge->predecessor());
+ fprintf(stderr, " |\n");
+ fprintf(stderr, " |\n");
+ fprintf(stderr, " '");
+
+ const char16_t* name = backEdge->name().get();
+ if (!name)
+ name = u"<no edge name>";
+ js_fputs(name, stderr);
+ fprintf(stderr, "'\n");
+
+ fprintf(stderr, " |\n");
+ fprintf(stderr, " V\n");
+ }
+
+ dumpNode(node);
+ fputc('\n', stderr);
+ return true;
+ });
+ MOZ_ASSERT(ok);
+
+ if (i == 0)
+ fprintf(stderr, "No retaining paths found.\n");
+}
+#endif
+
+} // namespace ubi
+} // namespace JS
diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h
new file mode 100644
index 000000000..93ad7bf28
--- /dev/null
+++ b/js/src/vm/UnboxedObject-inl.h
@@ -0,0 +1,840 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_UnboxedObject_inl_h
+#define vm_UnboxedObject_inl_h
+
+#include "vm/UnboxedObject.h"
+
+#include "gc/StoreBuffer-inl.h"
+#include "vm/ArrayObject-inl.h"
+#include "vm/NativeObject-inl.h"
+
+namespace js {
+
+static inline Value
+GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized)
+{
+ switch (type) {
+ case JSVAL_TYPE_BOOLEAN:
+ return BooleanValue(*p != 0);
+
+ case JSVAL_TYPE_INT32:
+ return Int32Value(*reinterpret_cast<int32_t*>(p));
+
+ case JSVAL_TYPE_DOUBLE: {
+ // During unboxed plain object creation, non-GC thing properties are
+ // left uninitialized. This is normally fine, since the properties will
+ // be filled in shortly, but if they are read before that happens we
+ // need to make sure that doubles are canonical.
+ double d = *reinterpret_cast<double*>(p);
+ if (maybeUninitialized)
+ return DoubleValue(JS::CanonicalizeNaN(d));
+ return DoubleValue(d);
+ }
+
+ case JSVAL_TYPE_STRING:
+ return StringValue(*reinterpret_cast<JSString**>(p));
+
+ case JSVAL_TYPE_OBJECT:
+ return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p));
+
+ default:
+ MOZ_CRASH("Invalid type for unboxed value");
+ }
+}
+
+static inline void
+SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
+ uint8_t* p, JSValueType type, const Value& v,
+ bool preBarrier)
+{
+ switch (type) {
+ case JSVAL_TYPE_BOOLEAN:
+ *p = v.toBoolean();
+ return;
+
+ case JSVAL_TYPE_INT32:
+ *reinterpret_cast<int32_t*>(p) = v.toInt32();
+ return;
+
+ case JSVAL_TYPE_DOUBLE:
+ *reinterpret_cast<double*>(p) = v.toNumber();
+ return;
+
+ case JSVAL_TYPE_STRING: {
+ MOZ_ASSERT(!IsInsideNursery(v.toString()));
+ JSString** np = reinterpret_cast<JSString**>(p);
+ if (preBarrier)
+ JSString::writeBarrierPre(*np);
+ *np = v.toString();
+ return;
+ }
+
+ case JSVAL_TYPE_OBJECT: {
+ JSObject** np = reinterpret_cast<JSObject**>(p);
+
+ // Manually trigger post barriers on the whole object. If we treat
+ // the pointer as a HeapPtrObject we will get confused later if the
+ // object is converted to its native representation.
+ JSObject* obj = v.toObjectOrNull();
+ if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) {
+ JSRuntime* rt = unboxedObject->runtimeFromMainThread();
+ rt->gc.storeBuffer.putWholeCell(unboxedObject);
+ }
+
+ if (preBarrier)
+ JSObject::writeBarrierPre(*np);
+ *np = obj;
+ return;
+ }
+
+ default:
+ MOZ_CRASH("Invalid type for unboxed value");
+ }
+}
+
+static inline bool
+SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id,
+ uint8_t* p, JSValueType type, const Value& v, bool preBarrier)
+{
+ switch (type) {
+ case JSVAL_TYPE_BOOLEAN:
+ if (v.isBoolean()) {
+ *p = v.toBoolean();
+ return true;
+ }
+ return false;
+
+ case JSVAL_TYPE_INT32:
+ if (v.isInt32()) {
+ *reinterpret_cast<int32_t*>(p) = v.toInt32();
+ return true;
+ }
+ return false;
+
+ case JSVAL_TYPE_DOUBLE:
+ if (v.isNumber()) {
+ *reinterpret_cast<double*>(p) = v.toNumber();
+ return true;
+ }
+ return false;
+
+ case JSVAL_TYPE_STRING:
+ if (v.isString()) {
+ MOZ_ASSERT(!IsInsideNursery(v.toString()));
+ JSString** np = reinterpret_cast<JSString**>(p);
+ if (preBarrier)
+ JSString::writeBarrierPre(*np);
+ *np = v.toString();
+ return true;
+ }
+ return false;
+
+ case JSVAL_TYPE_OBJECT:
+ if (v.isObjectOrNull()) {
+ JSObject** np = reinterpret_cast<JSObject**>(p);
+
+ // Update property types when writing object properties. Types for
+ // other properties were captured when the unboxed layout was
+ // created.
+ AddTypePropertyId(cx, unboxedObject, id, v);
+
+ // As above, trigger post barriers on the whole object.
+ JSObject* obj = v.toObjectOrNull();
+ if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) {
+ JSRuntime* rt = unboxedObject->runtimeFromMainThread();
+ rt->gc.storeBuffer.putWholeCell(unboxedObject);
+ }
+
+ if (preBarrier)
+ JSObject::writeBarrierPre(*np);
+ *np = obj;
+ return true;
+ }
+ return false;
+
+ default:
+ MOZ_CRASH("Invalid type for unboxed value");
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// UnboxedPlainObject
+/////////////////////////////////////////////////////////////////////
+
+inline const UnboxedLayout&
+UnboxedPlainObject::layout() const
+{
+ return group()->unboxedLayout();
+}
+
+/////////////////////////////////////////////////////////////////////
+// UnboxedArrayObject
+/////////////////////////////////////////////////////////////////////
+
+inline const UnboxedLayout&
+UnboxedArrayObject::layout() const
+{
+ return group()->unboxedLayout();
+}
+
+inline void
+UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
+{
+ if (length > INT32_MAX) {
+ // Track objects with overflowing lengths in type information.
+ MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
+ }
+
+ length_ = length;
+}
+
+inline void
+UnboxedArrayObject::setInitializedLength(uint32_t initlen)
+{
+ if (initlen < initializedLength()) {
+ switch (elementType()) {
+ case JSVAL_TYPE_STRING:
+ for (size_t i = initlen; i < initializedLength(); i++)
+ triggerPreBarrier<JSVAL_TYPE_STRING>(i);
+ break;
+ case JSVAL_TYPE_OBJECT:
+ for (size_t i = initlen; i < initializedLength(); i++)
+ triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
+ break;
+ default:
+ MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
+ }
+ }
+ setInitializedLengthNoBarrier(initlen);
+}
+
+template <JSValueType Type>
+inline bool
+UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ MOZ_ASSERT(Type == elementType());
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+ return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
+}
+
+template <JSValueType Type>
+inline void
+UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ MOZ_ASSERT(Type == elementType());
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+ return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true);
+}
+
+template <JSValueType Type>
+inline bool
+UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ MOZ_ASSERT(Type == elementType());
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+ return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
+}
+
+template <JSValueType Type>
+inline void
+UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ MOZ_ASSERT(Type == elementType());
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+ return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
+}
+
+template <JSValueType Type>
+inline Value
+UnboxedArrayObject::getElementSpecific(size_t index)
+{
+ MOZ_ASSERT(index < initializedLength());
+ MOZ_ASSERT(Type == elementType());
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+ return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false);
+}
+
+template <JSValueType Type>
+inline void
+UnboxedArrayObject::triggerPreBarrier(size_t index)
+{
+ MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type));
+
+ uint8_t* p = elements() + index * UnboxedTypeSize(Type);
+
+ switch (Type) {
+ case JSVAL_TYPE_STRING: {
+ JSString** np = reinterpret_cast<JSString**>(p);
+ JSString::writeBarrierPre(*np);
+ break;
+ }
+
+ case JSVAL_TYPE_OBJECT: {
+ JSObject** np = reinterpret_cast<JSObject**>(p);
+ JSObject::writeBarrierPre(*np);
+ break;
+ }
+
+ default:
+ MOZ_CRASH("Bad type");
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// Combined methods for NativeObject and UnboxedArrayObject accesses.
+/////////////////////////////////////////////////////////////////////
+
+static inline bool
+HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
+{
+ return obj->isNative() || obj->is<UnboxedArrayObject>();
+}
+
+static inline size_t
+GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
+{
+ if (obj->isNative())
+ return obj->as<NativeObject>().getDenseInitializedLength();
+ if (obj->is<UnboxedArrayObject>())
+ return obj->as<UnboxedArrayObject>().initializedLength();
+ return 0;
+}
+
+static inline size_t
+GetAnyBoxedOrUnboxedCapacity(JSObject* obj)
+{
+ if (obj->isNative())
+ return obj->as<NativeObject>().getDenseCapacity();
+ if (obj->is<UnboxedArrayObject>())
+ return obj->as<UnboxedArrayObject>().capacity();
+ return 0;
+}
+
+static inline Value
+GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
+{
+ if (obj->isNative())
+ return obj->as<NativeObject>().getDenseElement(index);
+ return obj->as<UnboxedArrayObject>().getElement(index);
+}
+
+static inline size_t
+GetAnyBoxedOrUnboxedArrayLength(JSObject* obj)
+{
+ if (obj->is<ArrayObject>())
+ return obj->as<ArrayObject>().length();
+ return obj->as<UnboxedArrayObject>().length();
+}
+
+static inline void
+SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length)
+{
+ if (obj->is<ArrayObject>()) {
+ MOZ_ASSERT(length >= obj->as<ArrayObject>().length());
+ obj->as<ArrayObject>().setLength(cx, length);
+ } else {
+ MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length());
+ obj->as<UnboxedArrayObject>().setLength(cx, length);
+ }
+}
+
+static inline bool
+SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
+{
+ if (obj->isNative()) {
+ obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
+ return true;
+ }
+ return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
+}
+
+static inline bool
+InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
+{
+ if (obj->isNative()) {
+ obj->as<NativeObject>().initDenseElementWithType(cx, index, value);
+ return true;
+ }
+ return obj->as<UnboxedArrayObject>().initElement(cx, index, value);
+}
+
+/////////////////////////////////////////////////////////////////////
+// Template methods for NativeObject and UnboxedArrayObject accesses.
+/////////////////////////////////////////////////////////////////////
+
+static inline JSValueType
+GetBoxedOrUnboxedType(JSObject* obj)
+{
+ if (obj->isNative())
+ return JSVAL_TYPE_MAGIC;
+ return obj->as<UnboxedArrayObject>().elementType();
+}
+
+template <JSValueType Type>
+static inline bool
+HasBoxedOrUnboxedDenseElements(JSObject* obj)
+{
+ if (Type == JSVAL_TYPE_MAGIC)
+ return obj->isNative();
+ return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type;
+}
+
+template <JSValueType Type>
+static inline size_t
+GetBoxedOrUnboxedInitializedLength(JSObject* obj)
+{
+ if (Type == JSVAL_TYPE_MAGIC)
+ return obj->as<NativeObject>().getDenseInitializedLength();
+ return obj->as<UnboxedArrayObject>().initializedLength();
+}
+
+template <JSValueType Type>
+static inline DenseElementResult
+SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
+{
+ size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
+ if (Type == JSVAL_TYPE_MAGIC) {
+ obj->as<NativeObject>().setDenseInitializedLength(initlen);
+ if (initlen < oldInitlen)
+ obj->as<NativeObject>().shrinkElements(cx, initlen);
+ } else {
+ obj->as<UnboxedArrayObject>().setInitializedLength(initlen);
+ if (initlen < oldInitlen)
+ obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen);
+ }
+ return DenseElementResult::Success;
+}
+
+template <JSValueType Type>
+static inline size_t
+GetBoxedOrUnboxedCapacity(JSObject* obj)
+{
+ if (Type == JSVAL_TYPE_MAGIC)
+ return obj->as<NativeObject>().getDenseCapacity();
+ return obj->as<UnboxedArrayObject>().capacity();
+}
+
+template <JSValueType Type>
+static inline Value
+GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
+{
+ if (Type == JSVAL_TYPE_MAGIC)
+ return obj->as<NativeObject>().getDenseElement(index);
+ return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index);
+}
+
+template <JSValueType Type>
+static inline void
+SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value)
+{
+ if (Type == JSVAL_TYPE_MAGIC)
+ obj->as<NativeObject>().setDenseElement(index, value);
+ else
+ obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value);
+}
+
+template <JSValueType Type>
+static inline bool
+SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
+{
+ if (Type == JSVAL_TYPE_MAGIC) {
+ obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
+ return true;
+ }
+ return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value);
+}
+
+template <JSValueType Type>
+static inline DenseElementResult
+EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
+{
+ if (Type == JSVAL_TYPE_MAGIC) {
+ if (!obj->as<ArrayObject>().ensureElements(cx, count))
+ return DenseElementResult::Failure;
+ } else {
+ if (obj->as<UnboxedArrayObject>().capacity() < count) {
+ if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
+ return DenseElementResult::Failure;
+ }
+ }
+ return DenseElementResult::Success;
+}
+
+template <JSValueType Type>
+static inline DenseElementResult
+SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
+ uint32_t start, const Value* vp, uint32_t count,
+ ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update)
+{
+ if (Type == JSVAL_TYPE_MAGIC) {
+ NativeObject* nobj = &obj->as<NativeObject>();
+
+ if (nobj->denseElementsAreFrozen())
+ return DenseElementResult::Incomplete;
+
+ if (obj->is<ArrayObject>() &&
+ !obj->as<ArrayObject>().lengthIsWritable() &&
+ start + count >= obj->as<ArrayObject>().length())
+ {
+ return DenseElementResult::Incomplete;
+ }
+
+ DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
+ if (result != DenseElementResult::Success)
+ return result;
+
+ if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
+ obj->as<ArrayObject>().setLengthInt32(start + count);
+
+ if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
+ nobj->copyDenseElements(start, vp, count);
+ } else {
+ for (size_t i = 0; i < count; i++)
+ nobj->setDenseElementWithType(cx, start + i, vp[i]);
+ }
+
+ return DenseElementResult::Success;
+ }
+
+ UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
+
+ if (start > nobj->initializedLength())
+ return DenseElementResult::Incomplete;
+
+ if (start + count >= UnboxedArrayObject::MaximumCapacity)
+ return DenseElementResult::Incomplete;
+
+ if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count))
+ return DenseElementResult::Failure;
+
+ size_t oldInitlen = nobj->initializedLength();
+
+ // Overwrite any existing elements covered by the new range. If we fail
+ // after this point due to some incompatible type being written to the
+ // object's elements, afterwards the contents will be different from when
+ // we started. The caller must retry the operation using a generic path,
+ // which will overwrite the already-modified elements as well as the ones
+ // that were left alone.
+ size_t i = 0;
+ if (updateTypes == ShouldUpdateTypes::DontUpdate) {
+ for (size_t j = start; i < count && j < oldInitlen; i++, j++)
+ nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]);
+ } else {
+ for (size_t j = start; i < count && j < oldInitlen; i++, j++) {
+ if (!nobj->setElementSpecific<Type>(cx, j, vp[i]))
+ return DenseElementResult::Incomplete;
+ }
+ }
+
+ if (i != count) {
+ obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
+ if (updateTypes == ShouldUpdateTypes::DontUpdate) {
+ for (; i < count; i++)
+ nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]);
+ } else {
+ for (; i < count; i++) {
+ if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) {
+ nobj->setInitializedLengthNoBarrier(oldInitlen);
+ return DenseElementResult::Incomplete;
+ }
+ }
+ }
+ }
+
+ if (start + count >= nobj->length())
+ nobj->setLength(cx, start + count);
+
+ return DenseElementResult::Success;
+}
+
+template <JSValueType Type>
+static inline DenseElementResult
+MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart,
+ uint32_t length)
+{
+ MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
+
+ if (Type == JSVAL_TYPE_MAGIC) {
+ if (obj->as<NativeObject>().denseElementsAreFrozen())
+ return DenseElementResult::Incomplete;
+
+ if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
+ return DenseElementResult::Failure;
+ obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
+ } else {
+ uint8_t* data = obj->as<UnboxedArrayObject>().elements();
+ size_t elementSize = UnboxedTypeSize(Type);
+
+ if (UnboxedTypeNeedsPreBarrier(Type) &&
+ JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier())
+ {
+ // Trigger pre barriers on any elements we are overwriting. See
+ // NativeObject::moveDenseElements. No post barrier is needed as
+ // only whole cell post barriers are used with unboxed objects.
+ for (size_t i = 0; i < length; i++)
+ obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i);
+ }
+
+ memmove(data + dstStart * elementSize,
+ data + srcStart * elementSize,
+ length * elementSize);
+ }
+
+ return DenseElementResult::Success;
+}
+
+template <JSValueType DstType, JSValueType SrcType>
+static inline DenseElementResult
+CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
+ uint32_t dstStart, uint32_t srcStart, uint32_t length)
+{
+ MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
+ MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
+ MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
+ MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
+ MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
+
+ SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
+
+ if (DstType == JSVAL_TYPE_MAGIC) {
+ if (SrcType == JSVAL_TYPE_MAGIC) {
+ const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
+ dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
+ } else {
+ for (size_t i = 0; i < length; i++) {
+ Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
+ dst->as<NativeObject>().initDenseElement(dstStart + i, v);
+ }
+ }
+ } else if (DstType == SrcType) {
+ uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
+ uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
+ size_t elementSize = UnboxedTypeSize(DstType);
+
+ memcpy(dstData + dstStart * elementSize,
+ srcData + srcStart * elementSize,
+ length * elementSize);
+
+ // Add a store buffer entry if we might have copied a nursery pointer to dst.
+ if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
+ dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst);
+ } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
+ uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
+ uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
+
+ for (size_t i = 0; i < length; i++) {
+ int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t));
+ *reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v;
+ }
+ } else {
+ for (size_t i = 0; i < length; i++) {
+ Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
+ dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v);
+ }
+ }
+
+ return DenseElementResult::Success;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Dispatch to specialized methods based on the type of an object.
+/////////////////////////////////////////////////////////////////////
+
+// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h.
+// The clang-cl front end defines _MSC_VER, but still requires the explicit
+// template declaration, so we must test for __clang__ here as well.
+#if defined(_MSC_VER) && !defined(__clang__)
+# define DEPENDENT_TEMPLATE_HINT
+#else
+# define DEPENDENT_TEMPLATE_HINT template
+#endif
+
+// Function to dispatch a method specialized to whatever boxed or unboxed dense
+// elements which an input object has.
+template <typename F>
+DenseElementResult
+CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
+{
+ if (!HasAnyBoxedOrUnboxedDenseElements(obj))
+ return DenseElementResult::Incomplete;
+ switch (GetBoxedOrUnboxedType(obj)) {
+ case JSVAL_TYPE_MAGIC:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
+ case JSVAL_TYPE_BOOLEAN:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
+ case JSVAL_TYPE_INT32:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
+ case JSVAL_TYPE_DOUBLE:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
+ case JSVAL_TYPE_STRING:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
+ case JSVAL_TYPE_OBJECT:
+ return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
+ default:
+ MOZ_CRASH();
+ }
+}
+
+// As above, except the specialization can reflect the unboxed type of two objects.
+template <typename F>
+DenseElementResult
+CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2)
+{
+ if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2))
+ return DenseElementResult::Incomplete;
+
+#define SPECIALIZE_OBJ2(TYPE) \
+ switch (GetBoxedOrUnboxedType(obj2)) { \
+ case JSVAL_TYPE_MAGIC: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \
+ case JSVAL_TYPE_BOOLEAN: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \
+ case JSVAL_TYPE_INT32: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \
+ case JSVAL_TYPE_DOUBLE: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \
+ case JSVAL_TYPE_STRING: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \
+ case JSVAL_TYPE_OBJECT: \
+ return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \
+ default: \
+ MOZ_CRASH(); \
+ }
+
+ switch (GetBoxedOrUnboxedType(obj1)) {
+ case JSVAL_TYPE_MAGIC:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC)
+ case JSVAL_TYPE_BOOLEAN:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN)
+ case JSVAL_TYPE_INT32:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_INT32)
+ case JSVAL_TYPE_DOUBLE:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE)
+ case JSVAL_TYPE_STRING:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_STRING)
+ case JSVAL_TYPE_OBJECT:
+ SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT)
+ default:
+ MOZ_CRASH();
+ }
+
+#undef SPECIALIZE_OBJ2
+}
+
+#undef DEPENDENT_TEMPLATE_HINT
+
+#define DefineBoxedOrUnboxedFunctor1(Signature, A) \
+struct Signature ## Functor { \
+ A a; \
+ explicit Signature ## Functor(A a) \
+ : a(a) \
+ {} \
+ template <JSValueType Type> \
+ DenseElementResult operator()() { \
+ return Signature<Type>(a); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C) \
+struct Signature ## Functor { \
+ A a; B b; C c; \
+ Signature ## Functor(A a, B b, C c) \
+ : a(a), b(b), c(c) \
+ {} \
+ template <JSValueType Type> \
+ DenseElementResult operator()() { \
+ return Signature<Type>(a, b, c); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D) \
+struct Signature ## Functor { \
+ A a; B b; C c; D d; \
+ Signature ## Functor(A a, B b, C c, D d) \
+ : a(a), b(b), c(c), d(d) \
+ {} \
+ template <JSValueType Type> \
+ DenseElementResult operator()() { \
+ return Signature<Type>(a, b, c, d); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \
+struct Signature ## Functor { \
+ A a; B b; C c; D d; \
+ Signature ## Functor(A a, B b, C c, D d) \
+ : a(a), b(b), c(c), d(d) \
+ {} \
+ template <JSValueType TypeOne, JSValueType TypeTwo> \
+ DenseElementResult operator()() { \
+ return Signature<TypeOne, TypeTwo>(a, b, c, d); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \
+struct Signature ## Functor { \
+ A a; B b; C c; D d; E e; \
+ Signature ## Functor(A a, B b, C c, D d, E e) \
+ : a(a), b(b), c(c), d(d), e(e) \
+ {} \
+ template <JSValueType Type> \
+ DenseElementResult operator()() { \
+ return Signature<Type>(a, b, c, d, e); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \
+struct Signature ## Functor { \
+ A a; B b; C c; D d; E e; F f; \
+ Signature ## Functor(A a, B b, C c, D d, E e, F f) \
+ : a(a), b(b), c(c), d(d), e(e), f(f) \
+ {} \
+ template <JSValueType Type> \
+ DenseElementResult operator()() { \
+ return Signature<Type>(a, b, c, d, e, f); \
+ } \
+}
+
+#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \
+struct Signature ## Functor { \
+ A a; B b; C c; D d; E e; F f; \
+ Signature ## Functor(A a, B b, C c, D d, E e, F f) \
+ : a(a), b(b), c(c), d(d), e(e), f(f) \
+ {} \
+ template <JSValueType TypeOne, JSValueType TypeTwo> \
+ DenseElementResult operator()() { \
+ return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f); \
+ } \
+}
+
+DenseElementResult
+SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
+ uint32_t start, const Value* vp, uint32_t count,
+ ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
+
+DenseElementResult
+MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
+ uint32_t dstStart, uint32_t srcStart, uint32_t length);
+
+DenseElementResult
+CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
+ uint32_t dstStart, uint32_t srcStart, uint32_t length);
+
+void
+SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
+
+DenseElementResult
+EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
+
+} // namespace js
+
+#endif // vm_UnboxedObject_inl_h
diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
new file mode 100644
index 000000000..3018ace67
--- /dev/null
+++ b/js/src/vm/UnboxedObject.cpp
@@ -0,0 +1,2152 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/UnboxedObject-inl.h"
+
+#include "jit/BaselineIC.h"
+#include "jit/ExecutableAllocator.h"
+#include "jit/JitCommon.h"
+#include "jit/Linker.h"
+
+#include "jsobjinlines.h"
+
+#include "gc/Nursery-inl.h"
+#include "jit/MacroAssembler-inl.h"
+#include "vm/Shape-inl.h"
+
+using mozilla::ArrayLength;
+using mozilla::DebugOnly;
+using mozilla::PodCopy;
+
+using namespace js;
+
+/////////////////////////////////////////////////////////////////////
+// UnboxedLayout
+/////////////////////////////////////////////////////////////////////
+
+void
+UnboxedLayout::trace(JSTracer* trc)
+{
+ for (size_t i = 0; i < properties_.length(); i++)
+ TraceManuallyBarrieredEdge(trc, &properties_[i].name, "unboxed_layout_name");
+
+ if (newScript())
+ newScript()->trace(trc);
+
+ TraceNullableEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup");
+ TraceNullableEdge(trc, &nativeShape_, "unboxed_layout_nativeShape");
+ TraceNullableEdge(trc, &allocationScript_, "unboxed_layout_allocationScript");
+ TraceNullableEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup");
+ TraceNullableEdge(trc, &constructorCode_, "unboxed_layout_constructorCode");
+}
+
+size_t
+UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+ return mallocSizeOf(this)
+ + properties_.sizeOfExcludingThis(mallocSizeOf)
+ + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0)
+ + mallocSizeOf(traceList());
+}
+
+void
+UnboxedLayout::setNewScript(TypeNewScript* newScript, bool writeBarrier /* = true */)
+{
+ if (newScript_ && writeBarrier)
+ TypeNewScript::writeBarrierPre(newScript_);
+ newScript_ = newScript;
+}
+
+// Constructor code returns a 0x1 value to indicate the constructor code should
+// be cleared.
+static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1;
+
+/* static */ bool
+UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
+{
+ gc::AutoSuppressGC suppress(cx);
+
+ using namespace jit;
+
+ if (!cx->compartment()->ensureJitCompartmentExists(cx))
+ return false;
+
+ UnboxedLayout& layout = group->unboxedLayout();
+ MOZ_ASSERT(!layout.constructorCode());
+
+ UnboxedPlainObject* templateObject = UnboxedPlainObject::create(cx, group, TenuredObject);
+ if (!templateObject)
+ return false;
+
+ JitContext jitContext(cx, nullptr);
+
+ MacroAssembler masm;
+
+ Register propertiesReg, newKindReg;
+#ifdef JS_CODEGEN_X86
+ propertiesReg = eax;
+ newKindReg = ecx;
+ masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg);
+ masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg);
+#else
+ propertiesReg = IntArgReg0;
+ newKindReg = IntArgReg1;
+#endif
+
+#ifdef JS_CODEGEN_ARM64
+ // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
+ masm.initStackPtr();
+#endif
+
+ MOZ_ASSERT(propertiesReg.volatile_());
+ MOZ_ASSERT(newKindReg.volatile_());
+
+ AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+ regs.take(propertiesReg);
+ regs.take(newKindReg);
+ Register object = regs.takeAny(), scratch1 = regs.takeAny(), scratch2 = regs.takeAny();
+
+ LiveGeneralRegisterSet savedNonVolatileRegisters = SavedNonVolatileRegisters(regs);
+ masm.PushRegsInMask(savedNonVolatileRegisters);
+
+ // The scratch double register might be used by MacroAssembler methods.
+ if (ScratchDoubleReg.volatile_())
+ masm.push(ScratchDoubleReg);
+
+ Label failure, tenuredObject, allocated;
+ masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), &tenuredObject);
+ masm.branchTest32(Assembler::NonZero, AbsoluteAddress(group->addressOfFlags()),
+ Imm32(OBJECT_FLAG_PRE_TENURE), &tenuredObject);
+
+ // Allocate an object in the nursery
+ masm.createGCObject(object, scratch1, templateObject, gc::DefaultHeap, &failure,
+ /* initFixedSlots = */ false);
+
+ masm.jump(&allocated);
+ masm.bind(&tenuredObject);
+
+ // Allocate an object in the tenured heap.
+ masm.createGCObject(object, scratch1, templateObject, gc::TenuredHeap, &failure,
+ /* initFixedSlots = */ false);
+
+ // If any of the properties being stored are in the nursery, add a store
+ // buffer entry for the new object.
+ Label postBarrier;
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+ if (property.type == JSVAL_TYPE_OBJECT) {
+ Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
+ Label notObject;
+ masm.branchTestObject(Assembler::NotEqual, valueAddress, &notObject);
+ Register valueObject = masm.extractObject(valueAddress, scratch1);
+ masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, &postBarrier);
+ masm.bind(&notObject);
+ }
+ }
+
+ masm.jump(&allocated);
+ masm.bind(&postBarrier);
+
+ LiveGeneralRegisterSet liveVolatileRegisters;
+ liveVolatileRegisters.add(propertiesReg);
+ if (object.volatile_())
+ liveVolatileRegisters.add(object);
+ masm.PushRegsInMask(liveVolatileRegisters);
+
+ masm.mov(ImmPtr(cx->runtime()), scratch1);
+ masm.setupUnalignedABICall(scratch2);
+ masm.passABIArg(scratch1);
+ masm.passABIArg(object);
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
+
+ masm.PopRegsInMask(liveVolatileRegisters);
+
+ masm.bind(&allocated);
+
+ ValueOperand valueOperand;
+#ifdef JS_NUNBOX32
+ valueOperand = ValueOperand(scratch1, scratch2);
+#else
+ valueOperand = ValueOperand(scratch1);
+#endif
+
+ Label failureStoreOther, failureStoreObject;
+
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+ Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
+ Address targetAddress(object, UnboxedPlainObject::offsetOfData() + property.offset);
+
+ masm.loadValue(valueAddress, valueOperand);
+
+ if (property.type == JSVAL_TYPE_OBJECT) {
+ HeapTypeSet* types = group->maybeGetProperty(IdToTypeId(NameToId(property.name)));
+
+ Label notObject;
+ masm.branchTestObject(Assembler::NotEqual, valueOperand,
+ types->mightBeMIRType(MIRType::Null) ? &notObject : &failureStoreObject);
+
+ Register payloadReg = masm.extractObject(valueOperand, scratch1);
+
+ if (!types->hasType(TypeSet::AnyObjectType())) {
+ Register scratch = (payloadReg == scratch1) ? scratch2 : scratch1;
+ masm.guardObjectType(payloadReg, types, scratch, &failureStoreObject);
+ }
+
+ masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT,
+ TypedOrValueRegister(MIRType::Object,
+ AnyRegister(payloadReg)), nullptr);
+
+ if (notObject.used()) {
+ Label done;
+ masm.jump(&done);
+ masm.bind(&notObject);
+ masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
+ masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, NullValue(), nullptr);
+ masm.bind(&done);
+ }
+ } else {
+ masm.storeUnboxedProperty(targetAddress, property.type,
+ ConstantOrRegister(valueOperand), &failureStoreOther);
+ }
+ }
+
+ Label done;
+ masm.bind(&done);
+
+ if (object != ReturnReg)
+ masm.movePtr(object, ReturnReg);
+
+ // Restore non-volatile registers which were saved on entry.
+ if (ScratchDoubleReg.volatile_())
+ masm.pop(ScratchDoubleReg);
+ masm.PopRegsInMask(savedNonVolatileRegisters);
+
+ masm.abiret();
+
+ masm.bind(&failureStoreOther);
+
+ // There was a failure while storing a value which cannot be stored at all
+ // in the unboxed object. Initialize the object so it is safe for GC and
+ // return null.
+ masm.initUnboxedObjectContents(object, templateObject);
+
+ masm.bind(&failure);
+
+ masm.movePtr(ImmWord(0), object);
+ masm.jump(&done);
+
+ masm.bind(&failureStoreObject);
+
+ // There was a failure while storing a value to an object slot of the
+ // unboxed object. If the value is storable, the failure occurred due to
+ // incomplete type information in the object, so return a token to trigger
+ // regeneration of the jitcode after a new object is created in the VM.
+ {
+ Label isObject;
+ masm.branchTestObject(Assembler::Equal, valueOperand, &isObject);
+ masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
+ masm.bind(&isObject);
+ }
+
+ // Initialize the object so it is safe for GC.
+ masm.initUnboxedObjectContents(object, templateObject);
+
+ masm.movePtr(ImmWord(CLEAR_CONSTRUCTOR_CODE_TOKEN), object);
+ masm.jump(&done);
+
+ Linker linker(masm);
+ AutoFlushICache afc("UnboxedObject");
+ JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
+ if (!code)
+ return false;
+
+ layout.setConstructorCode(code);
+ return true;
+}
+
+void
+UnboxedLayout::detachFromCompartment()
+{
+ if (isInList())
+ remove();
+}
+
+/////////////////////////////////////////////////////////////////////
+// UnboxedPlainObject
+/////////////////////////////////////////////////////////////////////
+
+bool
+UnboxedPlainObject::setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property,
+ const Value& v)
+{
+ uint8_t* p = &data_[property.offset];
+ return SetUnboxedValue(cx, this, NameToId(property.name), p, property.type, v,
+ /* preBarrier = */ true);
+}
+
+Value
+UnboxedPlainObject::getValue(const UnboxedLayout::Property& property,
+ bool maybeUninitialized /* = false */)
+{
+ uint8_t* p = &data_[property.offset];
+ return GetUnboxedValue(p, property.type, maybeUninitialized);
+}
+
+void
+UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj)
+{
+ if (obj->as<UnboxedPlainObject>().expando_) {
+ TraceManuallyBarrieredEdge(trc,
+ reinterpret_cast<NativeObject**>(&obj->as<UnboxedPlainObject>().expando_),
+ "unboxed_expando");
+ }
+
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration();
+ const int32_t* list = layout.traceList();
+ if (!list)
+ return;
+
+ uint8_t* data = obj->as<UnboxedPlainObject>().data();
+ while (*list != -1) {
+ GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
+ TraceEdge(trc, heap, "unboxed_string");
+ list++;
+ }
+ list++;
+ while (*list != -1) {
+ GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list);
+ TraceNullableEdge(trc, heap, "unboxed_object");
+ list++;
+ }
+
+ // Unboxed objects don't have Values to trace.
+ MOZ_ASSERT(*(list + 1) == -1);
+}
+
+/* static */ UnboxedExpandoObject*
+UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj)
+{
+ if (obj->expando_)
+ return obj->expando_;
+
+ UnboxedExpandoObject* expando =
+ NewObjectWithGivenProto<UnboxedExpandoObject>(cx, nullptr, gc::AllocKind::OBJECT4);
+ if (!expando)
+ return nullptr;
+
+ // Don't track property types for expando objects. This allows Baseline
+ // and Ion AddSlot ICs to guard on the unboxed group without guarding on
+ // the expando group.
+ MarkObjectGroupUnknownProperties(cx, expando->group());
+
+ // If the expando is tenured then the original object must also be tenured.
+ // Otherwise barriers triggered on the original object for writes to the
+ // expando (as can happen in the JIT) won't see the tenured->nursery edge.
+ // See WholeCellEdges::mark.
+ MOZ_ASSERT_IF(!IsInsideNursery(expando), !IsInsideNursery(obj));
+
+ // As with setValue(), we need to manually trigger post barriers on the
+ // whole object. If we treat the field as a GCPtrObject and later
+ // convert the object to its native representation, we will end up with a
+ // corrupted store buffer entry.
+ if (IsInsideNursery(expando) && !IsInsideNursery(obj))
+ cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+
+ obj->expando_ = expando;
+ return expando;
+}
+
+bool
+UnboxedPlainObject::containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const
+{
+ if (layout().lookup(id))
+ return true;
+
+ if (maybeExpando() && maybeExpando()->containsShapeOrElement(cx, id))
+ return true;
+
+ return false;
+}
+
+static bool
+PropagatePropertyTypes(JSContext* cx, jsid id, ObjectGroup* oldGroup, ObjectGroup* newGroup)
+{
+ HeapTypeSet* typeProperty = oldGroup->maybeGetProperty(id);
+ TypeSet::TypeList types;
+ if (!typeProperty->enumerateTypes(&types)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ for (size_t j = 0; j < types.length(); j++)
+ AddTypePropertyId(cx, newGroup, nullptr, id, types[j]);
+ return true;
+}
+
+static PlainObject*
+MakeReplacementTemplateObject(JSContext* cx, HandleObjectGroup group, const UnboxedLayout &layout)
+{
+ PlainObject* obj = NewObjectWithGroup<PlainObject>(cx, group, layout.getAllocKind(),
+ TenuredObject);
+ if (!obj)
+ return nullptr;
+
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+ if (!obj->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE))
+ return nullptr;
+ MOZ_ASSERT(obj->slotSpan() == i + 1);
+ MOZ_ASSERT(!obj->inDictionaryMode());
+ }
+
+ return obj;
+}
+
+/* static */ bool
+UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
+{
+ AutoEnterAnalysis enter(cx);
+
+ UnboxedLayout& layout = group->unboxedLayout();
+ Rooted<TaggedProto> proto(cx, group->proto());
+
+ MOZ_ASSERT(!layout.nativeGroup());
+
+ RootedObjectGroup replacementGroup(cx);
+
+ const Class* clasp = layout.isArray() ? &ArrayObject::class_ : &PlainObject::class_;
+
+ // Immediately clear any new script on the group. This is done by replacing
+ // the existing new script with one for a replacement default new group.
+ // This is done so that the size of the replacment group's objects is the
+ // same as that for the unboxed group, so that we do not see polymorphic
+ // slot accesses later on for sites that see converted objects from this
+ // group and objects that were allocated using the replacement new group.
+ if (layout.newScript()) {
+ MOZ_ASSERT(!layout.isArray());
+
+ replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
+ if (!replacementGroup)
+ return false;
+
+ PlainObject* templateObject = MakeReplacementTemplateObject(cx, replacementGroup, layout);
+ if (!templateObject)
+ return false;
+
+ TypeNewScript* replacementNewScript =
+ TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject);
+ if (!replacementNewScript)
+ return false;
+
+ replacementGroup->setNewScript(replacementNewScript);
+ gc::TraceTypeNewScript(replacementGroup);
+
+ group->clearNewScript(cx, replacementGroup);
+ }
+
+ // Similarly, if this group is keyed to an allocation site, replace its
+ // entry with a new group that has no unboxed layout.
+ if (layout.allocationScript()) {
+ RootedScript script(cx, layout.allocationScript());
+ jsbytecode* pc = layout.allocationPc();
+
+ replacementGroup = ObjectGroupCompartment::makeGroup(cx, clasp, proto);
+ if (!replacementGroup)
+ return false;
+
+ PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>();
+ replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty());
+
+ JSProtoKey key = layout.isArray() ? JSProto_Array : JSProto_Object;
+ cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, key,
+ replacementGroup);
+
+ // Clear any baseline information at this opcode which might use the old group.
+ if (script->hasBaselineScript()) {
+ jit::ICEntry& entry = script->baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc));
+ jit::ICFallbackStub* fallback = entry.fallbackStub();
+ for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd(); iter++)
+ iter.unlink(cx);
+ if (fallback->isNewObject_Fallback())
+ fallback->toNewObject_Fallback()->setTemplateObject(nullptr);
+ else if (fallback->isNewArray_Fallback())
+ fallback->toNewArray_Fallback()->setTemplateGroup(replacementGroup);
+ }
+ }
+
+ size_t nfixed = layout.isArray() ? 0 : gc::GetGCKindSlots(layout.getAllocKind());
+
+ if (layout.isArray()) {
+ // The length shape to use for arrays is cached via a modified initial
+ // shape for array objects. Create an array now to make sure this entry
+ // is instantiated.
+ if (!NewDenseEmptyArray(cx))
+ return false;
+ }
+
+ RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, proto, nfixed, 0));
+ if (!shape)
+ return false;
+
+ MOZ_ASSERT_IF(layout.isArray(), !shape->isEmptyShape() && shape->slotSpan() == 0);
+
+ // Add shapes for each property, if this is for a plain object.
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+
+ Rooted<StackShape> child(cx, StackShape(shape->base()->unowned(), NameToId(property.name),
+ i, JSPROP_ENUMERATE, 0));
+ shape = cx->zone()->propertyTree.getChild(cx, shape, child);
+ if (!shape)
+ return false;
+ }
+
+ ObjectGroup* nativeGroup =
+ ObjectGroupCompartment::makeGroup(cx, clasp, proto,
+ group->flags() & OBJECT_FLAG_DYNAMIC_MASK);
+ if (!nativeGroup)
+ return false;
+
+ // No sense propagating if we don't know what we started with.
+ if (!group->unknownProperties()) {
+ // Propagate all property types from the old group to the new group.
+ if (layout.isArray()) {
+ if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup))
+ return false;
+ } else {
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+ jsid id = NameToId(property.name);
+ if (!PropagatePropertyTypes(cx, id, group, nativeGroup))
+ return false;
+
+ // If we are OOM we may not be able to propagate properties.
+ if (nativeGroup->unknownProperties())
+ break;
+
+ HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id);
+ if (nativeProperty && nativeProperty->canSetDefinite(i))
+ nativeProperty->setDefinite(i);
+ }
+ }
+ } else {
+ // If we skip, though, the new group had better agree.
+ MOZ_ASSERT(nativeGroup->unknownProperties());
+ }
+
+ layout.nativeGroup_ = nativeGroup;
+ layout.nativeShape_ = shape;
+ layout.replacementGroup_ = replacementGroup;
+
+ nativeGroup->setOriginalUnboxedGroup(group);
+
+ group->markStateChange(cx);
+
+ return true;
+}
+
+/* static */ bool
+UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+ UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
+
+ if (!layout.nativeGroup()) {
+ if (!UnboxedLayout::makeNativeGroup(cx, obj->group()))
+ return false;
+
+ // makeNativeGroup can reentrantly invoke this method.
+ if (obj->is<PlainObject>())
+ return true;
+ }
+
+ AutoValueVector values(cx);
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ // We might be reading properties off the object which have not been
+ // initialized yet. Make sure any double values we read here are
+ // canonicalized.
+ if (!values.append(obj->as<UnboxedPlainObject>().getValue(layout.properties()[i], true)))
+ return false;
+ }
+
+ // We are eliminating the expando edge with the conversion, so trigger a
+ // pre barrier.
+ JSObject::writeBarrierPre(expando);
+
+ // Additionally trigger a post barrier on the expando itself. Whole cell
+ // store buffer entries can be added on the original unboxed object for
+ // writes to the expando (see WholeCellEdges::trace), so after conversion
+ // we need to make sure the expando itself will still be traced.
+ if (expando && !IsInsideNursery(expando))
+ cx->runtime()->gc.storeBuffer.putWholeCell(expando);
+
+ obj->setGroup(layout.nativeGroup());
+ obj->as<PlainObject>().setLastPropertyMakeNative(cx, layout.nativeShape());
+
+ for (size_t i = 0; i < values.length(); i++)
+ obj->as<PlainObject>().initSlotUnchecked(i, values[i]);
+
+ if (expando) {
+ // Add properties from the expando object to the object, in order.
+ // Suppress GC here, so that callers don't need to worry about this
+ // method collecting. The stuff below can only fail due to OOM, in
+ // which case the object will not have been completely filled back in.
+ gc::AutoSuppressGC suppress(cx);
+
+ Vector<jsid> ids(cx);
+ for (Shape::Range<NoGC> r(expando->lastProperty()); !r.empty(); r.popFront()) {
+ if (!ids.append(r.front().propid()))
+ return false;
+ }
+ for (size_t i = 0; i < expando->getDenseInitializedLength(); i++) {
+ if (!expando->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
+ if (!ids.append(INT_TO_JSID(i)))
+ return false;
+ }
+ }
+ ::Reverse(ids.begin(), ids.end());
+
+ RootedPlainObject nobj(cx, &obj->as<PlainObject>());
+ Rooted<UnboxedExpandoObject*> nexpando(cx, expando);
+ RootedId id(cx);
+ Rooted<PropertyDescriptor> desc(cx);
+ for (size_t i = 0; i < ids.length(); i++) {
+ id = ids[i];
+ if (!GetOwnPropertyDescriptor(cx, nexpando, id, &desc))
+ return false;
+ ObjectOpResult result;
+ if (!DefineProperty(cx, nobj, id, desc, result))
+ return false;
+ MOZ_ASSERT(result.ok());
+ }
+ }
+
+ return true;
+}
+
+/* static */
+UnboxedPlainObject*
+UnboxedPlainObject::create(ExclusiveContext* cx, HandleObjectGroup group, NewObjectKind newKind)
+{
+ AutoSetNewObjectMetadata metadata(cx);
+
+ MOZ_ASSERT(group->clasp() == &class_);
+ gc::AllocKind allocKind = group->unboxedLayout().getAllocKind();
+
+ UnboxedPlainObject* res =
+ NewObjectWithGroup<UnboxedPlainObject>(cx, group, allocKind, newKind);
+ if (!res)
+ return nullptr;
+
+ // Overwrite the dummy shape which was written to the object's expando field.
+ res->initExpando();
+
+ // Initialize reference fields of the object. All fields in the object will
+ // be overwritten shortly, but references need to be safe for the GC.
+ const int32_t* list = res->layout().traceList();
+ if (list) {
+ uint8_t* data = res->data();
+ while (*list != -1) {
+ GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
+ heap->init(cx->names().empty);
+ list++;
+ }
+ list++;
+ while (*list != -1) {
+ GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list);
+ heap->init(nullptr);
+ list++;
+ }
+ // Unboxed objects don't have Values to initialize.
+ MOZ_ASSERT(*(list + 1) == -1);
+ }
+
+ return res;
+}
+
+/* static */ JSObject*
+UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
+ NewObjectKind newKind, IdValuePair* properties)
+{
+ MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject);
+
+ UnboxedLayout& layout = group->unboxedLayout();
+
+ if (layout.constructorCode()) {
+ MOZ_ASSERT(cx->isJSContext());
+
+ typedef JSObject* (*ConstructorCodeSignature)(IdValuePair*, NewObjectKind);
+ ConstructorCodeSignature function =
+ reinterpret_cast<ConstructorCodeSignature>(layout.constructorCode()->raw());
+
+ JSObject* obj;
+ {
+ JS::AutoSuppressGCAnalysis nogc;
+ obj = reinterpret_cast<JSObject*>(CALL_GENERATED_2(function, properties, newKind));
+ }
+ if (obj > reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN))
+ return obj;
+
+ if (obj == reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN))
+ layout.setConstructorCode(nullptr);
+ }
+
+ UnboxedPlainObject* obj = UnboxedPlainObject::create(cx, group, newKind);
+ if (!obj)
+ return nullptr;
+
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ if (!obj->setValue(cx, layout.properties()[i], properties[i].value))
+ return NewPlainObjectWithProperties(cx, properties, layout.properties().length(), newKind);
+ }
+
+#ifndef JS_CODEGEN_NONE
+ if (cx->isJSContext() &&
+ !group->unknownProperties() &&
+ !layout.constructorCode() &&
+ cx->asJSContext()->runtime()->jitSupportsFloatingPoint &&
+ jit::CanLikelyAllocateMoreExecutableMemory())
+ {
+ if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group))
+ return nullptr;
+ }
+#endif
+
+ return obj;
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
+ HandleId id, MutableHandleObject objp,
+ MutableHandleShape propp)
+{
+ if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
+ MarkNonNativePropertyFound<CanGC>(propp);
+ objp.set(obj);
+ return true;
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+ }
+
+ return LookupProperty(cx, proto, id, objp, propp);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+
+ if (const UnboxedLayout::Property* property = layout.lookup(id)) {
+ if (!desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) {
+ // This define is equivalent to setting an existing property.
+ if (obj->as<UnboxedPlainObject>().setValue(cx, *property, desc.value()))
+ return result.succeed();
+ }
+
+ // Trying to incompatibly redefine an existing property requires the
+ // object to be converted to a native object.
+ if (!convertToNative(cx, obj))
+ return false;
+
+ return DefineProperty(cx, obj, id, desc, result);
+ }
+
+ // Define the property on the expando object.
+ Rooted<UnboxedExpandoObject*> expando(cx, ensureExpando(cx, obj.as<UnboxedPlainObject>()));
+ if (!expando)
+ return false;
+
+ // Update property types on the unboxed object as well.
+ AddTypePropertyId(cx, obj, id, desc.value());
+
+ return DefineProperty(cx, expando, id, desc, result);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
+ *foundp = true;
+ return true;
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ *foundp = false;
+ return true;
+ }
+
+ return HasProperty(cx, proto, id, foundp);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
+ HandleId id, MutableHandleValue vp)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+
+ if (const UnboxedLayout::Property* property = layout.lookup(id)) {
+ vp.set(obj->as<UnboxedPlainObject>().getValue(*property));
+ return true;
+ }
+
+ if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
+ if (expando->containsShapeOrElement(cx, id)) {
+ RootedObject nexpando(cx, expando);
+ return GetProperty(cx, nexpando, receiver, id, vp);
+ }
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ vp.setUndefined();
+ return true;
+ }
+
+ return GetProperty(cx, proto, receiver, id, vp);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+
+ if (const UnboxedLayout::Property* property = layout.lookup(id)) {
+ if (receiver.isObject() && obj == &receiver.toObject()) {
+ if (obj->as<UnboxedPlainObject>().setValue(cx, *property, v))
+ return result.succeed();
+
+ if (!convertToNative(cx, obj))
+ return false;
+ return SetProperty(cx, obj, id, v, receiver, result);
+ }
+
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+ }
+
+ if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
+ if (expando->containsShapeOrElement(cx, id)) {
+ // Update property types on the unboxed object as well.
+ AddTypePropertyId(cx, obj, id, v);
+
+ RootedObject nexpando(cx, expando);
+ return SetProperty(cx, nexpando, id, v, receiver, result);
+ }
+ }
+
+ return SetPropertyOnProto(cx, obj, id, v, receiver, result);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
+
+ if (const UnboxedLayout::Property* property = layout.lookup(id)) {
+ desc.value().set(obj->as<UnboxedPlainObject>().getValue(*property));
+ desc.setAttributes(JSPROP_ENUMERATE);
+ desc.object().set(obj);
+ return true;
+ }
+
+ if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
+ if (expando->containsShapeOrElement(cx, id)) {
+ RootedObject nexpando(cx, expando);
+ if (!GetOwnPropertyDescriptor(cx, nexpando, id, desc))
+ return false;
+ if (desc.object() == nexpando)
+ desc.object().set(obj);
+ return true;
+ }
+ }
+
+ desc.object().set(nullptr);
+ return true;
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result)
+{
+ if (!convertToNative(cx, obj))
+ return false;
+ return DeleteProperty(cx, obj, id, result);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
+{
+ if (!convertToNative(cx, obj))
+ return false;
+ return WatchProperty(cx, obj, id, callable);
+}
+
+/* static */ bool
+UnboxedPlainObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly)
+{
+ // Ignore expando properties here, they are special-cased by the property
+ // enumeration code.
+
+ const UnboxedLayout::PropertyVector& unboxed = obj->as<UnboxedPlainObject>().layout().properties();
+ for (size_t i = 0; i < unboxed.length(); i++) {
+ if (!properties.append(NameToId(unboxed[i].name)))
+ return false;
+ }
+
+ return true;
+}
+
+const Class UnboxedExpandoObject::class_ = {
+ "UnboxedExpandoObject",
+ 0
+};
+
+static const ClassOps UnboxedPlainObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ UnboxedPlainObject::trace,
+};
+
+static const ObjectOps UnboxedPlainObjectObjectOps = {
+ UnboxedPlainObject::obj_lookupProperty,
+ UnboxedPlainObject::obj_defineProperty,
+ UnboxedPlainObject::obj_hasProperty,
+ UnboxedPlainObject::obj_getProperty,
+ UnboxedPlainObject::obj_setProperty,
+ UnboxedPlainObject::obj_getOwnPropertyDescriptor,
+ UnboxedPlainObject::obj_deleteProperty,
+ UnboxedPlainObject::obj_watch,
+ nullptr, /* No unwatch needed, as watch() converts the object to native */
+ nullptr, /* getElements */
+ UnboxedPlainObject::obj_enumerate,
+ nullptr /* funToString */
+};
+
+const Class UnboxedPlainObject::class_ = {
+ js_Object_str,
+ Class::NON_NATIVE |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
+ JSCLASS_DELAY_METADATA_BUILDER,
+ &UnboxedPlainObjectClassOps,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ &UnboxedPlainObjectObjectOps
+};
+
+/////////////////////////////////////////////////////////////////////
+// UnboxedArrayObject
+/////////////////////////////////////////////////////////////////////
+
+template <JSValueType Type>
+DenseElementResult
+AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen,
+ MutableHandle<GCVector<Value>> values)
+{
+ for (size_t i = 0; i < initlen; i++)
+ values.infallibleAppend(obj->getElementSpecific<Type>(i));
+ return DenseElementResult::Success;
+}
+
+DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements,
+ UnboxedArrayObject*, uint32_t, MutableHandle<GCVector<Value>>);
+
+/* static */ bool
+UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
+ ObjectGroup* group, Shape* shape)
+{
+ size_t length = obj->as<UnboxedArrayObject>().length();
+ size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
+
+ Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
+ if (!values.reserve(initlen))
+ return false;
+
+ AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values);
+ DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj);
+ MOZ_ASSERT(result.value == DenseElementResult::Success);
+
+ obj->setGroup(group);
+
+ ArrayObject* aobj = &obj->as<ArrayObject>();
+ aobj->setLastPropertyMakeNative(cx, shape);
+
+ // Make sure there is at least one element, so that this array does not
+ // use emptyObjectElements / emptyObjectElementsShared.
+ if (!aobj->ensureElements(cx, Max<size_t>(initlen, 1)))
+ return false;
+
+ MOZ_ASSERT(!aobj->getDenseInitializedLength());
+ aobj->setDenseInitializedLength(initlen);
+ aobj->initDenseElements(0, values.begin(), initlen);
+ aobj->setLengthInt32(length);
+
+ return true;
+}
+
+/* static */ bool
+UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj)
+{
+ const UnboxedLayout& layout = obj->as<UnboxedArrayObject>().layout();
+
+ if (!layout.nativeGroup()) {
+ if (!UnboxedLayout::makeNativeGroup(cx, obj->group()))
+ return false;
+ }
+
+ return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape());
+}
+
+bool
+UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group)
+{
+ MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32);
+ MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE);
+
+ Vector<int32_t> values(cx);
+ if (!values.reserve(initializedLength()))
+ return false;
+ for (size_t i = 0; i < initializedLength(); i++)
+ values.infallibleAppend(getElementSpecific<JSVAL_TYPE_INT32>(i).toInt32());
+
+ uint8_t* newElements;
+ if (hasInlineElements()) {
+ newElements = AllocateObjectBuffer<uint8_t>(cx, this, capacity() * sizeof(double));
+ } else {
+ newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
+ capacity() * sizeof(int32_t),
+ capacity() * sizeof(double));
+ }
+ if (!newElements)
+ return false;
+
+ setGroup(group);
+ elements_ = newElements;
+
+ for (size_t i = 0; i < initializedLength(); i++)
+ setElementNoTypeChangeSpecific<JSVAL_TYPE_DOUBLE>(i, DoubleValue(values[i]));
+
+ return true;
+}
+
+/* static */ UnboxedArrayObject*
+UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length,
+ NewObjectKind newKind, uint32_t maxLength)
+{
+ MOZ_ASSERT(length <= MaximumCapacity);
+
+ MOZ_ASSERT(group->clasp() == &class_);
+ uint32_t elementSize = UnboxedTypeSize(group->unboxedLayout().elementType());
+ uint32_t capacity = Min(length, maxLength);
+ uint32_t nbytes = offsetOfInlineElements() + elementSize * capacity;
+
+ UnboxedArrayObject* res;
+ if (nbytes <= JSObject::MAX_BYTE_SIZE) {
+ gc::AllocKind allocKind = gc::GetGCObjectKindForBytes(nbytes);
+
+ // If there was no provided length information, pick an allocation kind
+ // to accommodate small arrays (as is done for normal native arrays).
+ if (capacity == 0)
+ allocKind = gc::AllocKind::OBJECT8;
+
+ res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, allocKind, newKind);
+ if (!res)
+ return nullptr;
+ res->setInitializedLengthNoBarrier(0);
+ res->setInlineElements();
+
+ size_t actualCapacity = (GetGCKindBytes(allocKind) - offsetOfInlineElements()) / elementSize;
+ MOZ_ASSERT(actualCapacity >= capacity);
+ res->setCapacityIndex(exactCapacityIndex(actualCapacity));
+ } else {
+ res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, gc::AllocKind::OBJECT0, newKind);
+ if (!res)
+ return nullptr;
+ res->setInitializedLengthNoBarrier(0);
+
+ uint32_t capacityIndex = (capacity == length)
+ ? CapacityMatchesLengthIndex
+ : chooseCapacityIndex(capacity, length);
+ uint32_t actualCapacity = computeCapacity(capacityIndex, length);
+
+ res->elements_ = AllocateObjectBuffer<uint8_t>(cx, res, actualCapacity * elementSize);
+ if (!res->elements_) {
+ // Make the object safe for GC.
+ res->setInlineElements();
+ return nullptr;
+ }
+
+ res->setCapacityIndex(capacityIndex);
+ }
+
+ res->setLength(cx, length);
+ return res;
+}
+
+bool
+UnboxedArrayObject::setElement(ExclusiveContext* cx, size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ uint8_t* p = elements() + index * elementSize();
+ return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
+}
+
+bool
+UnboxedArrayObject::initElement(ExclusiveContext* cx, size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ uint8_t* p = elements() + index * elementSize();
+ return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
+}
+
+void
+UnboxedArrayObject::initElementNoTypeChange(size_t index, const Value& v)
+{
+ MOZ_ASSERT(index < initializedLength());
+ uint8_t* p = elements() + index * elementSize();
+ if (UnboxedTypeNeedsPreBarrier(elementType()))
+ *reinterpret_cast<void**>(p) = nullptr;
+ SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
+}
+
+Value
+UnboxedArrayObject::getElement(size_t index)
+{
+ MOZ_ASSERT(index < initializedLength());
+ uint8_t* p = elements() + index * elementSize();
+ return GetUnboxedValue(p, elementType(), /* maybeUninitialized = */ false);
+}
+
+/* static */ void
+UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj)
+{
+ JSValueType type = obj->as<UnboxedArrayObject>().elementType();
+ if (!UnboxedTypeNeedsPreBarrier(type))
+ return;
+
+ MOZ_ASSERT(obj->as<UnboxedArrayObject>().elementSize() == sizeof(uintptr_t));
+ size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
+ void** elements = reinterpret_cast<void**>(obj->as<UnboxedArrayObject>().elements());
+
+ switch (type) {
+ case JSVAL_TYPE_OBJECT:
+ for (size_t i = 0; i < initlen; i++) {
+ GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(elements + i);
+ TraceNullableEdge(trc, heap, "unboxed_object");
+ }
+ break;
+
+ case JSVAL_TYPE_STRING:
+ for (size_t i = 0; i < initlen; i++) {
+ GCPtrString* heap = reinterpret_cast<GCPtrString*>(elements + i);
+ TraceEdge(trc, heap, "unboxed_string");
+ }
+ break;
+
+ default:
+ MOZ_CRASH();
+ }
+}
+
+/* static */ void
+UnboxedArrayObject::objectMoved(JSObject* obj, const JSObject* old)
+{
+ UnboxedArrayObject& dst = obj->as<UnboxedArrayObject>();
+ const UnboxedArrayObject& src = old->as<UnboxedArrayObject>();
+
+ // Fix up possible inline data pointer.
+ if (src.hasInlineElements())
+ dst.setInlineElements();
+}
+
+/* static */ void
+UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj)
+{
+ MOZ_ASSERT(!IsInsideNursery(obj));
+ if (!obj->as<UnboxedArrayObject>().hasInlineElements())
+ js_free(obj->as<UnboxedArrayObject>().elements());
+}
+
+/* static */ size_t
+UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
+ gc::AllocKind allocKind)
+{
+ UnboxedArrayObject* ndst = &dst->as<UnboxedArrayObject>();
+ UnboxedArrayObject* nsrc = &src->as<UnboxedArrayObject>();
+ MOZ_ASSERT(ndst->elements() == nsrc->elements());
+
+ Nursery& nursery = trc->runtime()->gc.nursery;
+
+ if (!nursery.isInside(nsrc->elements())) {
+ nursery.removeMallocedBuffer(nsrc->elements());
+ return 0;
+ }
+
+ // Determine if we can use inline data for the target array. If this is
+ // possible, the nursery will have picked an allocation size that is large
+ // enough.
+ size_t nbytes = nsrc->capacity() * nsrc->elementSize();
+ if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) {
+ ndst->setInlineElements();
+ } else {
+ MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0);
+
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes);
+ if (!data)
+ oomUnsafe.crash("Failed to allocate unboxed array elements while tenuring.");
+ ndst->elements_ = data;
+ }
+
+ PodCopy(ndst->elements(), nsrc->elements(), nsrc->initializedLength() * nsrc->elementSize());
+
+ // Set a forwarding pointer for the element buffers in case they were
+ // preserved on the stack by Ion.
+ bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t);
+ nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct);
+
+ return ndst->hasInlineElements() ? 0 : nbytes;
+}
+
+// Possible capacities for unboxed arrays. Some of these capacities might seem
+// a little weird, but were chosen to allow the inline data of objects of each
+// size to be fully utilized for arrays of the various types on both 32 bit and
+// 64 bit platforms.
+//
+// To find the possible inline capacities, the following script was used:
+//
+// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16];
+// var dataSizes = [1, 4, 8];
+// var header32 = 4 * 2 + 4 * 2;
+// var header64 = 8 * 2 + 4 * 2;
+//
+// for (var i = 0; i < fixedSlotCapacities.length; i++) {
+// var nfixed = fixedSlotCapacities[i];
+// var size32 = 4 * 4 + 8 * nfixed - header32;
+// var size64 = 8 * 4 + 8 * nfixed - header64;
+// for (var j = 0; j < dataSizes.length; j++) {
+// print(size32 / dataSizes[j]);
+// print(size64 / dataSizes[j]);
+// }
+// }
+//
+/* static */ const uint32_t
+UnboxedArrayObject::CapacityArray[] = {
+ UINT32_MAX, // For CapacityMatchesLengthIndex.
+ 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136,
+ 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
+ 1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336,
+ 13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464,
+ 46137344, 52428800, 59768832, MaximumCapacity
+};
+
+static const uint32_t
+Pow2CapacityIndexes[] = {
+ 2, // 1
+ 3, // 2
+ 5, // 4
+ 8, // 8
+ 13, // 16
+ 18, // 32
+ 21, // 64
+ 25, // 128
+ 27, // 256
+ 28, // 512
+ 29, // 1024
+ 30, // 2048
+ 31, // 4096
+ 32, // 8192
+ 33, // 16384
+ 34, // 32768
+ 35, // 65536
+ 36, // 131072
+ 37, // 262144
+ 38, // 524288
+ 39 // 1048576
+};
+
+static const uint32_t MebiCapacityIndex = 39;
+
+/* static */ uint32_t
+UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length)
+{
+ // Note: the structure and behavior of this method follow along with
+ // NativeObject::goodAllocated. Changes to the allocation strategy in one
+ // should generally be matched by the other.
+
+ // Make sure we have enough space to store all possible values for the capacity index.
+ // This ought to be a static_assert, but MSVC doesn't like that.
+ MOZ_ASSERT(mozilla::ArrayLength(CapacityArray) - 1 <= (CapacityMask >> CapacityShift));
+
+ // The caller should have ensured the capacity is possible for an unboxed array.
+ MOZ_ASSERT(capacity <= MaximumCapacity);
+
+ static const uint32_t Mebi = 1024 * 1024;
+
+ if (capacity <= Mebi) {
+ capacity = mozilla::RoundUpPow2(capacity);
+
+ // When the required capacity is close to the array length, then round
+ // up to the array length itself, as for NativeObject.
+ if (length >= capacity && capacity > (length / 3) * 2)
+ return CapacityMatchesLengthIndex;
+
+ if (capacity < MinimumDynamicCapacity)
+ capacity = MinimumDynamicCapacity;
+
+ uint32_t bit = mozilla::FloorLog2Size(capacity);
+ MOZ_ASSERT(capacity == uint32_t(1 << bit));
+ MOZ_ASSERT(bit <= 20);
+ MOZ_ASSERT(mozilla::ArrayLength(Pow2CapacityIndexes) == 21);
+
+ uint32_t index = Pow2CapacityIndexes[bit];
+ MOZ_ASSERT(CapacityArray[index] == capacity);
+
+ return index;
+ }
+
+ MOZ_ASSERT(CapacityArray[MebiCapacityIndex] == Mebi);
+
+ for (uint32_t i = MebiCapacityIndex + 1;; i++) {
+ if (CapacityArray[i] >= capacity)
+ return i;
+ }
+
+ MOZ_CRASH("Invalid capacity");
+}
+
+/* static */ uint32_t
+UnboxedArrayObject::exactCapacityIndex(uint32_t capacity)
+{
+ for (size_t i = CapacityMatchesLengthIndex + 1; i < ArrayLength(CapacityArray); i++) {
+ if (CapacityArray[i] == capacity)
+ return i;
+ }
+ MOZ_CRASH();
+}
+
+bool
+UnboxedArrayObject::growElements(ExclusiveContext* cx, size_t cap)
+{
+ // The caller should have checked if this capacity is possible for an
+ // unboxed array, so the only way this call can fail is from OOM.
+ MOZ_ASSERT(cap <= MaximumCapacity);
+
+ uint32_t oldCapacity = capacity();
+ uint32_t newCapacityIndex = chooseCapacityIndex(cap, length());
+ uint32_t newCapacity = computeCapacity(newCapacityIndex, length());
+
+ MOZ_ASSERT(oldCapacity < cap);
+ MOZ_ASSERT(cap <= newCapacity);
+
+ // The allocation size computation below cannot have integer overflows.
+ JS_STATIC_ASSERT(MaximumCapacity < UINT32_MAX / sizeof(double));
+
+ uint8_t* newElements;
+ if (hasInlineElements()) {
+ newElements = AllocateObjectBuffer<uint8_t>(cx, this, newCapacity * elementSize());
+ if (!newElements)
+ return false;
+ js_memcpy(newElements, elements(), initializedLength() * elementSize());
+ } else {
+ newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
+ oldCapacity * elementSize(),
+ newCapacity * elementSize());
+ if (!newElements)
+ return false;
+ }
+
+ elements_ = newElements;
+ setCapacityIndex(newCapacityIndex);
+
+ return true;
+}
+
+void
+UnboxedArrayObject::shrinkElements(ExclusiveContext* cx, size_t cap)
+{
+ if (hasInlineElements())
+ return;
+
+ uint32_t oldCapacity = capacity();
+ uint32_t newCapacityIndex = chooseCapacityIndex(cap, 0);
+ uint32_t newCapacity = computeCapacity(newCapacityIndex, 0);
+
+ MOZ_ASSERT(cap < oldCapacity);
+ MOZ_ASSERT(cap <= newCapacity);
+
+ if (newCapacity >= oldCapacity)
+ return;
+
+ uint8_t* newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
+ oldCapacity * elementSize(),
+ newCapacity * elementSize());
+ if (!newElements)
+ return;
+
+ elements_ = newElements;
+ setCapacityIndex(newCapacityIndex);
+}
+
+bool
+UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id)
+{
+ if (JSID_IS_INT(id) && uint32_t(JSID_TO_INT(id)) < initializedLength())
+ return true;
+ if (JSID_IS_ATOM(id) && JSID_TO_ATOM(id) == cx->names().length)
+ return true;
+ return false;
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
+ HandleId id, MutableHandleObject objp,
+ MutableHandleShape propp)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ MarkNonNativePropertyFound<CanGC>(propp);
+ objp.set(obj);
+ return true;
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+ }
+
+ return LookupProperty(cx, proto, id, objp, propp);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result)
+{
+ if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) {
+ UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
+
+ uint32_t index = JSID_TO_INT(id);
+ if (index < nobj->initializedLength()) {
+ if (nobj->setElement(cx, index, desc.value()))
+ return result.succeed();
+ } else if (index == nobj->initializedLength() && index < MaximumCapacity) {
+ if (nobj->initializedLength() == nobj->capacity()) {
+ if (!nobj->growElements(cx, index + 1))
+ return false;
+ }
+ nobj->setInitializedLength(index + 1);
+ if (nobj->initElement(cx, index, desc.value())) {
+ if (nobj->length() <= index)
+ nobj->setLengthInt32(index + 1);
+ return result.succeed();
+ }
+ nobj->setInitializedLengthNoBarrier(index);
+ }
+ }
+
+ if (!convertToNative(cx, obj))
+ return false;
+
+ return DefineProperty(cx, obj, id, desc, result);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ *foundp = true;
+ return true;
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ *foundp = false;
+ return true;
+ }
+
+ return HasProperty(cx, proto, id, foundp);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
+ HandleId id, MutableHandleValue vp)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ if (JSID_IS_INT(id))
+ vp.set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
+ else
+ vp.set(Int32Value(obj->as<UnboxedArrayObject>().length()));
+ return true;
+ }
+
+ RootedObject proto(cx, obj->staticPrototype());
+ if (!proto) {
+ vp.setUndefined();
+ return true;
+ }
+
+ return GetProperty(cx, proto, receiver, id, vp);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ if (receiver.isObject() && obj == &receiver.toObject()) {
+ if (JSID_IS_INT(id)) {
+ if (obj->as<UnboxedArrayObject>().setElement(cx, JSID_TO_INT(id), v))
+ return result.succeed();
+ } else {
+ uint32_t len;
+ if (!CanonicalizeArrayLengthValue(cx, v, &len))
+ return false;
+ UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
+ if (len < nobj->initializedLength()) {
+ nobj->setInitializedLength(len);
+ nobj->shrinkElements(cx, len);
+ }
+ nobj->setLength(cx, len);
+ return result.succeed();
+ }
+
+ if (!convertToNative(cx, obj))
+ return false;
+ return SetProperty(cx, obj, id, v, receiver, result);
+ }
+
+ return SetPropertyByDefining(cx, id, v, receiver, result);
+ }
+
+ return SetPropertyOnProto(cx, obj, id, v, receiver, result);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ if (JSID_IS_INT(id)) {
+ desc.value().set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
+ desc.setAttributes(JSPROP_ENUMERATE);
+ } else {
+ desc.value().set(Int32Value(obj->as<UnboxedArrayObject>().length()));
+ desc.setAttributes(JSPROP_PERMANENT);
+ }
+ desc.object().set(obj);
+ return true;
+ }
+
+ desc.object().set(nullptr);
+ return true;
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result)
+{
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
+ if (JSID_IS_INT(id) && JSID_TO_INT(id) == int32_t(initlen - 1)) {
+ obj->as<UnboxedArrayObject>().setInitializedLength(initlen - 1);
+ obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen - 1);
+ return result.succeed();
+ }
+ }
+
+ if (!convertToNative(cx, obj))
+ return false;
+ return DeleteProperty(cx, obj, id, result);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
+{
+ if (!convertToNative(cx, obj))
+ return false;
+ return WatchProperty(cx, obj, id, callable);
+}
+
+/* static */ bool
+UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly)
+{
+ for (size_t i = 0; i < obj->as<UnboxedArrayObject>().initializedLength(); i++) {
+ if (!properties.append(INT_TO_JSID(i)))
+ return false;
+ }
+
+ if (!enumerableOnly && !properties.append(NameToId(cx->names().length)))
+ return false;
+
+ return true;
+}
+
+static const ClassOps UnboxedArrayObjectClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ UnboxedArrayObject::finalize,
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ UnboxedArrayObject::trace,
+};
+
+static const ClassExtension UnboxedArrayObjectClassExtension = {
+ nullptr, /* weakmapKeyDelegateOp */
+ UnboxedArrayObject::objectMoved
+};
+
+static const ObjectOps UnboxedArrayObjectObjectOps = {
+ UnboxedArrayObject::obj_lookupProperty,
+ UnboxedArrayObject::obj_defineProperty,
+ UnboxedArrayObject::obj_hasProperty,
+ UnboxedArrayObject::obj_getProperty,
+ UnboxedArrayObject::obj_setProperty,
+ UnboxedArrayObject::obj_getOwnPropertyDescriptor,
+ UnboxedArrayObject::obj_deleteProperty,
+ UnboxedArrayObject::obj_watch,
+ nullptr, /* No unwatch needed, as watch() converts the object to native */
+ nullptr, /* getElements */
+ UnboxedArrayObject::obj_enumerate,
+ nullptr /* funToString */
+};
+
+const Class UnboxedArrayObject::class_ = {
+ "Array",
+ Class::NON_NATIVE |
+ JSCLASS_SKIP_NURSERY_FINALIZE |
+ JSCLASS_BACKGROUND_FINALIZE,
+ &UnboxedArrayObjectClassOps,
+ JS_NULL_CLASS_SPEC,
+ &UnboxedArrayObjectClassExtension,
+ &UnboxedArrayObjectObjectOps
+};
+
+/////////////////////////////////////////////////////////////////////
+// API
+/////////////////////////////////////////////////////////////////////
+
+static bool
+UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype)
+{
+ if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32)
+ return true;
+ if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL)
+ return true;
+ return false;
+}
+
+static bool
+CombineUnboxedTypes(const Value& value, JSValueType* existing)
+{
+ JSValueType type = value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType();
+
+ if (*existing == JSVAL_TYPE_MAGIC || *existing == type || UnboxedTypeIncludes(type, *existing)) {
+ *existing = type;
+ return true;
+ }
+ if (UnboxedTypeIncludes(*existing, type))
+ return true;
+ return false;
+}
+
+// Return whether the property names and types in layout are a subset of the
+// specified vector.
+static bool
+PropertiesAreSuperset(const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout)
+{
+ for (size_t i = 0; i < layout->properties().length(); i++) {
+ const UnboxedLayout::Property& layoutProperty = layout->properties()[i];
+ bool found = false;
+ for (size_t j = 0; j < properties.length(); j++) {
+ if (layoutProperty.name == properties[j].name) {
+ found = (layoutProperty.type == properties[j].type);
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+ return true;
+}
+
+static bool
+CombinePlainObjectProperties(PlainObject* obj, Shape* templateShape,
+ UnboxedLayout::PropertyVector& properties)
+{
+ // All preliminary objects must have been created with enough space to
+ // fill in their unboxed data inline. This is ensured either by using
+ // the largest allocation kind (which limits the maximum size of an
+ // unboxed object), or by using an allocation kind that covers all
+ // properties in the template, as the space used by unboxed properties
+ // is less than or equal to that used by boxed properties.
+ MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >=
+ Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan()));
+
+ if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) {
+ // Only use an unboxed representation if all created objects match
+ // the template shape exactly.
+ return false;
+ }
+
+ for (size_t i = 0; i < templateShape->slotSpan(); i++) {
+ Value val = obj->getSlot(i);
+
+ JSValueType& existing = properties[i].type;
+ if (!CombineUnboxedTypes(val, &existing))
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType* elementType)
+{
+ if (obj->inDictionaryMode() ||
+ obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
+ !obj->lastProperty()->previous()->isEmptyShape())
+ {
+ // Only use an unboxed representation if the object has no properties.
+ return false;
+ }
+
+ for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
+ Value val = obj->getDenseElement(i);
+
+ // For now, unboxed arrays cannot have holes.
+ if (val.isMagic(JS_ELEMENTS_HOLE))
+ return false;
+
+ if (!CombineUnboxedTypes(val, elementType))
+ return false;
+ }
+
+ return true;
+}
+
+static size_t
+ComputePlainObjectLayout(ExclusiveContext* cx, Shape* templateShape,
+ UnboxedLayout::PropertyVector& properties)
+{
+ // Fill in the names for all the object's properties.
+ for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
+ size_t slot = r.front().slot();
+ MOZ_ASSERT(!properties[slot].name);
+ properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
+ }
+
+ // Fill in all the unboxed object's property offsets.
+ uint32_t offset = 0;
+
+ // Search for an existing unboxed layout which is a subset of this one.
+ // If there are multiple such layouts, use the largest one. If we're able
+ // to find such a layout, use the same property offsets for the shared
+ // properties, which will allow us to generate better code if the objects
+ // have a subtype/supertype relation and are accessed at common sites.
+ UnboxedLayout* bestExisting = nullptr;
+ for (UnboxedLayout* existing : cx->compartment()->unboxedLayouts) {
+ if (PropertiesAreSuperset(properties, existing)) {
+ if (!bestExisting ||
+ existing->properties().length() > bestExisting->properties().length())
+ {
+ bestExisting = existing;
+ }
+ }
+ }
+ if (bestExisting) {
+ for (size_t i = 0; i < bestExisting->properties().length(); i++) {
+ const UnboxedLayout::Property& existingProperty = bestExisting->properties()[i];
+ for (size_t j = 0; j < templateShape->slotSpan(); j++) {
+ if (existingProperty.name == properties[j].name) {
+ MOZ_ASSERT(existingProperty.type == properties[j].type);
+ properties[j].offset = existingProperty.offset;
+ }
+ }
+ }
+ offset = bestExisting->size();
+ }
+
+ // Order remaining properties from the largest down for the best space
+ // utilization.
+ static const size_t typeSizes[] = { 8, 4, 1 };
+
+ for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
+ size_t size = typeSizes[i];
+ for (size_t j = 0; j < templateShape->slotSpan(); j++) {
+ if (properties[j].offset != UINT32_MAX)
+ continue;
+ JSValueType type = properties[j].type;
+ if (UnboxedTypeSize(type) == size) {
+ offset = JS_ROUNDUP(offset, size);
+ properties[j].offset = offset;
+ offset += size;
+ }
+ }
+ }
+
+ // The final offset is the amount of data needed by the object.
+ return offset;
+}
+
+static bool
+SetLayoutTraceList(ExclusiveContext* cx, UnboxedLayout* layout)
+{
+ // Figure out the offsets of any objects or string properties.
+ Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
+ for (size_t i = 0; i < layout->properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout->properties()[i];
+ MOZ_ASSERT(property.offset != UINT32_MAX);
+ if (property.type == JSVAL_TYPE_OBJECT) {
+ if (!objectOffsets.append(property.offset))
+ return false;
+ } else if (property.type == JSVAL_TYPE_STRING) {
+ if (!stringOffsets.append(property.offset))
+ return false;
+ }
+ }
+
+ // Construct the layout's trace list.
+ if (!objectOffsets.empty() || !stringOffsets.empty()) {
+ Vector<int32_t, 8, SystemAllocPolicy> entries;
+ if (!entries.appendAll(stringOffsets) ||
+ !entries.append(-1) ||
+ !entries.appendAll(objectOffsets) ||
+ !entries.append(-1) ||
+ !entries.append(-1))
+ {
+ return false;
+ }
+ int32_t* traceList = cx->zone()->pod_malloc<int32_t>(entries.length());
+ if (!traceList)
+ return false;
+ PodCopy(traceList, entries.begin(), entries.length());
+ layout->setTraceList(traceList);
+ }
+
+ return true;
+}
+
+static inline Value
+NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
+{
+ return values[(*valueCursor)++];
+}
+
+static bool
+GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle<GCVector<Value>> values)
+{
+ if (!values.append(Int32Value(obj->length())))
+ return false;
+ if (!values.append(Int32Value(obj->getDenseInitializedLength())))
+ return false;
+ for (size_t i = 0; i < obj->getDenseInitializedLength(); i++) {
+ if (!values.append(obj->getDenseElement(i)))
+ return false;
+ }
+ return true;
+}
+
+void
+UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
+ Handle<GCVector<Value>> values, size_t* valueCursor)
+{
+ MOZ_ASSERT(CapacityArray[1] == 0);
+ setCapacityIndex(1);
+ setInitializedLengthNoBarrier(0);
+ setInlineElements();
+
+ setLength(cx, NextValue(values, valueCursor).toInt32());
+
+ int32_t initlen = NextValue(values, valueCursor).toInt32();
+ if (!initlen)
+ return;
+
+ AutoEnterOOMUnsafeRegion oomUnsafe;
+ if (!growElements(cx, initlen))
+ oomUnsafe.crash("UnboxedArrayObject::fillAfterConvert");
+
+ setInitializedLength(initlen);
+
+ for (size_t i = 0; i < size_t(initlen); i++)
+ JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
+}
+
+static bool
+GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle<GCVector<Value>> values)
+{
+ for (size_t i = 0; i < obj->slotSpan(); i++) {
+ if (!values.append(obj->getSlot(i)))
+ return false;
+ }
+ return true;
+}
+
+void
+UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
+ Handle<GCVector<Value>> values, size_t* valueCursor)
+{
+ initExpando();
+ memset(data(), 0, layout().size());
+ for (size_t i = 0; i < layout().properties().length(); i++)
+ JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
+}
+
+bool
+js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
+ ObjectGroup* group, PreliminaryObjectArray* objects)
+{
+ bool isArray = !templateShape;
+
+ // Unboxed arrays are nightly only for now. The getenv() call will be
+ // removed when they are on by default. See bug 1153266.
+ if (isArray) {
+#ifdef NIGHTLY_BUILD
+ if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) {
+ if (!cx->options().unboxedArrays())
+ return true;
+ }
+#else
+ return true;
+#endif
+ } else {
+ if (jit::JitOptions.disableUnboxedObjects)
+ return true;
+ }
+
+ MOZ_ASSERT_IF(templateShape, !templateShape->getObjectFlags());
+
+ if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global()))
+ return true;
+
+ if (!isArray && templateShape->slotSpan() == 0)
+ return true;
+
+ UnboxedLayout::PropertyVector properties;
+ if (!isArray) {
+ if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan()))
+ return false;
+ }
+ JSValueType elementType = JSVAL_TYPE_MAGIC;
+
+ size_t objectCount = 0;
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* obj = objects->get(i);
+ if (!obj)
+ continue;
+
+ if (obj->isSingleton() || obj->group() != group)
+ return true;
+
+ objectCount++;
+
+ if (isArray) {
+ if (!CombineArrayObjectElements(cx, &obj->as<ArrayObject>(), &elementType))
+ return true;
+ } else {
+ if (!CombinePlainObjectProperties(&obj->as<PlainObject>(), templateShape, properties))
+ return true;
+ }
+ }
+
+ size_t layoutSize = 0;
+ if (isArray) {
+ // Don't use an unboxed representation if we couldn't determine an
+ // element type for the objects.
+ if (UnboxedTypeSize(elementType) == 0)
+ return true;
+ } else {
+ if (objectCount <= 1) {
+ // If only one of the objects has been created, it is more likely
+ // to have new properties added later. This heuristic is not used
+ // for array objects, where we might want an unboxed representation
+ // even if there is only one large array.
+ return true;
+ }
+
+ for (size_t i = 0; i < templateShape->slotSpan(); i++) {
+ // We can't use an unboxed representation if e.g. all the objects have
+ // a null value for one of the properties, as we can't decide what type
+ // it is supposed to have.
+ if (UnboxedTypeSize(properties[i].type) == 0)
+ return true;
+ }
+
+ // Make sure that all properties on the template shape are property
+ // names, and not indexes.
+ for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
+ jsid id = r.front().propid();
+ uint32_t dummy;
+ if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
+ return true;
+ }
+
+ layoutSize = ComputePlainObjectLayout(cx, templateShape, properties);
+
+ // The entire object must be allocatable inline.
+ if (UnboxedPlainObject::offsetOfData() + layoutSize > JSObject::MAX_BYTE_SIZE)
+ return true;
+ }
+
+ UniquePtr<UnboxedLayout>& layout = enter.unboxedLayoutToCleanUp;
+ MOZ_ASSERT(!layout);
+ layout = group->zone()->make_unique<UnboxedLayout>();
+ if (!layout)
+ return false;
+
+ if (isArray) {
+ layout->initArray(elementType);
+ } else {
+ if (!layout->initProperties(properties, layoutSize))
+ return false;
+
+ // The unboxedLayouts list only tracks layouts for plain objects.
+ cx->compartment()->unboxedLayouts.insertFront(layout.get());
+
+ if (!SetLayoutTraceList(cx, layout.get()))
+ return false;
+ }
+
+ // We've determined that all the preliminary objects can use the new layout
+ // just constructed, so convert the existing group to use the unboxed class,
+ // and update the preliminary objects to use the new layout. Do the
+ // fallible stuff first before modifying any objects.
+
+ // Get an empty shape which we can use for the preliminary objects.
+ const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_;
+ Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0);
+ if (!newShape) {
+ cx->recoverFromOutOfMemory();
+ return false;
+ }
+
+ // Accumulate a list of all the values in each preliminary object, and
+ // update their shapes.
+ Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* obj = objects->get(i);
+ if (!obj)
+ continue;
+
+ bool ok;
+ if (isArray)
+ ok = GetValuesFromPreliminaryArrayObject(&obj->as<ArrayObject>(), &values);
+ else
+ ok = GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(), &values);
+
+ if (!ok) {
+ cx->recoverFromOutOfMemory();
+ return false;
+ }
+ }
+
+ if (TypeNewScript* newScript = group->newScript())
+ layout->setNewScript(newScript);
+
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ if (JSObject* obj = objects->get(i))
+ obj->as<NativeObject>().setLastPropertyMakeNonNative(newShape);
+ }
+
+ group->setClasp(clasp);
+ group->setUnboxedLayout(layout.release());
+
+ size_t valueCursor = 0;
+ for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
+ JSObject* obj = objects->get(i);
+ if (!obj)
+ continue;
+
+ if (isArray)
+ obj->as<UnboxedArrayObject>().fillAfterConvert(cx, values, &valueCursor);
+ else
+ obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
+ }
+
+ MOZ_ASSERT(valueCursor == values.length());
+ return true;
+}
+
+DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
+ ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
+ ShouldUpdateTypes);
+
+DenseElementResult
+js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
+ uint32_t start, const Value* vp, uint32_t count,
+ ShouldUpdateTypes updateTypes)
+{
+ SetOrExtendBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, start, vp, count, updateTypes);
+ return CallBoxedOrUnboxedSpecialization(functor, obj);
+};
+
+DefineBoxedOrUnboxedFunctor5(MoveBoxedOrUnboxedDenseElements,
+ JSContext*, JSObject*, uint32_t, uint32_t, uint32_t);
+
+DenseElementResult
+js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
+ uint32_t dstStart, uint32_t srcStart, uint32_t length)
+{
+ MoveBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, dstStart, srcStart, length);
+ return CallBoxedOrUnboxedSpecialization(functor, obj);
+}
+
+DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements,
+ JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t);
+
+DenseElementResult
+js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
+ uint32_t dstStart, uint32_t srcStart, uint32_t length)
+{
+ CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length);
+ return CallBoxedOrUnboxedSpecialization(functor, dst, src);
+}
+
+DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength,
+ JSContext*, JSObject*, size_t);
+
+void
+js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
+{
+ SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen);
+ JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
+}
+
+DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements,
+ JSContext*, JSObject*, size_t);
+
+DenseElementResult
+js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen)
+{
+ EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen);
+ return CallBoxedOrUnboxedSpecialization(functor, obj);
+}
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h
new file mode 100644
index 000000000..ecff8be5b
--- /dev/null
+++ b/js/src/vm/UnboxedObject.h
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_UnboxedObject_h
+#define vm_UnboxedObject_h
+
+#include "jsgc.h"
+#include "jsobj.h"
+
+#include "vm/Runtime.h"
+#include "vm/TypeInference.h"
+
+namespace js {
+
+// Memory required for an unboxed value of a given type. Returns zero for types
+// which can't be used for unboxed objects.
+static inline size_t
+UnboxedTypeSize(JSValueType type)
+{
+ switch (type) {
+ case JSVAL_TYPE_BOOLEAN: return 1;
+ case JSVAL_TYPE_INT32: return 4;
+ case JSVAL_TYPE_DOUBLE: return 8;
+ case JSVAL_TYPE_STRING: return sizeof(void*);
+ case JSVAL_TYPE_OBJECT: return sizeof(void*);
+ default: return 0;
+ }
+}
+
+static inline bool
+UnboxedTypeNeedsPreBarrier(JSValueType type)
+{
+ return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
+}
+
+static inline bool
+UnboxedTypeNeedsPostBarrier(JSValueType type)
+{
+ return type == JSVAL_TYPE_OBJECT;
+}
+
+// Class tracking information specific to unboxed objects.
+class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
+{
+ public:
+ struct Property {
+ PropertyName* name;
+ uint32_t offset;
+ JSValueType type;
+
+ Property()
+ : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
+ {}
+ };
+
+ typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
+
+ private:
+ // If objects in this group have ever been converted to native objects,
+ // these store the corresponding native group and initial shape for such
+ // objects. Type information for this object is reflected in nativeGroup.
+ GCPtrObjectGroup nativeGroup_;
+ GCPtrShape nativeShape_;
+
+ // Any script/pc which the associated group is created for.
+ GCPtrScript allocationScript_;
+ jsbytecode* allocationPc_;
+
+ // If nativeGroup is set and this object originally had a TypeNewScript or
+ // was keyed to an allocation site, this points to the group which replaced
+ // this one. This link is only needed to keep the replacement group from
+ // being GC'ed. If it were GC'ed and a new one regenerated later, that new
+ // group might have a different allocation kind from this group.
+ GCPtrObjectGroup replacementGroup_;
+
+ // The following members are only used for unboxed plain objects.
+
+ // All properties on objects with this layout, in enumeration order.
+ PropertyVector properties_;
+
+ // Byte size of the data for objects with this layout.
+ size_t size_;
+
+ // Any 'new' script information associated with this layout.
+ TypeNewScript* newScript_;
+
+ // List for use in tracing objects with this layout. This has the same
+ // structure as the trace list on a TypeDescr.
+ int32_t* traceList_;
+
+ // If this layout has been used to construct script or JSON constant
+ // objects, this code might be filled in to more quickly fill in objects
+ // from an array of values.
+ GCPtrJitCode constructorCode_;
+
+ // The following members are only used for unboxed arrays.
+
+ // The type of array elements.
+ JSValueType elementType_;
+
+ public:
+ UnboxedLayout()
+ : nativeGroup_(nullptr), nativeShape_(nullptr),
+ allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
+ size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr),
+ elementType_(JSVAL_TYPE_MAGIC)
+ {}
+
+ bool initProperties(const PropertyVector& properties, size_t size) {
+ size_ = size;
+ return properties_.appendAll(properties);
+ }
+
+ void initArray(JSValueType elementType) {
+ elementType_ = elementType;
+ }
+
+ ~UnboxedLayout() {
+ if (newScript_)
+ newScript_->clear();
+ js_delete(newScript_);
+ js_free(traceList_);
+
+ nativeGroup_.init(nullptr);
+ nativeShape_.init(nullptr);
+ replacementGroup_.init(nullptr);
+ constructorCode_.init(nullptr);
+ }
+
+ bool isArray() const {
+ return elementType_ != JSVAL_TYPE_MAGIC;
+ }
+
+ void detachFromCompartment();
+
+ const PropertyVector& properties() const {
+ return properties_;
+ }
+
+ TypeNewScript* newScript() const {
+ return newScript_;
+ }
+
+ void setNewScript(TypeNewScript* newScript, bool writeBarrier = true);
+
+ JSScript* allocationScript() const {
+ return allocationScript_;
+ }
+
+ jsbytecode* allocationPc() const {
+ return allocationPc_;
+ }
+
+ void setAllocationSite(JSScript* script, jsbytecode* pc) {
+ allocationScript_ = script;
+ allocationPc_ = pc;
+ }
+
+ const int32_t* traceList() const {
+ return traceList_;
+ }
+
+ void setTraceList(int32_t* traceList) {
+ traceList_ = traceList;
+ }
+
+ const Property* lookup(JSAtom* atom) const {
+ for (size_t i = 0; i < properties_.length(); i++) {
+ if (properties_[i].name == atom)
+ return &properties_[i];
+ }
+ return nullptr;
+ }
+
+ const Property* lookup(jsid id) const {
+ if (JSID_IS_STRING(id))
+ return lookup(JSID_TO_ATOM(id));
+ return nullptr;
+ }
+
+ size_t size() const {
+ return size_;
+ }
+
+ ObjectGroup* nativeGroup() const {
+ return nativeGroup_;
+ }
+
+ Shape* nativeShape() const {
+ return nativeShape_;
+ }
+
+ jit::JitCode* constructorCode() const {
+ return constructorCode_;
+ }
+
+ void setConstructorCode(jit::JitCode* code) {
+ constructorCode_ = code;
+ }
+
+ JSValueType elementType() const {
+ return elementType_;
+ }
+
+ inline gc::AllocKind getAllocKind() const;
+
+ void trace(JSTracer* trc);
+
+ size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+ static bool makeNativeGroup(JSContext* cx, ObjectGroup* group);
+ static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group);
+};
+
+// Class for expando objects holding extra properties given to an unboxed plain
+// object. These objects behave identically to normal native plain objects, and
+// have a separate Class to distinguish them for memory usage reporting.
+class UnboxedExpandoObject : public NativeObject
+{
+ public:
+ static const Class class_;
+};
+
+// Class for a plain object using an unboxed representation. The physical
+// layout of these objects is identical to that of an InlineTypedObject, though
+// these objects use an UnboxedLayout instead of a TypeDescr to keep track of
+// how their properties are stored.
+class UnboxedPlainObject : public JSObject
+{
+ // Optional object which stores extra properties on this object. This is
+ // not automatically barriered to avoid problems if the object is converted
+ // to a native. See ensureExpando().
+ UnboxedExpandoObject* expando_;
+
+ // Start of the inline data, which immediately follows the group and extra properties.
+ uint8_t data_[1];
+
+ public:
+ static const Class class_;
+
+ static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
+ HandleId id, MutableHandleObject objp,
+ MutableHandleShape propp);
+
+ static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result);
+
+ static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
+
+ static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
+ HandleId id, MutableHandleValue vp);
+
+ static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+
+ static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc);
+
+ static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result);
+
+ static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly);
+ static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
+
+ inline const UnboxedLayout& layout() const;
+
+ const UnboxedLayout& layoutDontCheckGeneration() const {
+ return group()->unboxedLayoutDontCheckGeneration();
+ }
+
+ uint8_t* data() {
+ return &data_[0];
+ }
+
+ UnboxedExpandoObject* maybeExpando() const {
+ return expando_;
+ }
+
+ void initExpando() {
+ expando_ = nullptr;
+ }
+
+ // For use during GC.
+ JSObject** addressOfExpando() {
+ return reinterpret_cast<JSObject**>(&expando_);
+ }
+
+ bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const;
+
+ static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj);
+
+ bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v);
+ Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false);
+
+ static bool convertToNative(JSContext* cx, JSObject* obj);
+ static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group,
+ NewObjectKind newKind);
+ static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
+ NewObjectKind newKind, IdValuePair* properties);
+
+ void fillAfterConvert(ExclusiveContext* cx,
+ Handle<GCVector<Value>> values, size_t* valueCursor);
+
+ static void trace(JSTracer* trc, JSObject* object);
+
+ static size_t offsetOfExpando() {
+ return offsetof(UnboxedPlainObject, expando_);
+ }
+
+ static size_t offsetOfData() {
+ return offsetof(UnboxedPlainObject, data_[0]);
+ }
+};
+
+// Try to construct an UnboxedLayout for each of the preliminary objects,
+// provided they all match the template shape. If successful, converts the
+// preliminary objects and their group to the new unboxed representation.
+bool
+TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
+ ObjectGroup* group, PreliminaryObjectArray* objects);
+
+inline gc::AllocKind
+UnboxedLayout::getAllocKind() const
+{
+ MOZ_ASSERT(size());
+ return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
+}
+
+// Class for an array object using an unboxed representation.
+class UnboxedArrayObject : public JSObject
+{
+ // Elements pointer for the object.
+ uint8_t* elements_;
+
+ // The nominal array length. This always fits in an int32_t.
+ uint32_t length_;
+
+ // Value indicating the allocated capacity and initialized length of the
+ // array. The top CapacityBits bits are an index into CapacityArray, which
+ // indicates the elements capacity. The low InitializedLengthBits store the
+ // initialized length of the array.
+ uint32_t capacityIndexAndInitializedLength_;
+
+ // If the elements are inline, they will point here.
+ uint8_t inlineElements_[1];
+
+ public:
+ static const uint32_t CapacityBits = 6;
+ static const uint32_t CapacityShift = 26;
+
+ static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
+ static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
+
+ static const uint32_t MaximumCapacity = InitializedLengthMask;
+ static const uint32_t MinimumDynamicCapacity = 8;
+
+ static const uint32_t CapacityArray[];
+
+ // Capacity index which indicates the array's length is also its capacity.
+ static const uint32_t CapacityMatchesLengthIndex = 0;
+
+ private:
+ static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
+ if (index == CapacityMatchesLengthIndex)
+ return length;
+ return CapacityArray[index];
+ }
+
+ static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
+ static uint32_t exactCapacityIndex(uint32_t capacity);
+
+ public:
+ static const Class class_;
+
+ static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
+ HandleId id, MutableHandleObject objp,
+ MutableHandleShape propp);
+
+ static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result);
+
+ static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
+
+ static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
+ HandleId id, MutableHandleValue vp);
+
+ static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+
+ static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandle<PropertyDescriptor> desc);
+
+ static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
+ ObjectOpResult& result);
+
+ static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
+ bool enumerableOnly);
+ static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
+
+ inline const UnboxedLayout& layout() const;
+
+ const UnboxedLayout& layoutDontCheckGeneration() const {
+ return group()->unboxedLayoutDontCheckGeneration();
+ }
+
+ JSValueType elementType() const {
+ return layoutDontCheckGeneration().elementType();
+ }
+
+ uint32_t elementSize() const {
+ return UnboxedTypeSize(elementType());
+ }
+
+ static bool convertToNative(JSContext* cx, JSObject* obj);
+ static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group,
+ uint32_t length, NewObjectKind newKind,
+ uint32_t maxLength = MaximumCapacity);
+
+ static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
+ ObjectGroup* group, Shape* shape);
+ bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group);
+
+ void fillAfterConvert(ExclusiveContext* cx,
+ Handle<GCVector<Value>> values, size_t* valueCursor);
+
+ static void trace(JSTracer* trc, JSObject* object);
+ static void objectMoved(JSObject* obj, const JSObject* old);
+ static void finalize(FreeOp* fop, JSObject* obj);
+
+ static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
+ gc::AllocKind allocKind);
+
+ uint8_t* elements() {
+ return elements_;
+ }
+
+ bool hasInlineElements() const {
+ return elements_ == &inlineElements_[0];
+ }
+
+ uint32_t length() const {
+ return length_;
+ }
+
+ uint32_t initializedLength() const {
+ return capacityIndexAndInitializedLength_ & InitializedLengthMask;
+ }
+
+ uint32_t capacityIndex() const {
+ return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
+ }
+
+ uint32_t capacity() const {
+ return computeCapacity(capacityIndex(), length());
+ }
+
+ bool containsProperty(ExclusiveContext* cx, jsid id);
+
+ bool setElement(ExclusiveContext* cx, size_t index, const Value& v);
+ bool initElement(ExclusiveContext* cx, size_t index, const Value& v);
+ void initElementNoTypeChange(size_t index, const Value& v);
+ Value getElement(size_t index);
+
+ template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index,
+ const Value& v);
+ template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v);
+ template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index,
+ const Value& v);
+ template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v);
+ template <JSValueType Type> inline Value getElementSpecific(size_t index);
+ template <JSValueType Type> inline void triggerPreBarrier(size_t index);
+
+ bool growElements(ExclusiveContext* cx, size_t cap);
+ void shrinkElements(ExclusiveContext* cx, size_t cap);
+
+ static uint32_t offsetOfElements() {
+ return offsetof(UnboxedArrayObject, elements_);
+ }
+ static uint32_t offsetOfLength() {
+ return offsetof(UnboxedArrayObject, length_);
+ }
+ static uint32_t offsetOfCapacityIndexAndInitializedLength() {
+ return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
+ }
+ static uint32_t offsetOfInlineElements() {
+ return offsetof(UnboxedArrayObject, inlineElements_);
+ }
+
+ void setLengthInt32(uint32_t length) {
+ MOZ_ASSERT(length <= INT32_MAX);
+ length_ = length;
+ }
+
+ inline void setLength(ExclusiveContext* cx, uint32_t len);
+ inline void setInitializedLength(uint32_t initlen);
+
+ inline void setInitializedLengthNoBarrier(uint32_t initlen) {
+ MOZ_ASSERT(initlen <= InitializedLengthMask);
+ capacityIndexAndInitializedLength_ =
+ (capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
+ }
+
+ private:
+ void setInlineElements() {
+ elements_ = &inlineElements_[0];
+ }
+
+ void setCapacityIndex(uint32_t index) {
+ MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
+ capacityIndexAndInitializedLength_ =
+ (index << CapacityShift) | initializedLength();
+ }
+};
+
+} // namespace js
+
+namespace JS {
+
+template <>
+struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout>
+{};
+
+} /* namespace JS */
+
+#endif /* vm_UnboxedObject_h */
diff --git a/js/src/vm/Unicode.cpp b/js/src/vm/Unicode.cpp
new file mode 100644
index 000000000..f4acf8f31
--- /dev/null
+++ b/js/src/vm/Unicode.cpp
@@ -0,0 +1,1750 @@
+/* Generated by make_unicode.py DO NOT MODIFY */
+/* Unicode version: 9.0.0 */
+
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+#include "vm/Unicode.h"
+
+using namespace js;
+using namespace js::unicode;
+
+/*
+ * So how does indexing work?
+ * First let's have a look at a char16_t, 16-bits:
+ * [................]
+ * Step 1:
+ * Extracting the upper 11 bits from the char16_t.
+ * upper = char >> 5 ([***********.....])
+ * Step 2:
+ * Using these bits to get an reduced index from index1.
+ * index = index1[upper]
+ * Step 3:
+ * Combining the index and the bottom 5 bits of the original char16_t.
+ * real_index = index2[(index << 5) + (char & ((1 << 5) - 1))] ([...********+++++])
+ *
+ * The advantage here is that the biggest number in index1 doesn't need 10 bits,
+ * but 7 and we save some memory.
+ *
+ * Step 4:
+ * Get the character informations by looking up real_index in js_charinfo.
+ *
+ * Pseudocode of generation:
+ *
+ * let table be the mapping of char16_t => js_charinfo_index
+ * let index1 be an empty array
+ * let index2 be an empty array
+ * let cache be a hash map
+ *
+ * while shift is less then maximal amount you can shift 0xffff before it's 0
+ * let chunks be table split in chunks of size 2**shift
+ *
+ * for every chunk in chunks
+ * if chunk is in cache
+ * let index be cache[chunk]
+ * else
+ * let index be the max key of index2 + 1
+ * for element in chunk
+ * push element to index2
+ * put index as chunk in cache
+ *
+ * push index >> shift to index1
+ *
+ * increase shift
+ * stop if you found the best shift
+ */
+const CharacterInfo unicode::js_charinfo[] = {
+ {0, 0, 0},
+ {0, 0, 1},
+ {0, 0, 4},
+ {0, 32, 2},
+ {65504, 0, 2},
+ {0, 0, 2},
+ {743, 0, 2},
+ {121, 0, 2},
+ {0, 1, 2},
+ {65535, 0, 2},
+ {0, 65337, 2},
+ {65304, 0, 2},
+ {0, 65415, 2},
+ {65236, 0, 2},
+ {195, 0, 2},
+ {0, 210, 2},
+ {0, 206, 2},
+ {0, 205, 2},
+ {0, 79, 2},
+ {0, 202, 2},
+ {0, 203, 2},
+ {0, 207, 2},
+ {97, 0, 2},
+ {0, 211, 2},
+ {0, 209, 2},
+ {163, 0, 2},
+ {0, 213, 2},
+ {130, 0, 2},
+ {0, 214, 2},
+ {0, 218, 2},
+ {0, 217, 2},
+ {0, 219, 2},
+ {56, 0, 2},
+ {0, 2, 2},
+ {65535, 1, 2},
+ {65534, 0, 2},
+ {65457, 0, 2},
+ {0, 65439, 2},
+ {0, 65480, 2},
+ {0, 65406, 2},
+ {0, 10795, 2},
+ {0, 65373, 2},
+ {0, 10792, 2},
+ {10815, 0, 2},
+ {0, 65341, 2},
+ {0, 69, 2},
+ {0, 71, 2},
+ {10783, 0, 2},
+ {10780, 0, 2},
+ {10782, 0, 2},
+ {65326, 0, 2},
+ {65330, 0, 2},
+ {65331, 0, 2},
+ {65334, 0, 2},
+ {65333, 0, 2},
+ {42319, 0, 2},
+ {42315, 0, 2},
+ {65329, 0, 2},
+ {42280, 0, 2},
+ {42308, 0, 2},
+ {65327, 0, 2},
+ {65325, 0, 2},
+ {10743, 0, 2},
+ {42305, 0, 2},
+ {10749, 0, 2},
+ {65323, 0, 2},
+ {65322, 0, 2},
+ {10727, 0, 2},
+ {65318, 0, 2},
+ {42282, 0, 2},
+ {65467, 0, 2},
+ {65319, 0, 2},
+ {65465, 0, 2},
+ {65317, 0, 2},
+ {42261, 0, 2},
+ {42258, 0, 2},
+ {84, 0, 4},
+ {0, 116, 2},
+ {0, 38, 2},
+ {0, 37, 2},
+ {0, 64, 2},
+ {0, 63, 2},
+ {65498, 0, 2},
+ {65499, 0, 2},
+ {65505, 0, 2},
+ {65472, 0, 2},
+ {65473, 0, 2},
+ {0, 8, 2},
+ {65474, 0, 2},
+ {65479, 0, 2},
+ {65489, 0, 2},
+ {65482, 0, 2},
+ {65528, 0, 2},
+ {65450, 0, 2},
+ {65456, 0, 2},
+ {7, 0, 2},
+ {65420, 0, 2},
+ {0, 65476, 2},
+ {65440, 0, 2},
+ {0, 65529, 2},
+ {0, 80, 2},
+ {0, 15, 2},
+ {65521, 0, 2},
+ {0, 48, 2},
+ {65488, 0, 2},
+ {0, 7264, 2},
+ {0, 38864, 2},
+ {59282, 0, 2},
+ {59283, 0, 2},
+ {59292, 0, 2},
+ {59294, 0, 2},
+ {59293, 0, 2},
+ {59300, 0, 2},
+ {59355, 0, 2},
+ {35266, 0, 2},
+ {35332, 0, 2},
+ {3814, 0, 2},
+ {65477, 0, 2},
+ {0, 57921, 2},
+ {8, 0, 2},
+ {0, 65528, 2},
+ {74, 0, 2},
+ {86, 0, 2},
+ {100, 0, 2},
+ {128, 0, 2},
+ {112, 0, 2},
+ {126, 0, 2},
+ {9, 0, 2},
+ {0, 65462, 2},
+ {0, 65527, 2},
+ {58331, 0, 2},
+ {0, 65450, 2},
+ {0, 65436, 2},
+ {0, 65424, 2},
+ {0, 65408, 2},
+ {0, 65410, 2},
+ {0, 58019, 2},
+ {0, 57153, 2},
+ {0, 57274, 2},
+ {0, 28, 2},
+ {65508, 0, 2},
+ {0, 16, 2},
+ {65520, 0, 2},
+ {0, 26, 0},
+ {65510, 0, 0},
+ {0, 54793, 2},
+ {0, 61722, 2},
+ {0, 54809, 2},
+ {54741, 0, 2},
+ {54744, 0, 2},
+ {0, 54756, 2},
+ {0, 54787, 2},
+ {0, 54753, 2},
+ {0, 54754, 2},
+ {0, 54721, 2},
+ {58272, 0, 2},
+ {0, 30204, 2},
+ {0, 23256, 2},
+ {0, 23228, 2},
+ {0, 23217, 2},
+ {0, 23221, 2},
+ {0, 23231, 2},
+ {0, 23278, 2},
+ {0, 23254, 2},
+ {0, 23275, 2},
+ {0, 928, 2},
+ {64608, 0, 2},
+ {26672, 0, 2},
+};
+
+const uint8_t unicode::index1[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 26, 26, 26, 26,
+ 26, 68, 69, 70, 71, 72, 73, 74, 75, 26, 26, 26, 26, 26, 26, 26, 26, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 26, 103, 26, 104, 105, 105, 106, 105, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 118, 119, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 120, 121, 105, 122,
+ 123, 124, 125, 126, 94, 94, 94, 94, 94, 94, 94, 94, 127, 75, 128, 129, 130, 26,
+ 131, 132, 94, 94, 94, 94, 94, 94, 94, 94, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 86, 94, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 133, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 134, 135, 26, 26, 26, 26, 136, 137,
+ 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
+ 156, 157, 158, 159, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 160, 161,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 26, 26, 26, 26, 26, 162, 26, 163, 164, 165, 166, 167,
+ 26, 26, 26, 26, 168, 169, 170, 171, 172, 173, 26, 174, 175, 176, 177, 178,
+};
+
+const uint8_t unicode::index2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 0, 0, 0, 0, 2, 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, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 0, 2, 0, 0, 5, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0,
+ 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 4, 4, 4, 4, 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, 7, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 10, 11,
+ 8, 9, 8, 9, 8, 9, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8,
+ 9, 8, 9, 8, 9, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 12, 8,
+ 9, 8, 9, 8, 9, 13, 14, 15, 8, 9, 8, 9, 16, 8, 9, 17, 17, 8,
+ 9, 5, 18, 19, 20, 8, 9, 17, 21, 22, 23, 24, 8, 9, 25, 5, 23, 26,
+ 27, 28, 8, 9, 8, 9, 8, 9, 29, 8, 9, 29, 5, 5, 8, 9, 29, 8,
+ 9, 30, 30, 8, 9, 8, 9, 31, 8, 9, 5, 5, 8, 9, 5, 32, 5, 5,
+ 5, 5, 33, 34, 35, 33, 34, 35, 33, 34, 35, 8, 9, 8, 9, 8, 9, 8,
+ 9, 8, 9, 8, 9, 8, 9, 8, 9, 36, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 33, 34, 35, 8, 9, 37, 38,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 39, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 5, 5, 5, 5, 5, 5, 40, 8, 9, 41, 42, 43,
+ 43, 8, 9, 44, 45, 46, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 47, 48,
+ 49, 50, 51, 5, 52, 52, 5, 53, 5, 54, 55, 5, 5, 5, 52, 56, 5, 57,
+ 5, 58, 59, 5, 60, 61, 59, 62, 63, 5, 5, 61, 5, 64, 65, 5, 5, 66,
+ 5, 5, 5, 5, 5, 5, 5, 67, 5, 5, 68, 5, 5, 68, 5, 5, 5, 69,
+ 68, 70, 71, 71, 72, 5, 5, 5, 5, 5, 73, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 74, 75, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 76, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 9,
+ 8, 9, 5, 0, 8, 9, 0, 0, 5, 27, 27, 27, 0, 77, 0, 0, 0, 0,
+ 0, 0, 78, 2, 79, 79, 79, 0, 80, 0, 81, 81, 5, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 82, 83, 83, 83, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 84, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 85, 86, 86, 87, 88, 89, 5, 5, 5, 90, 91, 92, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 93, 94, 95, 96, 97, 98, 0, 8, 9, 99, 8, 9, 5, 39, 39, 39, 100, 100,
+ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 0, 2, 2, 2, 2, 2, 0, 0, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 101, 8, 9, 8, 9, 8, 9, 8,
+ 9, 8, 9, 8, 9, 8, 9, 102, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 0, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 0,
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2, 0,
+ 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 5, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2,
+ 2, 5, 5, 2, 2, 0, 2, 2, 2, 2, 5, 5, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 5, 5, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 5, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2,
+ 5, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5,
+ 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0,
+ 0, 0, 5, 5, 5, 5, 0, 0, 2, 5, 2, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 0, 0, 2, 2, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0,
+ 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0,
+ 5, 5, 0, 5, 5, 0, 5, 5, 0, 0, 2, 0, 2, 2, 2, 2, 2, 0,
+ 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 5, 5, 5, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5,
+ 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, 2, 5, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 5, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 2, 2, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5,
+ 5, 5, 5, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 0, 2, 5, 2, 2,
+ 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 2, 2,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 5, 5, 5,
+ 5, 5, 5, 0, 0, 0, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 0, 5,
+ 5, 0, 5, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 5, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 5, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 5, 5, 5, 0, 0, 0, 0, 0,
+ 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 2, 2,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5,
+ 0, 0, 2, 5, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 2, 2, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 5, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0,
+ 2, 2, 2, 2, 5, 0, 0, 0, 0, 0, 5, 5, 5, 2, 0, 0, 0, 0,
+ 0, 0, 0, 5, 5, 5, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 0, 0, 2, 2, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0,
+ 0, 0, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5,
+ 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 5, 0, 5, 0, 0, 5, 5, 0, 5, 0, 0, 5,
+ 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5,
+ 0, 5, 5, 5, 0, 5, 0, 5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 2,
+ 5, 5, 2, 2, 2, 2, 2, 2, 0, 2, 2, 5, 0, 0, 5, 5, 5, 5,
+ 5, 0, 5, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 2, 2, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 5, 5,
+ 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5, 5, 2, 2, 2, 5,
+ 2, 2, 2, 5, 5, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 2, 2, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
+ 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
+ 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 0, 105, 0, 0, 0, 0, 0, 105,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 0, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5,
+ 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0,
+ 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 2, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 87, 87, 87, 87,
+ 87, 87, 0, 0, 92, 92, 92, 92, 92, 92, 0, 0, 0, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 2, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,
+ 5, 5, 5, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, 0, 0,
+ 0, 0, 5, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 107, 108, 109, 110, 110, 111, 112, 113, 114, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
+ 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 2, 5, 5, 0, 2, 2, 0, 0,
+ 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 115, 5, 5, 5, 116, 5, 5, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 5, 5, 5, 5, 5, 117, 5, 5, 118, 5, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120,
+ 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 119, 119, 0, 0, 120, 120, 120, 120,
+ 120, 120, 0, 0, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, 120, 120, 120, 120,
+ 120, 120, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120,
+ 119, 119, 119, 119, 119, 119, 0, 0, 120, 120, 120, 120, 120, 120, 0, 0, 5, 119,
+ 5, 119, 5, 119, 5, 119, 0, 120, 0, 120, 0, 120, 0, 120, 119, 119, 119, 119,
+ 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 122, 122, 122, 122,
+ 123, 123, 124, 124, 125, 125, 126, 126, 0, 0, 119, 119, 119, 119, 119, 119, 119, 119,
+ 120, 120, 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120,
+ 120, 120, 120, 120, 120, 120, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, 120, 120,
+ 120, 120, 120, 120, 119, 119, 5, 127, 5, 0, 5, 5, 120, 120, 128, 128, 129, 0,
+ 130, 0, 0, 0, 5, 127, 5, 0, 5, 5, 131, 131, 131, 131, 129, 0, 0, 0,
+ 119, 119, 5, 5, 0, 0, 5, 5, 120, 120, 132, 132, 0, 0, 0, 0, 119, 119,
+ 5, 5, 5, 95, 5, 5, 120, 120, 133, 133, 99, 0, 0, 0, 0, 0, 5, 127,
+ 5, 0, 5, 5, 134, 134, 135, 135, 129, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 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,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
+ 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 5, 0,
+ 136, 0, 5, 0, 137, 138, 5, 5, 5, 5, 5, 5, 139, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
+ 141, 141, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 5, 5, 5, 8, 9, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 0, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 0,
+ 8, 9, 145, 146, 147, 148, 149, 8, 9, 8, 9, 8, 9, 150, 151, 152, 153, 5,
+ 8, 9, 5, 8, 9, 5, 5, 5, 5, 5, 5, 5, 154, 154, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 0, 0, 0,
+ 0, 0, 0, 8, 9, 8, 9, 2, 2, 2, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+ 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155,
+ 155, 155, 155, 155, 155, 155, 155, 155, 0, 155, 0, 0, 0, 0, 0, 155, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5,
+ 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0,
+ 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 5, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2,
+ 2, 2, 2, 2, 0, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 0, 2, 2, 5, 5, 5, 5, 5, 0, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,
+ 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 5, 2, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 5, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 5, 5, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, 9, 8, 9, 156, 8, 9, 8, 9,
+ 8, 9, 8, 9, 8, 9, 5, 0, 0, 8, 9, 157, 5, 5, 8, 9, 8, 9,
+ 5, 5, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9,
+ 8, 9, 8, 9, 158, 159, 160, 161, 158, 0, 162, 163, 164, 165, 8, 9, 8, 9,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 2, 5, 5, 5, 2, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
+ 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5,
+ 0, 5, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 0, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 2,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 0, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 0, 0, 5, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5,
+ 2, 2, 5, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 0, 0, 5, 5,
+ 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5,
+ 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 166, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 167, 167, 167, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0,
+ 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 5, 2, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 0, 5, 5, 0, 5, 5, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 2, 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, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5,
+ 5, 5, 5, 5, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {
+ {0, 0, 0},
+ {32, 0, 0},
+ {32, 232, 0},
+ {32, 300, 0},
+ {0, 200, 0},
+ {0, 268, 0},
+ {0, 775, 0},
+ {1, 0, 0},
+ {65336, 0, 0},
+ {65415, 0, 0},
+ {65268, 0, 0},
+ {210, 0, 0},
+ {206, 0, 0},
+ {205, 0, 0},
+ {79, 0, 0},
+ {202, 0, 0},
+ {203, 0, 0},
+ {207, 0, 0},
+ {211, 0, 0},
+ {209, 0, 0},
+ {213, 0, 0},
+ {214, 0, 0},
+ {218, 0, 0},
+ {217, 0, 0},
+ {219, 0, 0},
+ {1, 2, 0},
+ {0, 1, 0},
+ {65535, 0, 0},
+ {65439, 0, 0},
+ {65480, 0, 0},
+ {65406, 0, 0},
+ {10795, 0, 0},
+ {65373, 0, 0},
+ {10792, 0, 0},
+ {65341, 0, 0},
+ {69, 0, 0},
+ {71, 0, 0},
+ {0, 116, 7289},
+ {116, 0, 0},
+ {38, 0, 0},
+ {37, 0, 0},
+ {64, 0, 0},
+ {63, 0, 0},
+ {32, 62, 0},
+ {32, 96, 0},
+ {32, 57, 0},
+ {65452, 32, 7205},
+ {32, 86, 0},
+ {64793, 32, 0},
+ {32, 54, 0},
+ {32, 80, 0},
+ {31, 32, 0},
+ {32, 47, 0},
+ {0, 30, 0},
+ {0, 64, 0},
+ {0, 25, 0},
+ {65420, 0, 7173},
+ {0, 54, 0},
+ {64761, 0, 0},
+ {0, 22, 0},
+ {0, 48, 0},
+ {0, 15, 0},
+ {8, 0, 0},
+ {65506, 0, 0},
+ {65511, 0, 0},
+ {65521, 0, 0},
+ {65514, 0, 0},
+ {65482, 0, 0},
+ {65488, 0, 0},
+ {65472, 0, 0},
+ {65529, 0, 0},
+ {80, 0, 0},
+ {32, 6254, 0},
+ {32, 6253, 0},
+ {32, 6244, 0},
+ {32, 6242, 0},
+ {32, 6242, 6243},
+ {32, 6236, 0},
+ {0, 6222, 0},
+ {0, 6221, 0},
+ {0, 6212, 0},
+ {0, 6210, 0},
+ {0, 6210, 6211},
+ {0, 6204, 0},
+ {1, 6181, 0},
+ {0, 6180, 0},
+ {15, 0, 0},
+ {48, 0, 0},
+ {7264, 0, 0},
+ {38864, 0, 0},
+ {59314, 0, 0},
+ {59315, 0, 0},
+ {59324, 0, 0},
+ {59326, 0, 0},
+ {59326, 0, 1},
+ {59325, 65535, 0},
+ {59332, 0, 0},
+ {59356, 0, 0},
+ {0, 35267, 0},
+ {1, 59, 0},
+ {0, 58, 0},
+ {65478, 0, 0},
+ {65528, 0, 0},
+ {65462, 0, 0},
+ {65527, 0, 0},
+ {58247, 58363, 0},
+ {65450, 0, 0},
+ {65436, 0, 0},
+ {65424, 0, 0},
+ {65408, 0, 0},
+ {65410, 0, 0},
+ {28, 0, 0},
+ {16, 0, 0},
+ {26, 0, 0},
+ {54793, 0, 0},
+ {61722, 0, 0},
+ {54809, 0, 0},
+ {54756, 0, 0},
+ {54787, 0, 0},
+ {54753, 0, 0},
+ {54754, 0, 0},
+ {54721, 0, 0},
+ {30270, 1, 0},
+ {30269, 0, 0},
+ {30204, 0, 0},
+ {23256, 0, 0},
+ {23228, 0, 0},
+ {23217, 0, 0},
+ {23221, 0, 0},
+ {23231, 0, 0},
+ {23278, 0, 0},
+ {23254, 0, 0},
+ {23275, 0, 0},
+ {928, 0, 0},
+};
+
+const uint8_t unicode::codepoints_with_same_upper_index1[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 24, 25, 26, 24, 27, 28,
+ 29, 30, 0, 0, 0, 0, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 24, 38,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39,
+ 40, 0, 41, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0,
+};
+
+const uint8_t unicode::codepoints_with_same_upper_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, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 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, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8,
+ 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7,
+ 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 9, 7,
+ 0, 7, 0, 7, 0, 10, 0, 11, 7, 0, 7, 0, 12, 7, 0, 13, 13, 7,
+ 0, 0, 14, 15, 16, 7, 0, 13, 17, 0, 18, 19, 7, 0, 0, 0, 18, 20,
+ 0, 21, 7, 0, 7, 0, 7, 0, 22, 7, 0, 22, 0, 0, 7, 0, 22, 7,
+ 0, 23, 23, 7, 0, 7, 0, 24, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0,
+ 0, 0, 25, 26, 27, 25, 26, 27, 25, 26, 27, 7, 0, 7, 0, 7, 0, 7,
+ 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 25, 26, 27, 7, 0, 28, 29,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 30, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 31, 7, 0, 32, 33, 0,
+ 0, 7, 0, 34, 35, 36, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 38, 0, 0, 0, 0, 0, 0, 39, 0, 40, 40, 40, 0, 41, 0, 42, 42,
+ 0, 1, 43, 1, 1, 44, 1, 1, 45, 46, 47, 1, 48, 1, 1, 1, 49, 50,
+ 0, 51, 1, 1, 52, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 53, 0,
+ 0, 54, 0, 0, 55, 56, 57, 0, 58, 0, 0, 0, 59, 60, 26, 27, 0, 0,
+ 61, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 64, 0, 0, 0, 65, 66, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 67, 68, 0, 0, 0, 69, 0, 7, 0, 70, 7, 0,
+ 0, 30, 30, 30, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 1, 1, 72, 1, 73, 1, 1, 1, 1, 1, 1, 1, 1, 1, 74, 1,
+ 1, 75, 76, 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 0, 0,
+ 78, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 81, 82, 0,
+ 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 84, 85, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 86, 7,
+ 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 0, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 0, 88, 0, 0, 0, 0, 0, 88, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
+ 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 62, 62,
+ 62, 62, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 91, 92, 93,
+ 94, 95, 96, 97, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 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, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 99, 100, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 101,
+ 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 0, 0,
+ 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 0, 0, 0, 0, 0, 0,
+ 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0,
+ 102, 102, 102, 102, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
+ 0, 102, 0, 102, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102,
+ 102, 102, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102,
+ 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 0, 0,
+ 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 0, 0, 0, 0,
+ 0, 0, 0, 0, 102, 102, 103, 103, 104, 0, 105, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 106, 106, 106, 106, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 102, 102, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102,
+ 108, 108, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 109, 110, 110,
+ 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 112, 112, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 113,
+ 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
+ 113, 113, 113, 113, 113, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 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, 114, 115, 116, 0, 0, 7, 0, 7, 0, 7,
+ 0, 117, 118, 119, 120, 0, 7, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 121, 121, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 122, 123, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 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, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 124, 7, 0, 7, 0,
+ 7, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 125, 0, 0, 7, 0, 7, 0,
+ 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
+ 7, 0, 7, 0, 126, 127, 128, 129, 126, 0, 130, 131, 132, 133, 7, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
+};
+
+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},
+ {32, 6254, 0, 0},
+ {32, 6253, 0, 0},
+ {32, 6244, 0, 0},
+ {32, 6242, 0, 0},
+ {32, 6242, 6243, 0},
+ {32, 6236, 0, 0},
+ {0, 65504, 6222, 0},
+ {0, 65504, 6221, 0},
+ {0, 65504, 6212, 0},
+ {0, 65504, 6210, 0},
+ {0, 65504, 6210, 6211},
+ {0, 65504, 6204, 0},
+ {0, 65456, 0, 0},
+ {1, 6181, 0, 0},
+ {0, 65535, 6180, 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},
+ {59314, 59282, 0, 0},
+ {59315, 59283, 0, 0},
+ {59324, 59292, 0, 0},
+ {59326, 59294, 0, 0},
+ {59326, 59294, 1, 0},
+ {59325, 59293, 65535, 0},
+ {59332, 59300, 0, 0},
+ {59356, 59355, 0, 0},
+ {35267, 35266, 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},
+ {1, 30270, 0, 0},
+ {0, 30269, 65535, 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, 25, 0, 0, 26, 0, 0, 27, 28, 29, 27, 30, 31,
+ 32, 33, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 27, 41,
+ 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 44, 0, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 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, 61, 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, 125, 1, 126, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 127, 1, 1, 128, 129, 1, 1, 1, 1, 1,
+ 1, 1, 130, 1, 1, 1, 1, 1, 4, 4, 131, 4, 132, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 133, 4, 4, 134, 135, 4, 4, 4, 4, 4, 4, 4, 136, 4,
+ 4, 4, 4, 4, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
+ 137, 137, 12, 13, 138, 139, 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, 140, 12, 13, 12, 13, 12, 13, 12, 13, 12,
+ 13, 12, 13, 12, 13, 141, 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, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 0, 144, 0, 0, 0, 0, 0, 144,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145,
+ 146, 146, 146, 146, 146, 146, 0, 0, 147, 147, 147, 147, 147, 147, 0, 0, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 158, 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, 159, 160, 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, 161, 0, 0, 162, 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, 146, 146, 146, 146, 146, 146,
+ 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 0, 0,
+ 147, 147, 147, 147, 147, 147, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147,
+ 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147,
+ 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 0, 0, 147, 147, 147, 147, 147, 147,
+ 0, 0, 0, 146, 0, 146, 0, 146, 0, 146, 0, 147, 0, 147, 0, 147, 0, 147,
+ 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 163, 163,
+ 164, 164, 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, 0, 0, 146, 146, 146, 146,
+ 146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146,
+ 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146,
+ 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 0, 169, 0, 0, 0, 0, 147, 147,
+ 170, 170, 171, 0, 172, 0, 0, 0, 0, 169, 0, 0, 0, 0, 173, 173, 173, 173,
+ 171, 0, 0, 0, 146, 146, 0, 0, 0, 0, 0, 0, 147, 147, 174, 174, 0, 0,
+ 0, 0, 146, 146, 0, 0, 0, 119, 0, 0, 147, 147, 175, 175, 123, 0, 0, 0,
+ 0, 0, 0, 169, 0, 0, 0, 0, 176, 176, 177, 177, 171, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 178, 0, 0, 0, 179, 180, 0, 0, 0, 0, 0, 0, 181, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183,
+ 183, 183, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184,
+ 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, 185, 185, 185, 185, 185, 185, 185, 185,
+ 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
+ 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, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 0, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 0,
+ 12, 13, 187, 188, 189, 190, 191, 12, 13, 12, 13, 12, 13, 192, 193, 194, 195, 0,
+ 12, 13, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 196, 196, 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, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197,
+ 197, 197, 197, 197, 197, 197, 197, 197, 0, 197, 0, 0, 0, 0, 0, 197, 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, 198, 199, 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, 200,
+ 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 0, 0, 0, 12, 13, 201, 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, 202, 203, 204, 205, 202, 0, 206, 207, 208, 209,
+ 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, 210, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 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
new file mode 100644
index 000000000..8b538d06d
--- /dev/null
+++ b/js/src/vm/Unicode.h
@@ -0,0 +1,498 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Unicode_h
+#define vm_Unicode_h
+
+#include "jspubtd.h"
+#include "vm/UnicodeNonBMP.h"
+
+extern const bool js_isidstart[];
+extern const bool js_isident[];
+extern const bool js_isspace[];
+
+namespace js {
+namespace unicode {
+
+/*
+ * This namespace contains all the knowledge required to handle Unicode
+ * characters in JavaScript.
+ *
+ * SPACE
+ * Every character that is either in the ECMAScript class WhiteSpace
+ * (ES2016, § 11.2) or in LineTerminator (ES2016, § 11.3).
+ *
+ * WhiteSpace
+ * \u0009, \u000B, \u000C, \u0020, \u00A0 and \uFEFF
+ * and every other Unicode character with the General Category "Zs".
+ * See <http://www.unicode.org/reports/tr44/#UnicodeData.txt> for more
+ * information about General Categories and the UnicodeData.txt file.
+ *
+ * LineTerminator
+ * \u000A, \u000D, \u2028, \u2029
+ *
+ * UNICODE_ID_START
+ * These are all characters with the Unicode property «ID_Start».
+ *
+ * UNICODE_ID_CONTINUE_ONLY
+ * These are all characters with the Unicode property «ID_Continue» minus all
+ * characters with the Unicode property «ID_Start».
+ * And additionally <ZWNJ> and <ZWJ>. (ES2016, § 11.6)
+ *
+ * UNICODE_ID_CONTINUE
+ * These are all characters with the Unicode property «ID_Continue».
+ * And additionally <ZWNJ> and <ZWJ>. (ES2016, § 11.6)
+ *
+ * Attention: UNICODE_ID_START is _not_ IdentifierStart, but you could build
+ * a matcher for the real IdentifierPart like this:
+ *
+ * if char in ['$', '_']:
+ * return True
+ * if GetFlag(char) & UNICODE_ID_CONTINUE:
+ * return True
+ *
+ */
+
+namespace CharFlag {
+ const uint8_t SPACE = 1 << 0;
+ const uint8_t UNICODE_ID_START = 1 << 1;
+ const uint8_t UNICODE_ID_CONTINUE_ONLY = 1 << 2;
+ const uint8_t UNICODE_ID_CONTINUE = UNICODE_ID_START + UNICODE_ID_CONTINUE_ONLY;
+}
+
+const char16_t BYTE_ORDER_MARK2 = 0xFFFE;
+const char16_t NO_BREAK_SPACE = 0x00A0;
+
+const char16_t LeadSurrogateMin = 0xD800;
+const char16_t LeadSurrogateMax = 0xDBFF;
+const char16_t TrailSurrogateMin = 0xDC00;
+const char16_t TrailSurrogateMax = 0xDFFF;
+
+const uint32_t UTF16Max = 0xFFFF;
+const uint32_t NonBMPMin = 0x10000;
+const uint32_t NonBMPMax = 0x10FFFF;
+
+class CharacterInfo {
+ /*
+ * upperCase and lowerCase normally store the delta between two
+ * letters. For example the lower case alpha (a) has the char code
+ * 97, and the upper case alpha (A) has 65. So for "a" we would
+ * store -32 in upperCase (97 + (-32) = 65) and 0 in lowerCase,
+ * because this char is already in lower case.
+ * Well, not -32 exactly, but (2**16 - 32) to induce
+ * unsigned overflow with identical mathematical behavior.
+ * For upper case alpha, we would store 0 in upperCase and 32 in
+ * lowerCase (65 + 32 = 97).
+ *
+ * We use deltas to reuse information for multiple characters. For
+ * example the whole lower case latin alphabet fits into one entry,
+ * because it's always a UnicodeLetter and upperCase contains
+ * -32.
+ */
+ public:
+ uint16_t upperCase;
+ uint16_t lowerCase;
+ uint8_t flags;
+
+ inline bool isSpace() const {
+ return flags & CharFlag::SPACE;
+ }
+
+ inline bool isUnicodeIDStart() const {
+ return flags & CharFlag::UNICODE_ID_START;
+ }
+
+ inline bool isUnicodeIDContinue() const {
+ // Also matches <ZWNJ> and <ZWJ>!
+ return flags & CharFlag::UNICODE_ID_CONTINUE;
+ }
+};
+
+extern const uint8_t index1[];
+extern const uint8_t index2[];
+extern const CharacterInfo js_charinfo[];
+
+inline const CharacterInfo&
+CharInfo(char16_t code)
+{
+ const size_t shift = 6;
+ size_t index = index1[code >> shift];
+ index = index2[(index << shift) + (code & ((1 << shift) - 1))];
+
+ return js_charinfo[index];
+}
+
+inline bool
+IsIdentifierStart(char16_t ch)
+{
+ /*
+ * ES2016 11.6 IdentifierStart
+ * $ (dollar sign)
+ * _ (underscore)
+ * or any character with the Unicode property «ID_Start».
+ *
+ * We use a lookup table for small and thus common characters for speed.
+ */
+
+ if (ch < 128)
+ return js_isidstart[ch];
+
+ return CharInfo(ch).isUnicodeIDStart();
+}
+
+inline bool
+IsIdentifierStart(uint32_t codePoint)
+{
+ // TODO: Supplemental code points not yet supported (bug 1197230).
+ return codePoint <= UTF16Max && IsIdentifierStart(char16_t(codePoint));
+}
+
+inline bool
+IsIdentifierPart(char16_t ch)
+{
+ /*
+ * ES2016 11.6 IdentifierPart
+ * $ (dollar sign)
+ * _ (underscore)
+ * <ZWNJ>
+ * <ZWJ>
+ * or any character with the Unicode property «ID_Continue».
+ *
+ * We use a lookup table for small and thus common characters for speed.
+ */
+
+ if (ch < 128)
+ return js_isident[ch];
+
+ return CharInfo(ch).isUnicodeIDContinue();
+}
+
+inline bool
+IsIdentifierPart(uint32_t codePoint)
+{
+ // TODO: Supplemental code points not yet supported (bug 1197230).
+ return codePoint <= UTF16Max && IsIdentifierPart(char16_t(codePoint));
+}
+
+inline bool
+IsUnicodeIDStart(char16_t ch)
+{
+ return CharInfo(ch).isUnicodeIDStart();
+}
+
+inline bool
+IsSpace(char16_t ch)
+{
+ /*
+ * IsSpace checks if some character is included in the merged set
+ * of WhiteSpace and LineTerminator, specified by ES2016 11.2 and 11.3.
+ * We combined them, because in practice nearly every
+ * calling function wants this, except some code in the tokenizer.
+ *
+ * We use a lookup table for ASCII-7 characters, because they are
+ * very common and must be handled quickly in the tokenizer.
+ * NO-BREAK SPACE is supposed to be the most common character not in
+ * this range, so we inline this case, too.
+ */
+
+ if (ch < 128)
+ return js_isspace[ch];
+
+ if (ch == NO_BREAK_SPACE)
+ return true;
+
+ return CharInfo(ch).isSpace();
+}
+
+inline bool
+IsSpaceOrBOM2(char16_t ch)
+{
+ if (ch < 128)
+ return js_isspace[ch];
+
+ /* We accept BOM2 (0xFFFE) for compatibility reasons in the parser. */
+ if (ch == NO_BREAK_SPACE || ch == BYTE_ORDER_MARK2)
+ return true;
+
+ return CharInfo(ch).isSpace();
+}
+
+inline char16_t
+ToUpperCase(char16_t ch)
+{
+ if (ch < 128) {
+ if (ch >= 'a' && ch <= 'z')
+ return ch - ('a' - 'A');
+ return ch;
+ }
+
+ const CharacterInfo& info = CharInfo(ch);
+
+ return uint16_t(ch) + info.upperCase;
+}
+
+inline char16_t
+ToLowerCase(char16_t ch)
+{
+ if (ch < 128) {
+ if (ch >= 'A' && ch <= 'Z')
+ return ch + ('a' - 'A');
+ return ch;
+ }
+
+ const CharacterInfo& info = CharInfo(ch);
+
+ return uint16_t(ch) + info.lowerCase;
+}
+
+// Returns true iff ToUpperCase(ch) != ch.
+inline bool
+CanUpperCase(char16_t ch)
+{
+ if (ch < 128)
+ return ch >= 'a' && ch <= 'z';
+ return CharInfo(ch).upperCase != 0;
+}
+
+// Returns true iff ToLowerCase(ch) != ch.
+inline bool
+CanLowerCase(char16_t ch)
+{
+ if (ch < 128)
+ return ch >= 'A' && ch <= 'Z';
+ return CharInfo(ch).lowerCase != 0;
+}
+
+#define CHECK_RANGE(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF) \
+ if (lead == LEAD && trail >= TRAIL_FROM && trail <= TRAIL_TO) \
+ return true;
+
+inline bool
+CanUpperCaseNonBMP(char16_t lead, char16_t trail)
+{
+ FOR_EACH_NON_BMP_UPPERCASE(CHECK_RANGE)
+ return false;
+}
+
+inline bool
+CanLowerCaseNonBMP(char16_t lead, char16_t trail)
+{
+ FOR_EACH_NON_BMP_LOWERCASE(CHECK_RANGE)
+ return false;
+}
+
+#undef CHECK_RANGE
+
+inline char16_t
+ToUpperCaseNonBMPTrail(char16_t lead, char16_t trail)
+{
+#define CALC_TRAIL(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF) \
+ if (lead == LEAD && trail >= TRAIL_FROM && trail <= TRAIL_TO) \
+ return trail + DIFF;
+ FOR_EACH_NON_BMP_UPPERCASE(CALC_TRAIL)
+#undef CALL_TRAIL
+
+ return trail;
+}
+
+inline char16_t
+ToLowerCaseNonBMPTrail(char16_t lead, char16_t trail)
+{
+#define CALC_TRAIL(FROM, TO, LEAD, TRAIL_FROM, TRAIL_TO, DIFF) \
+ if (lead == LEAD && trail >= TRAIL_FROM && trail <= TRAIL_TO) \
+ return trail + DIFF;
+ FOR_EACH_NON_BMP_LOWERCASE(CALC_TRAIL)
+#undef CALL_TRAIL
+
+ return trail;
+}
+
+/*
+ * For a codepoint C, CodepointsWithSameUpperCaseInfo stores three offsets
+ * from C to up to three codepoints with same uppercase (no codepoint in
+ * UnicodeData.txt has more than three such codepoints).
+ *
+ * To illustrate, consider the codepoint U+0399 GREEK CAPITAL LETTER IOTA, the
+ * uppercased form of these three codepoints:
+ *
+ * U+03B9 GREEK SMALL LETTER IOTA
+ * U+1FBE GREEK PROSGEGRAMMENI
+ * U+0345 COMBINING GREEK YPOGEGRAMMENI
+ *
+ * For the CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
+ * delta{1,2,3} are 16-bit modular deltas from 0x0399 to each respective
+ * codepoint:
+ * uint16_t(0x03B9 - 0x0399),
+ * uint16_t(0x1FBE - 0x0399),
+ * uint16_t(0x0345 - 0x0399)
+ * in an unimportant order.
+ *
+ * If there are fewer than three other codepoints, some fields are zero.
+ * Consider the codepoint U+03B9 above, the other two codepoints U+1FBE and
+ * U+0345 have same uppercase (U+0399 is not). For the
+ * CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
+ * delta{1,2,3} are:
+ * uint16_t(0x1FBE - 0x03B9),
+ * uint16_t(0x0345 - 0x03B9),
+ * uint16_t(0)
+ * in an unimportant order.
+ *
+ * Because multiple codepoints map to a single CodepointsWithSameUpperCaseInfo,
+ * a CodepointsWithSameUpperCaseInfo and its delta{1,2,3} have no meaning
+ * standing alone: they have meaning only with respect to a codepoint mapping
+ * to that CodepointsWithSameUpperCaseInfo.
+ */
+class CodepointsWithSameUpperCaseInfo
+{
+ public:
+ uint16_t delta1;
+ uint16_t delta2;
+ uint16_t delta3;
+};
+
+extern const uint8_t codepoints_with_same_upper_index1[];
+extern const uint8_t codepoints_with_same_upper_index2[];
+extern const CodepointsWithSameUpperCaseInfo js_codepoints_with_same_upper_info[];
+
+class CodepointsWithSameUpperCase
+{
+ const CodepointsWithSameUpperCaseInfo& info_;
+ const char16_t code_;
+
+ static const CodepointsWithSameUpperCaseInfo& computeInfo(char16_t code) {
+ const size_t shift = 6;
+ size_t index = codepoints_with_same_upper_index1[code >> shift];
+ index = codepoints_with_same_upper_index2[(index << shift) + (code & ((1 << shift) - 1))];
+ return js_codepoints_with_same_upper_info[index];
+ }
+
+ public:
+ explicit CodepointsWithSameUpperCase(char16_t code)
+ : info_(computeInfo(code)),
+ code_(code)
+ {}
+
+ char16_t other1() const { return uint16_t(code_) + info_.delta1; }
+ char16_t other2() const { return uint16_t(code_) + info_.delta2; }
+ char16_t other3() const { return uint16_t(code_) + info_.delta3; }
+};
+
+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;
+}
+
+inline bool
+IsSupplementary(uint32_t codePoint)
+{
+ return codePoint >= NonBMPMin && codePoint <= NonBMPMax;
+}
+
+inline bool
+IsLeadSurrogate(uint32_t codePoint)
+{
+ return codePoint >= LeadSurrogateMin && codePoint <= LeadSurrogateMax;
+}
+
+inline bool
+IsTrailSurrogate(uint32_t codePoint)
+{
+ return codePoint >= TrailSurrogateMin && codePoint <= TrailSurrogateMax;
+}
+
+inline char16_t
+LeadSurrogate(uint32_t codePoint)
+{
+ MOZ_ASSERT(IsSupplementary(codePoint));
+
+ return char16_t((codePoint >> 10) + (LeadSurrogateMin - (NonBMPMin >> 10)));
+}
+
+inline char16_t
+TrailSurrogate(uint32_t codePoint)
+{
+ MOZ_ASSERT(IsSupplementary(codePoint));
+
+ return char16_t((codePoint & 0x3FF) | TrailSurrogateMin);
+}
+
+inline void
+UTF16Encode(uint32_t codePoint, char16_t* lead, char16_t* trail)
+{
+ MOZ_ASSERT(IsSupplementary(codePoint));
+
+ *lead = LeadSurrogate(codePoint);
+ *trail = TrailSurrogate(codePoint);
+}
+
+static inline void
+UTF16Encode(uint32_t codePoint, char16_t* elements, unsigned* index)
+{
+ if (!IsSupplementary(codePoint)) {
+ elements[(*index)++] = char16_t(codePoint);
+ } else {
+ elements[(*index)++] = LeadSurrogate(codePoint);
+ elements[(*index)++] = TrailSurrogate(codePoint);
+ }
+}
+
+inline uint32_t
+UTF16Decode(char16_t lead, char16_t trail)
+{
+ MOZ_ASSERT(IsLeadSurrogate(lead));
+ MOZ_ASSERT(IsTrailSurrogate(trail));
+
+ return (lead << 10) + trail + (NonBMPMin - (LeadSurrogateMin << 10) - TrailSurrogateMin);
+}
+
+} /* namespace unicode */
+} /* namespace js */
+
+#endif /* vm_Unicode_h */
diff --git a/js/src/vm/UnicodeData.txt b/js/src/vm/UnicodeData.txt
new file mode 100644
index 000000000..a75697646
--- /dev/null
+++ b/js/src/vm/UnicodeData.txt
@@ -0,0 +1,30592 @@
+0000;<control>;Cc;0;BN;;;;;N;NULL;;;;
+0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;;
+0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;;
+0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;;
+0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;
+0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;;
+0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;;
+0007;<control>;Cc;0;BN;;;;;N;BELL;;;;
+0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;;
+0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
+000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;;
+000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
+000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
+000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;;
+000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;;
+000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;;
+0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;;
+0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;;
+0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;;
+0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;;
+0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;;
+0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;;
+0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;;
+0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;;
+0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;;
+0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;;
+001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;;
+001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;;
+001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;;
+001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;;
+001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;;
+001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;;
+0020;SPACE;Zs;0;WS;;;;;N;;;;;
+0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;;
+0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;;
+0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;;
+0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+0026;AMPERSAND;Po;0;ON;;;;;N;;;;;
+0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;;
+0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;;
+0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;;
+002A;ASTERISK;Po;0;ON;;;;;N;;;;;
+002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;;
+002C;COMMA;Po;0;CS;;;;;N;;;;;
+002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;;
+002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;;
+002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;;
+0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;;
+0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;;
+0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;;
+0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;;
+0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;;
+0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;;
+0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;;
+0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;;
+0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;
+003A;COLON;Po;0;CS;;;;;N;;;;;
+003B;SEMICOLON;Po;0;ON;;;;;N;;;;;
+003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003F;QUESTION MARK;Po;0;ON;;;;;N;;;;;
+0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;;
+0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;
+0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062;
+0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063;
+0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;
+0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065;
+0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066;
+0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;
+0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068;
+0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069;
+004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;
+004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B;
+004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C;
+004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;
+004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E;
+004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F;
+0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;
+0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071;
+0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072;
+0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;
+0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074;
+0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075;
+0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;
+0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077;
+0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078;
+0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;
+005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A;
+005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;;
+005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;;
+005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;;
+005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;;
+005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;;
+0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;;
+0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041
+0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042
+0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043
+0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044
+0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045
+0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046
+0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047
+0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048
+0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049
+006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A
+006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B
+006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C
+006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D
+006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E
+006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F
+0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050
+0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051
+0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052
+0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053
+0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054
+0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055
+0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056
+0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057
+0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058
+0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059
+007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;;
+007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;;
+007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;;
+007E;TILDE;Sm;0;ON;;;;;N;;;;;
+007F;<control>;Cc;0;BN;;;;;N;DELETE;;;;
+0080;<control>;Cc;0;BN;;;;;N;;;;;
+0081;<control>;Cc;0;BN;;;;;N;;;;;
+0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;;
+0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;;
+0084;<control>;Cc;0;BN;;;;;N;;;;;
+0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;;
+0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;;
+0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;;
+0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;;
+0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;;
+008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;;
+008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;;
+008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;;
+008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;;
+008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;;
+008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;;
+0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;;
+0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;;
+0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;;
+0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;;
+0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;;
+0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;;
+0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;;
+0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;;
+0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;;
+0099;<control>;Cc;0;BN;;;;;N;;;;;
+009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;;
+009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;;
+009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;;
+009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;;
+009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;;
+009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;;
+00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
+00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;;
+00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;;
+00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;;
+00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;;
+00A7;SECTION SIGN;Po;0;ON;;;;;N;;;;;
+00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;;
+00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;;
+00AA;FEMININE ORDINAL INDICATOR;Lo;0;L;<super> 0061;;;;N;;;;;
+00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;;;;
+00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;;
+00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;;
+00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;;
+00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;;
+00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;;
+00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;;
+00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;;
+00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;;
+00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;;
+00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C
+00B6;PILCROW SIGN;Po;0;ON;;;;;N;PARAGRAPH SIGN;;;;
+00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;;
+00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;;
+00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L;<super> 006F;;;;N;;;;;
+00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;;
+00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;;
+00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;;
+00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;;
+00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;;
+00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0;
+00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1;
+00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2;
+00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3;
+00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;
+00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5;
+00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;;;00E6;
+00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;
+00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8;
+00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9;
+00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA;
+00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB;
+00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;
+00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED;
+00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;
+00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF;
+00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;00F0;
+00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1;
+00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2;
+00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3;
+00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4;
+00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5;
+00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;
+00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;;
+00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8;
+00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9;
+00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA;
+00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB;
+00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC;
+00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;
+00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;;;00FE;
+00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;;;;
+00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0
+00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1
+00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2
+00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3
+00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4
+00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5
+00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;;00C6;;00C6
+00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7
+00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8
+00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9
+00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA
+00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB
+00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC
+00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD
+00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE
+00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF
+00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;;00D0;;00D0
+00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1
+00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2
+00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3
+00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4
+00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5
+00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6
+00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8
+00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9
+00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA
+00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB
+00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC
+00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD
+00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;;00DE;;00DE
+00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178
+0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101;
+0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100
+0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103;
+0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102
+0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105;
+0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104
+0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107;
+0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106
+0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109;
+0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108
+010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B;
+010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A
+010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D;
+010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C
+010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F;
+010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E
+0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111;
+0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110
+0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113;
+0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112
+0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115;
+0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114
+0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117;
+0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116
+0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119;
+0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118
+011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B;
+011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A
+011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D;
+011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C
+011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F;
+011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E
+0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121;
+0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120
+0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123;
+0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122
+0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125;
+0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124
+0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127;
+0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126
+0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129;
+0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128
+012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;
+012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A
+012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D;
+012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C
+012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F;
+012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E
+0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069;
+0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133;
+0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135;
+0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134
+0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137;
+0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136
+0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;;;;
+0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139
+013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C;
+013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B
+013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E;
+013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D
+013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F
+0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142;
+0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141
+0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144;
+0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143
+0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146;
+0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145
+0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148;
+0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;;
+014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;014B;
+014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;;014A;;014A
+014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D;
+014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C
+014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F;
+014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E
+0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151;
+0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150
+0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153;
+0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152
+0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155;
+0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154
+0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157;
+0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156
+0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159;
+0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158
+015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B;
+015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A
+015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D;
+015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C
+015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;;;015F;
+015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;;015E;;015E
+0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161;
+0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160
+0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;;;0163;
+0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;;0162;;0162
+0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165;
+0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164
+0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167;
+0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166
+0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169;
+0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168
+016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B;
+016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A
+016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D;
+016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C
+016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F;
+016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E
+0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171;
+0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170
+0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173;
+0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172
+0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175;
+0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174
+0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177;
+0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176
+0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF;
+0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A;
+017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179
+017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C;
+017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B
+017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E;
+017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D
+017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053
+0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;0243;;0243
+0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253;
+0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183;
+0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182
+0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185;
+0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184
+0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254;
+0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188;
+0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187
+0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;;;0256;
+018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257;
+018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C;
+018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B
+018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;;
+018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD;
+018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259;
+0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B;
+0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192;
+0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191
+0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260;
+0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263;
+0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;;01F6;;01F6
+0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269;
+0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268;
+0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199;
+0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198
+019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D
+019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;;
+019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F;
+019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272;
+019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220
+019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;;;0275;
+01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1;
+01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0
+01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;;;01A3;
+01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;;01A2;;01A2
+01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5;
+01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4
+01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;;;0280;
+01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8;
+01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7
+01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283;
+01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;;
+01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;;
+01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD;
+01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC
+01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288;
+01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0;
+01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF
+01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A;
+01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B;
+01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4;
+01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3
+01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6;
+01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5
+01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292;
+01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9;
+01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8
+01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;;
+01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;;
+01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD;
+01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC
+01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;;
+01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7
+01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;;
+01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;;
+01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;;
+01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;;
+01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5
+01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5
+01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5
+01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8
+01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8
+01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8
+01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB
+01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB
+01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB
+01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE;
+01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD
+01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0;
+01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF
+01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2;
+01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1
+01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4;
+01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3
+01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6;
+01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5
+01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8;
+01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7
+01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA;
+01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9
+01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC;
+01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB
+01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E
+01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF;
+01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE
+01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1;
+01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0
+01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;;;01E3;
+01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;;01E2;;01E2
+01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5;
+01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4
+01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7;
+01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6
+01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9;
+01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8
+01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB;
+01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA
+01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED;
+01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC
+01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF;
+01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE
+01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;;
+01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2
+01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2
+01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2
+01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5;
+01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4
+01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195;
+01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF;
+01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9;
+01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8
+01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB;
+01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA
+01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;;;01FD;
+01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;;01FC;;01FC
+01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF;
+01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE
+0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201;
+0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200
+0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203;
+0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202
+0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205;
+0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204
+0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207;
+0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206
+0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209;
+0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208
+020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B;
+020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A
+020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D;
+020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C
+020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F;
+020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E
+0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211;
+0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210
+0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213;
+0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212
+0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215;
+0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214
+0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217;
+0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216
+0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;;;0219;
+0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;;0218;;0218
+021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;;;021B;
+021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;;021A;;021A
+021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D;
+021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C
+021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F;
+021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E
+0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E;
+0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;;
+0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223;
+0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222
+0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225;
+0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224
+0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227;
+0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226
+0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229;
+0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228
+022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B;
+022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A
+022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D;
+022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C
+022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F;
+022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E
+0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231;
+0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230
+0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233;
+0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232
+0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;;
+0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;;
+0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;;
+0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;;
+0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;;
+0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;;
+023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;2C65;
+023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C;
+023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B
+023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A;
+023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;2C66;
+023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7E;;2C7E
+0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;2C7F;;2C7F
+0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0242;
+0242;LATIN SMALL LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241
+0243;LATIN CAPITAL LETTER B WITH STROKE;Lu;0;L;;;;;N;;;;0180;
+0244;LATIN CAPITAL LETTER U BAR;Lu;0;L;;;;;N;;;;0289;
+0245;LATIN CAPITAL LETTER TURNED V;Lu;0;L;;;;;N;;;;028C;
+0246;LATIN CAPITAL LETTER E WITH STROKE;Lu;0;L;;;;;N;;;;0247;
+0247;LATIN SMALL LETTER E WITH STROKE;Ll;0;L;;;;;N;;;0246;;0246
+0248;LATIN CAPITAL LETTER J WITH STROKE;Lu;0;L;;;;;N;;;;0249;
+0249;LATIN SMALL LETTER J WITH STROKE;Ll;0;L;;;;;N;;;0248;;0248
+024A;LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL;Lu;0;L;;;;;N;;;;024B;
+024B;LATIN SMALL LETTER Q WITH HOOK TAIL;Ll;0;L;;;;;N;;;024A;;024A
+024C;LATIN CAPITAL LETTER R WITH STROKE;Lu;0;L;;;;;N;;;;024D;
+024D;LATIN SMALL LETTER R WITH STROKE;Ll;0;L;;;;;N;;;024C;;024C
+024E;LATIN CAPITAL LETTER Y WITH STROKE;Lu;0;L;;;;;N;;;;024F;
+024F;LATIN SMALL LETTER Y WITH STROKE;Ll;0;L;;;;;N;;;024E;;024E
+0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;2C6F;;2C6F
+0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;2C6D;;2C6D
+0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;2C70;;2C70
+0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181
+0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186
+0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;;
+0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189
+0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A
+0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;;
+0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F
+025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;;
+025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190
+025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;A7AB;;A7AB
+025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;;
+025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;;
+025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;;
+0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193
+0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;A7AC;;A7AC
+0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;;
+0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194
+0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;;
+0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D
+0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;A7AA;;A7AA
+0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;;
+0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197
+0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196
+026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE
+026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62
+026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD
+026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;;
+026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;;
+026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C
+0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;2C6E;;2C6E
+0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D
+0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;;
+0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;;
+0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F
+0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;;
+0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;;
+0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;;
+0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;;
+027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;;
+027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;2C64;;2C64
+027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;;
+027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;;
+0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;;01A6;;01A6
+0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;;
+0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;;
+0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9
+0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;;
+0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;;
+0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;;
+0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;A7B1;;A7B1
+0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE
+0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;0244;;0244
+028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1
+028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2
+028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;0245;;0245
+028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;;
+028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;;
+028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;;
+0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;;
+0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;;
+0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7
+0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;
+0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
+0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
+0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;
+0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;
+0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;;
+029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;;
+029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;;
+029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;;
+029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;A7B2;;A7B2
+029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;A7B0;;A7B0
+029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;;
+02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;;
+02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;;
+02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;;
+02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;;
+02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;;
+02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;;
+02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;;
+02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;;
+02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;;
+02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;;
+02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;;
+02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;;
+02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;;
+02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;;
+02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;;
+02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;;
+02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;;
+02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;;
+02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;;
+02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;;
+02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;;
+02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;;
+02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;;
+02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;;
+02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;;
+02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;;;;
+02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;;;;
+02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;;;;
+02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;;;;
+02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;;
+02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;;
+02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;;
+02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;;
+02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;;
+02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;;
+02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;;
+02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;;
+02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;;;;
+02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;;
+02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;;
+02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;;
+02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;;
+02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;;
+02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;;
+02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;;
+02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;;
+02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;;
+02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;;
+02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;;
+02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EC;MODIFIER LETTER VOICING;Lm;0;ON;;;;;N;;;;;
+02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;;
+02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;;
+02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;;
+02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;;
+02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;;
+02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;;
+02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;;
+0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;;
+0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;;;;
+0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;;
+0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;;
+0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;;
+0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;;
+0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;;;;
+0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;;
+0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;;;;
+0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;;
+030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;;
+030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;;
+030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;;
+030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;;
+030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;;
+030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;;
+0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;;
+0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;;
+0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;;
+0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;;;;
+0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;;;;
+0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;;
+0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;;
+0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;;
+0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;;
+0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;;
+031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;;
+031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;;
+031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;;
+031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;;
+031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;;
+031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;;
+0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;;
+0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;;
+0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;;
+0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;;
+0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;;
+0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
+0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;;
+0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
+0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;;
+0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;;
+032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;;
+032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;;
+032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;;
+032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;;
+032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;;
+032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;;
+0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;;
+0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;;
+0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;;
+0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;;
+0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;;
+0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;;
+0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;;
+0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;;
+0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;;
+0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;;
+033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;;
+033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;;
+033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;;
+033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;;
+033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;;
+033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;;
+0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;;;;
+0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;;;;
+0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;;
+0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;;
+0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;;
+0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399
+0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;
+0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;;
+034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;;
+034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;;
+034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;;
+034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;;
+0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;;
+0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;;
+0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;
+0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;;
+035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;;
+035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;;
+035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;;
+035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;;
+035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;;
+0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;;
+0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;;
+0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;;
+0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;;
+0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;;
+0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;;
+0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;;
+0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;;
+0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;;
+0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;;
+036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;;
+036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;;
+036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;;
+036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;;
+036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;;
+036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;;
+0370;GREEK CAPITAL LETTER HETA;Lu;0;L;;;;;N;;;;0371;
+0371;GREEK SMALL LETTER HETA;Ll;0;L;;;;;N;;;0370;;0370
+0372;GREEK CAPITAL LETTER ARCHAIC SAMPI;Lu;0;L;;;;;N;;;;0373;
+0373;GREEK SMALL LETTER ARCHAIC SAMPI;Ll;0;L;;;;;N;;;0372;;0372
+0374;GREEK NUMERAL SIGN;Lm;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;;;;
+0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;;;;
+0376;GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA;Lu;0;L;;;;;N;;;;0377;
+0377;GREEK SMALL LETTER PAMPHYLIAN DIGAMMA;Ll;0;L;;;;;N;;;0376;;0376
+037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;;
+037B;GREEK SMALL REVERSED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FD;;03FD
+037C;GREEK SMALL DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FE;;03FE
+037D;GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL;Ll;0;L;;;;;N;;;03FF;;03FF
+037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;;;;
+037F;GREEK CAPITAL LETTER YOT;Lu;0;L;;;;;N;;;;03F3;
+0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;;
+0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;;
+0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC;
+0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;;
+0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD;
+0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE;
+038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF;
+038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC;
+038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD;
+038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE;
+0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;;
+0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1;
+0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2;
+0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3;
+0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4;
+0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5;
+0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6;
+0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7;
+0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
+0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9;
+039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA;
+039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB;
+039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC;
+039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD;
+039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE;
+039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF;
+03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0;
+03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1;
+03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3;
+03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4;
+03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5;
+03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6;
+03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7;
+03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8;
+03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9;
+03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA;
+03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB;
+03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386
+03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388
+03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389
+03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A
+03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;;
+03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391
+03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392
+03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393
+03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394
+03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395
+03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396
+03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397
+03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
+03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399
+03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A
+03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B
+03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C
+03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D
+03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E
+03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F
+03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0
+03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1
+03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4
+03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5
+03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6
+03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7
+03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8
+03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9
+03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA
+03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB
+03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C
+03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E
+03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F
+03CF;GREEK CAPITAL KAI SYMBOL;Lu;0;L;;;;;N;;;;03D7;
+03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392
+03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
+03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;;
+03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;;
+03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;;
+03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6
+03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0
+03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;03CF;;03CF
+03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;;;03D9;
+03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;;03D8;;03D8
+03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB;
+03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA
+03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD;
+03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC
+03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF;
+03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE
+03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1;
+03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0
+03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3;
+03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2
+03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5;
+03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4
+03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7;
+03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6
+03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9;
+03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8
+03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB;
+03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA
+03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED;
+03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC
+03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF;
+03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE
+03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A
+03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1
+03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9
+03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;037F;;037F
+03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
+03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395
+03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;;
+03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8;
+03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7
+03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2;
+03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB;
+03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA
+03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;;
+03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037B;
+03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037C;
+03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;037D;
+0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450;
+0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451;
+0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;;;0452;
+0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453;
+0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454;
+0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455;
+0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456;
+0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;;;0457;
+0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458;
+0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459;
+040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A;
+040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;;;045B;
+040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C;
+040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D;
+040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;;;045E;
+040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F;
+0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430;
+0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431;
+0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432;
+0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433;
+0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434;
+0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435;
+0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436;
+0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437;
+0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438;
+0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439;
+041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A;
+041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B;
+041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C;
+041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D;
+041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E;
+041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F;
+0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440;
+0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441;
+0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442;
+0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443;
+0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444;
+0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445;
+0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446;
+0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447;
+0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448;
+0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449;
+042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A;
+042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B;
+042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C;
+042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D;
+042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E;
+042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F;
+0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410
+0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411
+0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412
+0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413
+0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414
+0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415
+0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416
+0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417
+0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418
+0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419
+043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A
+043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B
+043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C
+043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D
+043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E
+043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F
+0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420
+0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421
+0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422
+0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423
+0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424
+0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425
+0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426
+0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427
+0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428
+0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429
+044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
+044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B
+044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C
+044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D
+044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E
+044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F
+0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400
+0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401
+0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;;0402;;0402
+0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403
+0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404
+0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405
+0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406
+0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;;0407;;0407
+0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408
+0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409
+045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A
+045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;;040B;;040B
+045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C
+045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D
+045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;;040E;;040E
+045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F
+0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461;
+0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460
+0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463;
+0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462
+0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465;
+0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464
+0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467;
+0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466
+0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469;
+0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468
+046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B;
+046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A
+046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D;
+046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C
+046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F;
+046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E
+0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471;
+0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470
+0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473;
+0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472
+0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475;
+0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474
+0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477;
+0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476
+0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479;
+0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478
+047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B;
+047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A
+047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D;
+047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C
+047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F;
+047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E
+0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481;
+0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480
+0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;;
+0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;;
+0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;;
+0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;;
+0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;;
+0487;COMBINING CYRILLIC POKRYTIE;Mn;230;NSM;;;;;N;;;;;
+0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;
+0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B;
+048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A
+048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D;
+048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C
+048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F;
+048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E
+0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491;
+0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490
+0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493;
+0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492
+0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495;
+0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494
+0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497;
+0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496
+0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499;
+0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498
+049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B;
+049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A
+049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D;
+049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C
+049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F;
+049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E
+04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1;
+04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0
+04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3;
+04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2
+04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5;
+04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4
+04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;;;04A7;
+04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;;04A6;;04A6
+04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9;
+04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8
+04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB;
+04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA
+04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD;
+04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC
+04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF;
+04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE
+04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1;
+04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0
+04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3;
+04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2
+04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;;;04B5;
+04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;;04B4;;04B4
+04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7;
+04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6
+04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9;
+04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8
+04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB;
+04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA
+04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD;
+04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC
+04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF;
+04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE
+04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;04CF;
+04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2;
+04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1
+04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4;
+04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3
+04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6;
+04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5
+04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8;
+04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7
+04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA;
+04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9
+04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC;
+04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB
+04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE;
+04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD
+04CF;CYRILLIC SMALL LETTER PALOCHKA;Ll;0;L;;;;;N;;;04C0;;04C0
+04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1;
+04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0
+04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3;
+04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2
+04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5;
+04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4
+04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7;
+04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6
+04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9;
+04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8
+04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB;
+04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA
+04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD;
+04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC
+04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF;
+04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE
+04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1;
+04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0
+04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3;
+04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2
+04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5;
+04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4
+04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7;
+04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6
+04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9;
+04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8
+04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB;
+04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA
+04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED;
+04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC
+04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF;
+04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE
+04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1;
+04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0
+04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3;
+04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2
+04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5;
+04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4
+04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7;
+04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6
+04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9;
+04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8
+04FA;CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK;Lu;0;L;;;;;N;;;;04FB;
+04FB;CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK;Ll;0;L;;;;;N;;;04FA;;04FA
+04FC;CYRILLIC CAPITAL LETTER HA WITH HOOK;Lu;0;L;;;;;N;;;;04FD;
+04FD;CYRILLIC SMALL LETTER HA WITH HOOK;Ll;0;L;;;;;N;;;04FC;;04FC
+04FE;CYRILLIC CAPITAL LETTER HA WITH STROKE;Lu;0;L;;;;;N;;;;04FF;
+04FF;CYRILLIC SMALL LETTER HA WITH STROKE;Ll;0;L;;;;;N;;;04FE;;04FE
+0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501;
+0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500
+0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503;
+0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502
+0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505;
+0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504
+0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507;
+0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506
+0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509;
+0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508
+050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B;
+050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A
+050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D;
+050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C
+050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F;
+050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E
+0510;CYRILLIC CAPITAL LETTER REVERSED ZE;Lu;0;L;;;;;N;;;;0511;
+0511;CYRILLIC SMALL LETTER REVERSED ZE;Ll;0;L;;;;;N;;;0510;;0510
+0512;CYRILLIC CAPITAL LETTER EL WITH HOOK;Lu;0;L;;;;;N;;;;0513;
+0513;CYRILLIC SMALL LETTER EL WITH HOOK;Ll;0;L;;;;;N;;;0512;;0512
+0514;CYRILLIC CAPITAL LETTER LHA;Lu;0;L;;;;;N;;;;0515;
+0515;CYRILLIC SMALL LETTER LHA;Ll;0;L;;;;;N;;;0514;;0514
+0516;CYRILLIC CAPITAL LETTER RHA;Lu;0;L;;;;;N;;;;0517;
+0517;CYRILLIC SMALL LETTER RHA;Ll;0;L;;;;;N;;;0516;;0516
+0518;CYRILLIC CAPITAL LETTER YAE;Lu;0;L;;;;;N;;;;0519;
+0519;CYRILLIC SMALL LETTER YAE;Ll;0;L;;;;;N;;;0518;;0518
+051A;CYRILLIC CAPITAL LETTER QA;Lu;0;L;;;;;N;;;;051B;
+051B;CYRILLIC SMALL LETTER QA;Ll;0;L;;;;;N;;;051A;;051A
+051C;CYRILLIC CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;051D;
+051D;CYRILLIC SMALL LETTER WE;Ll;0;L;;;;;N;;;051C;;051C
+051E;CYRILLIC CAPITAL LETTER ALEUT KA;Lu;0;L;;;;;N;;;;051F;
+051F;CYRILLIC SMALL LETTER ALEUT KA;Ll;0;L;;;;;N;;;051E;;051E
+0520;CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0521;
+0521;CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0520;;0520
+0522;CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;0523;
+0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522
+0524;CYRILLIC CAPITAL LETTER PE WITH DESCENDER;Lu;0;L;;;;;N;;;;0525;
+0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524
+0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527;
+0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526
+0528;CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK;Lu;0;L;;;;;N;;;;0529;
+0529;CYRILLIC SMALL LETTER EN WITH LEFT HOOK;Ll;0;L;;;;;N;;;0528;;0528
+052A;CYRILLIC CAPITAL LETTER DZZHE;Lu;0;L;;;;;N;;;;052B;
+052B;CYRILLIC SMALL LETTER DZZHE;Ll;0;L;;;;;N;;;052A;;052A
+052C;CYRILLIC CAPITAL LETTER DCHE;Lu;0;L;;;;;N;;;;052D;
+052D;CYRILLIC SMALL LETTER DCHE;Ll;0;L;;;;;N;;;052C;;052C
+052E;CYRILLIC CAPITAL LETTER EL WITH DESCENDER;Lu;0;L;;;;;N;;;;052F;
+052F;CYRILLIC SMALL LETTER EL WITH DESCENDER;Ll;0;L;;;;;N;;;052E;;052E
+0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561;
+0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562;
+0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563;
+0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564;
+0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565;
+0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566;
+0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567;
+0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568;
+0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569;
+053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A;
+053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B;
+053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C;
+053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D;
+053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E;
+053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F;
+0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570;
+0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571;
+0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572;
+0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573;
+0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574;
+0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575;
+0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576;
+0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577;
+0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578;
+0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579;
+054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A;
+054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B;
+054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C;
+054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D;
+054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E;
+054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F;
+0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580;
+0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581;
+0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582;
+0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583;
+0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584;
+0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585;
+0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586;
+0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;;
+055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;;
+055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;;
+055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
+055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
+055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
+0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
+0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
+0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534
+0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535
+0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536
+0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537
+0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538
+0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539
+056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A
+056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B
+056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C
+056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D
+056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E
+056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F
+0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540
+0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541
+0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542
+0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543
+0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544
+0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545
+0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546
+0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547
+0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548
+0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549
+057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A
+057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B
+057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C
+057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D
+057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E
+057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F
+0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550
+0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551
+0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552
+0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553
+0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554
+0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
+0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
+0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
+058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
+058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;
+058E;LEFT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;
+058F;ARMENIAN DRAM SIGN;Sc;0;ET;;;;;N;;;;;
+0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;;
+0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;;
+0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;;
+0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;;
+0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;;
+0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;;;;
+0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;;
+0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;;;;
+0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;;
+059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;;
+059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;;
+059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;;
+059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;;
+059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;;
+059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;;
+05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;;
+05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;;
+05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;;
+05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;;
+05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;;
+05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;;;;
+05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;;
+05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;;
+05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;;;;
+05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;;
+05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;;;;
+05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;;
+05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;;
+05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;;
+05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;;
+05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;;
+05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;;
+05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;;
+05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;;
+05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;;
+05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;;
+05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;;
+05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;;
+05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;;
+05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;;
+05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;;
+05BA;HEBREW POINT HOLAM HASER FOR VAV;Mn;19;NSM;;;;;N;;;;;
+05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;;
+05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;;;;
+05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;;;;
+05BE;HEBREW PUNCTUATION MAQAF;Pd;0;R;;;;;N;;;;;
+05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;;
+05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;;;;
+05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;;
+05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;;
+05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;;;;
+05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;;
+05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;;
+05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;;
+05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;;
+05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;;
+05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;;
+05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;;
+05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;;
+05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;;
+05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;;
+05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;;
+05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;;
+05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;;
+05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;;
+05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;;
+05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;
+05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;;
+05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;;
+05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;;
+05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;;
+05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;;
+05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;;
+05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;;
+05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;;
+05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
+05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
+05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
+05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
+05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
+05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;;
+05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;;
+0600;ARABIC NUMBER SIGN;Cf;0;AN;;;;;N;;;;;
+0601;ARABIC SIGN SANAH;Cf;0;AN;;;;;N;;;;;
+0602;ARABIC FOOTNOTE MARKER;Cf;0;AN;;;;;N;;;;;
+0603;ARABIC SIGN SAFHA;Cf;0;AN;;;;;N;;;;;
+0604;ARABIC SIGN SAMVAT;Cf;0;AN;;;;;N;;;;;
+0605;ARABIC NUMBER MARK ABOVE;Cf;0;AN;;;;;N;;;;;
+0606;ARABIC-INDIC CUBE ROOT;Sm;0;ON;;;;;N;;;;;
+0607;ARABIC-INDIC FOURTH ROOT;Sm;0;ON;;;;;N;;;;;
+0608;ARABIC RAY;Sm;0;AL;;;;;N;;;;;
+0609;ARABIC-INDIC PER MILLE SIGN;Po;0;ET;;;;;N;;;;;
+060A;ARABIC-INDIC PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;
+060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;;
+060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;;
+060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;;
+060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;;
+060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;;
+0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;;
+0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;;
+0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;;
+0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;;
+0616;ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH;Mn;230;NSM;;;;;N;;;;;
+0617;ARABIC SMALL HIGH ZAIN;Mn;230;NSM;;;;;N;;;;;
+0618;ARABIC SMALL FATHA;Mn;30;NSM;;;;;N;;;;;
+0619;ARABIC SMALL DAMMA;Mn;31;NSM;;;;;N;;;;;
+061A;ARABIC SMALL KASRA;Mn;32;NSM;;;;;N;;;;;
+061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;;
+061C;ARABIC LETTER MARK;Cf;0;AL;;;;;N;;;;;
+061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;;
+061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;;
+0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;;
+0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;;
+0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;;
+0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;;
+0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;;
+0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;;
+0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;;
+0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;;
+0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;;
+0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;;
+062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;;
+062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;;
+062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;;
+062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;;
+062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;;
+062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;;
+0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;;
+0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;;
+0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;;
+0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;;
+0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;;
+0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;;
+0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;;
+0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;;
+0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;;
+063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;;
+063B;ARABIC LETTER KEHEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+063C;ARABIC LETTER KEHEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+063D;ARABIC LETTER FARSI YEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+063E;ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+063F;ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;;
+0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;;
+0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;;
+0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;;
+0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;;
+0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;;
+0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;;
+0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;;
+0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;;
+064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;;
+064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;;
+064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;;
+064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;;
+064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;;
+064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;;
+0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;;
+0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;;
+0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;;
+0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;;
+0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;
+0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;;
+0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;;
+0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;
+0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;;
+065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;;
+065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;;
+065F;ARABIC WAVY HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;
+0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
+066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
+066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;;
+066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;;
+066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;;
+066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;;
+0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;;
+0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;;
+0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;;
+0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;;
+0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;;
+0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;;
+0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;;
+0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;;
+0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;;
+0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;;
+067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;;
+067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;;
+067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;;
+067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;;
+067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;;
+067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;;
+0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;;
+0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;;
+0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;;
+0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;;
+0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;;
+0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;;
+0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;;
+0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;;
+0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;;
+0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;;
+068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;;
+068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;;
+068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;;
+068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;;
+0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;;
+0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;;
+0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;;
+0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;;
+0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;;
+0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;;
+0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;;
+0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;;
+0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;;
+069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;;
+06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;;
+06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;;
+06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;;
+06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;;
+06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;;
+06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;;
+06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;;
+06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;;
+06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;;
+06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;;
+06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;;
+06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;;;;
+06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;;
+06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;;
+06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;;
+06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;;
+06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;;
+06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;;
+06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;;
+06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;;
+06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;;
+06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;;
+06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;;
+06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;;
+06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;;
+06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;;
+06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;;
+06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;;
+06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;;
+06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;;
+06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;;
+06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;;
+06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;;
+06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;;;;
+06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;;
+06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;;
+06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;;
+06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;;
+06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;;
+06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;;
+06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;;
+06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;;
+06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;;
+06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;;
+06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;;
+06DE;ARABIC START OF RUB EL HIZB;So;0;ON;;;;;N;;;;;
+06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;;
+06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;;
+06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;;
+06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;;
+06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;;
+06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;;
+06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;;
+06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;;
+06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;;
+06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;;
+06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;;
+06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;;
+06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;;
+06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;;
+06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;;
+06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;;
+06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;;
+06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;;
+06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;;
+06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;;
+06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;;
+06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;;
+06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;;
+06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;;
+06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;;
+06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;;
+06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;;
+06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;;
+0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;;
+0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;;
+0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;;
+0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;;
+070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;;
+070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;;
+070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;;
+070F;SYRIAC ABBREVIATION MARK;Cf;0;AL;;;;;N;;;;;
+0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;;
+0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;;
+0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;;
+0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;;
+0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;;
+0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;;
+0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;;
+0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;;
+0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;;
+071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;;
+071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;;
+071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;;
+071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;;
+071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;;
+0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;;
+0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;;
+0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;;
+0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;;
+0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;;
+0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;;
+0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;;
+0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;;
+072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;;
+072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;;
+072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;;
+072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;;
+072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;;
+0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;;
+0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;;
+073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;;
+073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;;
+0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;;
+0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;;
+0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;;
+0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;;
+074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;;
+074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;;
+074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;;
+074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;;
+0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;;
+0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;;
+075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;;
+075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;;
+0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;;
+076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
+076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+076E;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW;Lo;0;AL;;;;;N;;;;;
+076F;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;
+0770;ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;
+0771;ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS;Lo;0;AL;;;;;N;;;;;
+0772;ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE;Lo;0;AL;;;;;N;;;;;
+0773;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;
+0774;ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;
+0775;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;
+0776;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;
+0777;ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;;
+0778;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;
+0779;ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;
+077A;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE;Lo;0;AL;;;;;N;;;;;
+077B;ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE;Lo;0;AL;;;;;N;;;;;
+077C;ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW;Lo;0;AL;;;;;N;;;;;
+077D;ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE;Lo;0;AL;;;;;N;;;;;
+077E;ARABIC LETTER SEEN WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+077F;ARABIC LETTER KAF WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;;
+0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;;
+0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;;
+0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;;
+0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;;
+0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;;
+0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;;
+0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;;
+078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;;
+078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;;
+078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;;
+078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;;
+078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;;
+078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;;
+0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;;
+0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;;
+0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;;
+0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;;
+0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;;
+0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;;
+0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;;
+0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;;
+0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;;
+079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;;
+079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;;
+079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;;
+079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;;
+079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;;
+079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;;
+07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;;
+07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;;
+07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;;
+07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;;
+07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;;
+07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;;
+07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;;
+07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;;
+07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;;
+07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;;
+07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;;
+07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;;
+07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;;
+07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;;
+07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;;
+07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;;
+07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;;
+07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;;
+07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;;
+07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;;
+07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;;
+07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;;
+07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;;
+07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;;
+07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;;
+07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;;
+07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;;
+07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;
+07CA;NKO LETTER A;Lo;0;R;;;;;N;;;;;
+07CB;NKO LETTER EE;Lo;0;R;;;;;N;;;;;
+07CC;NKO LETTER I;Lo;0;R;;;;;N;;;;;
+07CD;NKO LETTER E;Lo;0;R;;;;;N;;;;;
+07CE;NKO LETTER U;Lo;0;R;;;;;N;;;;;
+07CF;NKO LETTER OO;Lo;0;R;;;;;N;;;;;
+07D0;NKO LETTER O;Lo;0;R;;;;;N;;;;;
+07D1;NKO LETTER DAGBASINNA;Lo;0;R;;;;;N;;;;;
+07D2;NKO LETTER N;Lo;0;R;;;;;N;;;;;
+07D3;NKO LETTER BA;Lo;0;R;;;;;N;;;;;
+07D4;NKO LETTER PA;Lo;0;R;;;;;N;;;;;
+07D5;NKO LETTER TA;Lo;0;R;;;;;N;;;;;
+07D6;NKO LETTER JA;Lo;0;R;;;;;N;;;;;
+07D7;NKO LETTER CHA;Lo;0;R;;;;;N;;;;;
+07D8;NKO LETTER DA;Lo;0;R;;;;;N;;;;;
+07D9;NKO LETTER RA;Lo;0;R;;;;;N;;;;;
+07DA;NKO LETTER RRA;Lo;0;R;;;;;N;;;;;
+07DB;NKO LETTER SA;Lo;0;R;;;;;N;;;;;
+07DC;NKO LETTER GBA;Lo;0;R;;;;;N;;;;;
+07DD;NKO LETTER FA;Lo;0;R;;;;;N;;;;;
+07DE;NKO LETTER KA;Lo;0;R;;;;;N;;;;;
+07DF;NKO LETTER LA;Lo;0;R;;;;;N;;;;;
+07E0;NKO LETTER NA WOLOSO;Lo;0;R;;;;;N;;;;;
+07E1;NKO LETTER MA;Lo;0;R;;;;;N;;;;;
+07E2;NKO LETTER NYA;Lo;0;R;;;;;N;;;;;
+07E3;NKO LETTER NA;Lo;0;R;;;;;N;;;;;
+07E4;NKO LETTER HA;Lo;0;R;;;;;N;;;;;
+07E5;NKO LETTER WA;Lo;0;R;;;;;N;;;;;
+07E6;NKO LETTER YA;Lo;0;R;;;;;N;;;;;
+07E7;NKO LETTER NYA WOLOSO;Lo;0;R;;;;;N;;;;;
+07E8;NKO LETTER JONA JA;Lo;0;R;;;;;N;;;;;
+07E9;NKO LETTER JONA CHA;Lo;0;R;;;;;N;;;;;
+07EA;NKO LETTER JONA RA;Lo;0;R;;;;;N;;;;;
+07EB;NKO COMBINING SHORT HIGH TONE;Mn;230;NSM;;;;;N;;;;;
+07EC;NKO COMBINING SHORT LOW TONE;Mn;230;NSM;;;;;N;;;;;
+07ED;NKO COMBINING SHORT RISING TONE;Mn;230;NSM;;;;;N;;;;;
+07EE;NKO COMBINING LONG DESCENDING TONE;Mn;230;NSM;;;;;N;;;;;
+07EF;NKO COMBINING LONG HIGH TONE;Mn;230;NSM;;;;;N;;;;;
+07F0;NKO COMBINING LONG LOW TONE;Mn;230;NSM;;;;;N;;;;;
+07F1;NKO COMBINING LONG RISING TONE;Mn;230;NSM;;;;;N;;;;;
+07F2;NKO COMBINING NASALIZATION MARK;Mn;220;NSM;;;;;N;;;;;
+07F3;NKO COMBINING DOUBLE DOT ABOVE;Mn;230;NSM;;;;;N;;;;;
+07F4;NKO HIGH TONE APOSTROPHE;Lm;0;R;;;;;N;;;;;
+07F5;NKO LOW TONE APOSTROPHE;Lm;0;R;;;;;N;;;;;
+07F6;NKO SYMBOL OO DENNEN;So;0;ON;;;;;N;;;;;
+07F7;NKO SYMBOL GBAKURUNEN;Po;0;ON;;;;;N;;;;;
+07F8;NKO COMMA;Po;0;ON;;;;;N;;;;;
+07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;;
+0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;;
+0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;;
+0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;;
+0803;SAMARITAN LETTER DALAT;Lo;0;R;;;;;N;;;;;
+0804;SAMARITAN LETTER IY;Lo;0;R;;;;;N;;;;;
+0805;SAMARITAN LETTER BAA;Lo;0;R;;;;;N;;;;;
+0806;SAMARITAN LETTER ZEN;Lo;0;R;;;;;N;;;;;
+0807;SAMARITAN LETTER IT;Lo;0;R;;;;;N;;;;;
+0808;SAMARITAN LETTER TIT;Lo;0;R;;;;;N;;;;;
+0809;SAMARITAN LETTER YUT;Lo;0;R;;;;;N;;;;;
+080A;SAMARITAN LETTER KAAF;Lo;0;R;;;;;N;;;;;
+080B;SAMARITAN LETTER LABAT;Lo;0;R;;;;;N;;;;;
+080C;SAMARITAN LETTER MIM;Lo;0;R;;;;;N;;;;;
+080D;SAMARITAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+080E;SAMARITAN LETTER SINGAAT;Lo;0;R;;;;;N;;;;;
+080F;SAMARITAN LETTER IN;Lo;0;R;;;;;N;;;;;
+0810;SAMARITAN LETTER FI;Lo;0;R;;;;;N;;;;;
+0811;SAMARITAN LETTER TSAADIY;Lo;0;R;;;;;N;;;;;
+0812;SAMARITAN LETTER QUF;Lo;0;R;;;;;N;;;;;
+0813;SAMARITAN LETTER RISH;Lo;0;R;;;;;N;;;;;
+0814;SAMARITAN LETTER SHAN;Lo;0;R;;;;;N;;;;;
+0815;SAMARITAN LETTER TAAF;Lo;0;R;;;;;N;;;;;
+0816;SAMARITAN MARK IN;Mn;230;NSM;;;;;N;;;;;
+0817;SAMARITAN MARK IN-ALAF;Mn;230;NSM;;;;;N;;;;;
+0818;SAMARITAN MARK OCCLUSION;Mn;230;NSM;;;;;N;;;;;
+0819;SAMARITAN MARK DAGESH;Mn;230;NSM;;;;;N;;;;;
+081A;SAMARITAN MODIFIER LETTER EPENTHETIC YUT;Lm;0;R;;;;;N;;;;;
+081B;SAMARITAN MARK EPENTHETIC YUT;Mn;230;NSM;;;;;N;;;;;
+081C;SAMARITAN VOWEL SIGN LONG E;Mn;230;NSM;;;;;N;;;;;
+081D;SAMARITAN VOWEL SIGN E;Mn;230;NSM;;;;;N;;;;;
+081E;SAMARITAN VOWEL SIGN OVERLONG AA;Mn;230;NSM;;;;;N;;;;;
+081F;SAMARITAN VOWEL SIGN LONG AA;Mn;230;NSM;;;;;N;;;;;
+0820;SAMARITAN VOWEL SIGN AA;Mn;230;NSM;;;;;N;;;;;
+0821;SAMARITAN VOWEL SIGN OVERLONG A;Mn;230;NSM;;;;;N;;;;;
+0822;SAMARITAN VOWEL SIGN LONG A;Mn;230;NSM;;;;;N;;;;;
+0823;SAMARITAN VOWEL SIGN A;Mn;230;NSM;;;;;N;;;;;
+0824;SAMARITAN MODIFIER LETTER SHORT A;Lm;0;R;;;;;N;;;;;
+0825;SAMARITAN VOWEL SIGN SHORT A;Mn;230;NSM;;;;;N;;;;;
+0826;SAMARITAN VOWEL SIGN LONG U;Mn;230;NSM;;;;;N;;;;;
+0827;SAMARITAN VOWEL SIGN U;Mn;230;NSM;;;;;N;;;;;
+0828;SAMARITAN MODIFIER LETTER I;Lm;0;R;;;;;N;;;;;
+0829;SAMARITAN VOWEL SIGN LONG I;Mn;230;NSM;;;;;N;;;;;
+082A;SAMARITAN VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;
+082B;SAMARITAN VOWEL SIGN O;Mn;230;NSM;;;;;N;;;;;
+082C;SAMARITAN VOWEL SIGN SUKUN;Mn;230;NSM;;;;;N;;;;;
+082D;SAMARITAN MARK NEQUDAA;Mn;230;NSM;;;;;N;;;;;
+0830;SAMARITAN PUNCTUATION NEQUDAA;Po;0;R;;;;;N;;;;;
+0831;SAMARITAN PUNCTUATION AFSAAQ;Po;0;R;;;;;N;;;;;
+0832;SAMARITAN PUNCTUATION ANGED;Po;0;R;;;;;N;;;;;
+0833;SAMARITAN PUNCTUATION BAU;Po;0;R;;;;;N;;;;;
+0834;SAMARITAN PUNCTUATION ATMAAU;Po;0;R;;;;;N;;;;;
+0835;SAMARITAN PUNCTUATION SHIYYAALAA;Po;0;R;;;;;N;;;;;
+0836;SAMARITAN ABBREVIATION MARK;Po;0;R;;;;;N;;;;;
+0837;SAMARITAN PUNCTUATION MELODIC QITSA;Po;0;R;;;;;N;;;;;
+0838;SAMARITAN PUNCTUATION ZIQAA;Po;0;R;;;;;N;;;;;
+0839;SAMARITAN PUNCTUATION QITSA;Po;0;R;;;;;N;;;;;
+083A;SAMARITAN PUNCTUATION ZAEF;Po;0;R;;;;;N;;;;;
+083B;SAMARITAN PUNCTUATION TURU;Po;0;R;;;;;N;;;;;
+083C;SAMARITAN PUNCTUATION ARKAANU;Po;0;R;;;;;N;;;;;
+083D;SAMARITAN PUNCTUATION SOF MASHFAAT;Po;0;R;;;;;N;;;;;
+083E;SAMARITAN PUNCTUATION ANNAAU;Po;0;R;;;;;N;;;;;
+0840;MANDAIC LETTER HALQA;Lo;0;R;;;;;N;;;;;
+0841;MANDAIC LETTER AB;Lo;0;R;;;;;N;;;;;
+0842;MANDAIC LETTER AG;Lo;0;R;;;;;N;;;;;
+0843;MANDAIC LETTER AD;Lo;0;R;;;;;N;;;;;
+0844;MANDAIC LETTER AH;Lo;0;R;;;;;N;;;;;
+0845;MANDAIC LETTER USHENNA;Lo;0;R;;;;;N;;;;;
+0846;MANDAIC LETTER AZ;Lo;0;R;;;;;N;;;;;
+0847;MANDAIC LETTER IT;Lo;0;R;;;;;N;;;;;
+0848;MANDAIC LETTER ATT;Lo;0;R;;;;;N;;;;;
+0849;MANDAIC LETTER AKSA;Lo;0;R;;;;;N;;;;;
+084A;MANDAIC LETTER AK;Lo;0;R;;;;;N;;;;;
+084B;MANDAIC LETTER AL;Lo;0;R;;;;;N;;;;;
+084C;MANDAIC LETTER AM;Lo;0;R;;;;;N;;;;;
+084D;MANDAIC LETTER AN;Lo;0;R;;;;;N;;;;;
+084E;MANDAIC LETTER AS;Lo;0;R;;;;;N;;;;;
+084F;MANDAIC LETTER IN;Lo;0;R;;;;;N;;;;;
+0850;MANDAIC LETTER AP;Lo;0;R;;;;;N;;;;;
+0851;MANDAIC LETTER ASZ;Lo;0;R;;;;;N;;;;;
+0852;MANDAIC LETTER AQ;Lo;0;R;;;;;N;;;;;
+0853;MANDAIC LETTER AR;Lo;0;R;;;;;N;;;;;
+0854;MANDAIC LETTER ASH;Lo;0;R;;;;;N;;;;;
+0855;MANDAIC LETTER AT;Lo;0;R;;;;;N;;;;;
+0856;MANDAIC LETTER DUSHENNA;Lo;0;R;;;;;N;;;;;
+0857;MANDAIC LETTER KAD;Lo;0;R;;;;;N;;;;;
+0858;MANDAIC LETTER AIN;Lo;0;R;;;;;N;;;;;
+0859;MANDAIC AFFRICATION MARK;Mn;220;NSM;;;;;N;;;;;
+085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;;
+085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;;
+085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;;
+08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
+08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08A3;ARABIC LETTER TAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08A4;ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08A5;ARABIC LETTER QAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+08A6;ARABIC LETTER LAM WITH DOUBLE BAR;Lo;0;AL;;;;;N;;;;;
+08A7;ARABIC LETTER MEEM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+08A8;ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
+08A9;ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+08AA;ARABIC LETTER REH WITH LOOP;Lo;0;AL;;;;;N;;;;;
+08AB;ARABIC LETTER WAW WITH DOT WITHIN;Lo;0;AL;;;;;N;;;;;
+08AC;ARABIC LETTER ROHINGYA YEH;Lo;0;AL;;;;;N;;;;;
+08AD;ARABIC LETTER LOW ALEF;Lo;0;AL;;;;;N;;;;;
+08AE;ARABIC LETTER DAL WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+08AF;ARABIC LETTER SAD WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+08B0;ARABIC LETTER GAF WITH INVERTED STROKE;Lo;0;AL;;;;;N;;;;;
+08B1;ARABIC LETTER STRAIGHT WAW;Lo;0;AL;;;;;N;;;;;
+08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;;
+08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;;
+08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;;
+08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;;
+08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;;
+08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;;
+08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;;
+08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;;
+08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;;
+08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;;
+08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;;
+08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;;
+08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;;
+08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;;
+08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;;
+08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;;
+08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;;
+08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;;
+08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;;
+08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;;
+08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;;
+08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;;
+08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;;
+08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;;
+08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;;
+08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;;
+08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;;
+08E6;ARABIC CURLY KASRA;Mn;220;NSM;;;;;N;;;;;
+08E7;ARABIC CURLY FATHATAN;Mn;230;NSM;;;;;N;;;;;
+08E8;ARABIC CURLY DAMMATAN;Mn;230;NSM;;;;;N;;;;;
+08E9;ARABIC CURLY KASRATAN;Mn;220;NSM;;;;;N;;;;;
+08EA;ARABIC TONE ONE DOT ABOVE;Mn;230;NSM;;;;;N;;;;;
+08EB;ARABIC TONE TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+08EC;ARABIC TONE LOOP ABOVE;Mn;230;NSM;;;;;N;;;;;
+08ED;ARABIC TONE ONE DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+08EE;ARABIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+08EF;ARABIC TONE LOOP BELOW;Mn;220;NSM;;;;;N;;;;;
+08F0;ARABIC OPEN FATHATAN;Mn;27;NSM;;;;;N;;;;;
+08F1;ARABIC OPEN DAMMATAN;Mn;28;NSM;;;;;N;;;;;
+08F2;ARABIC OPEN KASRATAN;Mn;29;NSM;;;;;N;;;;;
+08F3;ARABIC SMALL HIGH WAW;Mn;230;NSM;;;;;N;;;;;
+08F4;ARABIC FATHA WITH RING;Mn;230;NSM;;;;;N;;;;;
+08F5;ARABIC FATHA WITH DOT ABOVE;Mn;230;NSM;;;;;N;;;;;
+08F6;ARABIC KASRA WITH DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+08F7;ARABIC LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+08F8;ARABIC RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+08F9;ARABIC LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+08FA;ARABIC RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+08FB;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+08FC;ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;;
+08FD;ARABIC RIGHT ARROWHEAD ABOVE WITH DOT;Mn;230;NSM;;;;;N;;;;;
+08FE;ARABIC DAMMA WITH DOT;Mn;230;NSM;;;;;N;;;;;
+08FF;ARABIC MARK SIDEWAYS NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;
+0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;;
+0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;;
+0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;;
+0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;;
+0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;;
+0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;;
+090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;;
+090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;;
+090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;;
+090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;;
+0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;;
+0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;;
+0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;;
+0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;;
+0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;;
+0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;;
+0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;;
+0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;
+091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;;
+091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;
+091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;;
+091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;
+091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;
+091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;;
+0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;;
+0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;;
+0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;;
+0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;;
+092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;;
+092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;
+092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;;
+092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;
+092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;;
+092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;;
+0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;;
+0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;;
+0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;;
+0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;;
+0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;;
+0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;;
+0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;;
+093A;DEVANAGARI VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
+093B;DEVANAGARI VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;;
+093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+094E;DEVANAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;;
+094F;DEVANAGARI VOWEL SIGN AW;Mc;0;L;;;;;N;;;;;
+0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;;
+0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;;
+0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;;
+0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0955;DEVANAGARI VOWEL SIGN CANDRA LONG E;Mn;0;NSM;;;;;N;;;;;
+0956;DEVANAGARI VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+0957;DEVANAGARI VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;
+0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;;
+0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;;
+095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;;
+095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;;
+095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;;
+095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;;
+095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;;
+095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;;
+0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;;
+0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;;
+0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;;
+0973;DEVANAGARI LETTER OE;Lo;0;L;;;;;N;;;;;
+0974;DEVANAGARI LETTER OOE;Lo;0;L;;;;;N;;;;;
+0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;;
+0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;;
+0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;;
+0978;DEVANAGARI LETTER MARWARI DDA;Lo;0;L;;;;;N;;;;;
+0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;;
+097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;;
+097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;;
+097C;DEVANAGARI LETTER JJA;Lo;0;L;;;;;N;;;;;
+097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+097E;DEVANAGARI LETTER DDDA;Lo;0;L;;;;;N;;;;;
+097F;DEVANAGARI LETTER BBA;Lo;0;L;;;;;N;;;;;
+0980;BENGALI ANJI;Lo;0;L;;;;;N;;;;;
+0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;;
+0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;;
+0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;;
+0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;;
+0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;;
+098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;;
+098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;;
+0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;;
+0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;;
+0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;;
+0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;;
+0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;;
+0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;;
+099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;;
+099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;;
+099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;;
+099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;;
+099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;;
+099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;;
+09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;;
+09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;;
+09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;;
+09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;;
+09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;;
+09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;;
+09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;;
+09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;;
+09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;;
+09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;;
+09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;;
+09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;;
+09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;;
+09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;;
+09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;;
+09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;;
+09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;;
+09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;;
+09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;;
+09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;;
+09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;;
+09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;;
+09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;;
+09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;;
+09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;;
+09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;;;;
+09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;;;;
+09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;;
+09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1/16;N;;;;;
+09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;1/8;N;;;;;
+09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3/16;N;;;;;
+09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;1/4;N;;;;;
+09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;3/4;N;;;;;
+09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;
+09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;
+09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;;
+0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;
+0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
+0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;;
+0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;;
+0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;;
+0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;;
+0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;;
+0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;;
+0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;;
+0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;;
+0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;;
+0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;;
+0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;;
+0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;;
+0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;;
+0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;;
+0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;;
+0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;;
+0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;;
+0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;;
+0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;;
+0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;;
+0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;;
+0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0A51;GURMUKHI SIGN UDAAT;Mn;0;NSM;;;;;N;;;;;
+0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;;
+0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;;
+0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;;
+0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;;
+0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;;
+0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;;
+0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;;
+0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;;
+0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
+0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
+0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;;
+0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;;
+0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;;
+0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;;
+0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;;
+0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;;
+0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;;
+0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;;
+0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;;
+0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;;
+0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;;
+0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;;
+0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;;
+0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;;
+0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;;
+0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;;
+0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;;
+0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;;
+0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;;
+0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;;
+0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;;
+0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;;
+0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;;
+0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;;
+0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;;
+0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;;
+0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;;
+0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;;
+0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;;
+0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;;
+0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;;
+0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;;
+0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;;
+0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;;
+0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;;
+0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;;
+0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;;
+0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;;
+0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;;
+0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;;
+0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;;
+0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;;
+0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;;
+0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;;
+0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;;
+0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;;
+0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;;
+0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;;
+0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;;
+0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;;
+0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0B44;ORIYA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;;
+0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;
+0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;
+0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;
+0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;;
+0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;;
+0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0B62;ORIYA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0B63;ORIYA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;;
+0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;;
+0B72;ORIYA FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;
+0B73;ORIYA FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;
+0B74;ORIYA FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;
+0B75;ORIYA FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;
+0B76;ORIYA FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;
+0B77;ORIYA FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;
+0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;;
+0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;;
+0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;;
+0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;;
+0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;;
+0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;;
+0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;;
+0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;;
+0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;;
+0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;;
+0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;;
+0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;;
+0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;;
+0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;;
+0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;;
+0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;;
+0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;;
+0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;;
+0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;;
+0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;;
+0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;;
+0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;;
+0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;;
+0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;;
+0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;;
+0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;;
+0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;;
+0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;;
+0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;;
+0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;;
+0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;;
+0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;;
+0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;;
+0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;;
+0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;;
+0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;;
+0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0BD0;TAMIL OM;Lo;0;L;;;;;N;;;;;
+0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;;
+0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;;;;
+0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;;;;
+0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;;;;
+0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;;;;
+0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;;;;
+0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;;;;
+0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;;;;
+0C00;TELUGU SIGN COMBINING CANDRABINDU ABOVE;Mn;0;NSM;;;;;N;;;;;
+0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
+0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
+0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
+0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
+0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;;
+0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;;
+0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;;
+0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;;
+0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;;
+0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;;
+0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;;
+0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;;
+0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;;
+0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;;
+0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;;
+0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;;
+0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;;
+0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;;
+0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;;
+0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;;
+0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;;
+0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;;
+0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;;
+0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;;
+0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;;
+0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;;
+0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;;
+0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;;
+0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;;
+0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;;
+0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;;
+0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;;
+0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;;
+0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;;
+0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;;
+0C34;TELUGU LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;;
+0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;;
+0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;;
+0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;;
+0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;;
+0C3D;TELUGU SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;;
+0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;;
+0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;;
+0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;;
+0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;;
+0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;;
+0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0C62;TELUGU VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0C63;TELUGU VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0C78;TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR;No;0;ON;;;;0;N;;;;;
+0C79;TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR;No;0;ON;;;;1;N;;;;;
+0C7A;TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR;No;0;ON;;;;2;N;;;;;
+0C7B;TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR;No;0;ON;;;;3;N;;;;;
+0C7C;TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR;No;0;ON;;;;1;N;;;;;
+0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;;
+0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;;
+0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;;
+0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;;
+0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
+0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
+0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
+0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;;
+0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;;
+0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;;
+0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;;
+0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;;
+0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;;
+0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;;
+0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;;
+0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;;
+0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;;
+0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;;
+0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;;
+0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;;
+0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;;
+0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;;
+0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;;
+0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;;
+0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;;
+0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;;
+0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;;
+0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;;
+0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;;
+0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;;
+0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;;
+0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;;
+0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;;
+0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;;
+0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;;
+0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;;
+0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;;
+0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;;
+0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;;
+0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;;
+0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;;
+0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;
+0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0CE2;KANNADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0CE3;KANNADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
+0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;
+0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;
+0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;
+0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;;
+0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;;
+0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;;
+0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;;
+0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;;
+0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;;
+0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;;
+0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;;
+0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;;
+0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;;
+0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;;
+0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;;
+0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;;
+0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;;
+0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;;
+0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;;
+0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;;
+0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;;
+0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;;
+0D29;MALAYALAM LETTER NNNA;Lo;0;L;;;;;N;;;;;
+0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;;
+0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;;
+0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;;
+0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;;
+0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;;
+0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;;
+0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;;
+0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;;
+0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;;
+0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;;
+0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;
+0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;
+0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;;
+0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0D44;MALAYALAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
+0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;;
+0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;;
+0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;;
+0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;;
+0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;;
+0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;;
+0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;;
+0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;;
+0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;;
+0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;;
+0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;;
+0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;;
+0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;;
+0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;;
+0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;;
+0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0D62;MALAYALAM VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0D63;MALAYALAM VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D70;MALAYALAM NUMBER TEN;No;0;L;;;;10;N;;;;;
+0D71;MALAYALAM NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+0D72;MALAYALAM NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;
+0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;
+0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;
+0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;
+0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;
+0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;
+0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;;
+0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;;
+0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;;
+0D7C;MALAYALAM LETTER CHILLU RR;Lo;0;L;;;;;N;;;;;
+0D7D;MALAYALAM LETTER CHILLU L;Lo;0;L;;;;;N;;;;;
+0D7E;MALAYALAM LETTER CHILLU LL;Lo;0;L;;;;;N;;;;;
+0D7F;MALAYALAM LETTER CHILLU K;Lo;0;L;;;;;N;;;;;
+0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;
+0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;
+0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;
+0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;;
+0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;;
+0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;;
+0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;;
+0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;;
+0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;;
+0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;;
+0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;;
+0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;;
+0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;;
+0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;;
+0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;;
+0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;;
+0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;;
+0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;;
+0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;;
+0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;;
+0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;;
+0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;;
+0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;;
+0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;;
+0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;;
+0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;;
+0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;;
+0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;;
+0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;;
+0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;;
+0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;;
+0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;;
+0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;;
+0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;;
+0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DE6;SINHALA LITH DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0DE7;SINHALA LITH DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0DE8;SINHALA LITH DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0DE9;SINHALA LITH DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0DEA;SINHALA LITH DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0DEB;SINHALA LITH DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0DEC;SINHALA LITH DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0DED;SINHALA LITH DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0DEE;SINHALA LITH DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0DEF;SINHALA LITH DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;;
+0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;;
+0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;;
+0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;;
+0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;;
+0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;;
+0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;;
+0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;;
+0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;;
+0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;;
+0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;;
+0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;;
+0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;;
+0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;;
+0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;;
+0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;;
+0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;;
+0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;;
+0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;;
+0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;;
+0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;;
+0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;;
+0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;;
+0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;;
+0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;;
+0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;;
+0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;;
+0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;;
+0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;;
+0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;;
+0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;;
+0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;;
+0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;;
+0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;;
+0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;;
+0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;;
+0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;;
+0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;;
+0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;;
+0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;;
+0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;;
+0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;;
+0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;;
+0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;;
+0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;;
+0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;;
+0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;;
+0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;;;;
+0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;;
+0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;;
+0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;;
+0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;;
+0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;;
+0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;;
+0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;;
+0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;;;;
+0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;;
+0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;;
+0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;;
+0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;;
+0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;;
+0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;;
+0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;;
+0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;;;;
+0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;;;;
+0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;;;;
+0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;;;;
+0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;;;;
+0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;;
+0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;;
+0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;;
+0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;;
+0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;;
+0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;;;;
+0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;;
+0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;;
+0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;;
+0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;;
+0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;;
+0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;;
+0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;;
+0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;;
+0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;;
+0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;;
+0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;;
+0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;;
+0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;;
+0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;;
+0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;;
+0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;;
+0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;;
+0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;;
+0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;;
+0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;;
+0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;;
+0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;;
+0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;;
+0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;;
+0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;;
+0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;;
+0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;;
+0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;;
+0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;;
+0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;;
+0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;;
+0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;;
+0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;;
+0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;;
+0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;
+0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;;
+0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;;
+0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;;
+0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;;
+0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;;
+0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;;
+0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;;
+0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;;
+0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;;
+0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;
+0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;;
+0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;;
+0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;;
+0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;;
+0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;;
+0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;;
+0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;;
+0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;;
+0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;;
+0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;;
+0EDE;LAO LETTER KHMU GO;Lo;0;L;;;;;N;;;;;
+0EDF;LAO LETTER KHMU NYO;Lo;0;L;;;;;N;;;;;
+0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;;
+0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;;;;
+0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;;;;
+0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;;;;
+0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;;;;
+0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;;
+0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;;;;
+0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;;;;
+0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;;;;
+0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;;;;
+0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;;;;
+0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;;;;
+0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;;;;
+0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;;;;
+0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;;;;
+0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;;;;
+0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;;;;
+0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;;;;
+0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;;;;
+0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;;;;
+0F14;TIBETAN MARK GTER TSHEG;Po;0;L;;;;;N;TIBETAN COMMA;;;;
+0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;;;;
+0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;;;;
+0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;;;;
+0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;;;;
+0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;;;;
+0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;;;;
+0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;;;;
+0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;;;;
+0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;;;;
+0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;;;;
+0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;;;;
+0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;;
+0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;;
+0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;;
+0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;;
+0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;;
+0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;;
+0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;;
+0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;;
+0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;;
+0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;;
+0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;;;;
+0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;;;;
+0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;;;;
+0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;;;;
+0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;;;;
+0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;;;;
+0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;Y;;;;;
+0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;Y;;;;;
+0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;Y;TIBETAN LEFT BRACE;;;;
+0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;Y;TIBETAN RIGHT BRACE;;;;
+0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;;;;
+0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;;;;
+0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;;
+0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;;
+0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;;
+0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;;
+0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;;
+0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;;
+0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;;
+0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;;
+0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;;
+0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;;
+0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;;
+0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;;
+0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;;
+0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;;
+0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;;
+0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;;
+0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;;
+0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;;
+0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;;
+0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;;
+0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;;
+0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;;
+0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;;
+0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;;
+0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;;
+0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;;
+0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;;
+0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;;
+0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;;;;
+0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;;
+0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;;
+0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;;
+0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;;
+0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;;
+0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;;
+0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;;;;
+0F6B;TIBETAN LETTER KKA;Lo;0;L;;;;;N;;;;;
+0F6C;TIBETAN LETTER RRA;Lo;0;L;;;;;N;;;;;
+0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;;
+0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;;
+0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;;
+0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;;
+0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;;
+0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;;
+0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;;
+0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;;
+0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;;
+0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;;
+0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;;
+0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;;
+0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;;
+0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;;;;
+0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;;;;
+0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;;
+0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;;
+0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;;;;
+0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;;;;
+0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;;
+0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;;
+0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;;;;
+0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;;;;
+0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;;;;
+0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;;;;
+0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;;;;
+0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;;;;
+0F8C;TIBETAN SIGN INVERTED MCHU CAN;Lo;0;L;;;;;N;;;;;
+0F8D;TIBETAN SUBJOINED SIGN LCE TSA CAN;Mn;0;NSM;;;;;N;;;;;
+0F8E;TIBETAN SUBJOINED SIGN MCHU CAN;Mn;0;NSM;;;;;N;;;;;
+0F8F;TIBETAN SUBJOINED SIGN INVERTED MCHU CAN;Mn;0;NSM;;;;;N;;;;;
+0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;
+0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;
+0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;
+0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;;
+0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;
+0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;
+0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;
+0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;
+0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;
+0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;;
+0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;;
+0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;;
+0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;;
+0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;;
+0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;
+0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;
+0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;
+0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;;
+0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;
+0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;
+0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;
+0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;
+0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;;
+0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;
+0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;
+0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;
+0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;
+0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;;
+0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;;
+0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;
+0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;
+0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;;
+0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;;;;
+0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;;
+0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;
+0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;
+0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;;
+0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;
+0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;
+0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;
+0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;;
+0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;;;;
+0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;;;;
+0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;;;;
+0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;;;;
+0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;;;;
+0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;;
+0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;;
+0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;;;;
+0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;;;;
+0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;;;;
+0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;;;;
+0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;;;;
+0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;;;;
+0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;;;;
+0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;;;;
+0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;;;;
+0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;;;;
+0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;;;;
+0FCE;TIBETAN SIGN RDEL NAG RDEL DKAR;So;0;L;;;;;N;;;;;
+0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;;;;
+0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;;;;
+0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;;;;
+0FD2;TIBETAN MARK NYIS TSHEG;Po;0;L;;;;;N;;;;;
+0FD3;TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA;Po;0;L;;;;;N;;;;;
+0FD4;TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA;Po;0;L;;;;;N;;;;;
+0FD5;RIGHT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;;
+0FD6;LEFT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;;
+0FD7;RIGHT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;;
+0FD8;LEFT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;;
+0FD9;TIBETAN MARK LEADING MCHAN RTAGS;Po;0;L;;;;;N;;;;;
+0FDA;TIBETAN MARK TRAILING MCHAN RTAGS;Po;0;L;;;;;N;;;;;
+1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;;
+1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;;
+1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;;
+1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;;
+1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;;
+1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;;
+1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;;
+1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;;
+1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;;
+100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;;
+100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;;
+100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;;
+100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;;
+100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;;
+1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;;
+1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;;
+1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;;
+1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;;
+1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;;
+1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;;
+1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;;
+1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;;
+1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;;
+1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;;
+101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;;
+101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;;
+101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;;
+101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;;
+101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;;
+101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;;
+1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;;
+1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;;
+1022;MYANMAR LETTER SHAN A;Lo;0;L;;;;;N;;;;;
+1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;;
+1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;;
+1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;;
+1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;;
+1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;;
+1028;MYANMAR LETTER MON E;Lo;0;L;;;;;N;;;;;
+1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;;
+102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;;
+102B;MYANMAR VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;;
+102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1033;MYANMAR VOWEL SIGN MON II;Mn;0;NSM;;;;;N;;;;;
+1034;MYANMAR VOWEL SIGN MON O;Mn;0;NSM;;;;;N;;;;;
+1035;MYANMAR VOWEL SIGN E ABOVE;Mn;0;NSM;;;;;N;;;;;
+1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;;
+1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+103A;MYANMAR SIGN ASAT;Mn;9;NSM;;;;;N;;;;;
+103B;MYANMAR CONSONANT SIGN MEDIAL YA;Mc;0;L;;;;;N;;;;;
+103C;MYANMAR CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;;
+103D;MYANMAR CONSONANT SIGN MEDIAL WA;Mn;0;NSM;;;;;N;;;;;
+103E;MYANMAR CONSONANT SIGN MEDIAL HA;Mn;0;NSM;;;;;N;;;;;
+103F;MYANMAR LETTER GREAT SA;Lo;0;L;;;;;N;;;;;
+1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;;
+104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;;
+104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;;
+104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;;
+104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;;
+104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;;
+1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;;
+1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;;
+1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+105A;MYANMAR LETTER MON NGA;Lo;0;L;;;;;N;;;;;
+105B;MYANMAR LETTER MON JHA;Lo;0;L;;;;;N;;;;;
+105C;MYANMAR LETTER MON BBA;Lo;0;L;;;;;N;;;;;
+105D;MYANMAR LETTER MON BBE;Lo;0;L;;;;;N;;;;;
+105E;MYANMAR CONSONANT SIGN MON MEDIAL NA;Mn;0;NSM;;;;;N;;;;;
+105F;MYANMAR CONSONANT SIGN MON MEDIAL MA;Mn;0;NSM;;;;;N;;;;;
+1060;MYANMAR CONSONANT SIGN MON MEDIAL LA;Mn;0;NSM;;;;;N;;;;;
+1061;MYANMAR LETTER SGAW KAREN SHA;Lo;0;L;;;;;N;;;;;
+1062;MYANMAR VOWEL SIGN SGAW KAREN EU;Mc;0;L;;;;;N;;;;;
+1063;MYANMAR TONE MARK SGAW KAREN HATHI;Mc;0;L;;;;;N;;;;;
+1064;MYANMAR TONE MARK SGAW KAREN KE PHO;Mc;0;L;;;;;N;;;;;
+1065;MYANMAR LETTER WESTERN PWO KAREN THA;Lo;0;L;;;;;N;;;;;
+1066;MYANMAR LETTER WESTERN PWO KAREN PWA;Lo;0;L;;;;;N;;;;;
+1067;MYANMAR VOWEL SIGN WESTERN PWO KAREN EU;Mc;0;L;;;;;N;;;;;
+1068;MYANMAR VOWEL SIGN WESTERN PWO KAREN UE;Mc;0;L;;;;;N;;;;;
+1069;MYANMAR SIGN WESTERN PWO KAREN TONE-1;Mc;0;L;;;;;N;;;;;
+106A;MYANMAR SIGN WESTERN PWO KAREN TONE-2;Mc;0;L;;;;;N;;;;;
+106B;MYANMAR SIGN WESTERN PWO KAREN TONE-3;Mc;0;L;;;;;N;;;;;
+106C;MYANMAR SIGN WESTERN PWO KAREN TONE-4;Mc;0;L;;;;;N;;;;;
+106D;MYANMAR SIGN WESTERN PWO KAREN TONE-5;Mc;0;L;;;;;N;;;;;
+106E;MYANMAR LETTER EASTERN PWO KAREN NNA;Lo;0;L;;;;;N;;;;;
+106F;MYANMAR LETTER EASTERN PWO KAREN YWA;Lo;0;L;;;;;N;;;;;
+1070;MYANMAR LETTER EASTERN PWO KAREN GHWA;Lo;0;L;;;;;N;;;;;
+1071;MYANMAR VOWEL SIGN GEBA KAREN I;Mn;0;NSM;;;;;N;;;;;
+1072;MYANMAR VOWEL SIGN KAYAH OE;Mn;0;NSM;;;;;N;;;;;
+1073;MYANMAR VOWEL SIGN KAYAH U;Mn;0;NSM;;;;;N;;;;;
+1074;MYANMAR VOWEL SIGN KAYAH EE;Mn;0;NSM;;;;;N;;;;;
+1075;MYANMAR LETTER SHAN KA;Lo;0;L;;;;;N;;;;;
+1076;MYANMAR LETTER SHAN KHA;Lo;0;L;;;;;N;;;;;
+1077;MYANMAR LETTER SHAN GA;Lo;0;L;;;;;N;;;;;
+1078;MYANMAR LETTER SHAN CA;Lo;0;L;;;;;N;;;;;
+1079;MYANMAR LETTER SHAN ZA;Lo;0;L;;;;;N;;;;;
+107A;MYANMAR LETTER SHAN NYA;Lo;0;L;;;;;N;;;;;
+107B;MYANMAR LETTER SHAN DA;Lo;0;L;;;;;N;;;;;
+107C;MYANMAR LETTER SHAN NA;Lo;0;L;;;;;N;;;;;
+107D;MYANMAR LETTER SHAN PHA;Lo;0;L;;;;;N;;;;;
+107E;MYANMAR LETTER SHAN FA;Lo;0;L;;;;;N;;;;;
+107F;MYANMAR LETTER SHAN BA;Lo;0;L;;;;;N;;;;;
+1080;MYANMAR LETTER SHAN THA;Lo;0;L;;;;;N;;;;;
+1081;MYANMAR LETTER SHAN HA;Lo;0;L;;;;;N;;;;;
+1082;MYANMAR CONSONANT SIGN SHAN MEDIAL WA;Mn;0;NSM;;;;;N;;;;;
+1083;MYANMAR VOWEL SIGN SHAN AA;Mc;0;L;;;;;N;;;;;
+1084;MYANMAR VOWEL SIGN SHAN E;Mc;0;L;;;;;N;;;;;
+1085;MYANMAR VOWEL SIGN SHAN E ABOVE;Mn;0;NSM;;;;;N;;;;;
+1086;MYANMAR VOWEL SIGN SHAN FINAL Y;Mn;0;NSM;;;;;N;;;;;
+1087;MYANMAR SIGN SHAN TONE-2;Mc;0;L;;;;;N;;;;;
+1088;MYANMAR SIGN SHAN TONE-3;Mc;0;L;;;;;N;;;;;
+1089;MYANMAR SIGN SHAN TONE-5;Mc;0;L;;;;;N;;;;;
+108A;MYANMAR SIGN SHAN TONE-6;Mc;0;L;;;;;N;;;;;
+108B;MYANMAR SIGN SHAN COUNCIL TONE-2;Mc;0;L;;;;;N;;;;;
+108C;MYANMAR SIGN SHAN COUNCIL TONE-3;Mc;0;L;;;;;N;;;;;
+108D;MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE;Mn;220;NSM;;;;;N;;;;;
+108E;MYANMAR LETTER RUMAI PALAUNG FA;Lo;0;L;;;;;N;;;;;
+108F;MYANMAR SIGN RUMAI PALAUNG TONE-5;Mc;0;L;;;;;N;;;;;
+1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+109A;MYANMAR SIGN KHAMTI TONE-1;Mc;0;L;;;;;N;;;;;
+109B;MYANMAR SIGN KHAMTI TONE-3;Mc;0;L;;;;;N;;;;;
+109C;MYANMAR VOWEL SIGN AITON A;Mc;0;L;;;;;N;;;;;
+109D;MYANMAR VOWEL SIGN AITON AI;Mn;0;NSM;;;;;N;;;;;
+109E;MYANMAR SYMBOL SHAN ONE;So;0;L;;;;;N;;;;;
+109F;MYANMAR SYMBOL SHAN EXCLAMATION;So;0;L;;;;;N;;;;;
+10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;2D00;
+10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;2D01;
+10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;2D02;
+10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;2D03;
+10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;2D04;
+10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;2D05;
+10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;2D06;
+10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;2D07;
+10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;2D08;
+10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;2D09;
+10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;2D0A;
+10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;2D0B;
+10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;2D0C;
+10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;2D0D;
+10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;2D0E;
+10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;2D0F;
+10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;2D10;
+10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;2D11;
+10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;2D12;
+10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;2D13;
+10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;2D14;
+10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;2D15;
+10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;2D16;
+10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;2D17;
+10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;2D18;
+10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;2D19;
+10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;2D1A;
+10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;2D1B;
+10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;2D1C;
+10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;2D1D;
+10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;2D1E;
+10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;2D1F;
+10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;2D20;
+10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;2D21;
+10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;2D22;
+10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;2D23;
+10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;2D24;
+10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25;
+10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27;
+10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D;
+10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
+10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
+10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
+10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
+10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
+10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
+10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
+10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
+10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
+10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
+10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
+10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
+10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
+10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
+10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
+10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
+10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
+10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
+10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
+10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
+10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
+10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
+10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
+10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
+10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
+10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
+10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
+10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
+10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
+10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
+10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
+10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
+10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
+10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
+10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
+10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
+10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
+10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
+10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
+10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;;
+10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;;
+10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;;
+10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;;
+10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;
+10FD;GEORGIAN LETTER AEN;Lo;0;L;;;;;N;;;;;
+10FE;GEORGIAN LETTER HARD SIGN;Lo;0;L;;;;;N;;;;;
+10FF;GEORGIAN LETTER LABIAL SIGN;Lo;0;L;;;;;N;;;;;
+1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
+1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;;
+1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;;;;
+1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;;
+1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;;;;
+1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;;;;
+1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;;;;
+1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;;
+1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;;;;
+110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;;
+110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;;
+110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;;;;
+110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;;
+110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;;;;
+110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;;;;
+1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;;;;
+1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;;;;
+1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;;;;
+1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;;
+1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;
+111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;
+111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;;
+1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;
+1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;;
+112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;;
+112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;;
+112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;
+1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;;
+1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;;
+113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;
+113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;;
+113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;;
+113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;;
+1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;;
+1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;;
+1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;;
+1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;;
+114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;;
+114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;;
+114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;;
+114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;;
+114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;;
+1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;;
+1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;;
+1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+115A;HANGUL CHOSEONG KIYEOK-TIKEUT;Lo;0;L;;;;;N;;;;;
+115B;HANGUL CHOSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;
+115C;HANGUL CHOSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;;
+115D;HANGUL CHOSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;;
+115E;HANGUL CHOSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;
+115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
+1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;;
+1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;;
+1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;;
+1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;;
+1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;;
+1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;;
+1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;;
+1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;;
+116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;;
+116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;;
+116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;;
+116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;;
+116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;;
+116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;;
+1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;;
+1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;;
+1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;;
+1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;;
+1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;;
+1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;;
+1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;;
+1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;;
+1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;;
+1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;;
+117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;;
+117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;;
+117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;;
+117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;;
+117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;;
+117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;;
+1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;;
+1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;;
+1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;;
+1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;;
+1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;;
+1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;;
+1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;;
+1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;;
+1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;;
+1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;;
+118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;;
+118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;;
+118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;;
+118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;;
+118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;;
+118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;;
+1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;;
+1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;;
+1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;;
+1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;;
+1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;;
+1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;;
+1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;;
+1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;;
+1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;;
+1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;;
+119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;;
+119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;;
+119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;;
+119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;;
+119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;;
+119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;;
+11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;;
+11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;;
+11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;;
+11A3;HANGUL JUNGSEONG A-EU;Lo;0;L;;;;;N;;;;;
+11A4;HANGUL JUNGSEONG YA-U;Lo;0;L;;;;;N;;;;;
+11A5;HANGUL JUNGSEONG YEO-YA;Lo;0;L;;;;;N;;;;;
+11A6;HANGUL JUNGSEONG O-YA;Lo;0;L;;;;;N;;;;;
+11A7;HANGUL JUNGSEONG O-YAE;Lo;0;L;;;;;N;;;;;
+11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
+11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;
+11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;;;;
+11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;;;;
+11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;;;;
+11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;;;;
+11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;;;;
+11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;;
+11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;;
+11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;;
+11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;;
+11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;;;;
+11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;;
+11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;
+11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;;;;
+11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;;;;
+11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;;;;
+11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;;;;
+11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;;;;
+11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;;;;
+11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;;;;
+11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;;;;
+11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;;;;
+11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;;;;
+11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;;
+11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;
+11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;;
+11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;;
+11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;
+11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;
+11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;
+11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;;
+11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;;
+11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;;
+11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;;
+11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;;
+11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;
+11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;;
+11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;;
+11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;;
+11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;;
+11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+11FA;HANGUL JONGSEONG KIYEOK-NIEUN;Lo;0;L;;;;;N;;;;;
+11FB;HANGUL JONGSEONG KIYEOK-PIEUP;Lo;0;L;;;;;N;;;;;
+11FC;HANGUL JONGSEONG KIYEOK-CHIEUCH;Lo;0;L;;;;;N;;;;;
+11FD;HANGUL JONGSEONG KIYEOK-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11FE;HANGUL JONGSEONG KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;;
+11FF;HANGUL JONGSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;;
+1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;;
+1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;;
+1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;;
+1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;;
+1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;;
+120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;;
+120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;;
+1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;;
+1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;;
+1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;;
+1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;;
+1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;;
+1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;;
+1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;;
+1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;;
+1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;;
+121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;;
+121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;;
+1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;;
+1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;;
+1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;;
+1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;;
+1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;;
+1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;;
+1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;;
+1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;;
+1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;;
+122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;;
+122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;;
+122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;;
+1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;;
+1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;;
+1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;;
+1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;;
+123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;;
+123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;
+123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;;
+1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;;
+1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;;
+1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;;
+1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;;
+1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;;
+1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;;
+124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;;
+124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;;
+124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;;
+124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;;
+1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;;
+1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;;
+1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;;
+1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;;
+1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;;
+1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;;
+1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;;
+1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;;
+125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;;
+125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;;
+125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;;
+125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;;
+1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;;
+1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;;
+1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;;
+1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;;
+126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;;
+126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;;
+126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;;
+1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;;
+1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;;
+1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;;
+1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;;
+127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;;
+127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;;
+1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;;
+1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;;
+1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;;
+1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;;
+1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;;
+1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;;
+1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;;
+128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;;
+128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;;
+128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;;
+128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;;
+1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;;
+1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;;
+1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;;
+1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;;
+1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;;
+129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;
+129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;;
+129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;;
+12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;;
+12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;;
+12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;;
+12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;;
+12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;;
+12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;;
+12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;;
+12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;;
+12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;;
+12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;;
+12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;;
+12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;;
+12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;;
+12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;;
+12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;;
+12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;;
+12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;;
+12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;;
+12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;;
+12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;;
+12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;;
+12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;;
+12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;;
+12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;;
+12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;;
+12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;;
+12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;;
+12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;;
+12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;;
+12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;;
+12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;;
+12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;;
+12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;;
+12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;;
+12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;;
+12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;;
+12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;;
+12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;;
+12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;;
+12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;;
+12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;
+12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;;
+12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;
+12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;;
+12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;
+12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;;
+12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;;
+12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;;
+12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;;
+12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;;
+12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;;
+12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;;
+12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;;
+12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;;
+12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;;
+12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;;
+12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;;
+1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;;
+1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;;
+1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;;
+1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;;
+1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;;
+1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;;
+130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;;
+130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;;
+1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;;
+1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;;
+1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;;
+1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;;
+1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;;
+1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;;
+131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;;
+131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;;
+1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;;
+1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;;
+1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;;
+1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;;
+1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;;
+1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;;
+1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;;
+1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;;
+1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;;
+132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;;
+132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;;
+132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;;
+1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;;
+1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;;
+1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;;
+1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;;
+1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;;
+1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;;
+1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;;
+1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;;
+1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;;
+1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;;
+133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;;
+133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;;
+133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;;
+133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;;
+133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;;
+133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;;
+1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;;
+1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;;
+1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;;
+1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;;
+1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;;
+1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;;
+1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;;
+1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;;
+1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;;
+134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;;
+134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;;
+134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;;
+1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;;
+1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;;
+1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;;
+1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;;
+1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;;
+1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;;
+135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;;
+135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;;
+135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;;
+135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;
+1360;ETHIOPIC SECTION MARK;Po;0;L;;;;;N;;;;;
+1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;;
+1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;;
+1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;;
+1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;;
+1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;;
+1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;;
+1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;;
+1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;;
+136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;;
+136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;;
+136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;;
+136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;;
+136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;;
+136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;;
+1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;;
+1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;;
+1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;;
+1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;;
+1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;;
+137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;;
+137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;;
+1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;;
+1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;;
+1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;;
+1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;;
+1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;;
+1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;;
+1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;;
+1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;;
+1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;;
+138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;;
+138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;;
+138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;;
+138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;;
+138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;;
+138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;;
+1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;;
+1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;;
+1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;;
+1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;;
+1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;;
+1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;;
+1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;;
+1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;;
+1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;;
+1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;;
+13A0;CHEROKEE LETTER A;Lu;0;L;;;;;N;;;;AB70;
+13A1;CHEROKEE LETTER E;Lu;0;L;;;;;N;;;;AB71;
+13A2;CHEROKEE LETTER I;Lu;0;L;;;;;N;;;;AB72;
+13A3;CHEROKEE LETTER O;Lu;0;L;;;;;N;;;;AB73;
+13A4;CHEROKEE LETTER U;Lu;0;L;;;;;N;;;;AB74;
+13A5;CHEROKEE LETTER V;Lu;0;L;;;;;N;;;;AB75;
+13A6;CHEROKEE LETTER GA;Lu;0;L;;;;;N;;;;AB76;
+13A7;CHEROKEE LETTER KA;Lu;0;L;;;;;N;;;;AB77;
+13A8;CHEROKEE LETTER GE;Lu;0;L;;;;;N;;;;AB78;
+13A9;CHEROKEE LETTER GI;Lu;0;L;;;;;N;;;;AB79;
+13AA;CHEROKEE LETTER GO;Lu;0;L;;;;;N;;;;AB7A;
+13AB;CHEROKEE LETTER GU;Lu;0;L;;;;;N;;;;AB7B;
+13AC;CHEROKEE LETTER GV;Lu;0;L;;;;;N;;;;AB7C;
+13AD;CHEROKEE LETTER HA;Lu;0;L;;;;;N;;;;AB7D;
+13AE;CHEROKEE LETTER HE;Lu;0;L;;;;;N;;;;AB7E;
+13AF;CHEROKEE LETTER HI;Lu;0;L;;;;;N;;;;AB7F;
+13B0;CHEROKEE LETTER HO;Lu;0;L;;;;;N;;;;AB80;
+13B1;CHEROKEE LETTER HU;Lu;0;L;;;;;N;;;;AB81;
+13B2;CHEROKEE LETTER HV;Lu;0;L;;;;;N;;;;AB82;
+13B3;CHEROKEE LETTER LA;Lu;0;L;;;;;N;;;;AB83;
+13B4;CHEROKEE LETTER LE;Lu;0;L;;;;;N;;;;AB84;
+13B5;CHEROKEE LETTER LI;Lu;0;L;;;;;N;;;;AB85;
+13B6;CHEROKEE LETTER LO;Lu;0;L;;;;;N;;;;AB86;
+13B7;CHEROKEE LETTER LU;Lu;0;L;;;;;N;;;;AB87;
+13B8;CHEROKEE LETTER LV;Lu;0;L;;;;;N;;;;AB88;
+13B9;CHEROKEE LETTER MA;Lu;0;L;;;;;N;;;;AB89;
+13BA;CHEROKEE LETTER ME;Lu;0;L;;;;;N;;;;AB8A;
+13BB;CHEROKEE LETTER MI;Lu;0;L;;;;;N;;;;AB8B;
+13BC;CHEROKEE LETTER MO;Lu;0;L;;;;;N;;;;AB8C;
+13BD;CHEROKEE LETTER MU;Lu;0;L;;;;;N;;;;AB8D;
+13BE;CHEROKEE LETTER NA;Lu;0;L;;;;;N;;;;AB8E;
+13BF;CHEROKEE LETTER HNA;Lu;0;L;;;;;N;;;;AB8F;
+13C0;CHEROKEE LETTER NAH;Lu;0;L;;;;;N;;;;AB90;
+13C1;CHEROKEE LETTER NE;Lu;0;L;;;;;N;;;;AB91;
+13C2;CHEROKEE LETTER NI;Lu;0;L;;;;;N;;;;AB92;
+13C3;CHEROKEE LETTER NO;Lu;0;L;;;;;N;;;;AB93;
+13C4;CHEROKEE LETTER NU;Lu;0;L;;;;;N;;;;AB94;
+13C5;CHEROKEE LETTER NV;Lu;0;L;;;;;N;;;;AB95;
+13C6;CHEROKEE LETTER QUA;Lu;0;L;;;;;N;;;;AB96;
+13C7;CHEROKEE LETTER QUE;Lu;0;L;;;;;N;;;;AB97;
+13C8;CHEROKEE LETTER QUI;Lu;0;L;;;;;N;;;;AB98;
+13C9;CHEROKEE LETTER QUO;Lu;0;L;;;;;N;;;;AB99;
+13CA;CHEROKEE LETTER QUU;Lu;0;L;;;;;N;;;;AB9A;
+13CB;CHEROKEE LETTER QUV;Lu;0;L;;;;;N;;;;AB9B;
+13CC;CHEROKEE LETTER SA;Lu;0;L;;;;;N;;;;AB9C;
+13CD;CHEROKEE LETTER S;Lu;0;L;;;;;N;;;;AB9D;
+13CE;CHEROKEE LETTER SE;Lu;0;L;;;;;N;;;;AB9E;
+13CF;CHEROKEE LETTER SI;Lu;0;L;;;;;N;;;;AB9F;
+13D0;CHEROKEE LETTER SO;Lu;0;L;;;;;N;;;;ABA0;
+13D1;CHEROKEE LETTER SU;Lu;0;L;;;;;N;;;;ABA1;
+13D2;CHEROKEE LETTER SV;Lu;0;L;;;;;N;;;;ABA2;
+13D3;CHEROKEE LETTER DA;Lu;0;L;;;;;N;;;;ABA3;
+13D4;CHEROKEE LETTER TA;Lu;0;L;;;;;N;;;;ABA4;
+13D5;CHEROKEE LETTER DE;Lu;0;L;;;;;N;;;;ABA5;
+13D6;CHEROKEE LETTER TE;Lu;0;L;;;;;N;;;;ABA6;
+13D7;CHEROKEE LETTER DI;Lu;0;L;;;;;N;;;;ABA7;
+13D8;CHEROKEE LETTER TI;Lu;0;L;;;;;N;;;;ABA8;
+13D9;CHEROKEE LETTER DO;Lu;0;L;;;;;N;;;;ABA9;
+13DA;CHEROKEE LETTER DU;Lu;0;L;;;;;N;;;;ABAA;
+13DB;CHEROKEE LETTER DV;Lu;0;L;;;;;N;;;;ABAB;
+13DC;CHEROKEE LETTER DLA;Lu;0;L;;;;;N;;;;ABAC;
+13DD;CHEROKEE LETTER TLA;Lu;0;L;;;;;N;;;;ABAD;
+13DE;CHEROKEE LETTER TLE;Lu;0;L;;;;;N;;;;ABAE;
+13DF;CHEROKEE LETTER TLI;Lu;0;L;;;;;N;;;;ABAF;
+13E0;CHEROKEE LETTER TLO;Lu;0;L;;;;;N;;;;ABB0;
+13E1;CHEROKEE LETTER TLU;Lu;0;L;;;;;N;;;;ABB1;
+13E2;CHEROKEE LETTER TLV;Lu;0;L;;;;;N;;;;ABB2;
+13E3;CHEROKEE LETTER TSA;Lu;0;L;;;;;N;;;;ABB3;
+13E4;CHEROKEE LETTER TSE;Lu;0;L;;;;;N;;;;ABB4;
+13E5;CHEROKEE LETTER TSI;Lu;0;L;;;;;N;;;;ABB5;
+13E6;CHEROKEE LETTER TSO;Lu;0;L;;;;;N;;;;ABB6;
+13E7;CHEROKEE LETTER TSU;Lu;0;L;;;;;N;;;;ABB7;
+13E8;CHEROKEE LETTER TSV;Lu;0;L;;;;;N;;;;ABB8;
+13E9;CHEROKEE LETTER WA;Lu;0;L;;;;;N;;;;ABB9;
+13EA;CHEROKEE LETTER WE;Lu;0;L;;;;;N;;;;ABBA;
+13EB;CHEROKEE LETTER WI;Lu;0;L;;;;;N;;;;ABBB;
+13EC;CHEROKEE LETTER WO;Lu;0;L;;;;;N;;;;ABBC;
+13ED;CHEROKEE LETTER WU;Lu;0;L;;;;;N;;;;ABBD;
+13EE;CHEROKEE LETTER WV;Lu;0;L;;;;;N;;;;ABBE;
+13EF;CHEROKEE LETTER YA;Lu;0;L;;;;;N;;;;ABBF;
+13F0;CHEROKEE LETTER YE;Lu;0;L;;;;;N;;;;13F8;
+13F1;CHEROKEE LETTER YI;Lu;0;L;;;;;N;;;;13F9;
+13F2;CHEROKEE LETTER YO;Lu;0;L;;;;;N;;;;13FA;
+13F3;CHEROKEE LETTER YU;Lu;0;L;;;;;N;;;;13FB;
+13F4;CHEROKEE LETTER YV;Lu;0;L;;;;;N;;;;13FC;
+13F5;CHEROKEE LETTER MV;Lu;0;L;;;;;N;;;;13FD;
+13F8;CHEROKEE SMALL LETTER YE;Ll;0;L;;;;;N;;;13F0;;13F0
+13F9;CHEROKEE SMALL LETTER YI;Ll;0;L;;;;;N;;;13F1;;13F1
+13FA;CHEROKEE SMALL LETTER YO;Ll;0;L;;;;;N;;;13F2;;13F2
+13FB;CHEROKEE SMALL LETTER YU;Ll;0;L;;;;;N;;;13F3;;13F3
+13FC;CHEROKEE SMALL LETTER YV;Ll;0;L;;;;;N;;;13F4;;13F4
+13FD;CHEROKEE SMALL LETTER MV;Ll;0;L;;;;;N;;;13F5;;13F5
+1400;CANADIAN SYLLABICS HYPHEN;Pd;0;ON;;;;;N;;;;;
+1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;;
+1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;;
+1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;;
+1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;;
+1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;;
+1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;;
+1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;;
+1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;;
+1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;;
+140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;;
+140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;;
+140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;;
+140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;;
+140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;;
+140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;;
+1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;;
+1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;;
+1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;;
+1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;;
+1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;;
+1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;;
+1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;;
+1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;;
+1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;;
+1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;;
+141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;;
+141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;;
+141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;;
+141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;;
+141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;;
+1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;;
+1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;;
+1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;;
+1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;;
+1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;;
+1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;;
+1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;;
+1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;;
+1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;;
+1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;;
+142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;;
+142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;;
+142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;;
+142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;;
+142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;;
+142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;;
+1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;;
+1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;;
+1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;;
+1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;;
+1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;;
+1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;;
+1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;;
+1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;;
+1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;;
+1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;;
+143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;;
+143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;;
+143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;;
+143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;;
+143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;;
+143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;;
+1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;;
+1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;;
+1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;;
+1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;;
+1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;;
+1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;;
+1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;;
+1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;;
+144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;;
+144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;;
+144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;;
+144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;;
+144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;;
+144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;;
+1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;;
+1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;;
+1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;;
+1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;;
+1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;;
+1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;;
+1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;;
+1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;;
+1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;;
+1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;;
+145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;;
+145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;;
+145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;;
+145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;;
+145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;;
+145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;;
+1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;;
+1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;;
+1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;;
+1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;;
+1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;;
+1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;;
+1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;;
+1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;;
+1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;;
+1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;;
+146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;;
+146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;;
+146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;;
+146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;;
+146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;;
+146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;;
+1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;;
+1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;;
+1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;;
+1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;;
+1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;;
+1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;;
+1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;;
+1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;;
+1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;;
+1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;;
+147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;;
+147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;;
+147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;;
+147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;;
+147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;;
+147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;;
+1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;;
+1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;;
+1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;;
+1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;;
+1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;;
+1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;;
+1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;;
+1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;;
+1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;;
+1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;;
+148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;;
+148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;;
+148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;;
+148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;;
+148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;;
+148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;;
+1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;;
+1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;;
+1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;;
+1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;;
+1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;;
+1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;;
+1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;;
+1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;;
+1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;;
+1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;;
+149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;;
+149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;;
+149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;;
+149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;;
+149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;;
+149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;;
+14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;;
+14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;;
+14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;;
+14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;;
+14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;;
+14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;;
+14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;;
+14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;;
+14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;;
+14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;;
+14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;;
+14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;;
+14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;;
+14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;;
+14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;;
+14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;;
+14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;;
+14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;;
+14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;;
+14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;;
+14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;;
+14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;;
+14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;;
+14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;;
+14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;;
+14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;;
+14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;;
+14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;;
+14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;;
+14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;;
+14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;;
+14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;;
+14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;;
+14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;;
+14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;;
+14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;;
+14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;;
+14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;;
+14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;;
+14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;;
+14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;;
+14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;;
+14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;;
+14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;;
+14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;;
+14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;;
+14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;;
+14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;;
+14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;;
+14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;;
+14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;;
+14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;;
+14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;;
+14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;;
+14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;;
+14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;;
+14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;;
+14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;;
+14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;;
+14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;;
+14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;;
+14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;;
+14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;;
+14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;;
+14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;;
+14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;;
+14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;;
+14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;;
+14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;;
+14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;;
+14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;;
+14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;;
+14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;;
+14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;;
+14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;;
+14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;;
+14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;;
+14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;;
+14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;;
+14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;;
+14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;;
+14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;;
+14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;;
+14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;;
+14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;;
+14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;;
+14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;;
+14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;;
+14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;;
+14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;;
+14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;;
+14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;;
+14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;;
+14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;;
+14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;;
+14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;;
+1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;;
+1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;;
+1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;;
+1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;;
+1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;;
+1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;;
+1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;;
+1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;;
+1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;;
+1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;;
+150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;;
+150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;;
+150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;;
+150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;;
+150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;;
+150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;;
+1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;;
+1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;;
+1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;;
+1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;;
+1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;;
+1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;;
+1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;;
+1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;;
+1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;;
+1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;;
+151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;;
+151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;;
+151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;;
+151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;;
+151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;;
+151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;;
+1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;;
+1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;;
+1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;;
+1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;;
+1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;;
+1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;;
+1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;;
+1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;;
+1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;;
+1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;;
+152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;;
+152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;;
+152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;;
+152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;;
+152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;;
+152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;;
+1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;;
+1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;;
+1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;;
+1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;;
+1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;;
+1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;;
+1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;;
+1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;;
+1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;;
+1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;;
+153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;;
+153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;;
+153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;;
+153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;;
+153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;;
+153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;;
+1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;;
+1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;;
+1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;;
+1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;;
+1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;;
+1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;;
+1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;;
+1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;;
+1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;;
+1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;;
+154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;;
+154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;;
+154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;;
+154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;;
+154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;;
+154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;;
+1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;;
+1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;;
+1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;;
+1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;;
+1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;;
+1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;;
+1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;;
+1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;;
+1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;;
+1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;;
+155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;;
+155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;;
+155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;;
+155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;;
+155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;;
+155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;;
+1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;;
+1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;;
+1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;;
+1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;;
+1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;;
+1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;;
+1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;;
+1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;;
+1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;;
+1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;;
+156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;;
+156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;;
+156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;;
+156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;;
+156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;;
+156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;;
+1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;;
+1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;;
+1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;;
+1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;;
+1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;;
+1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;;
+1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;;
+1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;;
+1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;;
+1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;;
+157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;;
+157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;;
+157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;;
+157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;;
+157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;;
+157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;;
+1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;;
+1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;;
+1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;;
+1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;;
+1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;;
+1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;;
+1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;;
+1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;;
+1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;;
+1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;;
+158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;;
+158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;;
+158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;;
+158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;;
+158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;;
+158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;;
+1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;;
+1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;;
+1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;;
+1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;;
+1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;;
+1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;;
+1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;;
+1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;;
+1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;;
+1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;;
+159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;;
+159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;;
+159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;;
+159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;;
+159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;;
+159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;;
+15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;;
+15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;;
+15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;;
+15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;;
+15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;;
+15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;;
+15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;;
+15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;;
+15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;;
+15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;;
+15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;;
+15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;;
+15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;;
+15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;;
+15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;;
+15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;;
+15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;;
+15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;;
+15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;;
+15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;;
+15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;;
+15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;;
+15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;;
+15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;;
+15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;;
+15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;;
+15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;;
+15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;;
+15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;;
+15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;;
+15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;;
+15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;;
+15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;;
+15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;;
+15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;;
+15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;;
+15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;;
+15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;;
+15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;;
+15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;;
+15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;;
+15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;;
+15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;;
+15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;;
+15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;;
+15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;;
+15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;;
+15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;;
+15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;;
+15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;;
+15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;;
+15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;;
+15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;;
+15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;;
+15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;;
+15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;;
+15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;;
+15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;;
+15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;;
+15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;;
+15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;;
+15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;;
+15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;;
+15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;;
+15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;;
+15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;;
+15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;;
+15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;;
+15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;;
+15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;;
+15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;;
+15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;;
+15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;;
+15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;;
+15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;;
+15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;;
+15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;;
+15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;;
+15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;;
+15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;;
+15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;;
+15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;;
+15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;;
+15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;;
+15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;;
+15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;;
+15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;;
+15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;;
+15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;;
+15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;;
+15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;;
+15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;;
+15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;;
+15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;;
+15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;;
+15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;;
+1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;;
+1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;;
+1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;;
+1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;;
+1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;;
+1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;;
+1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;;
+1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;;
+1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;;
+1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;;
+160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;;
+160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;;
+160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;;
+160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;;
+160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;;
+160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;;
+1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;;
+1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;;
+1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;;
+1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;;
+1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;;
+1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;;
+1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;;
+1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;;
+1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;;
+1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;;
+161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;;
+161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;;
+161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;;
+161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;;
+161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;;
+161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;;
+1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;;
+1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;;
+1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;;
+1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;;
+1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;;
+1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;;
+1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;;
+1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;;
+1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;;
+1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;;
+162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;;
+162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;;
+162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;;
+162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;;
+162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;;
+162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;;
+1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;;
+1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;;
+1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;;
+1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;;
+1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;;
+1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;;
+1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;;
+1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;;
+1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;;
+1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;;
+163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;;
+163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;;
+163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;;
+163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;;
+163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;;
+163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;;
+1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;;
+1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;;
+1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;;
+1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;;
+1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;;
+1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;;
+1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;;
+1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;;
+1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;;
+1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;;
+164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;;
+164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;;
+164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;;
+164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;;
+164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;;
+164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;;
+1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;;
+1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;;
+1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;;
+1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;;
+1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;;
+1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;;
+1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;;
+1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;;
+1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;;
+1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;;
+165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;;
+165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;;
+165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;;
+165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;;
+165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;;
+165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;;
+1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;;
+1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;;
+1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;;
+1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;;
+1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;;
+1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;;
+1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;;
+1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;;
+1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;;
+1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;;
+166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;;
+166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;;
+166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;;
+166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;;
+166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;;
+166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;;
+1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;;
+1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;;
+1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;;
+1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;;
+1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;;
+1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;;
+1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;;
+1677;CANADIAN SYLLABICS WOODS-CREE THWEE;Lo;0;L;;;;;N;;;;;
+1678;CANADIAN SYLLABICS WOODS-CREE THWI;Lo;0;L;;;;;N;;;;;
+1679;CANADIAN SYLLABICS WOODS-CREE THWII;Lo;0;L;;;;;N;;;;;
+167A;CANADIAN SYLLABICS WOODS-CREE THWO;Lo;0;L;;;;;N;;;;;
+167B;CANADIAN SYLLABICS WOODS-CREE THWOO;Lo;0;L;;;;;N;;;;;
+167C;CANADIAN SYLLABICS WOODS-CREE THWA;Lo;0;L;;;;;N;;;;;
+167D;CANADIAN SYLLABICS WOODS-CREE THWAA;Lo;0;L;;;;;N;;;;;
+167E;CANADIAN SYLLABICS WOODS-CREE FINAL TH;Lo;0;L;;;;;N;;;;;
+167F;CANADIAN SYLLABICS BLACKFOOT W;Lo;0;L;;;;;N;;;;;
+1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
+1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;;
+1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;;
+1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;;
+1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;;
+1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;;
+1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;;
+1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;;
+1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;;
+1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;;
+168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;;
+168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;;
+168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;;
+168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;;
+168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;;
+168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;;
+1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;;
+1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;;
+1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;;
+1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;;
+1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;;
+1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;;
+1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;;
+1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;;
+1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;;
+1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;;
+169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;;
+169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;Y;;;;;
+169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;Y;;;;;
+16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;;
+16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;;
+16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;;
+16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;;
+16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;;
+16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;;
+16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;;
+16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;;
+16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;;
+16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;;
+16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;;
+16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;;
+16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;;
+16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;;
+16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;;
+16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;;
+16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;;
+16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;;
+16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;;
+16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;;
+16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;;
+16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;;
+16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;;
+16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;;
+16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;;
+16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;;
+16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;;
+16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;;
+16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;;
+16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;;
+16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;;
+16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;;
+16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;;
+16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;;
+16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;;
+16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;;
+16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;;
+16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;;
+16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;;
+16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;;
+16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;;
+16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;;
+16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;;
+16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;;
+16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;;
+16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;;
+16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;;
+16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;;
+16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;;
+16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;;
+16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;;
+16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;;
+16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;;
+16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;;
+16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;;
+16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;;
+16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;;
+16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;;
+16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;;
+16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;;
+16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;;
+16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;;
+16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;;
+16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;;
+16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;;
+16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;;
+16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;;
+16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;;
+16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;;
+16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;;
+16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;;
+16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;;;;
+16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;;;;
+16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;;;;
+16F1;RUNIC LETTER K;Lo;0;L;;;;;N;;;;;
+16F2;RUNIC LETTER SH;Lo;0;L;;;;;N;;;;;
+16F3;RUNIC LETTER OO;Lo;0;L;;;;;N;;;;;
+16F4;RUNIC LETTER FRANKS CASKET OS;Lo;0;L;;;;;N;;;;;
+16F5;RUNIC LETTER FRANKS CASKET IS;Lo;0;L;;;;;N;;;;;
+16F6;RUNIC LETTER FRANKS CASKET EH;Lo;0;L;;;;;N;;;;;
+16F7;RUNIC LETTER FRANKS CASKET AC;Lo;0;L;;;;;N;;;;;
+16F8;RUNIC LETTER FRANKS CASKET AESC;Lo;0;L;;;;;N;;;;;
+1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;;
+1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;;
+1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;;
+1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;;
+1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;;
+1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;;
+1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;;
+1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;;
+1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;;
+1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;;
+170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;;
+170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;;
+170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;;
+170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;;
+170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;;
+1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;;
+1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;;
+1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;;
+1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;;
+1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;;
+1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;;
+1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;;
+1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;;
+1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;;
+1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;;
+1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;;
+1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;;
+172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;;
+172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;;
+172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;;
+172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;;
+172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;;
+172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;;
+1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;;
+1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;;
+1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;;
+1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;;
+1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;;
+1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;;
+1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;;
+1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;;
+1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;;
+1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;;
+1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;;
+1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;;
+1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;;
+174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;;
+174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;;
+174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;;
+174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;;
+174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;;
+174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;;
+1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;;
+1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;;
+1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;;
+1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;;
+1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;;
+1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;;
+1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;;
+1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;;
+1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;;
+1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;;
+1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;;
+176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;;
+176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;;
+176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;;
+176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;;
+176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;;
+1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;;
+1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;;
+1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;;
+1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;;
+1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;;
+1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;;
+1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;;
+1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;;
+1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;;
+1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;;
+1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;;
+178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;;
+178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;;
+178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;;
+178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;;
+178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;;
+178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;;
+1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;;
+1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;;
+1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;;
+1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;;
+1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;;
+1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;;
+1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;;
+1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;;
+1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;;
+1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;;
+179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;;
+179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;;
+179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;;
+179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;;
+179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;;
+179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;;
+17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;;
+17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;;
+17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;;
+17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;;
+17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;;
+17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;;
+17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;;
+17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;;
+17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;;
+17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;;
+17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;;
+17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;;
+17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;;
+17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;;
+17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;;
+17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;;
+17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;;
+17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;;
+17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;;
+17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;;
+17B4;KHMER VOWEL INHERENT AQ;Mn;0;NSM;;;;;N;;;;;
+17B5;KHMER VOWEL INHERENT AA;Mn;0;NSM;;;;;N;;;;;
+17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;;
+17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;;
+17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;;
+17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;
+17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;;
+17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;;
+17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;;
+17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;;
+17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;;
+17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;;
+17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;;
+17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;;
+17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;;
+17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;;
+17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;;
+17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;;
+17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;;
+17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;;
+17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;;
+17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;;
+17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;;
+17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;;
+17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;;
+17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;;
+17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;;
+17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;;
+17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;;
+17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;;
+17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;;
+17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;;
+17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;;
+17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;;
+17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;;
+17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;;
+17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;;
+17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;;
+17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;;
+17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;;
+1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;;
+1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;;
+1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;;
+1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;;
+1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;;
+1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;
+1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;;
+1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;;
+1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;;
+180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;;
+180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;;
+180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;;
+180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;;
+180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;;
+1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;;
+1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;;
+1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;;
+1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;;
+1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;;
+1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;;
+1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;;
+1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;;
+1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;;
+1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;;
+182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;;
+182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;;
+182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;;
+182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;;
+182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;;
+182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;;
+1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;;
+1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;;
+1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;;
+1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;;
+1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;;
+1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;;
+1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;;
+1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;;
+183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;;
+183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;;
+183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;;
+1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;;
+1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;;
+1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;;
+1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;;
+1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;;
+1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;;
+1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;;
+1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;;
+1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;;
+1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;;
+184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;;
+184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;;
+184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;;
+184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;;
+184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;;
+184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;;
+1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;;
+1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;;
+1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;;
+1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;;
+1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;;
+1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;;
+1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;;
+1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;;
+1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;;
+1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;;
+185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;;
+185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;;
+185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;;
+185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;;
+185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;;
+185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;;
+1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;;
+1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;;
+1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;;
+1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;;
+1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;;
+1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;;
+1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;;
+1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;;
+1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;;
+1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;;
+186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;;
+186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;;
+186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;;
+186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;;
+186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;;
+186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;;
+1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;;
+1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;;
+1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;;
+1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;;
+1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;;
+1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
+1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
+1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
+1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
+1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
+1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;;
+1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;;
+1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;;
+1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;;
+1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;;
+1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;;
+1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;;
+188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;;
+188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;;
+188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;;
+188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;;
+1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;;
+1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;;
+1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;;
+1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;;
+1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;;
+189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;;
+189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;;
+189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;;
+18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;;
+18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;;
+18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;;
+18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;;
+18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;;
+18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;;
+18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;;
+18AA;MONGOLIAN LETTER MANCHU ALI GALI LHA;Lo;0;L;;;;;N;;;;;
+18B0;CANADIAN SYLLABICS OY;Lo;0;L;;;;;N;;;;;
+18B1;CANADIAN SYLLABICS AY;Lo;0;L;;;;;N;;;;;
+18B2;CANADIAN SYLLABICS AAY;Lo;0;L;;;;;N;;;;;
+18B3;CANADIAN SYLLABICS WAY;Lo;0;L;;;;;N;;;;;
+18B4;CANADIAN SYLLABICS POY;Lo;0;L;;;;;N;;;;;
+18B5;CANADIAN SYLLABICS PAY;Lo;0;L;;;;;N;;;;;
+18B6;CANADIAN SYLLABICS PWOY;Lo;0;L;;;;;N;;;;;
+18B7;CANADIAN SYLLABICS TAY;Lo;0;L;;;;;N;;;;;
+18B8;CANADIAN SYLLABICS KAY;Lo;0;L;;;;;N;;;;;
+18B9;CANADIAN SYLLABICS KWAY;Lo;0;L;;;;;N;;;;;
+18BA;CANADIAN SYLLABICS MAY;Lo;0;L;;;;;N;;;;;
+18BB;CANADIAN SYLLABICS NOY;Lo;0;L;;;;;N;;;;;
+18BC;CANADIAN SYLLABICS NAY;Lo;0;L;;;;;N;;;;;
+18BD;CANADIAN SYLLABICS LAY;Lo;0;L;;;;;N;;;;;
+18BE;CANADIAN SYLLABICS SOY;Lo;0;L;;;;;N;;;;;
+18BF;CANADIAN SYLLABICS SAY;Lo;0;L;;;;;N;;;;;
+18C0;CANADIAN SYLLABICS SHOY;Lo;0;L;;;;;N;;;;;
+18C1;CANADIAN SYLLABICS SHAY;Lo;0;L;;;;;N;;;;;
+18C2;CANADIAN SYLLABICS SHWOY;Lo;0;L;;;;;N;;;;;
+18C3;CANADIAN SYLLABICS YOY;Lo;0;L;;;;;N;;;;;
+18C4;CANADIAN SYLLABICS YAY;Lo;0;L;;;;;N;;;;;
+18C5;CANADIAN SYLLABICS RAY;Lo;0;L;;;;;N;;;;;
+18C6;CANADIAN SYLLABICS NWI;Lo;0;L;;;;;N;;;;;
+18C7;CANADIAN SYLLABICS OJIBWAY NWI;Lo;0;L;;;;;N;;;;;
+18C8;CANADIAN SYLLABICS NWII;Lo;0;L;;;;;N;;;;;
+18C9;CANADIAN SYLLABICS OJIBWAY NWII;Lo;0;L;;;;;N;;;;;
+18CA;CANADIAN SYLLABICS NWO;Lo;0;L;;;;;N;;;;;
+18CB;CANADIAN SYLLABICS OJIBWAY NWO;Lo;0;L;;;;;N;;;;;
+18CC;CANADIAN SYLLABICS NWOO;Lo;0;L;;;;;N;;;;;
+18CD;CANADIAN SYLLABICS OJIBWAY NWOO;Lo;0;L;;;;;N;;;;;
+18CE;CANADIAN SYLLABICS RWEE;Lo;0;L;;;;;N;;;;;
+18CF;CANADIAN SYLLABICS RWI;Lo;0;L;;;;;N;;;;;
+18D0;CANADIAN SYLLABICS RWII;Lo;0;L;;;;;N;;;;;
+18D1;CANADIAN SYLLABICS RWO;Lo;0;L;;;;;N;;;;;
+18D2;CANADIAN SYLLABICS RWOO;Lo;0;L;;;;;N;;;;;
+18D3;CANADIAN SYLLABICS RWA;Lo;0;L;;;;;N;;;;;
+18D4;CANADIAN SYLLABICS OJIBWAY P;Lo;0;L;;;;;N;;;;;
+18D5;CANADIAN SYLLABICS OJIBWAY T;Lo;0;L;;;;;N;;;;;
+18D6;CANADIAN SYLLABICS OJIBWAY K;Lo;0;L;;;;;N;;;;;
+18D7;CANADIAN SYLLABICS OJIBWAY C;Lo;0;L;;;;;N;;;;;
+18D8;CANADIAN SYLLABICS OJIBWAY M;Lo;0;L;;;;;N;;;;;
+18D9;CANADIAN SYLLABICS OJIBWAY N;Lo;0;L;;;;;N;;;;;
+18DA;CANADIAN SYLLABICS OJIBWAY S;Lo;0;L;;;;;N;;;;;
+18DB;CANADIAN SYLLABICS OJIBWAY SH;Lo;0;L;;;;;N;;;;;
+18DC;CANADIAN SYLLABICS EASTERN W;Lo;0;L;;;;;N;;;;;
+18DD;CANADIAN SYLLABICS WESTERN W;Lo;0;L;;;;;N;;;;;
+18DE;CANADIAN SYLLABICS FINAL SMALL RING;Lo;0;L;;;;;N;;;;;
+18DF;CANADIAN SYLLABICS FINAL RAISED DOT;Lo;0;L;;;;;N;;;;;
+18E0;CANADIAN SYLLABICS R-CREE RWE;Lo;0;L;;;;;N;;;;;
+18E1;CANADIAN SYLLABICS WEST-CREE LOO;Lo;0;L;;;;;N;;;;;
+18E2;CANADIAN SYLLABICS WEST-CREE LAA;Lo;0;L;;;;;N;;;;;
+18E3;CANADIAN SYLLABICS THWE;Lo;0;L;;;;;N;;;;;
+18E4;CANADIAN SYLLABICS THWA;Lo;0;L;;;;;N;;;;;
+18E5;CANADIAN SYLLABICS TTHWE;Lo;0;L;;;;;N;;;;;
+18E6;CANADIAN SYLLABICS TTHOO;Lo;0;L;;;;;N;;;;;
+18E7;CANADIAN SYLLABICS TTHAA;Lo;0;L;;;;;N;;;;;
+18E8;CANADIAN SYLLABICS TLHWE;Lo;0;L;;;;;N;;;;;
+18E9;CANADIAN SYLLABICS TLHOO;Lo;0;L;;;;;N;;;;;
+18EA;CANADIAN SYLLABICS SAYISI SHWE;Lo;0;L;;;;;N;;;;;
+18EB;CANADIAN SYLLABICS SAYISI SHOO;Lo;0;L;;;;;N;;;;;
+18EC;CANADIAN SYLLABICS SAYISI HOO;Lo;0;L;;;;;N;;;;;
+18ED;CANADIAN SYLLABICS CARRIER GWU;Lo;0;L;;;;;N;;;;;
+18EE;CANADIAN SYLLABICS CARRIER DENE GEE;Lo;0;L;;;;;N;;;;;
+18EF;CANADIAN SYLLABICS CARRIER GAA;Lo;0;L;;;;;N;;;;;
+18F0;CANADIAN SYLLABICS CARRIER GWA;Lo;0;L;;;;;N;;;;;
+18F1;CANADIAN SYLLABICS SAYISI JUU;Lo;0;L;;;;;N;;;;;
+18F2;CANADIAN SYLLABICS CARRIER JWA;Lo;0;L;;;;;N;;;;;
+18F3;CANADIAN SYLLABICS BEAVER DENE L;Lo;0;L;;;;;N;;;;;
+18F4;CANADIAN SYLLABICS BEAVER DENE R;Lo;0;L;;;;;N;;;;;
+18F5;CANADIAN SYLLABICS CARRIER DENTAL S;Lo;0;L;;;;;N;;;;;
+1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;;
+1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;;
+1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;;
+1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;;
+1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;;
+1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;;
+1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;;
+1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;;
+1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;;
+1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;;
+190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;;
+190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;;
+190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;;
+190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;;
+190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;;
+190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;;
+1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;;
+1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;;
+1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;;
+1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;;
+1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;;
+1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;;
+1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;;
+1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;;
+1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;;
+1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;;
+191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;;
+191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;;
+191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;;
+191D;LIMBU LETTER GYAN;Lo;0;L;;;;;N;;;;;
+191E;LIMBU LETTER TRA;Lo;0;L;;;;;N;;;;;
+1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;
+1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+1929;LIMBU SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;
+192A;LIMBU SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;;
+192B;LIMBU SUBJOINED LETTER WA;Mc;0;L;;;;;N;;;;;
+1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;;
+1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;;
+1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;;
+1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;;
+1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;;
+1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;;
+1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;;
+1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;;
+1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;;
+193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;;
+193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;;
+1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;;
+1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;;
+1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;;
+1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;;
+1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;;
+1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;;
+1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;;
+1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;;
+1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;;
+1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;;
+1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;;
+195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;;
+195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;;
+195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;;
+195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;;
+195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;;
+195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;;
+1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;;
+1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;;
+1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;;
+1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;;
+1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;;
+1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;;
+1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;;
+1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;;
+1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;;
+1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;;
+196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;;
+196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;;
+196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;;
+196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;;
+1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;;
+1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;;
+1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;;
+1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;;
+1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;;
+1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;;
+1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;;
+1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;;
+1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;;
+1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;;
+1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;;
+1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;;
+1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;;
+1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;;
+1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;;
+198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;;
+198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;;
+198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;;
+198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;;
+198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;;
+198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;;
+1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;;
+1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;;
+1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;;
+1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;;
+1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;;
+1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;
+1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;;
+1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;;
+1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;;
+1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;;
+199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;;
+199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;;
+199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;;
+199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;;
+199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;;
+199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;;
+19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;;
+19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;;
+19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;;
+19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;;
+19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;;
+19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;;
+19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;;
+19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;;
+19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;;
+19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;;
+19AA;NEW TAI LUE LETTER HIGH SUA;Lo;0;L;;;;;N;;;;;
+19AB;NEW TAI LUE LETTER LOW SUA;Lo;0;L;;;;;N;;;;;
+19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Lo;0;L;;;;;N;;;;;
+19B1;NEW TAI LUE VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;
+19B2;NEW TAI LUE VOWEL SIGN II;Lo;0;L;;;;;N;;;;;
+19B3;NEW TAI LUE VOWEL SIGN U;Lo;0;L;;;;;N;;;;;
+19B4;NEW TAI LUE VOWEL SIGN UU;Lo;0;L;;;;;N;;;;;
+19B5;NEW TAI LUE VOWEL SIGN E;Lo;0;L;;;;;N;;;;;
+19B6;NEW TAI LUE VOWEL SIGN AE;Lo;0;L;;;;;N;;;;;
+19B7;NEW TAI LUE VOWEL SIGN O;Lo;0;L;;;;;N;;;;;
+19B8;NEW TAI LUE VOWEL SIGN OA;Lo;0;L;;;;;N;;;;;
+19B9;NEW TAI LUE VOWEL SIGN UE;Lo;0;L;;;;;N;;;;;
+19BA;NEW TAI LUE VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;
+19BB;NEW TAI LUE VOWEL SIGN AAY;Lo;0;L;;;;;N;;;;;
+19BC;NEW TAI LUE VOWEL SIGN UY;Lo;0;L;;;;;N;;;;;
+19BD;NEW TAI LUE VOWEL SIGN OY;Lo;0;L;;;;;N;;;;;
+19BE;NEW TAI LUE VOWEL SIGN OAY;Lo;0;L;;;;;N;;;;;
+19BF;NEW TAI LUE VOWEL SIGN UEY;Lo;0;L;;;;;N;;;;;
+19C0;NEW TAI LUE VOWEL SIGN IY;Lo;0;L;;;;;N;;;;;
+19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;;
+19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;;
+19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;;
+19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;;
+19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;;
+19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;;
+19C8;NEW TAI LUE TONE MARK-1;Lo;0;L;;;;;N;;;;;
+19C9;NEW TAI LUE TONE MARK-2;Lo;0;L;;;;;N;;;;;
+19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+19DA;NEW TAI LUE THAM DIGIT ONE;No;0;L;;;1;1;N;;;;;
+19DE;NEW TAI LUE SIGN LAE;So;0;ON;;;;;N;;;;;
+19DF;NEW TAI LUE SIGN LAEV;So;0;ON;;;;;N;;;;;
+19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;;
+19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;;
+19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;;
+19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;;
+19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;;
+19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;;
+19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;;
+19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;;
+19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;;
+19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;;
+19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;;
+19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;;
+19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;;
+19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;;
+19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;;
+19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;;
+19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;;
+19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;;
+19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;;
+19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;;
+19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;;
+19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;;
+19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;;
+19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;;
+19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;;
+19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;;
+19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;;
+19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;;
+19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;;
+19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;;
+19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;;
+19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;;
+1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;;
+1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;;
+1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;;
+1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;;
+1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;;
+1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;;
+1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;;
+1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;;
+1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;;
+1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;;
+1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;;
+1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;;
+1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;;
+1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;;
+1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;;
+1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;;
+1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;;
+1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;;
+1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;;
+1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;;
+1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;;
+1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;
+1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;;
+1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1A1B;BUGINESE VOWEL SIGN AE;Mn;0;NSM;;;;;N;;;;;
+1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;;
+1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;;
+1A20;TAI THAM LETTER HIGH KA;Lo;0;L;;;;;N;;;;;
+1A21;TAI THAM LETTER HIGH KHA;Lo;0;L;;;;;N;;;;;
+1A22;TAI THAM LETTER HIGH KXA;Lo;0;L;;;;;N;;;;;
+1A23;TAI THAM LETTER LOW KA;Lo;0;L;;;;;N;;;;;
+1A24;TAI THAM LETTER LOW KXA;Lo;0;L;;;;;N;;;;;
+1A25;TAI THAM LETTER LOW KHA;Lo;0;L;;;;;N;;;;;
+1A26;TAI THAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+1A27;TAI THAM LETTER HIGH CA;Lo;0;L;;;;;N;;;;;
+1A28;TAI THAM LETTER HIGH CHA;Lo;0;L;;;;;N;;;;;
+1A29;TAI THAM LETTER LOW CA;Lo;0;L;;;;;N;;;;;
+1A2A;TAI THAM LETTER LOW SA;Lo;0;L;;;;;N;;;;;
+1A2B;TAI THAM LETTER LOW CHA;Lo;0;L;;;;;N;;;;;
+1A2C;TAI THAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+1A2D;TAI THAM LETTER RATA;Lo;0;L;;;;;N;;;;;
+1A2E;TAI THAM LETTER HIGH RATHA;Lo;0;L;;;;;N;;;;;
+1A2F;TAI THAM LETTER DA;Lo;0;L;;;;;N;;;;;
+1A30;TAI THAM LETTER LOW RATHA;Lo;0;L;;;;;N;;;;;
+1A31;TAI THAM LETTER RANA;Lo;0;L;;;;;N;;;;;
+1A32;TAI THAM LETTER HIGH TA;Lo;0;L;;;;;N;;;;;
+1A33;TAI THAM LETTER HIGH THA;Lo;0;L;;;;;N;;;;;
+1A34;TAI THAM LETTER LOW TA;Lo;0;L;;;;;N;;;;;
+1A35;TAI THAM LETTER LOW THA;Lo;0;L;;;;;N;;;;;
+1A36;TAI THAM LETTER NA;Lo;0;L;;;;;N;;;;;
+1A37;TAI THAM LETTER BA;Lo;0;L;;;;;N;;;;;
+1A38;TAI THAM LETTER HIGH PA;Lo;0;L;;;;;N;;;;;
+1A39;TAI THAM LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;
+1A3A;TAI THAM LETTER HIGH FA;Lo;0;L;;;;;N;;;;;
+1A3B;TAI THAM LETTER LOW PA;Lo;0;L;;;;;N;;;;;
+1A3C;TAI THAM LETTER LOW FA;Lo;0;L;;;;;N;;;;;
+1A3D;TAI THAM LETTER LOW PHA;Lo;0;L;;;;;N;;;;;
+1A3E;TAI THAM LETTER MA;Lo;0;L;;;;;N;;;;;
+1A3F;TAI THAM LETTER LOW YA;Lo;0;L;;;;;N;;;;;
+1A40;TAI THAM LETTER HIGH YA;Lo;0;L;;;;;N;;;;;
+1A41;TAI THAM LETTER RA;Lo;0;L;;;;;N;;;;;
+1A42;TAI THAM LETTER RUE;Lo;0;L;;;;;N;;;;;
+1A43;TAI THAM LETTER LA;Lo;0;L;;;;;N;;;;;
+1A44;TAI THAM LETTER LUE;Lo;0;L;;;;;N;;;;;
+1A45;TAI THAM LETTER WA;Lo;0;L;;;;;N;;;;;
+1A46;TAI THAM LETTER HIGH SHA;Lo;0;L;;;;;N;;;;;
+1A47;TAI THAM LETTER HIGH SSA;Lo;0;L;;;;;N;;;;;
+1A48;TAI THAM LETTER HIGH SA;Lo;0;L;;;;;N;;;;;
+1A49;TAI THAM LETTER HIGH HA;Lo;0;L;;;;;N;;;;;
+1A4A;TAI THAM LETTER LLA;Lo;0;L;;;;;N;;;;;
+1A4B;TAI THAM LETTER A;Lo;0;L;;;;;N;;;;;
+1A4C;TAI THAM LETTER LOW HA;Lo;0;L;;;;;N;;;;;
+1A4D;TAI THAM LETTER I;Lo;0;L;;;;;N;;;;;
+1A4E;TAI THAM LETTER II;Lo;0;L;;;;;N;;;;;
+1A4F;TAI THAM LETTER U;Lo;0;L;;;;;N;;;;;
+1A50;TAI THAM LETTER UU;Lo;0;L;;;;;N;;;;;
+1A51;TAI THAM LETTER EE;Lo;0;L;;;;;N;;;;;
+1A52;TAI THAM LETTER OO;Lo;0;L;;;;;N;;;;;
+1A53;TAI THAM LETTER LAE;Lo;0;L;;;;;N;;;;;
+1A54;TAI THAM LETTER GREAT SA;Lo;0;L;;;;;N;;;;;
+1A55;TAI THAM CONSONANT SIGN MEDIAL RA;Mc;0;L;;;;;N;;;;;
+1A56;TAI THAM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;
+1A57;TAI THAM CONSONANT SIGN LA TANG LAI;Mc;0;L;;;;;N;;;;;
+1A58;TAI THAM SIGN MAI KANG LAI;Mn;0;NSM;;;;;N;;;;;
+1A59;TAI THAM CONSONANT SIGN FINAL NGA;Mn;0;NSM;;;;;N;;;;;
+1A5A;TAI THAM CONSONANT SIGN LOW PA;Mn;0;NSM;;;;;N;;;;;
+1A5B;TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA;Mn;0;NSM;;;;;N;;;;;
+1A5C;TAI THAM CONSONANT SIGN MA;Mn;0;NSM;;;;;N;;;;;
+1A5D;TAI THAM CONSONANT SIGN BA;Mn;0;NSM;;;;;N;;;;;
+1A5E;TAI THAM CONSONANT SIGN SA;Mn;0;NSM;;;;;N;;;;;
+1A60;TAI THAM SIGN SAKOT;Mn;9;NSM;;;;;N;;;;;
+1A61;TAI THAM VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+1A62;TAI THAM VOWEL SIGN MAI SAT;Mn;0;NSM;;;;;N;;;;;
+1A63;TAI THAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1A64;TAI THAM VOWEL SIGN TALL AA;Mc;0;L;;;;;N;;;;;
+1A65;TAI THAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1A66;TAI THAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+1A67;TAI THAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+1A68;TAI THAM VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;
+1A69;TAI THAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1A6A;TAI THAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1A6B;TAI THAM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+1A6C;TAI THAM VOWEL SIGN OA BELOW;Mn;0;NSM;;;;;N;;;;;
+1A6D;TAI THAM VOWEL SIGN OY;Mc;0;L;;;;;N;;;;;
+1A6E;TAI THAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1A6F;TAI THAM VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+1A70;TAI THAM VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+1A71;TAI THAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+1A72;TAI THAM VOWEL SIGN THAM AI;Mc;0;L;;;;;N;;;;;
+1A73;TAI THAM VOWEL SIGN OA ABOVE;Mn;0;NSM;;;;;N;;;;;
+1A74;TAI THAM SIGN MAI KANG;Mn;0;NSM;;;;;N;;;;;
+1A75;TAI THAM SIGN TONE-1;Mn;230;NSM;;;;;N;;;;;
+1A76;TAI THAM SIGN TONE-2;Mn;230;NSM;;;;;N;;;;;
+1A77;TAI THAM SIGN KHUEN TONE-3;Mn;230;NSM;;;;;N;;;;;
+1A78;TAI THAM SIGN KHUEN TONE-4;Mn;230;NSM;;;;;N;;;;;
+1A79;TAI THAM SIGN KHUEN TONE-5;Mn;230;NSM;;;;;N;;;;;
+1A7A;TAI THAM SIGN RA HAAM;Mn;230;NSM;;;;;N;;;;;
+1A7B;TAI THAM SIGN MAI SAM;Mn;230;NSM;;;;;N;;;;;
+1A7C;TAI THAM SIGN KHUEN-LUE KARAN;Mn;230;NSM;;;;;N;;;;;
+1A7F;TAI THAM COMBINING CRYPTOGRAMMIC DOT;Mn;220;NSM;;;;;N;;;;;
+1A80;TAI THAM HORA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1A81;TAI THAM HORA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1A82;TAI THAM HORA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1A83;TAI THAM HORA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1A84;TAI THAM HORA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1A85;TAI THAM HORA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1A86;TAI THAM HORA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1A87;TAI THAM HORA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1A88;TAI THAM HORA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1A89;TAI THAM HORA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1A90;TAI THAM THAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1A91;TAI THAM THAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1A92;TAI THAM THAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1A93;TAI THAM THAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1A94;TAI THAM THAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1A95;TAI THAM THAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1A96;TAI THAM THAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1A97;TAI THAM THAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1A98;TAI THAM THAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1A99;TAI THAM THAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1AA0;TAI THAM SIGN WIANG;Po;0;L;;;;;N;;;;;
+1AA1;TAI THAM SIGN WIANGWAAK;Po;0;L;;;;;N;;;;;
+1AA2;TAI THAM SIGN SAWAN;Po;0;L;;;;;N;;;;;
+1AA3;TAI THAM SIGN KEOW;Po;0;L;;;;;N;;;;;
+1AA4;TAI THAM SIGN HOY;Po;0;L;;;;;N;;;;;
+1AA5;TAI THAM SIGN DOKMAI;Po;0;L;;;;;N;;;;;
+1AA6;TAI THAM SIGN REVERSED ROTATED RANA;Po;0;L;;;;;N;;;;;
+1AA7;TAI THAM SIGN MAI YAMOK;Lm;0;L;;;;;N;;;;;
+1AA8;TAI THAM SIGN KAAN;Po;0;L;;;;;N;;;;;
+1AA9;TAI THAM SIGN KAANKUU;Po;0;L;;;;;N;;;;;
+1AAA;TAI THAM SIGN SATKAAN;Po;0;L;;;;;N;;;;;
+1AAB;TAI THAM SIGN SATKAANKUU;Po;0;L;;;;;N;;;;;
+1AAC;TAI THAM SIGN HANG;Po;0;L;;;;;N;;;;;
+1AAD;TAI THAM SIGN CAANG;Po;0;L;;;;;N;;;;;
+1AB0;COMBINING DOUBLED CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;;;;;
+1AB1;COMBINING DIAERESIS-RING;Mn;230;NSM;;;;;N;;;;;
+1AB2;COMBINING INFINITY;Mn;230;NSM;;;;;N;;;;;
+1AB3;COMBINING DOWNWARDS ARROW;Mn;230;NSM;;;;;N;;;;;
+1AB4;COMBINING TRIPLE DOT;Mn;230;NSM;;;;;N;;;;;
+1AB5;COMBINING X-X BELOW;Mn;220;NSM;;;;;N;;;;;
+1AB6;COMBINING WIGGLY LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+1AB7;COMBINING OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;;
+1AB8;COMBINING DOUBLE OPEN MARK BELOW;Mn;220;NSM;;;;;N;;;;;
+1AB9;COMBINING LIGHT CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;;
+1ABA;COMBINING STRONG CENTRALIZATION STROKE BELOW;Mn;220;NSM;;;;;N;;;;;
+1ABB;COMBINING PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;;
+1ABC;COMBINING DOUBLE PARENTHESES ABOVE;Mn;230;NSM;;;;;N;;;;;
+1ABD;COMBINING PARENTHESES BELOW;Mn;220;NSM;;;;;N;;;;;
+1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;;
+1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;;
+1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;;
+1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;;
+1B03;BALINESE SIGN SURANG;Mn;0;NSM;;;;;N;;;;;
+1B04;BALINESE SIGN BISAH;Mc;0;L;;;;;N;;;;;
+1B05;BALINESE LETTER AKARA;Lo;0;L;;;;;N;;;;;
+1B06;BALINESE LETTER AKARA TEDUNG;Lo;0;L;1B05 1B35;;;;N;;;;;
+1B07;BALINESE LETTER IKARA;Lo;0;L;;;;;N;;;;;
+1B08;BALINESE LETTER IKARA TEDUNG;Lo;0;L;1B07 1B35;;;;N;;;;;
+1B09;BALINESE LETTER UKARA;Lo;0;L;;;;;N;;;;;
+1B0A;BALINESE LETTER UKARA TEDUNG;Lo;0;L;1B09 1B35;;;;N;;;;;
+1B0B;BALINESE LETTER RA REPA;Lo;0;L;;;;;N;;;;;
+1B0C;BALINESE LETTER RA REPA TEDUNG;Lo;0;L;1B0B 1B35;;;;N;;;;;
+1B0D;BALINESE LETTER LA LENGA;Lo;0;L;;;;;N;;;;;
+1B0E;BALINESE LETTER LA LENGA TEDUNG;Lo;0;L;1B0D 1B35;;;;N;;;;;
+1B0F;BALINESE LETTER EKARA;Lo;0;L;;;;;N;;;;;
+1B10;BALINESE LETTER AIKARA;Lo;0;L;;;;;N;;;;;
+1B11;BALINESE LETTER OKARA;Lo;0;L;;;;;N;;;;;
+1B12;BALINESE LETTER OKARA TEDUNG;Lo;0;L;1B11 1B35;;;;N;;;;;
+1B13;BALINESE LETTER KA;Lo;0;L;;;;;N;;;;;
+1B14;BALINESE LETTER KA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+1B15;BALINESE LETTER GA;Lo;0;L;;;;;N;;;;;
+1B16;BALINESE LETTER GA GORA;Lo;0;L;;;;;N;;;;;
+1B17;BALINESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1B18;BALINESE LETTER CA;Lo;0;L;;;;;N;;;;;
+1B19;BALINESE LETTER CA LACA;Lo;0;L;;;;;N;;;;;
+1B1A;BALINESE LETTER JA;Lo;0;L;;;;;N;;;;;
+1B1B;BALINESE LETTER JA JERA;Lo;0;L;;;;;N;;;;;
+1B1C;BALINESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+1B1D;BALINESE LETTER TA LATIK;Lo;0;L;;;;;N;;;;;
+1B1E;BALINESE LETTER TA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+1B1F;BALINESE LETTER DA MURDA ALPAPRANA;Lo;0;L;;;;;N;;;;;
+1B20;BALINESE LETTER DA MURDA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+1B21;BALINESE LETTER NA RAMBAT;Lo;0;L;;;;;N;;;;;
+1B22;BALINESE LETTER TA;Lo;0;L;;;;;N;;;;;
+1B23;BALINESE LETTER TA TAWA;Lo;0;L;;;;;N;;;;;
+1B24;BALINESE LETTER DA;Lo;0;L;;;;;N;;;;;
+1B25;BALINESE LETTER DA MADU;Lo;0;L;;;;;N;;;;;
+1B26;BALINESE LETTER NA;Lo;0;L;;;;;N;;;;;
+1B27;BALINESE LETTER PA;Lo;0;L;;;;;N;;;;;
+1B28;BALINESE LETTER PA KAPAL;Lo;0;L;;;;;N;;;;;
+1B29;BALINESE LETTER BA;Lo;0;L;;;;;N;;;;;
+1B2A;BALINESE LETTER BA KEMBANG;Lo;0;L;;;;;N;;;;;
+1B2B;BALINESE LETTER MA;Lo;0;L;;;;;N;;;;;
+1B2C;BALINESE LETTER YA;Lo;0;L;;;;;N;;;;;
+1B2D;BALINESE LETTER RA;Lo;0;L;;;;;N;;;;;
+1B2E;BALINESE LETTER LA;Lo;0;L;;;;;N;;;;;
+1B2F;BALINESE LETTER WA;Lo;0;L;;;;;N;;;;;
+1B30;BALINESE LETTER SA SAGA;Lo;0;L;;;;;N;;;;;
+1B31;BALINESE LETTER SA SAPA;Lo;0;L;;;;;N;;;;;
+1B32;BALINESE LETTER SA;Lo;0;L;;;;;N;;;;;
+1B33;BALINESE LETTER HA;Lo;0;L;;;;;N;;;;;
+1B34;BALINESE SIGN REREKAN;Mn;7;NSM;;;;;N;;;;;
+1B35;BALINESE VOWEL SIGN TEDUNG;Mc;0;L;;;;;N;;;;;
+1B36;BALINESE VOWEL SIGN ULU;Mn;0;NSM;;;;;N;;;;;
+1B37;BALINESE VOWEL SIGN ULU SARI;Mn;0;NSM;;;;;N;;;;;
+1B38;BALINESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;;
+1B39;BALINESE VOWEL SIGN SUKU ILUT;Mn;0;NSM;;;;;N;;;;;
+1B3A;BALINESE VOWEL SIGN RA REPA;Mn;0;NSM;;;;;N;;;;;
+1B3B;BALINESE VOWEL SIGN RA REPA TEDUNG;Mc;0;L;1B3A 1B35;;;;N;;;;;
+1B3C;BALINESE VOWEL SIGN LA LENGA;Mn;0;NSM;;;;;N;;;;;
+1B3D;BALINESE VOWEL SIGN LA LENGA TEDUNG;Mc;0;L;1B3C 1B35;;;;N;;;;;
+1B3E;BALINESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;;
+1B3F;BALINESE VOWEL SIGN TALING REPA;Mc;0;L;;;;;N;;;;;
+1B40;BALINESE VOWEL SIGN TALING TEDUNG;Mc;0;L;1B3E 1B35;;;;N;;;;;
+1B41;BALINESE VOWEL SIGN TALING REPA TEDUNG;Mc;0;L;1B3F 1B35;;;;N;;;;;
+1B42;BALINESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;;
+1B43;BALINESE VOWEL SIGN PEPET TEDUNG;Mc;0;L;1B42 1B35;;;;N;;;;;
+1B44;BALINESE ADEG ADEG;Mc;9;L;;;;;N;;;;;
+1B45;BALINESE LETTER KAF SASAK;Lo;0;L;;;;;N;;;;;
+1B46;BALINESE LETTER KHOT SASAK;Lo;0;L;;;;;N;;;;;
+1B47;BALINESE LETTER TZIR SASAK;Lo;0;L;;;;;N;;;;;
+1B48;BALINESE LETTER EF SASAK;Lo;0;L;;;;;N;;;;;
+1B49;BALINESE LETTER VE SASAK;Lo;0;L;;;;;N;;;;;
+1B4A;BALINESE LETTER ZAL SASAK;Lo;0;L;;;;;N;;;;;
+1B4B;BALINESE LETTER ASYURA SASAK;Lo;0;L;;;;;N;;;;;
+1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1B5A;BALINESE PANTI;Po;0;L;;;;;N;;;;;
+1B5B;BALINESE PAMADA;Po;0;L;;;;;N;;;;;
+1B5C;BALINESE WINDU;Po;0;L;;;;;N;;;;;
+1B5D;BALINESE CARIK PAMUNGKAH;Po;0;L;;;;;N;;;;;
+1B5E;BALINESE CARIK SIKI;Po;0;L;;;;;N;;;;;
+1B5F;BALINESE CARIK PAREREN;Po;0;L;;;;;N;;;;;
+1B60;BALINESE PAMENENG;Po;0;L;;;;;N;;;;;
+1B61;BALINESE MUSICAL SYMBOL DONG;So;0;L;;;;;N;;;;;
+1B62;BALINESE MUSICAL SYMBOL DENG;So;0;L;;;;;N;;;;;
+1B63;BALINESE MUSICAL SYMBOL DUNG;So;0;L;;;;;N;;;;;
+1B64;BALINESE MUSICAL SYMBOL DANG;So;0;L;;;;;N;;;;;
+1B65;BALINESE MUSICAL SYMBOL DANG SURANG;So;0;L;;;;;N;;;;;
+1B66;BALINESE MUSICAL SYMBOL DING;So;0;L;;;;;N;;;;;
+1B67;BALINESE MUSICAL SYMBOL DAENG;So;0;L;;;;;N;;;;;
+1B68;BALINESE MUSICAL SYMBOL DEUNG;So;0;L;;;;;N;;;;;
+1B69;BALINESE MUSICAL SYMBOL DAING;So;0;L;;;;;N;;;;;
+1B6A;BALINESE MUSICAL SYMBOL DANG GEDE;So;0;L;;;;;N;;;;;
+1B6B;BALINESE MUSICAL SYMBOL COMBINING TEGEH;Mn;230;NSM;;;;;N;;;;;
+1B6C;BALINESE MUSICAL SYMBOL COMBINING ENDEP;Mn;220;NSM;;;;;N;;;;;
+1B6D;BALINESE MUSICAL SYMBOL COMBINING KEMPUL;Mn;230;NSM;;;;;N;;;;;
+1B6E;BALINESE MUSICAL SYMBOL COMBINING KEMPLI;Mn;230;NSM;;;;;N;;;;;
+1B6F;BALINESE MUSICAL SYMBOL COMBINING JEGOGAN;Mn;230;NSM;;;;;N;;;;;
+1B70;BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;;
+1B71;BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN;Mn;230;NSM;;;;;N;;;;;
+1B72;BALINESE MUSICAL SYMBOL COMBINING BENDE;Mn;230;NSM;;;;;N;;;;;
+1B73;BALINESE MUSICAL SYMBOL COMBINING GONG;Mn;230;NSM;;;;;N;;;;;
+1B74;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG;So;0;L;;;;;N;;;;;
+1B75;BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG;So;0;L;;;;;N;;;;;
+1B76;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK;So;0;L;;;;;N;;;;;
+1B77;BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK;So;0;L;;;;;N;;;;;
+1B78;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG;So;0;L;;;;;N;;;;;
+1B79;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG;So;0;L;;;;;N;;;;;
+1B7A;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK;So;0;L;;;;;N;;;;;
+1B7B;BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK;So;0;L;;;;;N;;;;;
+1B7C;BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING;So;0;L;;;;;N;;;;;
+1B80;SUNDANESE SIGN PANYECEK;Mn;0;NSM;;;;;N;;;;;
+1B81;SUNDANESE SIGN PANGLAYAR;Mn;0;NSM;;;;;N;;;;;
+1B82;SUNDANESE SIGN PANGWISAD;Mc;0;L;;;;;N;;;;;
+1B83;SUNDANESE LETTER A;Lo;0;L;;;;;N;;;;;
+1B84;SUNDANESE LETTER I;Lo;0;L;;;;;N;;;;;
+1B85;SUNDANESE LETTER U;Lo;0;L;;;;;N;;;;;
+1B86;SUNDANESE LETTER AE;Lo;0;L;;;;;N;;;;;
+1B87;SUNDANESE LETTER O;Lo;0;L;;;;;N;;;;;
+1B88;SUNDANESE LETTER E;Lo;0;L;;;;;N;;;;;
+1B89;SUNDANESE LETTER EU;Lo;0;L;;;;;N;;;;;
+1B8A;SUNDANESE LETTER KA;Lo;0;L;;;;;N;;;;;
+1B8B;SUNDANESE LETTER QA;Lo;0;L;;;;;N;;;;;
+1B8C;SUNDANESE LETTER GA;Lo;0;L;;;;;N;;;;;
+1B8D;SUNDANESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1B8E;SUNDANESE LETTER CA;Lo;0;L;;;;;N;;;;;
+1B8F;SUNDANESE LETTER JA;Lo;0;L;;;;;N;;;;;
+1B90;SUNDANESE LETTER ZA;Lo;0;L;;;;;N;;;;;
+1B91;SUNDANESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+1B92;SUNDANESE LETTER TA;Lo;0;L;;;;;N;;;;;
+1B93;SUNDANESE LETTER DA;Lo;0;L;;;;;N;;;;;
+1B94;SUNDANESE LETTER NA;Lo;0;L;;;;;N;;;;;
+1B95;SUNDANESE LETTER PA;Lo;0;L;;;;;N;;;;;
+1B96;SUNDANESE LETTER FA;Lo;0;L;;;;;N;;;;;
+1B97;SUNDANESE LETTER VA;Lo;0;L;;;;;N;;;;;
+1B98;SUNDANESE LETTER BA;Lo;0;L;;;;;N;;;;;
+1B99;SUNDANESE LETTER MA;Lo;0;L;;;;;N;;;;;
+1B9A;SUNDANESE LETTER YA;Lo;0;L;;;;;N;;;;;
+1B9B;SUNDANESE LETTER RA;Lo;0;L;;;;;N;;;;;
+1B9C;SUNDANESE LETTER LA;Lo;0;L;;;;;N;;;;;
+1B9D;SUNDANESE LETTER WA;Lo;0;L;;;;;N;;;;;
+1B9E;SUNDANESE LETTER SA;Lo;0;L;;;;;N;;;;;
+1B9F;SUNDANESE LETTER XA;Lo;0;L;;;;;N;;;;;
+1BA0;SUNDANESE LETTER HA;Lo;0;L;;;;;N;;;;;
+1BA1;SUNDANESE CONSONANT SIGN PAMINGKAL;Mc;0;L;;;;;N;;;;;
+1BA2;SUNDANESE CONSONANT SIGN PANYAKRA;Mn;0;NSM;;;;;N;;;;;
+1BA3;SUNDANESE CONSONANT SIGN PANYIKU;Mn;0;NSM;;;;;N;;;;;
+1BA4;SUNDANESE VOWEL SIGN PANGHULU;Mn;0;NSM;;;;;N;;;;;
+1BA5;SUNDANESE VOWEL SIGN PANYUKU;Mn;0;NSM;;;;;N;;;;;
+1BA6;SUNDANESE VOWEL SIGN PANAELAENG;Mc;0;L;;;;;N;;;;;
+1BA7;SUNDANESE VOWEL SIGN PANOLONG;Mc;0;L;;;;;N;;;;;
+1BA8;SUNDANESE VOWEL SIGN PAMEPET;Mn;0;NSM;;;;;N;;;;;
+1BA9;SUNDANESE VOWEL SIGN PANEULEUNG;Mn;0;NSM;;;;;N;;;;;
+1BAA;SUNDANESE SIGN PAMAAEH;Mc;9;L;;;;;N;;;;;
+1BAB;SUNDANESE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1BAC;SUNDANESE CONSONANT SIGN PASANGAN MA;Mn;0;NSM;;;;;N;;;;;
+1BAD;SUNDANESE CONSONANT SIGN PASANGAN WA;Mn;0;NSM;;;;;N;;;;;
+1BAE;SUNDANESE LETTER KHA;Lo;0;L;;;;;N;;;;;
+1BAF;SUNDANESE LETTER SYA;Lo;0;L;;;;;N;;;;;
+1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1BBA;SUNDANESE AVAGRAHA;Lo;0;L;;;;;N;;;;;
+1BBB;SUNDANESE LETTER REU;Lo;0;L;;;;;N;;;;;
+1BBC;SUNDANESE LETTER LEU;Lo;0;L;;;;;N;;;;;
+1BBD;SUNDANESE LETTER BHA;Lo;0;L;;;;;N;;;;;
+1BBE;SUNDANESE LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+1BBF;SUNDANESE LETTER FINAL M;Lo;0;L;;;;;N;;;;;
+1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;;
+1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;;
+1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;;
+1BC3;BATAK LETTER SIMALUNGUN HA;Lo;0;L;;;;;N;;;;;
+1BC4;BATAK LETTER MANDAILING HA;Lo;0;L;;;;;N;;;;;
+1BC5;BATAK LETTER BA;Lo;0;L;;;;;N;;;;;
+1BC6;BATAK LETTER KARO BA;Lo;0;L;;;;;N;;;;;
+1BC7;BATAK LETTER PA;Lo;0;L;;;;;N;;;;;
+1BC8;BATAK LETTER SIMALUNGUN PA;Lo;0;L;;;;;N;;;;;
+1BC9;BATAK LETTER NA;Lo;0;L;;;;;N;;;;;
+1BCA;BATAK LETTER MANDAILING NA;Lo;0;L;;;;;N;;;;;
+1BCB;BATAK LETTER WA;Lo;0;L;;;;;N;;;;;
+1BCC;BATAK LETTER SIMALUNGUN WA;Lo;0;L;;;;;N;;;;;
+1BCD;BATAK LETTER PAKPAK WA;Lo;0;L;;;;;N;;;;;
+1BCE;BATAK LETTER GA;Lo;0;L;;;;;N;;;;;
+1BCF;BATAK LETTER SIMALUNGUN GA;Lo;0;L;;;;;N;;;;;
+1BD0;BATAK LETTER JA;Lo;0;L;;;;;N;;;;;
+1BD1;BATAK LETTER DA;Lo;0;L;;;;;N;;;;;
+1BD2;BATAK LETTER RA;Lo;0;L;;;;;N;;;;;
+1BD3;BATAK LETTER SIMALUNGUN RA;Lo;0;L;;;;;N;;;;;
+1BD4;BATAK LETTER MA;Lo;0;L;;;;;N;;;;;
+1BD5;BATAK LETTER SIMALUNGUN MA;Lo;0;L;;;;;N;;;;;
+1BD6;BATAK LETTER SOUTHERN TA;Lo;0;L;;;;;N;;;;;
+1BD7;BATAK LETTER NORTHERN TA;Lo;0;L;;;;;N;;;;;
+1BD8;BATAK LETTER SA;Lo;0;L;;;;;N;;;;;
+1BD9;BATAK LETTER SIMALUNGUN SA;Lo;0;L;;;;;N;;;;;
+1BDA;BATAK LETTER MANDAILING SA;Lo;0;L;;;;;N;;;;;
+1BDB;BATAK LETTER YA;Lo;0;L;;;;;N;;;;;
+1BDC;BATAK LETTER SIMALUNGUN YA;Lo;0;L;;;;;N;;;;;
+1BDD;BATAK LETTER NGA;Lo;0;L;;;;;N;;;;;
+1BDE;BATAK LETTER LA;Lo;0;L;;;;;N;;;;;
+1BDF;BATAK LETTER SIMALUNGUN LA;Lo;0;L;;;;;N;;;;;
+1BE0;BATAK LETTER NYA;Lo;0;L;;;;;N;;;;;
+1BE1;BATAK LETTER CA;Lo;0;L;;;;;N;;;;;
+1BE2;BATAK LETTER NDA;Lo;0;L;;;;;N;;;;;
+1BE3;BATAK LETTER MBA;Lo;0;L;;;;;N;;;;;
+1BE4;BATAK LETTER I;Lo;0;L;;;;;N;;;;;
+1BE5;BATAK LETTER U;Lo;0;L;;;;;N;;;;;
+1BE6;BATAK SIGN TOMPI;Mn;7;NSM;;;;;N;;;;;
+1BE7;BATAK VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1BE8;BATAK VOWEL SIGN PAKPAK E;Mn;0;NSM;;;;;N;;;;;
+1BE9;BATAK VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+1BEA;BATAK VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+1BEB;BATAK VOWEL SIGN KARO I;Mc;0;L;;;;;N;;;;;
+1BEC;BATAK VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1BED;BATAK VOWEL SIGN KARO O;Mn;0;NSM;;;;;N;;;;;
+1BEE;BATAK VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+1BEF;BATAK VOWEL SIGN U FOR SIMALUNGUN SA;Mn;0;NSM;;;;;N;;;;;
+1BF0;BATAK CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;
+1BF1;BATAK CONSONANT SIGN H;Mn;0;NSM;;;;;N;;;;;
+1BF2;BATAK PANGOLAT;Mc;9;L;;;;;N;;;;;
+1BF3;BATAK PANONGONAN;Mc;9;L;;;;;N;;;;;
+1BFC;BATAK SYMBOL BINDU NA METEK;Po;0;L;;;;;N;;;;;
+1BFD;BATAK SYMBOL BINDU PINARBORAS;Po;0;L;;;;;N;;;;;
+1BFE;BATAK SYMBOL BINDU JUDUL;Po;0;L;;;;;N;;;;;
+1BFF;BATAK SYMBOL BINDU PANGOLAT;Po;0;L;;;;;N;;;;;
+1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;;
+1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;;
+1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;;
+1C03;LEPCHA LETTER GA;Lo;0;L;;;;;N;;;;;
+1C04;LEPCHA LETTER GLA;Lo;0;L;;;;;N;;;;;
+1C05;LEPCHA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1C06;LEPCHA LETTER CA;Lo;0;L;;;;;N;;;;;
+1C07;LEPCHA LETTER CHA;Lo;0;L;;;;;N;;;;;
+1C08;LEPCHA LETTER JA;Lo;0;L;;;;;N;;;;;
+1C09;LEPCHA LETTER NYA;Lo;0;L;;;;;N;;;;;
+1C0A;LEPCHA LETTER TA;Lo;0;L;;;;;N;;;;;
+1C0B;LEPCHA LETTER THA;Lo;0;L;;;;;N;;;;;
+1C0C;LEPCHA LETTER DA;Lo;0;L;;;;;N;;;;;
+1C0D;LEPCHA LETTER NA;Lo;0;L;;;;;N;;;;;
+1C0E;LEPCHA LETTER PA;Lo;0;L;;;;;N;;;;;
+1C0F;LEPCHA LETTER PLA;Lo;0;L;;;;;N;;;;;
+1C10;LEPCHA LETTER PHA;Lo;0;L;;;;;N;;;;;
+1C11;LEPCHA LETTER FA;Lo;0;L;;;;;N;;;;;
+1C12;LEPCHA LETTER FLA;Lo;0;L;;;;;N;;;;;
+1C13;LEPCHA LETTER BA;Lo;0;L;;;;;N;;;;;
+1C14;LEPCHA LETTER BLA;Lo;0;L;;;;;N;;;;;
+1C15;LEPCHA LETTER MA;Lo;0;L;;;;;N;;;;;
+1C16;LEPCHA LETTER MLA;Lo;0;L;;;;;N;;;;;
+1C17;LEPCHA LETTER TSA;Lo;0;L;;;;;N;;;;;
+1C18;LEPCHA LETTER TSHA;Lo;0;L;;;;;N;;;;;
+1C19;LEPCHA LETTER DZA;Lo;0;L;;;;;N;;;;;
+1C1A;LEPCHA LETTER YA;Lo;0;L;;;;;N;;;;;
+1C1B;LEPCHA LETTER RA;Lo;0;L;;;;;N;;;;;
+1C1C;LEPCHA LETTER LA;Lo;0;L;;;;;N;;;;;
+1C1D;LEPCHA LETTER HA;Lo;0;L;;;;;N;;;;;
+1C1E;LEPCHA LETTER HLA;Lo;0;L;;;;;N;;;;;
+1C1F;LEPCHA LETTER VA;Lo;0;L;;;;;N;;;;;
+1C20;LEPCHA LETTER SA;Lo;0;L;;;;;N;;;;;
+1C21;LEPCHA LETTER SHA;Lo;0;L;;;;;N;;;;;
+1C22;LEPCHA LETTER WA;Lo;0;L;;;;;N;;;;;
+1C23;LEPCHA LETTER A;Lo;0;L;;;;;N;;;;;
+1C24;LEPCHA SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;
+1C25;LEPCHA SUBJOINED LETTER RA;Mc;0;L;;;;;N;;;;;
+1C26;LEPCHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1C27;LEPCHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+1C28;LEPCHA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1C29;LEPCHA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+1C2A;LEPCHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+1C2B;LEPCHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+1C2C;LEPCHA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1C2D;LEPCHA CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;;
+1C2E;LEPCHA CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;;
+1C2F;LEPCHA CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;;
+1C30;LEPCHA CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;
+1C31;LEPCHA CONSONANT SIGN P;Mn;0;NSM;;;;;N;;;;;
+1C32;LEPCHA CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;
+1C33;LEPCHA CONSONANT SIGN T;Mn;0;NSM;;;;;N;;;;;
+1C34;LEPCHA CONSONANT SIGN NYIN-DO;Mc;0;L;;;;;N;;;;;
+1C35;LEPCHA CONSONANT SIGN KANG;Mc;0;L;;;;;N;;;;;
+1C36;LEPCHA SIGN RAN;Mn;0;NSM;;;;;N;;;;;
+1C37;LEPCHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+1C3B;LEPCHA PUNCTUATION TA-ROL;Po;0;L;;;;;N;;;;;
+1C3C;LEPCHA PUNCTUATION NYET THYOOM TA-ROL;Po;0;L;;;;;N;;;;;
+1C3D;LEPCHA PUNCTUATION CER-WA;Po;0;L;;;;;N;;;;;
+1C3E;LEPCHA PUNCTUATION TSHOOK CER-WA;Po;0;L;;;;;N;;;;;
+1C3F;LEPCHA PUNCTUATION TSHOOK;Po;0;L;;;;;N;;;;;
+1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1C4D;LEPCHA LETTER TTA;Lo;0;L;;;;;N;;;;;
+1C4E;LEPCHA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1C4F;LEPCHA LETTER DDA;Lo;0;L;;;;;N;;;;;
+1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1C5A;OL CHIKI LETTER LA;Lo;0;L;;;;;N;;;;;
+1C5B;OL CHIKI LETTER AT;Lo;0;L;;;;;N;;;;;
+1C5C;OL CHIKI LETTER AG;Lo;0;L;;;;;N;;;;;
+1C5D;OL CHIKI LETTER ANG;Lo;0;L;;;;;N;;;;;
+1C5E;OL CHIKI LETTER AL;Lo;0;L;;;;;N;;;;;
+1C5F;OL CHIKI LETTER LAA;Lo;0;L;;;;;N;;;;;
+1C60;OL CHIKI LETTER AAK;Lo;0;L;;;;;N;;;;;
+1C61;OL CHIKI LETTER AAJ;Lo;0;L;;;;;N;;;;;
+1C62;OL CHIKI LETTER AAM;Lo;0;L;;;;;N;;;;;
+1C63;OL CHIKI LETTER AAW;Lo;0;L;;;;;N;;;;;
+1C64;OL CHIKI LETTER LI;Lo;0;L;;;;;N;;;;;
+1C65;OL CHIKI LETTER IS;Lo;0;L;;;;;N;;;;;
+1C66;OL CHIKI LETTER IH;Lo;0;L;;;;;N;;;;;
+1C67;OL CHIKI LETTER INY;Lo;0;L;;;;;N;;;;;
+1C68;OL CHIKI LETTER IR;Lo;0;L;;;;;N;;;;;
+1C69;OL CHIKI LETTER LU;Lo;0;L;;;;;N;;;;;
+1C6A;OL CHIKI LETTER UC;Lo;0;L;;;;;N;;;;;
+1C6B;OL CHIKI LETTER UD;Lo;0;L;;;;;N;;;;;
+1C6C;OL CHIKI LETTER UNN;Lo;0;L;;;;;N;;;;;
+1C6D;OL CHIKI LETTER UY;Lo;0;L;;;;;N;;;;;
+1C6E;OL CHIKI LETTER LE;Lo;0;L;;;;;N;;;;;
+1C6F;OL CHIKI LETTER EP;Lo;0;L;;;;;N;;;;;
+1C70;OL CHIKI LETTER EDD;Lo;0;L;;;;;N;;;;;
+1C71;OL CHIKI LETTER EN;Lo;0;L;;;;;N;;;;;
+1C72;OL CHIKI LETTER ERR;Lo;0;L;;;;;N;;;;;
+1C73;OL CHIKI LETTER LO;Lo;0;L;;;;;N;;;;;
+1C74;OL CHIKI LETTER OTT;Lo;0;L;;;;;N;;;;;
+1C75;OL CHIKI LETTER OB;Lo;0;L;;;;;N;;;;;
+1C76;OL CHIKI LETTER OV;Lo;0;L;;;;;N;;;;;
+1C77;OL CHIKI LETTER OH;Lo;0;L;;;;;N;;;;;
+1C78;OL CHIKI MU TTUDDAG;Lm;0;L;;;;;N;;;;;
+1C79;OL CHIKI GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;;
+1C7A;OL CHIKI MU-GAAHLAA TTUDDAAG;Lm;0;L;;;;;N;;;;;
+1C7B;OL CHIKI RELAA;Lm;0;L;;;;;N;;;;;
+1C7C;OL CHIKI PHAARKAA;Lm;0;L;;;;;N;;;;;
+1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;;
+1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;;
+1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;;
+1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412
+1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414
+1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E
+1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421
+1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422
+1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422
+1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
+1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462
+1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A
+1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;;
+1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;;
+1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;;
+1CC3;SUNDANESE PUNCTUATION BINDU CAKRA;Po;0;L;;;;;N;;;;;
+1CC4;SUNDANESE PUNCTUATION BINDU LEU SATANGA;Po;0;L;;;;;N;;;;;
+1CC5;SUNDANESE PUNCTUATION BINDU KA SATANGA;Po;0;L;;;;;N;;;;;
+1CC6;SUNDANESE PUNCTUATION BINDU DA SATANGA;Po;0;L;;;;;N;;;;;
+1CC7;SUNDANESE PUNCTUATION BINDU BA SATANGA;Po;0;L;;;;;N;;;;;
+1CD0;VEDIC TONE KARSHANA;Mn;230;NSM;;;;;N;;;;;
+1CD1;VEDIC TONE SHARA;Mn;230;NSM;;;;;N;;;;;
+1CD2;VEDIC TONE PRENKHA;Mn;230;NSM;;;;;N;;;;;
+1CD3;VEDIC SIGN NIHSHVASA;Po;0;L;;;;;N;;;;;
+1CD4;VEDIC SIGN YAJURVEDIC MIDLINE SVARITA;Mn;1;NSM;;;;;N;;;;;
+1CD5;VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;
+1CD6;VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;
+1CD7;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA;Mn;220;NSM;;;;;N;;;;;
+1CD8;VEDIC TONE CANDRA BELOW;Mn;220;NSM;;;;;N;;;;;
+1CD9;VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER;Mn;220;NSM;;;;;N;;;;;
+1CDA;VEDIC TONE DOUBLE SVARITA;Mn;230;NSM;;;;;N;;;;;
+1CDB;VEDIC TONE TRIPLE SVARITA;Mn;230;NSM;;;;;N;;;;;
+1CDC;VEDIC TONE KATHAKA ANUDATTA;Mn;220;NSM;;;;;N;;;;;
+1CDD;VEDIC TONE DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+1CDE;VEDIC TONE TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+1CDF;VEDIC TONE THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+1CE0;VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA;Mn;230;NSM;;;;;N;;;;;
+1CE1;VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA;Mc;0;L;;;;;N;;;;;
+1CE2;VEDIC SIGN VISARGA SVARITA;Mn;1;NSM;;;;;N;;;;;
+1CE3;VEDIC SIGN VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;;
+1CE4;VEDIC SIGN REVERSED VISARGA UDATTA;Mn;1;NSM;;;;;N;;;;;
+1CE5;VEDIC SIGN VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;;
+1CE6;VEDIC SIGN REVERSED VISARGA ANUDATTA;Mn;1;NSM;;;;;N;;;;;
+1CE7;VEDIC SIGN VISARGA UDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;;
+1CE8;VEDIC SIGN VISARGA ANUDATTA WITH TAIL;Mn;1;NSM;;;;;N;;;;;
+1CE9;VEDIC SIGN ANUSVARA ANTARGOMUKHA;Lo;0;L;;;;;N;;;;;
+1CEA;VEDIC SIGN ANUSVARA BAHIRGOMUKHA;Lo;0;L;;;;;N;;;;;
+1CEB;VEDIC SIGN ANUSVARA VAMAGOMUKHA;Lo;0;L;;;;;N;;;;;
+1CEC;VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL;Lo;0;L;;;;;N;;;;;
+1CED;VEDIC SIGN TIRYAK;Mn;220;NSM;;;;;N;;;;;
+1CEE;VEDIC SIGN HEXIFORM LONG ANUSVARA;Lo;0;L;;;;;N;;;;;
+1CEF;VEDIC SIGN LONG ANUSVARA;Lo;0;L;;;;;N;;;;;
+1CF0;VEDIC SIGN RTHANG LONG ANUSVARA;Lo;0;L;;;;;N;;;;;
+1CF1;VEDIC SIGN ANUSVARA UBHAYATO MUKHA;Lo;0;L;;;;;N;;;;;
+1CF2;VEDIC SIGN ARDHAVISARGA;Mc;0;L;;;;;N;;;;;
+1CF3;VEDIC SIGN ROTATED ARDHAVISARGA;Mc;0;L;;;;;N;;;;;
+1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;;
+1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
+1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;;
+1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;;
+1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;;
+1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;;
+1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;;
+1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;;
+1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;;
+1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;;
+1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;;
+1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;;
+1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;;
+1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;;
+1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;;
+1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;;
+1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;;
+1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;;
+1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;;
+1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;;
+1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;;
+1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;;
+1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;;
+1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;;
+1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;;
+1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;;
+1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;;
+1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;;
+1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;;
+1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;;
+1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;;
+1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;;
+1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;;
+1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;;
+1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;;
+1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;;
+1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;;
+1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;;
+1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;;
+1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;;
+1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;;
+1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;;
+1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;;
+1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;;
+1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;;
+1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;;
+1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;;
+1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;;
+1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;;
+1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;;
+1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;;
+1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;;
+1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;;
+1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;;
+1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;;
+1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;;
+1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;;
+1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;;
+1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;;
+1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;;
+1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;;
+1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;;
+1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;;
+1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;;
+1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;;
+1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;;
+1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;;
+1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;;
+1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;;
+1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;;
+1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;;
+1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;;
+1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;;
+1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;;
+1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;;
+1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;;
+1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;;
+1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;;
+1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;;
+1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;;
+1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;;
+1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;;
+1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;;
+1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;;
+1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;;
+1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;;
+1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;;
+1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;;
+1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;;
+1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;;
+1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;;
+1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;;
+1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;;
+1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;;
+1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;;
+1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;;
+1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;;
+1D62;LATIN SUBSCRIPT SMALL LETTER I;Lm;0;L;<sub> 0069;;;;N;;;;;
+1D63;LATIN SUBSCRIPT SMALL LETTER R;Lm;0;L;<sub> 0072;;;;N;;;;;
+1D64;LATIN SUBSCRIPT SMALL LETTER U;Lm;0;L;<sub> 0075;;;;N;;;;;
+1D65;LATIN SUBSCRIPT SMALL LETTER V;Lm;0;L;<sub> 0076;;;;N;;;;;
+1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Lm;0;L;<sub> 03B2;;;;N;;;;;
+1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Lm;0;L;<sub> 03B3;;;;N;;;;;
+1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Lm;0;L;<sub> 03C1;;;;N;;;;;
+1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Lm;0;L;<sub> 03C6;;;;N;;;;;
+1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Lm;0;L;<sub> 03C7;;;;N;;;;;
+1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;;
+1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;;
+1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;;
+1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;A77D;;A77D
+1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;;
+1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;2C63;;2C63
+1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;;
+1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;;
+1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;;
+1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;;
+1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;;
+1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;;
+1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;;
+1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;;
+1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;;
+1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;;
+1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;;
+1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;;
+1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;;
+1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;;
+1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;;
+1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;;
+1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;;
+1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;;
+1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;;
+1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;;
+1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;;
+1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;;
+1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;;
+1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;;
+1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;;
+1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;;
+1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;;
+1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;;
+1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;;
+1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;;
+1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;;
+1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;;
+1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;;
+1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;;
+1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;;
+1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;;
+1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;;
+1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;;
+1DC4;COMBINING MACRON-ACUTE;Mn;230;NSM;;;;;N;;;;;
+1DC5;COMBINING GRAVE-MACRON;Mn;230;NSM;;;;;N;;;;;
+1DC6;COMBINING MACRON-GRAVE;Mn;230;NSM;;;;;N;;;;;
+1DC7;COMBINING ACUTE-MACRON;Mn;230;NSM;;;;;N;;;;;
+1DC8;COMBINING GRAVE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;
+1DC9;COMBINING ACUTE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;;
+1DCA;COMBINING LATIN SMALL LETTER R BELOW;Mn;220;NSM;;;;;N;;;;;
+1DCB;COMBINING BREVE-MACRON;Mn;230;NSM;;;;;N;;;;;
+1DCC;COMBINING MACRON-BREVE;Mn;230;NSM;;;;;N;;;;;
+1DCD;COMBINING DOUBLE CIRCUMFLEX ABOVE;Mn;234;NSM;;;;;N;;;;;
+1DCE;COMBINING OGONEK ABOVE;Mn;214;NSM;;;;;N;;;;;
+1DCF;COMBINING ZIGZAG BELOW;Mn;220;NSM;;;;;N;;;;;
+1DD0;COMBINING IS BELOW;Mn;202;NSM;;;;;N;;;;;
+1DD1;COMBINING UR ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DD2;COMBINING US ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DD3;COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DD4;COMBINING LATIN SMALL LETTER AE;Mn;230;NSM;;;;;N;;;;;
+1DD5;COMBINING LATIN SMALL LETTER AO;Mn;230;NSM;;;;;N;;;;;
+1DD6;COMBINING LATIN SMALL LETTER AV;Mn;230;NSM;;;;;N;;;;;
+1DD7;COMBINING LATIN SMALL LETTER C CEDILLA;Mn;230;NSM;;;;;N;;;;;
+1DD8;COMBINING LATIN SMALL LETTER INSULAR D;Mn;230;NSM;;;;;N;;;;;
+1DD9;COMBINING LATIN SMALL LETTER ETH;Mn;230;NSM;;;;;N;;;;;
+1DDA;COMBINING LATIN SMALL LETTER G;Mn;230;NSM;;;;;N;;;;;
+1DDB;COMBINING LATIN LETTER SMALL CAPITAL G;Mn;230;NSM;;;;;N;;;;;
+1DDC;COMBINING LATIN SMALL LETTER K;Mn;230;NSM;;;;;N;;;;;
+1DDD;COMBINING LATIN SMALL LETTER L;Mn;230;NSM;;;;;N;;;;;
+1DDE;COMBINING LATIN LETTER SMALL CAPITAL L;Mn;230;NSM;;;;;N;;;;;
+1DDF;COMBINING LATIN LETTER SMALL CAPITAL M;Mn;230;NSM;;;;;N;;;;;
+1DE0;COMBINING LATIN SMALL LETTER N;Mn;230;NSM;;;;;N;;;;;
+1DE1;COMBINING LATIN LETTER SMALL CAPITAL N;Mn;230;NSM;;;;;N;;;;;
+1DE2;COMBINING LATIN LETTER SMALL CAPITAL R;Mn;230;NSM;;;;;N;;;;;
+1DE3;COMBINING LATIN SMALL LETTER R ROTUNDA;Mn;230;NSM;;;;;N;;;;;
+1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;;
+1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;;
+1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;;
+1DE7;COMBINING LATIN SMALL LETTER ALPHA;Mn;230;NSM;;;;;N;;;;;
+1DE8;COMBINING LATIN SMALL LETTER B;Mn;230;NSM;;;;;N;;;;;
+1DE9;COMBINING LATIN SMALL LETTER BETA;Mn;230;NSM;;;;;N;;;;;
+1DEA;COMBINING LATIN SMALL LETTER SCHWA;Mn;230;NSM;;;;;N;;;;;
+1DEB;COMBINING LATIN SMALL LETTER F;Mn;230;NSM;;;;;N;;;;;
+1DEC;COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Mn;230;NSM;;;;;N;;;;;
+1DED;COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;;
+1DEE;COMBINING LATIN SMALL LETTER P;Mn;230;NSM;;;;;N;;;;;
+1DEF;COMBINING LATIN SMALL LETTER ESH;Mn;230;NSM;;;;;N;;;;;
+1DF0;COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE;Mn;230;NSM;;;;;N;;;;;
+1DF1;COMBINING LATIN SMALL LETTER W;Mn;230;NSM;;;;;N;;;;;
+1DF2;COMBINING LATIN SMALL LETTER A WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;
+1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;
+1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;;
+1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;;
+1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;;
+1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;;
+1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01;
+1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00
+1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03;
+1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02
+1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05;
+1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04
+1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07;
+1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06
+1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09;
+1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08
+1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B;
+1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A
+1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D;
+1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C
+1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F;
+1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E
+1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11;
+1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10
+1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13;
+1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12
+1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15;
+1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14
+1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17;
+1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16
+1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19;
+1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18
+1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B;
+1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A
+1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D;
+1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C
+1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F;
+1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E
+1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21;
+1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20
+1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23;
+1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22
+1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25;
+1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24
+1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27;
+1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26
+1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29;
+1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28
+1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B;
+1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A
+1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D;
+1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C
+1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F;
+1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E
+1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31;
+1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30
+1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33;
+1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32
+1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35;
+1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34
+1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37;
+1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36
+1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39;
+1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38
+1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B;
+1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A
+1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D;
+1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C
+1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F;
+1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E
+1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41;
+1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40
+1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43;
+1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42
+1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45;
+1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44
+1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47;
+1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46
+1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49;
+1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48
+1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B;
+1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A
+1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D;
+1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C
+1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F;
+1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E
+1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51;
+1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50
+1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53;
+1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52
+1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55;
+1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54
+1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57;
+1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56
+1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59;
+1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58
+1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B;
+1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A
+1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D;
+1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C
+1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F;
+1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E
+1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61;
+1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60
+1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63;
+1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62
+1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65;
+1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64
+1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67;
+1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66
+1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69;
+1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68
+1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B;
+1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A
+1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D;
+1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C
+1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F;
+1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E
+1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71;
+1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70
+1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73;
+1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72
+1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75;
+1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74
+1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77;
+1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76
+1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79;
+1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78
+1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B;
+1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A
+1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D;
+1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C
+1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F;
+1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E
+1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81;
+1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80
+1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83;
+1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82
+1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85;
+1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84
+1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87;
+1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86
+1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89;
+1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88
+1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B;
+1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A
+1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D;
+1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C
+1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F;
+1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E
+1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91;
+1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90
+1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93;
+1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92
+1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95;
+1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94
+1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;;
+1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;;
+1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;;
+1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;;
+1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;;
+1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60
+1E9C;LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;;;
+1E9D;LATIN SMALL LETTER LONG S WITH HIGH STROKE;Ll;0;L;;;;;N;;;;;
+1E9E;LATIN CAPITAL LETTER SHARP S;Lu;0;L;;;;;N;;;;00DF;
+1E9F;LATIN SMALL LETTER DELTA;Ll;0;L;;;;;N;;;;;
+1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1;
+1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0
+1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3;
+1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2
+1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5;
+1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4
+1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7;
+1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6
+1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9;
+1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8
+1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB;
+1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA
+1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD;
+1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC
+1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF;
+1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE
+1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1;
+1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0
+1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3;
+1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2
+1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5;
+1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4
+1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7;
+1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6
+1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9;
+1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8
+1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB;
+1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA
+1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD;
+1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC
+1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF;
+1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE
+1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1;
+1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0
+1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3;
+1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2
+1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5;
+1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4
+1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7;
+1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6
+1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9;
+1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8
+1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB;
+1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA
+1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD;
+1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
+1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF;
+1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE
+1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1;
+1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0
+1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3;
+1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2
+1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5;
+1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4
+1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7;
+1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6
+1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9;
+1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
+1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB;
+1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA
+1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD;
+1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC
+1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF;
+1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE
+1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1;
+1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0
+1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3;
+1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2
+1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5;
+1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4
+1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7;
+1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6
+1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9;
+1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8
+1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB;
+1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA
+1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED;
+1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC
+1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF;
+1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE
+1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1;
+1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0
+1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3;
+1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2
+1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5;
+1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4
+1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7;
+1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6
+1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9;
+1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8
+1EFA;LATIN CAPITAL LETTER MIDDLE-WELSH LL;Lu;0;L;;;;;N;;;;1EFB;
+1EFB;LATIN SMALL LETTER MIDDLE-WELSH LL;Ll;0;L;;;;;N;;;1EFA;;1EFA
+1EFC;LATIN CAPITAL LETTER MIDDLE-WELSH V;Lu;0;L;;;;;N;;;;1EFD;
+1EFD;LATIN SMALL LETTER MIDDLE-WELSH V;Ll;0;L;;;;;N;;;1EFC;;1EFC
+1EFE;LATIN CAPITAL LETTER Y WITH LOOP;Lu;0;L;;;;;N;;;;1EFF;
+1EFF;LATIN SMALL LETTER Y WITH LOOP;Ll;0;L;;;;;N;;;1EFE;;1EFE
+1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08
+1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09
+1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A
+1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B
+1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C
+1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D
+1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E
+1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F
+1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00;
+1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01;
+1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02;
+1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03;
+1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04;
+1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05;
+1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06;
+1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07;
+1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18
+1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19
+1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A
+1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B
+1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C
+1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D
+1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10;
+1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11;
+1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12;
+1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13;
+1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14;
+1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15;
+1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28
+1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29
+1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A
+1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B
+1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C
+1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D
+1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E
+1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F
+1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20;
+1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21;
+1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22;
+1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23;
+1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24;
+1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25;
+1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26;
+1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27;
+1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38
+1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39
+1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A
+1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B
+1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C
+1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D
+1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E
+1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F
+1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30;
+1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31;
+1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32;
+1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33;
+1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34;
+1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35;
+1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36;
+1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37;
+1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48
+1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49
+1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A
+1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B
+1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C
+1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D
+1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40;
+1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41;
+1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42;
+1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43;
+1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44;
+1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45;
+1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;;
+1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59
+1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;;
+1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B
+1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;;
+1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D
+1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;;
+1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F
+1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51;
+1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53;
+1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55;
+1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57;
+1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68
+1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69
+1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A
+1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B
+1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C
+1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D
+1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E
+1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F
+1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60;
+1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61;
+1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62;
+1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63;
+1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64;
+1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65;
+1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66;
+1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67;
+1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA
+1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB
+1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8
+1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9
+1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA
+1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB
+1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA
+1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB
+1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8
+1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9
+1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA
+1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB
+1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA
+1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB
+1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88
+1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89
+1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A
+1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B
+1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C
+1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D
+1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E
+1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F
+1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80;
+1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81;
+1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82;
+1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83;
+1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84;
+1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85;
+1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86;
+1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87;
+1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98
+1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99
+1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A
+1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B
+1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C
+1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D
+1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E
+1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F
+1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90;
+1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91;
+1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92;
+1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93;
+1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94;
+1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95;
+1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96;
+1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97;
+1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8
+1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9
+1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA
+1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB
+1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC
+1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD
+1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE
+1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF
+1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0;
+1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1;
+1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2;
+1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3;
+1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4;
+1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5;
+1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6;
+1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7;
+1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8
+1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9
+1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;;
+1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC
+1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;;
+1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;;
+1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;;
+1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0;
+1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1;
+1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70;
+1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71;
+1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3;
+1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399
+1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;;
+1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;;
+1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;;
+1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC
+1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;;
+1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;;
+1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;;
+1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72;
+1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73;
+1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74;
+1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75;
+1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3;
+1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;;
+1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;;
+1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;;
+1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8
+1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9
+1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;;
+1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;;
+1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;;
+1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;;
+1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0;
+1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1;
+1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76;
+1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77;
+1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;;
+1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;;
+1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;;
+1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8
+1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9
+1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;;
+1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;;
+1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;;
+1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC
+1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;;
+1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;;
+1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0;
+1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1;
+1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A;
+1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B;
+1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5;
+1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;;
+1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;;
+1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;;
+1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;;
+1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC
+1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;;
+1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;;
+1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;;
+1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78;
+1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79;
+1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C;
+1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D;
+1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3;
+1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;;
+1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;;
+2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
+2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
+2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
+2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;;
+200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;;
+200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;;
+200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;
+200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;;
+2010;HYPHEN;Pd;0;ON;;;;;N;;;;;
+2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;;
+2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;;
+2013;EN DASH;Pd;0;ON;;;;;N;;;;;
+2014;EM DASH;Pd;0;ON;;;;;N;;;;;
+2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;;
+2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;;
+2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;;
+2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;;
+2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;;
+201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;;
+201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;;
+201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;;
+201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;;
+201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;;
+201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;;
+2020;DAGGER;Po;0;ON;;;;;N;;;;;
+2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;;
+2022;BULLET;Po;0;ON;;;;;N;;;;;
+2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;;
+2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;;
+2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;;
+2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;;
+2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;;
+2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;;
+2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;;
+202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;;
+202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;;
+202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;;
+202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;;
+202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;;
+202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
+2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;;
+2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;
+2032;PRIME;Po;0;ET;;;;;N;;;;;
+2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;;
+2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;;
+2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;;
+2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;;
+2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;;
+2038;CARET;Po;0;ON;;;;;N;;;;;
+2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;;
+203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;;
+203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;;
+203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;;
+203D;INTERROBANG;Po;0;ON;;;;;N;;;;;
+203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;;
+203F;UNDERTIE;Pc;0;ON;;;;;N;;;;;
+2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;;
+2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;;
+2042;ASTERISM;Po;0;ON;;;;;N;;;;;
+2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;;
+2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;;
+2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;;
+2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;;
+2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;;
+2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;;
+2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;;
+204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;;
+204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;;
+204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;;
+204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;;
+2050;CLOSE UP;Po;0;ON;;;;;N;;;;;
+2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;;
+2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2053;SWUNG DASH;Po;0;ON;;;;;N;;;;;
+2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;;
+2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;;
+2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;;
+2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;;
+205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;;
+205D;TRICOLON;Po;0;ON;;;;;N;;;;;
+205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;;
+205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2060;WORD JOINER;Cf;0;BN;;;;;N;;;;;
+2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;;
+2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;;
+2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;;
+2064;INVISIBLE PLUS;Cf;0;BN;;;;;N;;;;;
+2066;LEFT-TO-RIGHT ISOLATE;Cf;0;LRI;;;;;N;;;;;
+2067;RIGHT-TO-LEFT ISOLATE;Cf;0;RLI;;;;;N;;;;;
+2068;FIRST STRONG ISOLATE;Cf;0;FSI;;;;;N;;;;;
+2069;POP DIRECTIONAL ISOLATE;Cf;0;PDI;;;;;N;;;;;
+206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;;
+2071;SUPERSCRIPT LATIN SMALL LETTER I;Lm;0;L;<super> 0069;;;;N;;;;;
+2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;;
+2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;;
+2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;;
+2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;;
+2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;;
+2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;;
+207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;;
+207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;;
+207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;;
+207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;;
+207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;;
+207F;SUPERSCRIPT LATIN SMALL LETTER N;Lm;0;L;<super> 006E;;;;N;;;;;
+2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;;
+2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;;
+2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;;
+2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;;
+2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;;
+2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;;
+2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;;
+2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;;
+2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;;
+2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;;
+208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;;
+208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;;
+208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;;
+208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;;
+208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;;
+2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;;
+2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;;
+2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;;
+2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;;
+2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;;
+2095;LATIN SUBSCRIPT SMALL LETTER H;Lm;0;L;<sub> 0068;;;;N;;;;;
+2096;LATIN SUBSCRIPT SMALL LETTER K;Lm;0;L;<sub> 006B;;;;N;;;;;
+2097;LATIN SUBSCRIPT SMALL LETTER L;Lm;0;L;<sub> 006C;;;;N;;;;;
+2098;LATIN SUBSCRIPT SMALL LETTER M;Lm;0;L;<sub> 006D;;;;N;;;;;
+2099;LATIN SUBSCRIPT SMALL LETTER N;Lm;0;L;<sub> 006E;;;;N;;;;;
+209A;LATIN SUBSCRIPT SMALL LETTER P;Lm;0;L;<sub> 0070;;;;N;;;;;
+209B;LATIN SUBSCRIPT SMALL LETTER S;Lm;0;L;<sub> 0073;;;;N;;;;;
+209C;LATIN SUBSCRIPT SMALL LETTER T;Lm;0;L;<sub> 0074;;;;N;;;;;
+20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;;
+20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;;
+20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;;
+20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;;
+20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;;
+20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;;
+20A9;WON SIGN;Sc;0;ET;;;;;N;;;;;
+20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;;
+20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;;
+20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;;
+20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;;
+20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;;
+20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;;
+20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;;
+20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;;
+20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;;
+20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;;
+20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;;
+20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;;
+20B6;LIVRE TOURNOIS SIGN;Sc;0;ET;;;;;N;;;;;
+20B7;SPESMILO SIGN;Sc;0;ET;;;;;N;;;;;
+20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;;
+20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+20BA;TURKISH LIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20BB;NORDIC MARK SIGN;Sc;0;ET;;;;;N;;;;;
+20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;;
+20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;;
+20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;;
+20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
+20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
+20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
+20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;;
+20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;;
+20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;;
+20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;;
+20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;;
+20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;;
+20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;;
+20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;;
+20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;;
+20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;;
+20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;
+20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;
+20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;
+20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;
+20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;;
+20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;
+20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;
+20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;;
+20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;;
+20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;;
+20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20EC;COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;;
+20ED;COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS;Mn;220;NSM;;;;;N;;;;;
+20EE;COMBINING LEFT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+20EF;COMBINING RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+20F0;COMBINING ASTERISK ABOVE;Mn;230;NSM;;;;;N;;;;;
+2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;;
+2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;;
+2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;;
+2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;;
+2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;;
+2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;;
+2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;;
+2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;;
+2108;SCRUPLE;So;0;ON;;;;;N;;;;;
+2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;;
+210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;;
+210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;;
+210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;;
+210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;;
+210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;;
+2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;;
+2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;;
+2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;;
+2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;;
+2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;;
+2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;;
+2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;;
+2118;SCRIPT CAPITAL P;Sm;0;ON;;;;;N;SCRIPT P;;;;
+2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;;
+211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;;
+211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;;
+211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;;
+211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;;
+211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;;
+211F;RESPONSE;So;0;ON;;;;;N;;;;;
+2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;;
+2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;
+2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;;
+2123;VERSICLE;So;0;ON;;;;;N;;;;;
+2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;;
+2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;;
+2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9;
+2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;;
+2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;;
+2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;;
+212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5;
+212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;;
+212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;;
+212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;;
+212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;;
+2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;;
+2132;TURNED CAPITAL F;Lu;0;L;;;;;N;TURNED F;;;214E;
+2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;;
+2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;;
+2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;;
+2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;;
+2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;;
+2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;;
+213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;;
+213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;;
+213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;;
+2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;;
+2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;;
+2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+214A;PROPERTY LINE;So;0;ON;;;;;N;;;;;
+214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;;
+214C;PER SIGN;So;0;ON;;;;;N;;;;;
+214D;AKTIESELSKAB;So;0;ON;;;;;N;;;;;
+214E;TURNED SMALL F;Ll;0;L;;;;;N;;;2132;;2132
+214F;SYMBOL FOR SAMARITAN SOURCE;So;0;L;;;;;N;;;;;
+2150;VULGAR FRACTION ONE SEVENTH;No;0;ON;<fraction> 0031 2044 0037;;;1/7;N;;;;;
+2151;VULGAR FRACTION ONE NINTH;No;0;ON;<fraction> 0031 2044 0039;;;1/9;N;;;;;
+2152;VULGAR FRACTION ONE TENTH;No;0;ON;<fraction> 0031 2044 0031 0030;;;1/10;N;;;;;
+2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;;
+2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;;
+2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;;
+2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;;
+2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;;
+2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;;
+2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;;
+215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;;
+215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;;
+215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;;
+215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;;
+215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;;
+215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;;
+2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170;
+2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171;
+2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172;
+2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173;
+2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174;
+2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175;
+2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176;
+2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177;
+2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178;
+2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179;
+216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A;
+216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B;
+216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C;
+216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D;
+216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E;
+216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F;
+2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160
+2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161
+2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162
+2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163
+2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164
+2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165
+2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166
+2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167
+2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168
+2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169
+217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A
+217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B
+217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C
+217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D
+217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E
+217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F
+2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;;
+2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;;
+2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;;
+2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Lu;0;L;;;;;N;;;;2184;
+2184;LATIN SMALL LETTER REVERSED C;Ll;0;L;;;;;N;;;2183;;2183
+2185;ROMAN NUMERAL SIX LATE FORM;Nl;0;L;;;;6;N;;;;;
+2186;ROMAN NUMERAL FIFTY EARLY FORM;Nl;0;L;;;;50;N;;;;;
+2187;ROMAN NUMERAL FIFTY THOUSAND;Nl;0;L;;;;50000;N;;;;;
+2188;ROMAN NUMERAL ONE HUNDRED THOUSAND;Nl;0;L;;;;100000;N;;;;;
+2189;VULGAR FRACTION ZERO THIRDS;No;0;ON;<fraction> 0030 2044 0033;;;0;N;;;;;
+218A;TURNED DIGIT TWO;So;0;ON;;;;;N;;;;;
+218B;TURNED DIGIT THREE;So;0;ON;;;;;N;;;;;
+2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;;
+2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;;
+2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;;
+2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;;
+2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;;
+2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;;
+2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;;
+2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;;
+2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;;
+219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;;
+219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;;
+219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;;
+219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;;
+219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;;
+219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;;
+21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;;
+21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;;
+21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;;
+21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;;
+21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;;
+21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;;
+21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;;
+21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;;
+21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;;
+21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;;
+21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;;
+21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;;
+21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;;
+21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;;
+21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;;
+21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;;
+21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;;
+21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;;
+21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;;
+21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;;
+21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;;
+21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;;
+21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;;
+21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;;
+21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;;
+21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;;
+21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;;
+21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;;
+21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;;
+21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;;
+21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;;
+21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;;
+21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;;
+21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;;
+21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;;
+21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;;
+21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;;
+21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;;
+21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;;
+21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;;
+21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;;
+21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;;
+21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;;
+21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;;
+21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;;
+21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;;
+21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;;
+21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;;
+21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;;
+21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;;
+21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;;
+21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;;
+21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;;
+21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;;
+21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;;
+21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;;
+21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;;
+21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;;
+21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;;
+21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;;
+21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;;
+21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;;
+21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;;
+21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;;
+21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;;
+21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;;
+21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;;
+21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;;
+21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;;
+21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
+21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;;
+21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;;
+21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;
+21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+2200;FOR ALL;Sm;0;ON;;;;;N;;;;;
+2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;;
+2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;;
+2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;;
+2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;;
+2205;EMPTY SET;Sm;0;ON;;;;;N;;;;;
+2206;INCREMENT;Sm;0;ON;;;;;N;;;;;
+2207;NABLA;Sm;0;ON;;;;;N;;;;;
+2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;;
+220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;;
+220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220E;END OF PROOF;Sm;0;ON;;;;;N;;;;;
+220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;;
+2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;;
+2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;;
+2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;;
+2214;DOT PLUS;Sm;0;ON;;;;;N;;;;;
+2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2216;SET MINUS;Sm;0;ON;;;;;Y;;;;;
+2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;;
+221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;;
+221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;;
+221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;;
+221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;;
+221E;INFINITY;Sm;0;ON;;;;;N;;;;;
+221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;;
+2220;ANGLE;Sm;0;ON;;;;;Y;;;;;
+2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;;
+2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+2223;DIVIDES;Sm;0;ON;;;;;N;;;;;
+2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;;
+2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;;
+2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2229;INTERSECTION;Sm;0;ON;;;;;N;;;;;
+222A;UNION;Sm;0;ON;;;;;N;;;;;
+222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;;
+222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;;
+222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;;
+2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;;
+2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2234;THEREFORE;Sm;0;ON;;;;;N;;;;;
+2235;BECAUSE;Sm;0;ON;;;;;N;;;;;
+2236;RATIO;Sm;0;ON;;;;;N;;;;;
+2237;PROPORTION;Sm;0;ON;;;;;N;;;;;
+2238;DOT MINUS;Sm;0;ON;;;;;N;;;;;
+2239;EXCESS;Sm;0;ON;;;;;Y;;;;;
+223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;;
+223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;;
+223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;;;;
+223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;;
+223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;;
+2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;;
+2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;;
+2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;;
+2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;;
+2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;;
+224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;;
+224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;;
+2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;;
+2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;;
+2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;;
+2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;;
+2259;ESTIMATES;Sm;0;ON;;;;;N;;;;;
+225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;;
+225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;;
+225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;;
+225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;;
+225E;MEASURED BY;Sm;0;ON;;;;;N;;;;;
+225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;;
+2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;;
+2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;;
+2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;;
+2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;;
+2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;;
+2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;;
+2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;;
+2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;;
+226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;;
+226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;;
+226C;BETWEEN;Sm;0;ON;;;;;N;;;;;
+226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;;
+226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;;
+226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;;
+2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;;
+2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;;
+2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;;
+2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;;
+2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;;
+2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;;
+2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;;
+2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;;
+2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;;
+2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;;
+227A;PRECEDES;Sm;0;ON;;;;;Y;;;;;
+227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;;
+2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;;
+2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;;
+2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;;
+2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;;
+2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;;
+2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;;
+2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;;
+228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;;
+228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;;
+228C;MULTISET;Sm;0;ON;;;;;Y;;;;;
+228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;;
+228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;;
+228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;;
+2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;;
+2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;;
+2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;;
+2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;;
+229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;;
+229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;;
+229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;;
+22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;;
+22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;;
+22A5;UP TACK;Sm;0;ON;;;;;N;;;;;
+22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;;
+22A7;MODELS;Sm;0;ON;;;;;Y;;;;;
+22A8;TRUE;Sm;0;ON;;;;;Y;;;;;
+22A9;FORCES;Sm;0;ON;;;;;Y;;;;;
+22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;;
+22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;;
+22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;;
+22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;;
+22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;;
+22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;;
+22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;;
+22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;;
+22BB;XOR;Sm;0;ON;;;;;N;;;;;
+22BC;NAND;Sm;0;ON;;;;;N;;;;;
+22BD;NOR;Sm;0;ON;;;;;N;;;;;
+22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;;
+22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;;
+22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;;
+22C8;BOWTIE;Sm;0;ON;;;;;N;;;;;
+22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;;
+22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;;
+22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;;
+22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;;
+22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;;
+22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;;
+22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;;
+22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;;
+22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;;
+22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;;
+22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;;
+22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;;
+22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;;
+22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;;
+22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;;
+22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;;
+22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;;
+22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;;
+22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;;
+22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;;
+22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;;
+22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;;
+22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;;
+22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;;
+22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;;
+2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;;
+2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;;
+2302;HOUSE;So;0;ON;;;;;N;;;;;
+2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;;
+2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;;
+2305;PROJECTIVE;So;0;ON;;;;;N;;;;;
+2306;PERSPECTIVE;So;0;ON;;;;;N;;;;;
+2307;WAVY LINE;So;0;ON;;;;;N;;;;;
+2308;LEFT CEILING;Ps;0;ON;;;;;Y;;;;;
+2309;RIGHT CEILING;Pe;0;ON;;;;;Y;;;;;
+230A;LEFT FLOOR;Ps;0;ON;;;;;Y;;;;;
+230B;RIGHT FLOOR;Pe;0;ON;;;;;Y;;;;;
+230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;;
+230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;;
+230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;;
+230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;;
+2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;;
+2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;;
+2312;ARC;So;0;ON;;;;;N;;;;;
+2313;SEGMENT;So;0;ON;;;;;N;;;;;
+2314;SECTOR;So;0;ON;;;;;N;;;;;
+2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;
+2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;;
+2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;;
+2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;;
+2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;;
+231A;WATCH;So;0;ON;;;;;N;;;;;
+231B;HOURGLASS;So;0;ON;;;;;N;;;;;
+231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;;
+231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;;
+231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;;
+231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;;
+2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2322;FROWN;So;0;ON;;;;;N;;;;;
+2323;SMILE;So;0;ON;;;;;N;;;;;
+2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;;
+2325;OPTION KEY;So;0;ON;;;;;N;;;;;
+2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;;
+2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;;
+2328;KEYBOARD;So;0;ON;;;;;N;;;;;
+2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;;
+232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;;
+232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;;
+232C;BENZENE RING;So;0;ON;;;;;N;;;;;
+232D;CYLINDRICITY;So;0;ON;;;;;N;;;;;
+232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;;
+232F;SYMMETRY;So;0;ON;;;;;N;;;;;
+2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;;
+2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;;
+2332;CONICAL TAPER;So;0;ON;;;;;N;;;;;
+2333;SLOPE;So;0;ON;;;;;N;;;;;
+2334;COUNTERBORE;So;0;ON;;;;;N;;;;;
+2335;COUNTERSINK;So;0;ON;;;;;N;;;;;
+2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;;
+2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;;
+2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;;
+2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;;
+233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;;
+233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;;
+233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;;
+233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;;
+233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;;
+233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;;
+2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;;
+2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;;
+2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;;
+2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;;
+2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;;
+2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;;
+2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;;
+2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;;
+2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;;
+2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;;
+234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;;;;
+234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;;
+234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;;
+234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;;
+234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;;;;
+234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;;
+2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;;
+2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;;;;
+2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;;
+2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;;
+2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;;
+2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;;;;
+2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;;
+2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;;
+2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;;
+2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;;
+235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;;
+235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;;
+235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;;
+235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;;
+235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;;
+235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;;
+2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;;
+2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;;;;
+2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;;
+2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;;
+2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;;
+2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;;
+2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;;
+2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;;
+2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;;
+2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;;
+236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;;
+236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;;
+236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;;
+236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;;
+236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;;
+236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;;
+2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;;
+2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;;
+2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;;
+2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;;
+2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;;
+2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;;
+2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;;
+2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;;
+2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;;
+2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;;
+237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;;
+237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;;
+237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;;
+237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;;
+237E;BELL SYMBOL;So;0;ON;;;;;N;;;;;
+237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;
+2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;;
+2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;;
+2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;;
+2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;;
+2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;;
+2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2388;HELM SYMBOL;So;0;ON;;;;;N;;;;;
+2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;;;;
+238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;;;;
+238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;;;;
+238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;;
+238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;;
+238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;;
+238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;;
+2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;;
+2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;;
+2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;;
+2398;NEXT PAGE;So;0;ON;;;;;N;;;;;
+2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;;
+23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;;
+23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;;
+23B4;TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;;
+23B5;BOTTOM SQUARE BRACKET;So;0;ON;;;;;N;;;;;
+23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;So;0;ON;;;;;N;;;;;
+23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;;
+23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;;
+23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;;
+23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;;
+23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;;
+23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;;
+23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;;
+23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;;
+23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;;
+23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;;
+23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;;
+23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;;
+23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;;
+23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;;
+23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;;
+23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;;
+23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;;
+23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;;
+23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;;
+23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;;
+23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;;
+23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;;
+23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;;
+23DA;EARTH GROUND;So;0;ON;;;;;N;;;;;
+23DB;FUSE;So;0;ON;;;;;N;;;;;
+23DC;TOP PARENTHESIS;Sm;0;ON;;;;;N;;;;;
+23DD;BOTTOM PARENTHESIS;Sm;0;ON;;;;;N;;;;;
+23DE;TOP CURLY BRACKET;Sm;0;ON;;;;;N;;;;;
+23DF;BOTTOM CURLY BRACKET;Sm;0;ON;;;;;N;;;;;
+23E0;TOP TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;;
+23E1;BOTTOM TORTOISE SHELL BRACKET;Sm;0;ON;;;;;N;;;;;
+23E2;WHITE TRAPEZIUM;So;0;ON;;;;;N;;;;;
+23E3;BENZENE RING WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23E4;STRAIGHTNESS;So;0;ON;;;;;N;;;;;
+23E5;FLATNESS;So;0;ON;;;;;N;;;;;
+23E6;AC CURRENT;So;0;ON;;;;;N;;;;;
+23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;;
+23E8;DECIMAL EXPONENT SYMBOL;So;0;ON;;;;;N;;;;;
+23E9;BLACK RIGHT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;
+23EA;BLACK LEFT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;
+23EB;BLACK UP-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;
+23EC;BLACK DOWN-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;;
+23ED;BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+23EE;BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+23EF;BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;;
+23F0;ALARM CLOCK;So;0;ON;;;;;N;;;;;
+23F1;STOPWATCH;So;0;ON;;;;;N;;;;;
+23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;;
+23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;;
+23F4;BLACK MEDIUM LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;
+23F5;BLACK MEDIUM RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;
+23F6;BLACK MEDIUM UP-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;
+23F7;BLACK MEDIUM DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;
+23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;;
+23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;;
+23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;;
+23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;;
+23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;;
+23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;;
+23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;;
+2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;
+2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;
+2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;
+2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;;
+2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;;
+2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;;
+2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;;
+2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;;
+2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;;
+2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;;
+240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;;
+240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;;
+240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;;
+240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;;
+240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;;
+240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;;
+2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;;
+2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;;
+2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;;
+2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;;
+2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;;
+2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;;
+2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;;
+2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;;
+2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;;
+2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;;
+241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;;
+241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;;
+241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;;
+241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;;
+241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;;
+241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;;
+2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;;
+2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;;
+2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;;
+2423;OPEN BOX;So;0;ON;;;;;N;;;;;
+2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;;
+2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;;
+2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;;
+2440;OCR HOOK;So;0;ON;;;;;N;;;;;
+2441;OCR CHAIR;So;0;ON;;;;;N;;;;;
+2442;OCR FORK;So;0;ON;;;;;N;;;;;
+2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;;
+2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;;
+2445;OCR BOW TIE;So;0;ON;;;;;N;;;;;
+2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;;
+2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;;
+2448;OCR DASH;So;0;ON;;;;;N;;;;;
+2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;;
+244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;;
+2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;;
+2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;;
+2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;;
+2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;;
+2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;;
+2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;;
+2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;;
+2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;;
+2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;;
+2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;;
+246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;;
+246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;;
+246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;;
+246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;;
+246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;;
+246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;;
+2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;;
+2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;;
+2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;;
+2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;;
+2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;;
+2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;;
+2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;;
+2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;;
+2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;;
+2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;;
+247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;;
+247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;;
+247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;;
+247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;;
+247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;;
+247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;;
+2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;;
+2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;;
+2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;;
+2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;;
+2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;;
+2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;;
+2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;;
+2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;;
+2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;;
+2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;;
+248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;;
+248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;;
+248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;;
+248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;;
+248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;;
+248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;;
+2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;;
+2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;;
+2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;;
+2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;;
+2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;;
+2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;;
+2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;;
+2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;;
+2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;;
+2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;;
+249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;;
+249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;;
+249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;;
+249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;;
+249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;;
+249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;;
+24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;;
+24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;;
+24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;;
+24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;;
+24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;;
+24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;;
+24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;;
+24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;;
+24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;;
+24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;;
+24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;;
+24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;;
+24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;;
+24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;;
+24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;;
+24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;;
+24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;;
+24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;;
+24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;;
+24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;;
+24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;;
+24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;;
+24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0;
+24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1;
+24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2;
+24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3;
+24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4;
+24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5;
+24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6;
+24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7;
+24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8;
+24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9;
+24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA;
+24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB;
+24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC;
+24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD;
+24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE;
+24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF;
+24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0;
+24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1;
+24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2;
+24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3;
+24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4;
+24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5;
+24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6;
+24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7;
+24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8;
+24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9;
+24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6
+24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7
+24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8
+24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9
+24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA
+24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB
+24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC
+24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD
+24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE
+24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF
+24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0
+24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1
+24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2
+24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3
+24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4
+24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5
+24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6
+24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7
+24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8
+24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9
+24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA
+24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB
+24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC
+24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD
+24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE
+24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF
+24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;;
+24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;;
+24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;;
+24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;;
+24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;;
+24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;;
+24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;;
+24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;;
+24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;;
+24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;;
+24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;;
+24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;;
+24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;;
+24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;;
+24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;;
+24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;;
+24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;;
+24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;;
+24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;;
+24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;;
+24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;;
+24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;;
+2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;;
+2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;;
+2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;;
+2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;;
+2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;;
+2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;;
+2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;;
+2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;;
+2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;;
+2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;;
+250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;;
+250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;;
+250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;;
+250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;;
+250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;;
+250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;;
+2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;;
+2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;;
+2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;;
+2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;;
+2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;;
+2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;;
+2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;;
+2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;;
+2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;;
+2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;;
+251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;;
+251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;;
+251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;;
+251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;;
+251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;;
+251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;;
+2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;;
+2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;;
+2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;;
+2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;;
+2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;;
+2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;;
+2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;;
+2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;;
+2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;;
+252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;;
+252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;;
+252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;;
+252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;;
+252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;;
+252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;;
+2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;;
+2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;;
+2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;;
+2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;;
+2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;;
+2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;;
+2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;;
+2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;;
+2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;;
+2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;;
+253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;;
+253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;;
+253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;;
+253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;;
+253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;;
+253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;;
+2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;;
+2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;;
+2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;;
+2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;;
+2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;;
+2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;;
+2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;;
+2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;;
+2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;;
+254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;;
+254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;;
+254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;;
+254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;;
+254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;;
+254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;;
+2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;;
+2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;;
+2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;;
+2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;;
+2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;;
+2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;;
+2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;;
+2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;;
+2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;;
+2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;;
+255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;;
+255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;;
+255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;;
+255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;;
+255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;;
+255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;;
+2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;;
+2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;;
+2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;;
+2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;;
+2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;;
+2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;;
+2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;;
+2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;;
+2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;;
+2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;;
+256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;;
+256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;;
+256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;;
+256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;;
+256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;;
+256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;;
+2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;;
+2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;;
+2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;;
+2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;;
+2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;;
+2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;;
+2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;;
+2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;;
+2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;;
+2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;;
+257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;;
+257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;;
+257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;;
+257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;;
+257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;;
+257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;;
+2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;;
+2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2588;FULL BLOCK;So;0;ON;;;;;N;;;;;
+2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;;
+258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;;
+258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;
+2591;LIGHT SHADE;So;0;ON;;;;;N;;;;;
+2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+2593;DARK SHADE;So;0;ON;;;;;N;;;;;
+2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;;
+2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;;
+2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;;
+2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;;
+259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;;
+25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;;
+25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;;
+25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;
+25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;
+25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;;
+25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;;
+25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;;
+25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;;
+25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;;
+25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;;
+25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;;
+25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;;
+25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;;
+25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;;
+25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;;
+25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;;
+25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;;
+25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;;
+25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;;
+25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;;
+25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;;
+25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;;
+25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;;
+25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;;
+25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;;
+25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;;
+25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;;
+25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;;
+25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+25C9;FISHEYE;So;0;ON;;;;;N;;;;;
+25CA;LOZENGE;So;0;ON;;;;;N;;;;;
+25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;;
+25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25CE;BULLSEYE;So;0;ON;;;;;N;;;;;
+25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;;
+25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E6;WHITE BULLET;So;0;ON;;;;;N;;;;;
+25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;;
+25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;;
+25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;;
+25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;;
+25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+2601;CLOUD;So;0;ON;;;;;N;;;;;
+2602;UMBRELLA;So;0;ON;;;;;N;;;;;
+2603;SNOWMAN;So;0;ON;;;;;N;;;;;
+2604;COMET;So;0;ON;;;;;N;;;;;
+2605;BLACK STAR;So;0;ON;;;;;N;;;;;
+2606;WHITE STAR;So;0;ON;;;;;N;;;;;
+2607;LIGHTNING;So;0;ON;;;;;N;;;;;
+2608;THUNDERSTORM;So;0;ON;;;;;N;;;;;
+2609;SUN;So;0;ON;;;;;N;;;;;
+260A;ASCENDING NODE;So;0;ON;;;;;N;;;;;
+260B;DESCENDING NODE;So;0;ON;;;;;N;;;;;
+260C;CONJUNCTION;So;0;ON;;;;;N;;;;;
+260D;OPPOSITION;So;0;ON;;;;;N;;;;;
+260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;
+260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;;
+2610;BALLOT BOX;So;0;ON;;;;;N;;;;;
+2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;;
+2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;;
+2613;SALTIRE;So;0;ON;;;;;N;;;;;
+2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;;
+2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;;
+2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2618;SHAMROCK;So;0;ON;;;;;N;;;;;
+2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;
+2621;CAUTION SIGN;So;0;ON;;;;;N;;;;;
+2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;;
+2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;;
+2624;CADUCEUS;So;0;ON;;;;;N;;;;;
+2625;ANKH;So;0;ON;;;;;N;;;;;
+2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;;
+2627;CHI RHO;So;0;ON;;;;;N;;;;;
+2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;;
+2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;;
+262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;;
+262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;;
+262C;ADI SHAKTI;So;0;ON;;;;;N;;;;;
+262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;;
+262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;;
+262F;YIN YANG;So;0;ON;;;;;N;;;;;
+2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;;
+2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;;
+2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;;
+2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;;
+2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;;
+2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;;
+2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;;
+2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;;
+2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;;
+263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;;
+263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;;
+263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263F;MERCURY;So;0;ON;;;;;N;;;;;
+2640;FEMALE SIGN;So;0;ON;;;;;N;;;;;
+2641;EARTH;So;0;ON;;;;;N;;;;;
+2642;MALE SIGN;So;0;ON;;;;;N;;;;;
+2643;JUPITER;So;0;ON;;;;;N;;;;;
+2644;SATURN;So;0;ON;;;;;N;;;;;
+2645;URANUS;So;0;ON;;;;;N;;;;;
+2646;NEPTUNE;So;0;ON;;;;;N;;;;;
+2647;PLUTO;So;0;ON;;;;;N;;;;;
+2648;ARIES;So;0;ON;;;;;N;;;;;
+2649;TAURUS;So;0;ON;;;;;N;;;;;
+264A;GEMINI;So;0;ON;;;;;N;;;;;
+264B;CANCER;So;0;ON;;;;;N;;;;;
+264C;LEO;So;0;ON;;;;;N;;;;;
+264D;VIRGO;So;0;ON;;;;;N;;;;;
+264E;LIBRA;So;0;ON;;;;;N;;;;;
+264F;SCORPIUS;So;0;ON;;;;;N;;;;;
+2650;SAGITTARIUS;So;0;ON;;;;;N;;;;;
+2651;CAPRICORN;So;0;ON;;;;;N;;;;;
+2652;AQUARIUS;So;0;ON;;;;;N;;;;;
+2653;PISCES;So;0;ON;;;;;N;;;;;
+2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;;
+2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;;
+2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;;
+2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;;
+2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;;
+265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;;
+265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;;
+265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;;
+265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;;
+265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;;
+2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;;
+2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;;
+2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;;
+2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;;
+2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;;
+2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;;
+2668;HOT SPRINGS;So;0;ON;;;;;N;;;;;
+2669;QUARTER NOTE;So;0;ON;;;;;N;;;;;
+266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;;
+266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;;
+266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;;
+266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;;
+266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;;
+266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;;
+2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;;;;
+2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;;;;
+2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;;;;
+2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;;;;
+2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;;;;
+2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;;;;
+2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;;;;
+267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;;
+267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;;
+267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;;
+2680;DIE FACE-1;So;0;ON;;;;;N;;;;;
+2681;DIE FACE-2;So;0;ON;;;;;N;;;;;
+2682;DIE FACE-3;So;0;ON;;;;;N;;;;;
+2683;DIE FACE-4;So;0;ON;;;;;N;;;;;
+2684;DIE FACE-5;So;0;ON;;;;;N;;;;;
+2685;DIE FACE-6;So;0;ON;;;;;N;;;;;
+2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;;
+2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
+2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;;
+2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;;
+268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;;
+268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;;
+268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;;
+268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;;
+268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;;
+268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;;
+2690;WHITE FLAG;So;0;ON;;;;;N;;;;;
+2691;BLACK FLAG;So;0;ON;;;;;N;;;;;
+2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;;
+2693;ANCHOR;So;0;ON;;;;;N;;;;;
+2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;;
+2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;;
+2696;SCALES;So;0;ON;;;;;N;;;;;
+2697;ALEMBIC;So;0;ON;;;;;N;;;;;
+2698;FLOWER;So;0;ON;;;;;N;;;;;
+2699;GEAR;So;0;ON;;;;;N;;;;;
+269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;;
+269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;;
+269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;;
+269D;OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;
+269E;THREE LINES CONVERGING RIGHT;So;0;ON;;;;;N;;;;;
+269F;THREE LINES CONVERGING LEFT;So;0;ON;;;;;N;;;;;
+26A0;WARNING SIGN;So;0;ON;;;;;N;;;;;
+26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;;
+26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;;
+26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;;
+26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;;
+26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;;
+26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;;
+26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;;
+26B0;COFFIN;So;0;ON;;;;;N;;;;;
+26B1;FUNERAL URN;So;0;ON;;;;;N;;;;;
+26B2;NEUTER;So;0;ON;;;;;N;;;;;
+26B3;CERES;So;0;ON;;;;;N;;;;;
+26B4;PALLAS;So;0;ON;;;;;N;;;;;
+26B5;JUNO;So;0;ON;;;;;N;;;;;
+26B6;VESTA;So;0;ON;;;;;N;;;;;
+26B7;CHIRON;So;0;ON;;;;;N;;;;;
+26B8;BLACK MOON LILITH;So;0;ON;;;;;N;;;;;
+26B9;SEXTILE;So;0;ON;;;;;N;;;;;
+26BA;SEMISEXTILE;So;0;ON;;;;;N;;;;;
+26BB;QUINCUNX;So;0;ON;;;;;N;;;;;
+26BC;SESQUIQUADRATE;So;0;ON;;;;;N;;;;;
+26BD;SOCCER BALL;So;0;ON;;;;;N;;;;;
+26BE;BASEBALL;So;0;ON;;;;;N;;;;;
+26BF;SQUARED KEY;So;0;ON;;;;;N;;;;;
+26C0;WHITE DRAUGHTS MAN;So;0;ON;;;;;N;;;;;
+26C1;WHITE DRAUGHTS KING;So;0;ON;;;;;N;;;;;
+26C2;BLACK DRAUGHTS MAN;So;0;ON;;;;;N;;;;;
+26C3;BLACK DRAUGHTS KING;So;0;ON;;;;;N;;;;;
+26C4;SNOWMAN WITHOUT SNOW;So;0;ON;;;;;N;;;;;
+26C5;SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;;
+26C6;RAIN;So;0;ON;;;;;N;;;;;
+26C7;BLACK SNOWMAN;So;0;ON;;;;;N;;;;;
+26C8;THUNDER CLOUD AND RAIN;So;0;ON;;;;;N;;;;;
+26C9;TURNED WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;
+26CA;TURNED BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;
+26CB;WHITE DIAMOND IN SQUARE;So;0;ON;;;;;N;;;;;
+26CC;CROSSING LANES;So;0;ON;;;;;N;;;;;
+26CD;DISABLED CAR;So;0;ON;;;;;N;;;;;
+26CE;OPHIUCHUS;So;0;ON;;;;;N;;;;;
+26CF;PICK;So;0;ON;;;;;N;;;;;
+26D0;CAR SLIDING;So;0;ON;;;;;N;;;;;
+26D1;HELMET WITH WHITE CROSS;So;0;ON;;;;;N;;;;;
+26D2;CIRCLED CROSSING LANES;So;0;ON;;;;;N;;;;;
+26D3;CHAINS;So;0;ON;;;;;N;;;;;
+26D4;NO ENTRY;So;0;ON;;;;;N;;;;;
+26D5;ALTERNATE ONE-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;
+26D6;BLACK TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;
+26D7;WHITE TWO-WAY LEFT WAY TRAFFIC;So;0;ON;;;;;N;;;;;
+26D8;BLACK LEFT LANE MERGE;So;0;ON;;;;;N;;;;;
+26D9;WHITE LEFT LANE MERGE;So;0;ON;;;;;N;;;;;
+26DA;DRIVE SLOW SIGN;So;0;ON;;;;;N;;;;;
+26DB;HEAVY WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;;;;;
+26DC;LEFT CLOSED ENTRY;So;0;ON;;;;;N;;;;;
+26DD;SQUARED SALTIRE;So;0;ON;;;;;N;;;;;
+26DE;FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE;So;0;ON;;;;;N;;;;;
+26DF;BLACK TRUCK;So;0;ON;;;;;N;;;;;
+26E0;RESTRICTED LEFT ENTRY-1;So;0;ON;;;;;N;;;;;
+26E1;RESTRICTED LEFT ENTRY-2;So;0;ON;;;;;N;;;;;
+26E2;ASTRONOMICAL SYMBOL FOR URANUS;So;0;ON;;;;;N;;;;;
+26E3;HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE;So;0;ON;;;;;N;;;;;
+26E4;PENTAGRAM;So;0;ON;;;;;N;;;;;
+26E5;RIGHT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;;
+26E6;LEFT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;;
+26E7;INVERTED PENTAGRAM;So;0;ON;;;;;N;;;;;
+26E8;BLACK CROSS ON SHIELD;So;0;ON;;;;;N;;;;;
+26E9;SHINTO SHRINE;So;0;ON;;;;;N;;;;;
+26EA;CHURCH;So;0;ON;;;;;N;;;;;
+26EB;CASTLE;So;0;ON;;;;;N;;;;;
+26EC;HISTORIC SITE;So;0;ON;;;;;N;;;;;
+26ED;GEAR WITHOUT HUB;So;0;ON;;;;;N;;;;;
+26EE;GEAR WITH HANDLES;So;0;ON;;;;;N;;;;;
+26EF;MAP SYMBOL FOR LIGHTHOUSE;So;0;ON;;;;;N;;;;;
+26F0;MOUNTAIN;So;0;ON;;;;;N;;;;;
+26F1;UMBRELLA ON GROUND;So;0;ON;;;;;N;;;;;
+26F2;FOUNTAIN;So;0;ON;;;;;N;;;;;
+26F3;FLAG IN HOLE;So;0;ON;;;;;N;;;;;
+26F4;FERRY;So;0;ON;;;;;N;;;;;
+26F5;SAILBOAT;So;0;ON;;;;;N;;;;;
+26F6;SQUARE FOUR CORNERS;So;0;ON;;;;;N;;;;;
+26F7;SKIER;So;0;ON;;;;;N;;;;;
+26F8;ICE SKATE;So;0;ON;;;;;N;;;;;
+26F9;PERSON WITH BALL;So;0;ON;;;;;N;;;;;
+26FA;TENT;So;0;ON;;;;;N;;;;;
+26FB;JAPANESE BANK SYMBOL;So;0;ON;;;;;N;;;;;
+26FC;HEADSTONE GRAVEYARD SYMBOL;So;0;ON;;;;;N;;;;;
+26FD;FUEL PUMP;So;0;ON;;;;;N;;;;;
+26FE;CUP ON BLACK SQUARE;So;0;ON;;;;;N;;;;;
+26FF;WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE;So;0;ON;;;;;N;;;;;
+2700;BLACK SAFETY SCISSORS;So;0;ON;;;;;N;;;;;
+2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;;
+2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;;
+2705;WHITE HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;
+2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;;
+2707;TAPE DRIVE;So;0;ON;;;;;N;;;;;
+2708;AIRPLANE;So;0;ON;;;;;N;;;;;
+2709;ENVELOPE;So;0;ON;;;;;N;;;;;
+270A;RAISED FIST;So;0;ON;;;;;N;;;;;
+270B;RAISED HAND;So;0;ON;;;;;N;;;;;
+270C;VICTORY HAND;So;0;ON;;;;;N;;;;;
+270D;WRITING HAND;So;0;ON;;;;;N;;;;;
+270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+270F;PENCIL;So;0;ON;;;;;N;;;;;
+2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+2711;WHITE NIB;So;0;ON;;;;;N;;;;;
+2712;BLACK NIB;So;0;ON;;;;;N;;;;;
+2713;CHECK MARK;So;0;ON;;;;;N;;;;;
+2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;
+2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2717;BALLOT X;So;0;ON;;;;;N;;;;;
+2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;;
+2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;;
+271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;;
+271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;;
+271D;LATIN CROSS;So;0;ON;;;;;N;;;;;
+271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;
+271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;;
+2720;MALTESE CROSS;So;0;ON;;;;;N;;;;;
+2721;STAR OF DAVID;So;0;ON;;;;;N;;;;;
+2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2728;SPARKLES;So;0;ON;;;;;N;;;;;
+2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;
+272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;;
+272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;;
+272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;;
+272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;;
+2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;;
+2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;;
+2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;;
+273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;;
+273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;;
+2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;;
+2744;SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2747;SPARKLE;So;0;ON;;;;;N;;;;;
+2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;;
+2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274C;CROSS MARK;So;0;ON;;;;;N;;;;;
+274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+274E;NEGATIVE SQUARED CROSS MARK;So;0;ON;;;;;N;;;;;
+274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2753;BLACK QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2754;WHITE QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2755;WHITE EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;;
+2757;HEAVY EXCLAMATION MARK SYMBOL;So;0;ON;;;;;N;;;;;
+2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;;
+2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275F;HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2760;HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;;
+2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;;
+2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;;
+2766;FLORAL HEART;So;0;ON;;;;;N;;;;;
+2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;;
+2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;;
+2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;;
+2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;;
+277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;;
+277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;;
+277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;;
+277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;;
+277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;;
+277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;;
+2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;;
+2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;;
+2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;;
+2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;;
+2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;;
+2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;;
+2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;;
+2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;;
+278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;;
+278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;;
+278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;;
+278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;;
+278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;;
+278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;;
+2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;;
+2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;;
+2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;;
+2795;HEAVY PLUS SIGN;So;0;ON;;;;;N;;;;;
+2796;HEAVY MINUS SIGN;So;0;ON;;;;;N;;;;;
+2797;HEAVY DIVISION SIGN;So;0;ON;;;;;N;;;;;
+2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;;
+2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;;
+279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;;
+279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;;
+279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;;
+279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;;
+279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;;
+279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;;
+27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;;
+27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;;
+27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;;
+27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;;
+27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;;
+27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;;
+27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;;
+27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;;
+27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;;
+27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B0;CURLY LOOP;So;0;ON;;;;;N;;;;;
+27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;;
+27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;;
+27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;;
+27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;;
+27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;;
+27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;;
+27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;;
+27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;;
+27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;;
+27BF;DOUBLE CURLY LOOP;So;0;ON;;;;;N;;;;;
+27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;;
+27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;;
+27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;;
+27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;;
+27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;;
+27C7;OR WITH DOT INSIDE;Sm;0;ON;;;;;N;;;;;
+27C8;REVERSE SOLIDUS PRECEDING SUBSET;Sm;0;ON;;;;;Y;;;;;
+27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+27CB;MATHEMATICAL RISING DIAGONAL;Sm;0;ON;;;;;Y;;;;;
+27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;;
+27CD;MATHEMATICAL FALLING DIAGONAL;Sm;0;ON;;;;;Y;;;;;
+27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;;
+27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;;
+27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;;
+27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;;
+27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;;
+27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;;
+27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;;
+27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;;
+27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;;
+27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;
+27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;
+27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps;0;ON;;;;;Y;;;;;
+27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe;0;ON;;;;;Y;;;;;
+27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;
+2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;;
+2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;;
+2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;;
+2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;;
+2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;;
+2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;;
+2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;;
+2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;;
+2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;;
+2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;;
+280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;;
+280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;;
+280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;;
+280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;;
+280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;;
+280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;;
+2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;;
+2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;;
+2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;;
+2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;;
+2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;;
+2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;;
+2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;;
+2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;;
+2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;;
+2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;;
+281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;;
+281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;;
+281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;;
+281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;;
+281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;;
+281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;;
+2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;;
+2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;;
+2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;;
+2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;;
+2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;;
+2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;;
+2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;;
+2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;;
+2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;;
+2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;;
+282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;;
+282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;;
+282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;;
+282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;;
+282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;;
+282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;;
+2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;;
+2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;;
+2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;;
+2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;;
+2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;;
+2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;;
+2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;;
+2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;;
+2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;;
+2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;;
+283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;;
+283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;;
+283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;;
+283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;;
+283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;;
+283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;;
+2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;;
+2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;;
+2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;;
+2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;;
+2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;;
+2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;;
+2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;;
+2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;;
+2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;;
+2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;;
+284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;;
+284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;;
+284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;;
+284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;;
+284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;;
+284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;;
+2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;;
+2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;;
+2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;;
+2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;;
+2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;;
+2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;;
+2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;;
+2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;;
+2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;;
+2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;;
+285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;;
+285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;;
+285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;;
+285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;;
+285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;;
+285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;;
+2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;;
+2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;;
+2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;;
+2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;;
+2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;;
+2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;;
+2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;;
+2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;;
+2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;;
+2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;;
+286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;;
+286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;;
+286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;;
+286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;;
+286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;;
+286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;;
+2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;;
+2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;;
+2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;;
+2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;;
+2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;;
+2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;;
+2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;;
+2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;;
+2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;;
+2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;;
+287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;;
+287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;;
+287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;;
+287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;;
+287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;;
+287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;;
+2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;;
+2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;;
+2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;;
+2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;;
+2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;;
+2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;;
+2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;;
+2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;;
+2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;;
+2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;;
+288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;;
+288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;;
+288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;;
+288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;;
+288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;;
+288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;;
+2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;;
+2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;;
+2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;;
+2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;;
+2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;;
+2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;;
+2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;;
+2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;;
+2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;;
+2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;;
+289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;;
+289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;;
+289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;;
+289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;;
+289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;;
+289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;;
+28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;;
+28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;;
+28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;;
+28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;;
+28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;;
+28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;;
+28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;;
+28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;;
+28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;;
+28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;;
+28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;;
+28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;;
+28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;;
+28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;;
+28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;;
+28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;;
+28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;;
+28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;;
+28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;;
+28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;;
+28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;;
+28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;;
+28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;;
+28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;;
+28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;;
+28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;;
+28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;;
+28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;;
+28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;;
+28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;;
+28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;;
+28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;;
+28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;;
+28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;;
+28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;;
+28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;;
+28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;;
+28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;;
+28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;;
+28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;;
+28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;;
+28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;;
+28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;;
+28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;;
+28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;;
+28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;;
+28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;;
+28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;;
+28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;;
+28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;;
+28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;;
+28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;;
+28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;;
+28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;;
+28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;;
+28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;;
+28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;;
+28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;;
+28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;;
+28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;;
+28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;;
+28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;;
+28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;;
+28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;;
+28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;;
+28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;;
+28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;;
+28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;;
+28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;;
+28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;;
+28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;;
+28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;;
+28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;;
+28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;;
+28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;;
+28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;;
+28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;;
+28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;;
+28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;;
+28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;;
+28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;;
+28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;;
+28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;;
+28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;;
+28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;;
+28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;;
+28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;;
+28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;;
+28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;;
+28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;;
+28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;;
+28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;;
+28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;;
+28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;;
+28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;;
+28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;;
+2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;
+2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;
+2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;;
+2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;;
+2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;;
+2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;;
+2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;;
+293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;;
+293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;
+2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;;
+2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;;
+297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;;
+2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;;
+2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;;
+2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;;
+2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;;
+2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;;
+2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;
+2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;
+2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;;
+2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;;
+2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;;
+298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;;
+298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;;
+298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;;
+298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;;
+298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;;
+298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;;
+2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;;
+2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;;
+2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;;
+2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;
+2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;
+2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;;
+299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;;
+299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;;
+299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;;
+299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;
+299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;;
+29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;;
+29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;
+29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;;
+29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;;
+29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;;
+29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;;
+29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;;
+29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;;
+29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;;
+29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;;
+29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;;
+29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;;
+29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;;
+29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;;
+29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;;
+29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;;
+29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;;
+29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;;
+29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;;
+29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;;
+29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;;
+29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;;
+29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;;
+29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;;
+29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;;
+29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+29FE;TINY;Sm;0;ON;;;;;N;;;;;
+29FF;MINY;Sm;0;ON;;;;;N;;;;;
+2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;;
+2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;;
+2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;;
+2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;;
+2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;;
+2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;;
+2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;;
+2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;;
+2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;;
+2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;;
+2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;;
+2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;;
+2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1D;JOIN;Sm;0;ON;;;;;N;;;;;
+2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;;
+2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;;
+2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;;
+2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;;
+2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;;
+2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;;
+2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;;
+2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;;
+2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;;
+2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;;
+2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;;
+2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;;
+2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;;
+2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;;
+2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;;
+2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;;
+2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;;
+2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;;
+2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;;
+2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;;
+2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;;
+2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;;
+2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;;
+2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;;
+2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;;;;
+2ADD;NONFORKING;Sm;0;ON;;;;;N;;;;;
+2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;;
+2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;;
+2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;;
+2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;;
+2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;;
+2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;;
+2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;;
+2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;
+2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;
+2B14;SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+2B15;SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+2B16;DIAMOND WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+2B17;DIAMOND WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+2B18;DIAMOND WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;
+2B19;DIAMOND WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;
+2B1A;DOTTED SQUARE;So;0;ON;;;;;N;;;;;
+2B1B;BLACK LARGE SQUARE;So;0;ON;;;;;N;;;;;
+2B1C;WHITE LARGE SQUARE;So;0;ON;;;;;N;;;;;
+2B1D;BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;
+2B1E;WHITE VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;
+2B1F;BLACK PENTAGON;So;0;ON;;;;;N;;;;;
+2B20;WHITE PENTAGON;So;0;ON;;;;;N;;;;;
+2B21;WHITE HEXAGON;So;0;ON;;;;;N;;;;;
+2B22;BLACK HEXAGON;So;0;ON;;;;;N;;;;;
+2B23;HORIZONTAL BLACK HEXAGON;So;0;ON;;;;;N;;;;;
+2B24;BLACK LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+2B25;BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;
+2B26;WHITE MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;
+2B27;BLACK MEDIUM LOZENGE;So;0;ON;;;;;N;;;;;
+2B28;WHITE MEDIUM LOZENGE;So;0;ON;;;;;N;;;;;
+2B29;BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+2B2A;BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;;
+2B2B;WHITE SMALL LOZENGE;So;0;ON;;;;;N;;;;;
+2B2C;BLACK HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;;
+2B2D;WHITE HORIZONTAL ELLIPSE;So;0;ON;;;;;N;;;;;
+2B2E;BLACK VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;;
+2B2F;WHITE VERTICAL ELLIPSE;So;0;ON;;;;;N;;;;;
+2B30;LEFT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+2B31;THREE LEFTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;
+2B32;LEFT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+2B33;LONG LEFTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;
+2B34;LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B35;LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B36;LEFTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2B37;LEFTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2B38;LEFTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;
+2B39;LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B3A;LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B3B;LEFTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;
+2B3C;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B3D;LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2B3E;LEFTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;
+2B3F;WAVE ARROW POINTING DIRECTLY LEFT;Sm;0;ON;;;;;N;;;;;
+2B40;EQUALS SIGN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2B41;REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2B42;LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2B43;RIGHTWARDS ARROW THROUGH GREATER-THAN;Sm;0;ON;;;;;N;;;;;
+2B44;RIGHTWARDS ARROW THROUGH SUPERSET;Sm;0;ON;;;;;N;;;;;
+2B45;LEFTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;;
+2B46;RIGHTWARDS QUADRUPLE ARROW;So;0;ON;;;;;N;;;;;
+2B47;REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2B48;RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2B49;TILDE OPERATOR ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2B4A;LEFTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2B4B;LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2B4C;RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2B4D;DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW;So;0;ON;;;;;N;;;;;
+2B4E;SHORT SLANTED NORTH ARROW;So;0;ON;;;;;N;;;;;
+2B4F;SHORT BACKSLANTED SOUTH ARROW;So;0;ON;;;;;N;;;;;
+2B50;WHITE MEDIUM STAR;So;0;ON;;;;;N;;;;;
+2B51;BLACK SMALL STAR;So;0;ON;;;;;N;;;;;
+2B52;WHITE SMALL STAR;So;0;ON;;;;;N;;;;;
+2B53;BLACK RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;;
+2B54;WHITE RIGHT-POINTING PENTAGON;So;0;ON;;;;;N;;;;;
+2B55;HEAVY LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+2B56;HEAVY OVAL WITH OVAL INSIDE;So;0;ON;;;;;N;;;;;
+2B57;HEAVY CIRCLE WITH CIRCLE INSIDE;So;0;ON;;;;;N;;;;;
+2B58;HEAVY CIRCLE;So;0;ON;;;;;N;;;;;
+2B59;HEAVY CIRCLED SALTIRE;So;0;ON;;;;;N;;;;;
+2B5A;SLANTED NORTH ARROW WITH HOOKED HEAD;So;0;ON;;;;;N;;;;;
+2B5B;BACKSLANTED SOUTH ARROW WITH HOOKED TAIL;So;0;ON;;;;;N;;;;;
+2B5C;SLANTED NORTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;;
+2B5D;BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL;So;0;ON;;;;;N;;;;;
+2B5E;BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;;
+2B5F;SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST;So;0;ON;;;;;N;;;;;
+2B60;LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B61;UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B62;RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B63;DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B64;LEFT RIGHT TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B65;UP DOWN TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B66;NORTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B67;NORTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B68;SOUTH EAST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B69;SOUTH WEST TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B6A;LEFTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;
+2B6B;UPWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;
+2B6C;RIGHTWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;
+2B6D;DOWNWARDS TRIANGLE-HEADED DASHED ARROW;So;0;ON;;;;;N;;;;;
+2B6E;CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+2B6F;ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+2B70;LEFTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B71;UPWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B72;RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B73;DOWNWARDS TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B76;NORTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B77;NORTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B78;SOUTH EAST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B79;SOUTH WEST TRIANGLE-HEADED ARROW TO BAR;So;0;ON;;;;;N;;;;;
+2B7A;LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;
+2B7B;UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;
+2B7C;RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;
+2B7D;DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE;So;0;ON;;;;;N;;;;;
+2B7E;HORIZONTAL TAB KEY;So;0;ON;;;;;N;;;;;
+2B7F;VERTICAL TAB KEY;So;0;ON;;;;;N;;;;;
+2B80;LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B81;UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B82;RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B83;DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW;So;0;ON;;;;;N;;;;;
+2B84;LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;
+2B85;UPWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;
+2B86;RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;
+2B87;DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS;So;0;ON;;;;;N;;;;;
+2B88;LEFTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B89;UPWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B8A;RIGHTWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B8B;DOWNWARDS BLACK CIRCLED WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B8C;ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW;So;0;ON;;;;;N;;;;;
+2B8D;ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW;So;0;ON;;;;;N;;;;;
+2B8E;ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW;So;0;ON;;;;;N;;;;;
+2B8F;ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW;So;0;ON;;;;;N;;;;;
+2B90;RETURN LEFT;So;0;ON;;;;;N;;;;;
+2B91;RETURN RIGHT;So;0;ON;;;;;N;;;;;
+2B92;NEWLINE LEFT;So;0;ON;;;;;N;;;;;
+2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;;
+2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;;
+2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9A;THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9B;THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9C;BLACK LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9D;BLACK UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9E;BLACK RIGHTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2B9F;BLACK DOWNWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+2BA0;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;;
+2BA1;DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;;
+2BA2;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS;So;0;ON;;;;;N;;;;;
+2BA3;UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS;So;0;ON;;;;;N;;;;;
+2BA4;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2BA5;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2BA6;LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2BA7;RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2BA8;BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BA9;BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAA;BLACK CURVED UPWARDS AND LEFTWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAB;BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAC;BLACK CURVED LEFTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAD;BLACK CURVED RIGHTWARDS AND UPWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAE;BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BAF;BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;
+2BB0;RIBBON ARROW DOWN LEFT;So;0;ON;;;;;N;;;;;
+2BB1;RIBBON ARROW DOWN RIGHT;So;0;ON;;;;;N;;;;;
+2BB2;RIBBON ARROW UP LEFT;So;0;ON;;;;;N;;;;;
+2BB3;RIBBON ARROW UP RIGHT;So;0;ON;;;;;N;;;;;
+2BB4;RIBBON ARROW LEFT UP;So;0;ON;;;;;N;;;;;
+2BB5;RIBBON ARROW RIGHT UP;So;0;ON;;;;;N;;;;;
+2BB6;RIBBON ARROW LEFT DOWN;So;0;ON;;;;;N;;;;;
+2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;;
+2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
+2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;;
+2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;;
+2BBE;CIRCLED X;So;0;ON;;;;;N;;;;;
+2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;;
+2BC0;BLACK SQUARE CENTRED;So;0;ON;;;;;N;;;;;
+2BC1;BLACK DIAMOND CENTRED;So;0;ON;;;;;N;;;;;
+2BC2;TURNED BLACK PENTAGON;So;0;ON;;;;;N;;;;;
+2BC3;HORIZONTAL BLACK OCTAGON;So;0;ON;;;;;N;;;;;
+2BC4;BLACK OCTAGON;So;0;ON;;;;;N;;;;;
+2BC5;BLACK MEDIUM UP-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;
+2BC6;BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;
+2BC7;BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;
+2BC8;BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED;So;0;ON;;;;;N;;;;;
+2BCA;TOP HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+2BCB;BOTTOM HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+2BCC;LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;;
+2BCD;ROTATED LIGHT FOUR POINTED BLACK CUSP;So;0;ON;;;;;N;;;;;
+2BCE;WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;;
+2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;;
+2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;;
+2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;;
+2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;
+2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;
+2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;
+2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33;
+2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34;
+2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35;
+2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36;
+2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37;
+2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38;
+2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39;
+2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A;
+2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B;
+2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C;
+2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D;
+2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E;
+2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F;
+2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40;
+2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41;
+2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42;
+2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43;
+2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44;
+2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45;
+2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46;
+2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47;
+2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48;
+2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49;
+2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A;
+2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B;
+2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C;
+2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D;
+2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E;
+2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F;
+2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50;
+2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51;
+2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52;
+2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53;
+2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54;
+2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55;
+2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56;
+2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57;
+2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58;
+2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59;
+2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A;
+2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B;
+2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C;
+2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D;
+2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E;
+2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00
+2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01
+2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02
+2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03
+2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04
+2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05
+2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06
+2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07
+2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08
+2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09
+2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A
+2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B
+2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C
+2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D
+2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E
+2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F
+2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10
+2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11
+2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12
+2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13
+2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14
+2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15
+2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16
+2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17
+2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18
+2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19
+2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A
+2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B
+2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C
+2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D
+2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E
+2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F
+2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20
+2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21
+2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22
+2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23
+2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24
+2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25
+2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26
+2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27
+2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28
+2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29
+2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A
+2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B
+2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C
+2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D
+2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E
+2C60;LATIN CAPITAL LETTER L WITH DOUBLE BAR;Lu;0;L;;;;;N;;;;2C61;
+2C61;LATIN SMALL LETTER L WITH DOUBLE BAR;Ll;0;L;;;;;N;;;2C60;;2C60
+2C62;LATIN CAPITAL LETTER L WITH MIDDLE TILDE;Lu;0;L;;;;;N;;;;026B;
+2C63;LATIN CAPITAL LETTER P WITH STROKE;Lu;0;L;;;;;N;;;;1D7D;
+2C64;LATIN CAPITAL LETTER R WITH TAIL;Lu;0;L;;;;;N;;;;027D;
+2C65;LATIN SMALL LETTER A WITH STROKE;Ll;0;L;;;;;N;;;023A;;023A
+2C66;LATIN SMALL LETTER T WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;023E;;023E
+2C67;LATIN CAPITAL LETTER H WITH DESCENDER;Lu;0;L;;;;;N;;;;2C68;
+2C68;LATIN SMALL LETTER H WITH DESCENDER;Ll;0;L;;;;;N;;;2C67;;2C67
+2C69;LATIN CAPITAL LETTER K WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6A;
+2C6A;LATIN SMALL LETTER K WITH DESCENDER;Ll;0;L;;;;;N;;;2C69;;2C69
+2C6B;LATIN CAPITAL LETTER Z WITH DESCENDER;Lu;0;L;;;;;N;;;;2C6C;
+2C6C;LATIN SMALL LETTER Z WITH DESCENDER;Ll;0;L;;;;;N;;;2C6B;;2C6B
+2C6D;LATIN CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;0251;
+2C6E;LATIN CAPITAL LETTER M WITH HOOK;Lu;0;L;;;;;N;;;;0271;
+2C6F;LATIN CAPITAL LETTER TURNED A;Lu;0;L;;;;;N;;;;0250;
+2C70;LATIN CAPITAL LETTER TURNED ALPHA;Lu;0;L;;;;;N;;;;0252;
+2C71;LATIN SMALL LETTER V WITH RIGHT HOOK;Ll;0;L;;;;;N;;;;;
+2C72;LATIN CAPITAL LETTER W WITH HOOK;Lu;0;L;;;;;N;;;;2C73;
+2C73;LATIN SMALL LETTER W WITH HOOK;Ll;0;L;;;;;N;;;2C72;;2C72
+2C74;LATIN SMALL LETTER V WITH CURL;Ll;0;L;;;;;N;;;;;
+2C75;LATIN CAPITAL LETTER HALF H;Lu;0;L;;;;;N;;;;2C76;
+2C76;LATIN SMALL LETTER HALF H;Ll;0;L;;;;;N;;;2C75;;2C75
+2C77;LATIN SMALL LETTER TAILLESS PHI;Ll;0;L;;;;;N;;;;;
+2C78;LATIN SMALL LETTER E WITH NOTCH;Ll;0;L;;;;;N;;;;;
+2C79;LATIN SMALL LETTER TURNED R WITH TAIL;Ll;0;L;;;;;N;;;;;
+2C7A;LATIN SMALL LETTER O WITH LOW RING INSIDE;Ll;0;L;;;;;N;;;;;
+2C7B;LATIN LETTER SMALL CAPITAL TURNED E;Ll;0;L;;;;;N;;;;;
+2C7C;LATIN SUBSCRIPT SMALL LETTER J;Lm;0;L;<sub> 006A;;;;N;;;;;
+2C7D;MODIFIER LETTER CAPITAL V;Lm;0;L;<super> 0056;;;;N;;;;;
+2C7E;LATIN CAPITAL LETTER S WITH SWASH TAIL;Lu;0;L;;;;;N;;;;023F;
+2C7F;LATIN CAPITAL LETTER Z WITH SWASH TAIL;Lu;0;L;;;;;N;;;;0240;
+2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81;
+2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80
+2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83;
+2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82
+2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85;
+2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84
+2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87;
+2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86
+2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89;
+2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88
+2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B;
+2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A
+2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D;
+2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C
+2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F;
+2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E
+2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91;
+2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90
+2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93;
+2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92
+2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95;
+2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94
+2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97;
+2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96
+2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99;
+2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98
+2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B;
+2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A
+2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D;
+2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C
+2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F;
+2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E
+2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1;
+2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0
+2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3;
+2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2
+2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5;
+2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4
+2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7;
+2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6
+2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9;
+2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8
+2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB;
+2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA
+2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD;
+2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC
+2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF;
+2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE
+2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1;
+2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0
+2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3;
+2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2
+2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5;
+2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4
+2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7;
+2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6
+2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9;
+2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8
+2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB;
+2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA
+2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD;
+2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC
+2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF;
+2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE
+2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1;
+2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0
+2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3;
+2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2
+2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5;
+2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4
+2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7;
+2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6
+2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9;
+2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8
+2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB;
+2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA
+2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD;
+2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC
+2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF;
+2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE
+2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1;
+2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0
+2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3;
+2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2
+2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5;
+2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4
+2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7;
+2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6
+2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9;
+2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8
+2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB;
+2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA
+2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD;
+2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC
+2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF;
+2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE
+2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1;
+2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0
+2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3;
+2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2
+2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;;
+2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;;
+2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;;
+2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;;
+2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;;
+2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;;
+2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;;
+2CEB;COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI;Lu;0;L;;;;;N;;;;2CEC;
+2CEC;COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI;Ll;0;L;;;;;N;;;2CEB;;2CEB
+2CED;COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA;Lu;0;L;;;;;N;;;;2CEE;
+2CEE;COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA;Ll;0;L;;;;;N;;;2CED;;2CED
+2CEF;COPTIC COMBINING NI ABOVE;Mn;230;NSM;;;;;N;;;;;
+2CF0;COPTIC COMBINING SPIRITUS ASPER;Mn;230;NSM;;;;;N;;;;;
+2CF1;COPTIC COMBINING SPIRITUS LENIS;Mn;230;NSM;;;;;N;;;;;
+2CF2;COPTIC CAPITAL LETTER BOHAIRIC KHEI;Lu;0;L;;;;;N;;;;2CF3;
+2CF3;COPTIC SMALL LETTER BOHAIRIC KHEI;Ll;0;L;;;;;N;;;2CF2;;2CF2
+2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;;
+2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;;
+2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;;
+2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;;10A0;;10A0
+2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;;10A1;;10A1
+2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;;10A2;;10A2
+2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;;10A3;;10A3
+2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;;10A4;;10A4
+2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;;10A5;;10A5
+2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;;10A6;;10A6
+2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;;10A7;;10A7
+2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;;10A8;;10A8
+2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;;10A9;;10A9
+2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;;10AA;;10AA
+2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;;10AB;;10AB
+2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;;10AC;;10AC
+2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;;10AD;;10AD
+2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;;10AE;;10AE
+2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;;10AF;;10AF
+2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;;10B0;;10B0
+2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;;10B1;;10B1
+2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;;10B2;;10B2
+2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;;10B3;;10B3
+2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;;10B4;;10B4
+2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;;10B5;;10B5
+2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;;10B6;;10B6
+2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;;10B7;;10B7
+2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;;10B8;;10B8
+2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;;10B9;;10B9
+2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;;10BA;;10BA
+2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;;10BB;;10BB
+2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;;10BC;;10BC
+2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;;10BD;;10BD
+2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;;10BE;;10BE
+2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;;10BF;;10BF
+2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;;10C0;;10C0
+2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;;10C1;;10C1
+2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;;10C2;;10C2
+2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;;10C3;;10C3
+2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;;10C4;;10C4
+2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;;10C5;;10C5
+2D27;GEORGIAN SMALL LETTER YN;Ll;0;L;;;;;N;;;10C7;;10C7
+2D2D;GEORGIAN SMALL LETTER AEN;Ll;0;L;;;;;N;;;10CD;;10CD
+2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;;
+2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;;
+2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;;
+2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;;
+2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;;
+2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;;
+2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;;
+2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;;
+2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;;
+2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;;
+2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;;
+2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;;
+2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;;
+2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;;
+2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;;
+2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;;
+2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;;;;
+2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;;
+2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;;
+2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;;
+2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;;
+2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;;
+2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;;
+2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;;
+2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;;
+2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;;
+2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;;
+2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;;
+2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;;
+2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;;
+2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;;
+2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;;
+2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;;
+2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;;
+2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;;
+2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;;;;
+2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;;
+2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;;
+2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;;
+2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;;
+2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;;;;
+2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;;
+2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;;
+2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;;
+2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;;
+2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;;
+2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;;
+2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;;
+2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;;
+2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;;
+2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;;
+2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;;
+2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;;
+2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;;
+2D66;TIFINAGH LETTER YE;Lo;0;L;;;;;N;;;;;
+2D67;TIFINAGH LETTER YO;Lo;0;L;;;;;N;;;;;
+2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;;;;
+2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;;
+2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;;
+2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;;
+2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;;
+2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;;
+2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;;
+2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;;
+2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;;
+2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;;
+2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;;
+2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;;
+2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;;
+2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;;
+2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;;
+2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;;
+2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;;
+2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;;
+2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;;
+2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;;
+2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;;
+2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;;
+2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;;
+2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;;
+2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;;
+2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;;
+2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;;
+2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;;
+2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;;
+2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;;
+2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;;
+2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;;
+2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;;
+2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;;
+2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;;
+2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;;
+2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;;
+2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;;
+2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;;
+2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;;
+2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;;
+2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;;
+2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;;
+2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;;
+2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;;
+2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;;
+2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;;
+2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;;
+2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;;
+2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;;
+2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;;
+2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;;
+2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;;
+2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;;
+2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;;
+2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;;
+2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;;
+2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;;
+2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;;
+2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;;
+2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;;
+2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;;
+2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;;
+2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;;
+2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;;
+2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;;
+2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;;
+2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;;
+2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;;
+2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;;
+2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;;
+2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;;
+2DE0;COMBINING CYRILLIC LETTER BE;Mn;230;NSM;;;;;N;;;;;
+2DE1;COMBINING CYRILLIC LETTER VE;Mn;230;NSM;;;;;N;;;;;
+2DE2;COMBINING CYRILLIC LETTER GHE;Mn;230;NSM;;;;;N;;;;;
+2DE3;COMBINING CYRILLIC LETTER DE;Mn;230;NSM;;;;;N;;;;;
+2DE4;COMBINING CYRILLIC LETTER ZHE;Mn;230;NSM;;;;;N;;;;;
+2DE5;COMBINING CYRILLIC LETTER ZE;Mn;230;NSM;;;;;N;;;;;
+2DE6;COMBINING CYRILLIC LETTER KA;Mn;230;NSM;;;;;N;;;;;
+2DE7;COMBINING CYRILLIC LETTER EL;Mn;230;NSM;;;;;N;;;;;
+2DE8;COMBINING CYRILLIC LETTER EM;Mn;230;NSM;;;;;N;;;;;
+2DE9;COMBINING CYRILLIC LETTER EN;Mn;230;NSM;;;;;N;;;;;
+2DEA;COMBINING CYRILLIC LETTER O;Mn;230;NSM;;;;;N;;;;;
+2DEB;COMBINING CYRILLIC LETTER PE;Mn;230;NSM;;;;;N;;;;;
+2DEC;COMBINING CYRILLIC LETTER ER;Mn;230;NSM;;;;;N;;;;;
+2DED;COMBINING CYRILLIC LETTER ES;Mn;230;NSM;;;;;N;;;;;
+2DEE;COMBINING CYRILLIC LETTER TE;Mn;230;NSM;;;;;N;;;;;
+2DEF;COMBINING CYRILLIC LETTER HA;Mn;230;NSM;;;;;N;;;;;
+2DF0;COMBINING CYRILLIC LETTER TSE;Mn;230;NSM;;;;;N;;;;;
+2DF1;COMBINING CYRILLIC LETTER CHE;Mn;230;NSM;;;;;N;;;;;
+2DF2;COMBINING CYRILLIC LETTER SHA;Mn;230;NSM;;;;;N;;;;;
+2DF3;COMBINING CYRILLIC LETTER SHCHA;Mn;230;NSM;;;;;N;;;;;
+2DF4;COMBINING CYRILLIC LETTER FITA;Mn;230;NSM;;;;;N;;;;;
+2DF5;COMBINING CYRILLIC LETTER ES-TE;Mn;230;NSM;;;;;N;;;;;
+2DF6;COMBINING CYRILLIC LETTER A;Mn;230;NSM;;;;;N;;;;;
+2DF7;COMBINING CYRILLIC LETTER IE;Mn;230;NSM;;;;;N;;;;;
+2DF8;COMBINING CYRILLIC LETTER DJERV;Mn;230;NSM;;;;;N;;;;;
+2DF9;COMBINING CYRILLIC LETTER MONOGRAPH UK;Mn;230;NSM;;;;;N;;;;;
+2DFA;COMBINING CYRILLIC LETTER YAT;Mn;230;NSM;;;;;N;;;;;
+2DFB;COMBINING CYRILLIC LETTER YU;Mn;230;NSM;;;;;N;;;;;
+2DFC;COMBINING CYRILLIC LETTER IOTIFIED A;Mn;230;NSM;;;;;N;;;;;
+2DFD;COMBINING CYRILLIC LETTER LITTLE YUS;Mn;230;NSM;;;;;N;;;;;
+2DFE;COMBINING CYRILLIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;;
+2DFF;COMBINING CYRILLIC LETTER IOTIFIED BIG YUS;Mn;230;NSM;;;;;N;;;;;
+2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;;
+2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;;
+2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;;
+2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;;
+2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;;
+2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;;
+2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;;
+2E18;INVERTED INTERROBANG;Po;0;ON;;;;;N;;;;;
+2E19;PALM BRANCH;Po;0;ON;;;;;N;;;;;
+2E1A;HYPHEN WITH DIAERESIS;Pd;0;ON;;;;;N;;;;;
+2E1B;TILDE WITH RING ABOVE;Po;0;ON;;;;;N;;;;;
+2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E1E;TILDE WITH DOT ABOVE;Po;0;ON;;;;;N;;;;;
+2E1F;TILDE WITH DOT BELOW;Po;0;ON;;;;;N;;;;;
+2E20;LEFT VERTICAL BAR WITH QUILL;Pi;0;ON;;;;;Y;;;;;
+2E21;RIGHT VERTICAL BAR WITH QUILL;Pf;0;ON;;;;;Y;;;;;
+2E22;TOP LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;;
+2E23;TOP RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;;
+2E24;BOTTOM LEFT HALF BRACKET;Ps;0;ON;;;;;Y;;;;;
+2E25;BOTTOM RIGHT HALF BRACKET;Pe;0;ON;;;;;Y;;;;;
+2E26;LEFT SIDEWAYS U BRACKET;Ps;0;ON;;;;;Y;;;;;
+2E27;RIGHT SIDEWAYS U BRACKET;Pe;0;ON;;;;;Y;;;;;
+2E28;LEFT DOUBLE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;
+2E29;RIGHT DOUBLE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;
+2E2A;TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2E2B;ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2E2C;SQUARED FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2E2D;FIVE DOT MARK;Po;0;ON;;;;;N;;;;;
+2E2E;REVERSED QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2E2F;VERTICAL TILDE;Lm;0;ON;;;;;N;;;;;
+2E30;RING POINT;Po;0;ON;;;;;N;;;;;
+2E31;WORD SEPARATOR MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+2E32;TURNED COMMA;Po;0;ON;;;;;N;;;;;
+2E33;RAISED DOT;Po;0;ON;;;;;N;;;;;
+2E34;RAISED COMMA;Po;0;ON;;;;;N;;;;;
+2E35;TURNED SEMICOLON;Po;0;ON;;;;;N;;;;;
+2E36;DAGGER WITH LEFT GUARD;Po;0;ON;;;;;N;;;;;
+2E37;DAGGER WITH RIGHT GUARD;Po;0;ON;;;;;N;;;;;
+2E38;TURNED DAGGER;Po;0;ON;;;;;N;;;;;
+2E39;TOP HALF SECTION SIGN;Po;0;ON;;;;;N;;;;;
+2E3A;TWO-EM DASH;Pd;0;ON;;;;;N;;;;;
+2E3B;THREE-EM DASH;Pd;0;ON;;;;;N;;;;;
+2E3C;STENOGRAPHIC FULL STOP;Po;0;ON;;;;;N;;;;;
+2E3D;VERTICAL SIX DOTS;Po;0;ON;;;;;N;;;;;
+2E3E;WIGGLY VERTICAL LINE;Po;0;ON;;;;;N;;;;;
+2E3F;CAPITULUM;Po;0;ON;;;;;N;;;;;
+2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;
+2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;;
+2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
+2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;;
+2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;;
+2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
+2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
+2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
+2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;;
+2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;;
+2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;;
+2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;;
+2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;;
+2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;;
+2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;;
+2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;;
+2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;;
+2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;;
+2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;;
+2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;;
+2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;;
+2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;;
+2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;;
+2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;;
+2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;;
+2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;;
+2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;;
+2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;;
+2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;;
+2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;;
+2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;;
+2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;;
+2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;;
+2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;;
+2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;;
+2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;;
+2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;;
+2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;;
+2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;;
+2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;;
+2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;;
+2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;;
+2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;;
+2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;;
+2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;;
+2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;;
+2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;;
+2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;;
+2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;;
+2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;;
+2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;;
+2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;;
+2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;;
+2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;;
+2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;;
+2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;;
+2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;;
+2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;;
+2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;;
+2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;;
+2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;;
+2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;;
+2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;;
+2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;;
+2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;;
+2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;;
+2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;;
+2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;;
+2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;;
+2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;;
+2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;;
+2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;;
+2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;;
+2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;;
+2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;;
+2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;;
+2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;;
+2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;;
+2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;;
+2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;;
+2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;;
+2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;;
+2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;;
+2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;;
+2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;;
+2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;;
+2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;;
+2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;;
+2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;;
+2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;;
+2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;;
+2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;;
+2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;;
+2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;;
+2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;;
+2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;;
+2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;;
+2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;;
+2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;;
+2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;;
+2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;;
+2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;;
+2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;;
+2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;;
+2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;;
+2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;;
+2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;;
+2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;;
+2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;;
+2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;;
+2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;;
+2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;;
+2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;;
+2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;;
+2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;;
+2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;;
+2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;;
+2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;;
+2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;;
+2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;;
+2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;;
+2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;;
+2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;;
+2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;;
+2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;;
+2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;;
+2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;;
+2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;;
+2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;;
+2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;;
+2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;;
+2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;;
+2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;;
+2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;;
+2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;;
+2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;;
+2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;;
+2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;;
+2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;;
+2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;;
+2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;;
+2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;;
+2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;;
+2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;;
+2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;;
+2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;;
+2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;;
+2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;;
+2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;;
+2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;;
+2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;;
+2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;;
+2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;;
+2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;;
+2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;;
+2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;
+2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;;
+2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;;
+2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;;
+2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;;
+2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;;
+2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;;
+2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;;
+2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;;
+2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;;
+2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;;
+2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;;
+2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;;
+2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;;
+2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;;
+2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;;
+2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;;
+2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;;
+2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;;
+2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;;
+2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;;
+2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;;
+2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;;
+2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;;
+2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;;
+2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;;
+2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;;
+2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;;
+2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;;
+2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;;
+2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;;
+2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;;
+2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;;
+2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;;
+2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;;
+2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;;
+2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;;
+2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;;
+2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;;
+2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;;
+2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;;
+2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;;
+2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;;
+2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;;
+2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;;
+2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;;
+2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;;
+2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;;
+2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;;
+2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;;
+2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;;
+2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;;
+2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;;
+2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;;
+2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;;
+2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;;
+2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;;
+2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;;
+2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;;
+2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;;
+2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;;
+2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;;
+2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;;
+2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;;
+2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;;
+2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;;
+2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;;
+2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;;
+2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;;
+2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;;
+2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;;
+2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;;
+2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;;
+2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;;
+2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;;
+2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;;
+2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;;
+2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;;
+2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;;
+2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;;
+2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;;
+2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;;
+2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;;
+2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;;
+2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;;
+2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;;
+2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;;
+2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;;
+2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;;
+2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;;
+2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;;
+2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;;
+2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;;
+2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;;
+2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;;
+2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;;
+2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;;
+2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;;
+2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;;
+2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;;
+2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;;
+2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;;
+2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;;
+2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;;
+2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;;
+2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;;
+2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;;
+2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;;
+2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;;
+2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;;
+2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;;
+2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;;
+2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;;
+2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;;
+2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;;
+2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;;
+2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;;
+2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;;
+2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;;
+2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;;
+2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;;
+2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;;
+2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;;
+2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;;
+2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;;
+2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;;
+2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;;
+2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;;
+2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;;
+2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;;
+2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;;
+2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;;
+2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;;
+2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;;
+2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;;
+2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;;
+2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;;
+2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;;
+2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;;
+2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;;
+2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;;
+2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;;
+2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;
+2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;;
+2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;;
+2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;;
+2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;;
+2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;;
+2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;;
+2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;;
+2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;;
+2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;;
+2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;;
+2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;;
+2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;;
+2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;;
+2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;;
+2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;;
+2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;;
+2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;;
+2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;;
+2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;;
+2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;;
+2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;;
+2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;;
+2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;;
+2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;;
+2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;;
+2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;;
+2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;;
+2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;;
+2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;;
+2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;;
+2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;;
+2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;;
+2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;;
+2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;;
+2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;;
+2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;;
+2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;;
+2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;;
+2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;;
+2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;;
+2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;;
+2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;;
+3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
+3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;;
+3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;;
+3003;DITTO MARK;Po;0;ON;;;;;N;;;;;
+3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;;
+3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;;
+3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;;
+3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;;
+3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;;
+300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;;
+300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;;
+300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;
+300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;;
+300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;;
+300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;;
+3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;;
+3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;;
+3012;POSTAL MARK;So;0;ON;;;;;N;;;;;
+3013;GETA MARK;So;0;ON;;;;;N;;;;;
+3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;;
+3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;;
+3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;;
+3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;;
+3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;;
+3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;;
+301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;;
+301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;;
+301C;WAVE DASH;Pd;0;ON;;;;;N;;;;;
+301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
+301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;;
+3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;;
+3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;;
+3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;;
+3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;;
+3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;;
+3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;;
+3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;;
+3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;;
+3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;;
+302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;;
+302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;;
+302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;;
+302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;;
+302E;HANGUL SINGLE DOT TONE MARK;Mc;224;L;;;;;N;;;;;
+302F;HANGUL DOUBLE DOT TONE MARK;Mc;224;L;;;;;N;;;;;
+3030;WAVY DASH;Pd;0;ON;;;;;N;;;;;
+3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;;
+3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;;
+3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;;
+3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;;
+3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;;
+3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;;
+3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;;
+303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;;
+303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+303C;MASU MARK;Lo;0;L;;;;;N;;;;;
+303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;;
+303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;;
+303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;;
+3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;;
+3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;;
+3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;;
+3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;;
+3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;;
+304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;;
+304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;;
+304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;;
+304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;;
+304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;;
+3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;;
+3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;;
+3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;;
+3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;;
+3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;;
+3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;;
+3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;;
+3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;;
+3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;;
+3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;;
+305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;;
+305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;;
+305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;;
+305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;;
+305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;;
+305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;;
+3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;;
+3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;;
+3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;;
+3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;;
+3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;;
+3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;;
+3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;;
+3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;;
+3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;;
+306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;;
+306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;;
+306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;;
+306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;;
+306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;;
+306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;;
+3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;;
+3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;;
+3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;;
+3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;;
+3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;;
+3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;;
+3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;;
+3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;;
+3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;;
+3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;;
+307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;;
+307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;;
+307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;;
+307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;;
+307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;;
+307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;;
+3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;;
+3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;;
+3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;;
+3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;;
+3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;;
+3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;;
+3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;;
+308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;;
+308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;;
+308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;;
+308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;;
+308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;;
+3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;;
+3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;;
+3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;;
+3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;;
+3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;;
+3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;;
+309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;;
+309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;;
+309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;;
+309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;;
+309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;;
+30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;
+30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;;
+30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;;
+30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;;
+30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;;
+30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;;
+30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;;
+30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;;
+30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;;
+30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;;
+30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;;
+30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;;
+30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;;
+30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;;
+30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;;
+30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;;
+30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;;
+30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;;
+30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;;
+30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;;
+30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;;
+30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;;
+30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;;
+30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;;
+30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;;
+30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;;
+30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;;
+30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;;
+30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;;
+30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;;
+30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;;
+30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;;
+30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;;
+30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;;
+30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;
+30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;
+30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;;
+30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;;
+30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;;
+30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;;
+30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;;
+30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;;
+30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;;
+30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;;
+30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;;
+30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;;
+30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;;
+30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;;
+30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;;
+30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;;
+30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;;
+30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;;
+30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;;
+30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;;
+30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;;
+30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;;
+30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;;
+30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;;
+30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;;
+30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;;
+30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;;
+30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;;
+30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;;
+30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;;
+30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;;
+30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;;
+30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;;
+30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;;
+30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;;
+30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;;
+30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;;
+30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;;
+30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;;
+30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;;
+30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;;
+30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;;
+30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;;
+30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;;
+30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;;
+30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;;
+30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;;
+30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;;
+3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;;
+3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;;
+3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;;
+3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;;
+3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;;
+310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;;
+310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;;
+310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;;
+310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;;
+310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;;
+310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;;
+3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;;
+3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;;
+3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;;
+3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;;
+3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;;
+3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;;
+3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;;
+3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;;
+3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;;
+3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;;
+311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;;
+311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;;
+311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;;
+311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;;
+311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;;
+311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;;
+3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;;
+3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;;
+3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;;
+3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;;
+3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;;
+3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;;
+3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;;
+3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;;
+3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;;
+3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;;
+312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;;
+312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;
+312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
+312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;;
+3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
+3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
+3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
+3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;;
+3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;;
+3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;;
+3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;;
+3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;;
+3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;;
+313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;;
+313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;;
+313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;;
+313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;;
+313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;;
+313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;;
+3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;;
+3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;;
+3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;;
+3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;;
+3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;;
+3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;;
+3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;;
+3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;;
+3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;;
+3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;;
+314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;;
+314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;;
+314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;;
+314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;;
+314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;;
+314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;;
+3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;;
+3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;;
+3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;;
+3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;;
+3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;;
+3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;;
+3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;;
+3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;;
+3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;;
+3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;;
+315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;;
+315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;;
+315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;;
+315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;;
+315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;;
+315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;;
+3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;;
+3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;;
+3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;;
+3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;;
+3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;;
+3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;;
+3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;;
+3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;;
+3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;;
+3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;;
+316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;;
+316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;;
+316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;;
+316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;;
+316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;;
+316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;;
+3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;;
+3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;;
+3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;;
+3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;;
+3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;;
+3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;;
+3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;;
+3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;;
+3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;;
+3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;;
+317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;;
+317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;;
+317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;;
+317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;;
+317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;;
+317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;;
+3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;;
+3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;;
+3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;;
+3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;;
+3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;;
+3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;;
+3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;;
+3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;;
+3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;;
+3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;;
+318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;;
+318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;;
+318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;;
+318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;;
+318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
+3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;;;;
+3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;;;;
+3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;;;;
+3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;;;;
+3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;;;;
+3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;;;;
+3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;;;;
+3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;;;;
+3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;;;;
+3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;;;;
+319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;;;;
+319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;;;;
+319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;;;;
+319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;;;;
+319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;;;;
+319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;;;;
+31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;;
+31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;;
+31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;;
+31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;;
+31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;;
+31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;;
+31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;;
+31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;;
+31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;;
+31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;;
+31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;;
+31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;;
+31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;;
+31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;;
+31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;;
+31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;;
+31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;;
+31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;;
+31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;;
+31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;;
+31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;;
+31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;;
+31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;;
+31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;;
+31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;;
+31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;;
+31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;;
+31C0;CJK STROKE T;So;0;ON;;;;;N;;;;;
+31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;;
+31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;;
+31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;;
+31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;;
+31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;;
+31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;;
+31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;;
+31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;;
+31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;;
+31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;;
+31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;;
+31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;;
+31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;;
+31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;;
+31CF;CJK STROKE N;So;0;ON;;;;;N;;;;;
+31D0;CJK STROKE H;So;0;ON;;;;;N;;;;;
+31D1;CJK STROKE S;So;0;ON;;;;;N;;;;;
+31D2;CJK STROKE P;So;0;ON;;;;;N;;;;;
+31D3;CJK STROKE SP;So;0;ON;;;;;N;;;;;
+31D4;CJK STROKE D;So;0;ON;;;;;N;;;;;
+31D5;CJK STROKE HZ;So;0;ON;;;;;N;;;;;
+31D6;CJK STROKE HG;So;0;ON;;;;;N;;;;;
+31D7;CJK STROKE SZ;So;0;ON;;;;;N;;;;;
+31D8;CJK STROKE SWZ;So;0;ON;;;;;N;;;;;
+31D9;CJK STROKE ST;So;0;ON;;;;;N;;;;;
+31DA;CJK STROKE SG;So;0;ON;;;;;N;;;;;
+31DB;CJK STROKE PD;So;0;ON;;;;;N;;;;;
+31DC;CJK STROKE PZ;So;0;ON;;;;;N;;;;;
+31DD;CJK STROKE TN;So;0;ON;;;;;N;;;;;
+31DE;CJK STROKE SZZ;So;0;ON;;;;;N;;;;;
+31DF;CJK STROKE SWG;So;0;ON;;;;;N;;;;;
+31E0;CJK STROKE HXWG;So;0;ON;;;;;N;;;;;
+31E1;CJK STROKE HZZZG;So;0;ON;;;;;N;;;;;
+31E2;CJK STROKE PG;So;0;ON;;;;;N;;;;;
+31E3;CJK STROKE Q;So;0;ON;;;;;N;;;;;
+31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;;
+31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;;
+31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;;
+31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;;
+31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;;
+31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;;
+31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;;
+31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;;
+31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;;
+31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;;
+31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;;
+31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;;
+31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;;
+31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;;
+31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;;
+31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;;
+3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;;
+3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;;
+3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;;
+3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;;
+3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;;
+3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;;
+3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;;
+3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;;
+3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;;
+3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;;
+320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;;
+320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;;
+320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;;
+320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;;
+320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;;
+320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;;
+3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;;
+3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;;
+3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;;
+3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;;
+3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;;
+3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;;
+3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;;
+3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;;
+3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;;
+3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;;
+321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;;
+321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;;
+321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;;
+321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;;
+321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;;
+3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;;
+3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;;
+3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;;
+3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;;
+3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;;
+3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;;
+3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;;
+3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;;
+3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;;
+3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;;
+322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;;
+322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;;
+322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;;
+322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;;
+322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;;
+322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;;
+3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;;
+3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;;
+3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;;
+3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;;
+3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;;
+3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;;
+3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;;
+3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;;
+3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;;
+3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;;
+323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;;
+323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;;
+323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;;
+323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;;
+323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;;
+323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;;
+3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;;
+3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;;
+3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;;
+3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;;
+3244;CIRCLED IDEOGRAPH QUESTION;So;0;L;<circle> 554F;;;;N;;;;;
+3245;CIRCLED IDEOGRAPH KINDERGARTEN;So;0;L;<circle> 5E7C;;;;N;;;;;
+3246;CIRCLED IDEOGRAPH SCHOOL;So;0;L;<circle> 6587;;;;N;;;;;
+3247;CIRCLED IDEOGRAPH KOTO;So;0;L;<circle> 7B8F;;;;N;;;;;
+3248;CIRCLED NUMBER TEN ON BLACK SQUARE;No;0;L;;;;10;N;;;;;
+3249;CIRCLED NUMBER TWENTY ON BLACK SQUARE;No;0;L;;;;20;N;;;;;
+324A;CIRCLED NUMBER THIRTY ON BLACK SQUARE;No;0;L;;;;30;N;;;;;
+324B;CIRCLED NUMBER FORTY ON BLACK SQUARE;No;0;L;;;;40;N;;;;;
+324C;CIRCLED NUMBER FIFTY ON BLACK SQUARE;No;0;L;;;;50;N;;;;;
+324D;CIRCLED NUMBER SIXTY ON BLACK SQUARE;No;0;L;;;;60;N;;;;;
+324E;CIRCLED NUMBER SEVENTY ON BLACK SQUARE;No;0;L;;;;70;N;;;;;
+324F;CIRCLED NUMBER EIGHTY ON BLACK SQUARE;No;0;L;;;;80;N;;;;;
+3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;;
+3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;;
+3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;;
+3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;;
+3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;;
+3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;;
+3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;;
+3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;;
+3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;;
+3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;;
+325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;;
+325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;;
+325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;;
+325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;;
+325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;;
+325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;;
+3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;;
+3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;;
+3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;;
+3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;;
+3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;;
+3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;;
+3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;;
+3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;;
+3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;;
+3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;;
+326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;;
+326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;;
+326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;;
+326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;;
+326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;;
+326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;;
+3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;;
+3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;;
+3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;;
+3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;;
+3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;;
+3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;;
+3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;;
+3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;;
+3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;;
+3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;;
+327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;;
+327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;;
+327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;;
+327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;;
+327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;;
+327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;;
+3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;;
+3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;;
+3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;;
+3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;;
+3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;;
+3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;;
+3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;;
+3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;;
+3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;;
+3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;;
+328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;;
+328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;;
+328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;;
+328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;;
+328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;;
+328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;;
+3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;;
+3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;;
+3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;;
+3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;;
+3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;;
+3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;;
+3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;;
+3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;;
+3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;;
+3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;;
+329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;;
+329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;;
+329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;;
+329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;;
+329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;;
+329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;;
+32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;;
+32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;;
+32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;;
+32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;;
+32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;;
+32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;;
+32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;;
+32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;;
+32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;;
+32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;;
+32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;;
+32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;;
+32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;;
+32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;;
+32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;;
+32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;;
+32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;;
+32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;;
+32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;;
+32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;;
+32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;;
+32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;;
+32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;;
+32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;;
+32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;;
+32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;;
+32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;;
+32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;;
+32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;;
+32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;;
+32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;;
+32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;;
+32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;;
+32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;;
+32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;;
+32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;;
+32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;;
+32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;;
+32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;;
+32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;;
+32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;;
+32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;;
+32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;;
+32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;;
+32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;;
+32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;;
+32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;;
+32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;;
+32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;;
+32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;;
+32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;;
+32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;;
+32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;;
+32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;;
+32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;;
+32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;;
+32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;;
+32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;;
+32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;;
+32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;;
+32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;;
+32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;;
+32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;;
+32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;;
+32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;;
+32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;;
+32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;;
+32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;;
+32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;;
+32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;;
+32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;;
+32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;;
+32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;;
+32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;;
+32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;;
+32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;;
+32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;;
+32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;;
+32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;;
+32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;;
+32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;;
+32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;;
+32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;;
+32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;;
+32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;;
+32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;;
+32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;;
+32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;;
+32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;;
+32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;;
+32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;;
+32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;;
+32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;;
+32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;;
+32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;;
+3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;
+3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;
+3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;
+3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;;
+3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;;
+3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;;
+3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;;
+3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;;
+3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;;
+3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;;
+330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;;
+330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;;
+330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;;
+330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;;
+330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;;
+330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;;
+3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;;
+3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;;
+3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;;
+3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;;
+3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;;
+3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;;
+3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;;
+3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;;
+3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;;
+3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;;
+331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;;
+331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;;
+331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;;
+331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;;
+331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;;
+331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;;
+3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;;
+3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;;
+3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;;
+3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;;
+3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;;
+3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;;
+3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;;
+3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;;
+3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;;
+3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;;
+332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;;
+332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;;
+332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;;
+332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;;
+332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;;
+332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;;
+3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;;
+3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;;
+3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;;
+3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;;
+3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;;
+3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;;
+3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;;
+3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;;
+3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;;
+3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;;
+333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;;
+333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;;
+333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;;
+333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;;
+333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;;
+333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;;
+3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;;
+3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;;
+3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;;
+3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;;
+3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;;
+3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;;
+3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;;
+3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;;
+3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;;
+3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;;
+334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;;
+334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;;
+334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;;
+334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;;
+334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;;
+334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;;
+3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;;
+3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;;
+3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;;
+3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;;
+3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;;
+3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;;
+3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;;
+3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;;
+3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;;
+3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;;
+335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;;
+335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;;
+335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;;
+335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;;
+335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;;
+335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;;
+3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;;
+3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;;
+3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;;
+3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;;
+3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;;
+3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;;
+3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;;
+3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;;
+3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;;
+3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;;
+336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;;
+336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;;
+336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;;
+336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;;
+336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;;
+336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;;
+3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;;
+3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;;
+3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;;
+3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;;
+3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;;
+3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;;
+3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;;
+3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;;
+3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;;
+3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;;
+337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;;
+337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;;
+337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;;
+337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;;
+337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;;
+337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;;
+3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;;
+3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;;
+3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;;
+3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;;
+3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;;
+3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;;
+3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;;
+3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;;
+3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;;
+3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;;
+338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;;
+338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;;
+338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;;
+338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;;
+338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;;
+338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;;
+3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;;
+3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;;
+3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;;
+3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;;
+3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;;
+3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;;
+3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;;
+3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;;
+3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;;
+3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;;
+339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;;
+339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;;
+339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;;
+339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;;
+339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;;
+339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;;
+33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;;
+33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;;
+33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;;
+33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;;
+33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;;
+33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;;
+33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;;
+33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;;
+33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;;
+33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;;
+33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;;
+33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;;
+33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;;
+33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;;
+33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;;
+33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;;
+33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;;
+33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;;
+33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;;
+33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;;
+33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;;
+33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;;
+33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;;
+33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;;
+33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;;
+33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;;
+33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;;
+33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;;
+33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;;
+33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;;
+33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;;
+33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;;
+33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;;
+33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;;
+33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;;
+33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;;
+33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;;
+33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;;
+33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;;
+33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;;
+33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;;
+33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;;
+33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;;
+33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;;
+33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;;
+33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;;
+33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;;
+33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;;
+33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;;
+33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;;
+33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;;
+33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;;
+33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;;
+33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;;
+33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;;
+33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;;
+33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;;
+33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;;
+33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;;
+33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;;
+33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;;
+33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;;
+33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;;
+33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;;
+33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;;
+33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;;
+33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;;
+33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;;
+33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;;
+33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;;
+33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;;
+33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;;
+33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;;
+33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;;
+33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;;
+33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;;
+33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;;
+33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;;
+33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;;
+33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;;
+33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;;
+33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;;
+33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;;
+33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;;
+33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;;
+33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;;
+33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;;
+33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;;
+33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;;
+33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;;
+33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;;
+33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;;
+33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;;
+33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;;
+33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;
+33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;;
+3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;;
+4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;;
+4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;;
+4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;;
+4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;;
+4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;;
+4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;;
+4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;;
+4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;;
+4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;;
+4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;;
+4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;;
+4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;;
+4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;;
+4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;;
+4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;;
+4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;;
+4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;;
+4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;;
+4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;;
+4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;;
+4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;;
+4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;;
+4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;;
+4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;;
+4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;;
+4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;;
+4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;;
+4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;;
+4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;;
+4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;;
+4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;;
+4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;;
+4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;;
+4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;;
+4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;;
+4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;;
+4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;;
+4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;;
+4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;;
+4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;;
+4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;;
+4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;;
+4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;;
+4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;;
+4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;;
+4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;;
+4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;;
+4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;;
+4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;;
+4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;;
+4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;;
+4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;;
+4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;;
+4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;;
+4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;;
+4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
+4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
+4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
+9FD5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
+A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
+A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
+A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;;
+A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;;
+A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;;
+A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;;
+A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;;
+A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;;
+A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;;
+A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;;
+A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;;
+A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;;
+A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;;
+A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;;
+A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;;
+A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;;
+A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;;
+A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;;
+A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;;
+A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;;
+A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;;
+A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;;
+A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;;
+A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;;
+A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;;
+A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;;
+A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;;
+A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;;
+A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;;
+A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;;
+A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;;
+A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;;
+A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;;
+A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;;
+A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;;
+A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;;
+A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;;
+A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;;
+A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;;
+A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;;
+A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;;
+A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;;
+A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;;
+A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;;
+A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;;
+A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;;
+A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;;
+A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;;
+A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;;
+A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;;
+A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;;
+A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;;
+A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;;
+A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;;
+A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;;
+A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;;
+A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;;
+A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;;
+A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;;
+A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;;
+A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;;
+A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;;
+A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;;
+A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;;
+A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;;
+A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;;
+A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;;
+A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;;
+A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;;
+A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;;
+A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;;
+A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;;
+A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;;
+A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;;
+A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;;
+A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;;
+A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;;
+A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;;
+A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;;
+A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;;
+A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;;
+A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;;
+A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;;
+A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;;
+A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;;
+A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;;
+A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;;
+A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;;
+A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;;
+A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;;
+A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;;
+A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;;
+A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;;
+A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;;
+A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;;
+A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;;
+A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;;
+A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;;
+A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;;
+A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;;
+A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;;
+A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;;
+A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;;
+A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;;
+A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;;
+A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;;
+A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;;
+A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;;
+A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;;
+A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;;
+A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;;
+A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;;
+A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;;
+A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;;
+A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;;
+A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;;
+A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;;
+A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;;
+A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;;
+A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;;
+A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;;
+A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;;
+A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;;
+A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;;
+A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;;
+A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;;
+A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;;
+A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;;
+A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;;
+A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;;
+A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;;
+A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;;
+A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;;
+A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;;
+A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;;
+A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;;
+A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;;
+A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;;
+A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;;
+A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;;
+A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;;
+A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;;
+A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;;
+A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;;
+A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;;
+A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;;
+A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;;
+A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;;
+A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;;
+A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;;
+A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;;
+A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;;
+A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;;
+A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;;
+A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;;
+A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;;
+A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;;
+A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;;
+A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;;
+A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;;
+A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;;
+A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;;
+A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;;
+A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;;
+A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;;
+A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;;
+A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;;
+A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;;
+A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;;
+A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;;
+A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;;
+A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;;
+A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;;
+A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;;
+A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;;
+A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;;
+A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;;
+A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;;
+A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;;
+A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;;
+A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;;
+A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;;
+A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;;
+A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;;
+A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;;
+A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;;
+A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;;
+A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;;
+A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;;
+A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;;
+A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;;
+A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;;
+A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;;
+A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;;
+A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;;
+A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;;
+A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;;
+A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;;
+A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;;
+A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;;
+A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;;
+A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;;
+A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;;
+A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;;
+A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;;
+A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;;
+A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;;
+A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;;
+A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;;
+A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;;
+A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;;
+A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;;
+A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;;
+A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;;
+A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;;
+A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;;
+A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;;
+A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;;
+A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;;
+A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;;
+A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;;
+A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;;
+A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;;
+A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;;
+A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;;
+A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;;
+A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;;
+A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;;
+A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;;
+A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;;
+A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;;
+A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;;
+A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;;
+A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;;
+A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;;
+A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;;
+A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;;
+A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;;
+A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;;
+A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;;
+A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;;
+A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;;
+A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;;
+A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;;
+A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;;
+A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;;
+A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;;
+A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;;
+A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;;
+A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;;
+A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;;
+A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;;
+A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;;
+A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;;
+A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;;
+A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;;
+A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;;
+A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;;
+A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;;
+A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;;
+A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;;
+A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;;
+A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;;
+A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;;
+A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;;
+A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;;
+A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;;
+A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;;
+A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;;
+A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;;
+A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;;
+A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;;
+A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;;
+A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;;
+A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;;
+A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;;
+A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;;
+A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;;
+A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;;
+A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;;
+A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;;
+A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;;
+A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;;
+A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;;
+A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;;
+A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;;
+A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;;
+A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;;
+A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;;
+A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;;
+A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;;
+A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;;
+A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;;
+A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;;
+A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;;
+A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;;
+A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;;
+A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;;
+A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;;
+A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;;
+A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;;
+A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;
+A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;;
+A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;;
+A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;;
+A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;;
+A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;;
+A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;
+A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;;
+A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;;
+A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;;
+A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;
+A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;;
+A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;;
+A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;
+A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;;
+A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;;
+A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;;
+A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;
+A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;;
+A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;;
+A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;;
+A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;;
+A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;;
+A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;;
+A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;;
+A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;;
+A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;;
+A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;;
+A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;;
+A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;;
+A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;;
+A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;;
+A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;;
+A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;;
+A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;;
+A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;;
+A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;;
+A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;;
+A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;;
+A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;;
+A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;;
+A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;;
+A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;;
+A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;;
+A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;;
+A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;;
+A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;;
+A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;;
+A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;;
+A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;;
+A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;;
+A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;;
+A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;;
+A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;;
+A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;;
+A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;;
+A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;;
+A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;;
+A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;;
+A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;;
+A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;;
+A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;;
+A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;;
+A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;;
+A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;;
+A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;;
+A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;;
+A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;;
+A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;;
+A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;;
+A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;;
+A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;;
+A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;;
+A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;;
+A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;;
+A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;;
+A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;;
+A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;;
+A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;;
+A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;;
+A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;;
+A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;;
+A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;;
+A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;;
+A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;;
+A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;;
+A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;;
+A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;;
+A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;;
+A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;;
+A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;;
+A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;;
+A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;;
+A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;;
+A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;;
+A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;;
+A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;;
+A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;;
+A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;;
+A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;;
+A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;;
+A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;;
+A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;;
+A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;;
+A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;;
+A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;;
+A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;;
+A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;;
+A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;;
+A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;;
+A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;;
+A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;;
+A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;;
+A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;;
+A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;;
+A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;;
+A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;;
+A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;;
+A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;;
+A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;;
+A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;;
+A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;;
+A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;;
+A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;;
+A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;;
+A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;;
+A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;;
+A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;;
+A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;;
+A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;;
+A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;;
+A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;;
+A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;;
+A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;;
+A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;;
+A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;;
+A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;;
+A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;;
+A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;;
+A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;;
+A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;;
+A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;;
+A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;;
+A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;;
+A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;;
+A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;;
+A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;;
+A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;;
+A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;;
+A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;;
+A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;;
+A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;;
+A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;;
+A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;;
+A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;;
+A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;;
+A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;;
+A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;;
+A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;;
+A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;;
+A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;;
+A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;;
+A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;;
+A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;;
+A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;;
+A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;;
+A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;;
+A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;;
+A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;;
+A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;;
+A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;;
+A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;;
+A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;;
+A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;;
+A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;;
+A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;;
+A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;;
+A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;;
+A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;;
+A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;;
+A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;;
+A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;;
+A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;;
+A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;;
+A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;;
+A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;;
+A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;;
+A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;;
+A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;;
+A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;;
+A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;;
+A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;;
+A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;;
+A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;;
+A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;;
+A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;;
+A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;;
+A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;;
+A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;;
+A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;;
+A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;;
+A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;;
+A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;;
+A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;;
+A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;;
+A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;;
+A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;;
+A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;;
+A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;;
+A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;;
+A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;;
+A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;;
+A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;;
+A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;;
+A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;;
+A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;;
+A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;;
+A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;;
+A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;;
+A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;;
+A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;;
+A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;;
+A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;;
+A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;;
+A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;;
+A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;;
+A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;;
+A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;;
+A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;;
+A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;;
+A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;;
+A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;;
+A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;;
+A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;;
+A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;;
+A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;;
+A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;;
+A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;;
+A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;;
+A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;;
+A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;;
+A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;;
+A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;;
+A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;;
+A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;;
+A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;;
+A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;;
+A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;;
+A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;;
+A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;;
+A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;;
+A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;;
+A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;;
+A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;;
+A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;;
+A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;;
+A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;;
+A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;;
+A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;;
+A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;;
+A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;;
+A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;;
+A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;;
+A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;;
+A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;;
+A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;;
+A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;;
+A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;;
+A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;;
+A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;;
+A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;;
+A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;;
+A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;;
+A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;;
+A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;;
+A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;;
+A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;;
+A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;;
+A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;;
+A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;;
+A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;;
+A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;;
+A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;;
+A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;;
+A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;;
+A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;;
+A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;;
+A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;;
+A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;;
+A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;;
+A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;;
+A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;;
+A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;;
+A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;;
+A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;;
+A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;;
+A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;;
+A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;;
+A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;;
+A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;;
+A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;;
+A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;;
+A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;;
+A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;;
+A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;;
+A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;;
+A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;;
+A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;;
+A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;;
+A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;;
+A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;;
+A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;;
+A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;;
+A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;;
+A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;;
+A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;;
+A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;;
+A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;;
+A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;;
+A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;;
+A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;;
+A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;;
+A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;;
+A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;;
+A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;;
+A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;;
+A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;;
+A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;;
+A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;;
+A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;;
+A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;;
+A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;;
+A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;;
+A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;;
+A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;;
+A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;;
+A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;;
+A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;;
+A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;;
+A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;;
+A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;;
+A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;;
+A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;;
+A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;;
+A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;;
+A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;;
+A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;;
+A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;;
+A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;;
+A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;;
+A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;;
+A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;;
+A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;;
+A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;;
+A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;;
+A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;;
+A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;;
+A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;;
+A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;;
+A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;;
+A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;;
+A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;;
+A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;;
+A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;;
+A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;;
+A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;;
+A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;;
+A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;;
+A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;;
+A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;;
+A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;;
+A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;;
+A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;;
+A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;;
+A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;;
+A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;;
+A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;;
+A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;;
+A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;;
+A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;;
+A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;;
+A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;;
+A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;;
+A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;;
+A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;;
+A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;;
+A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;;
+A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;;
+A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;;
+A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;;
+A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;;
+A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;;
+A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;;
+A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;;
+A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;;
+A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;;
+A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;;
+A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;;
+A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;;
+A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;;
+A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;;
+A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;;
+A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;;
+A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;;
+A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;;
+A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;;
+A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;;
+A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;;
+A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;;
+A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;;
+A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;;
+A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;;
+A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;;
+A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;;
+A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;;
+A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;;
+A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;;
+A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;;
+A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;;
+A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;;
+A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;;
+A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;;
+A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;;
+A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;;
+A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;;
+A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;;
+A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;;
+A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;;
+A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;;
+A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;;
+A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;;
+A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;;
+A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;;
+A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;;
+A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;;
+A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;;
+A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;;
+A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;;
+A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;;
+A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;;
+A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;;
+A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;;
+A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;;
+A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;;
+A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;;
+A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;;
+A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;;
+A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;;
+A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;;
+A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;;
+A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;;
+A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;;
+A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;;
+A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;;
+A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;;
+A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;;
+A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;;
+A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;;
+A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;;
+A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;;
+A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;;
+A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;;
+A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;;
+A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;;
+A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;;
+A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;;
+A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;;
+A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;;
+A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;;
+A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;;
+A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;;
+A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;;
+A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;;
+A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;;
+A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;;
+A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;;
+A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;;
+A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;;
+A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;;
+A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;;
+A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;;
+A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;;
+A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;;
+A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;;
+A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;;
+A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;;
+A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;;
+A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;;
+A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;;
+A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;;
+A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;;
+A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;;
+A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;;
+A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;;
+A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;;
+A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;;
+A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;;
+A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;;
+A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;;
+A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;;
+A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;;
+A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;;
+A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;;
+A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;;
+A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;;
+A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;;
+A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;;
+A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;;
+A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;;
+A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;;
+A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;;
+A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;;
+A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;;
+A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;;
+A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;;
+A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;;
+A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;;
+A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;;
+A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;;
+A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;;
+A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;;
+A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;;
+A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;;
+A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;;
+A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;;
+A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;;
+A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;;
+A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;;
+A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;;
+A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;;
+A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;;
+A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;;
+A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;;
+A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;;
+A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;;
+A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;;
+A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;;
+A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;;
+A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;;
+A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;;
+A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;;
+A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;;
+A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;;
+A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;;
+A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;;
+A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;;
+A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;;
+A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;;
+A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;;
+A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;;
+A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;;
+A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;;
+A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;;
+A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;;
+A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;;
+A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;;
+A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;;
+A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;;
+A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;;
+A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;;
+A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;;
+A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;;
+A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;;
+A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;;
+A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;;
+A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;;
+A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;;
+A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;;
+A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;;
+A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;;
+A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;;
+A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;;
+A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;;
+A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;;
+A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;;
+A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;;
+A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;;
+A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;;
+A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;;
+A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;;
+A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;;
+A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;;
+A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;;
+A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;;
+A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;;
+A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;;
+A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;;
+A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;;
+A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;;
+A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;;
+A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;;
+A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;;
+A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;;
+A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;;
+A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;;
+A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;;
+A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;;
+A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;;
+A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;;
+A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;;
+A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;;
+A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;;
+A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;;
+A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;;
+A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;;
+A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;;
+A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;;
+A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;;
+A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;;
+A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;;
+A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;;
+A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;;
+A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;;
+A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;;
+A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;;
+A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;;
+A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;;
+A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;;
+A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;;
+A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;;
+A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;;
+A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;;
+A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;;
+A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;;
+A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;;
+A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;;
+A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;;
+A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;;
+A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;;
+A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;;
+A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;;
+A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;;
+A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;;
+A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;;
+A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;;
+A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;;
+A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;;
+A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;;
+A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;;
+A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;;
+A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;;
+A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;;
+A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;;
+A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;;
+A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;;
+A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;;
+A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;;
+A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;;
+A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;;
+A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;;
+A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;;
+A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;;
+A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;;
+A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;;
+A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;;
+A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;;
+A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;;
+A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;;
+A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;
+A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;;
+A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;;
+A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;;
+A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;;
+A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;;
+A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;;
+A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;;
+A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;;
+A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;;
+A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;
+A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;;
+A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;;
+A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;
+A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;;
+A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;;
+A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;;
+A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;;
+A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;;
+A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;;
+A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;;
+A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;;
+A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;;
+A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;;
+A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;;
+A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;;
+A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;;
+A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;;
+A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;;
+A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;;
+A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;;
+A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;;
+A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;;
+A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;;
+A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;;
+A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;;
+A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;;
+A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;;
+A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;;
+A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;;
+A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;;
+A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;;
+A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;;
+A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;;
+A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;;
+A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;;
+A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;;
+A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;;
+A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;;
+A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;;
+A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;;
+A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;;
+A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;;
+A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;;
+A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;;
+A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;;
+A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;;
+A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;;
+A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;;
+A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;;
+A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;;
+A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;;
+A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;;
+A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;;
+A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;;
+A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;;
+A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;;
+A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;;
+A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;;
+A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;;
+A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;;
+A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;;
+A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;;
+A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;;
+A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;;
+A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;;
+A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;;
+A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;;
+A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;;
+A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;;
+A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;;
+A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;;
+A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;;
+A491;YI RADICAL LI;So;0;ON;;;;;N;;;;;
+A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;;
+A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;;
+A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;;
+A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;;
+A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;;
+A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;;
+A498;YI RADICAL MI;So;0;ON;;;;;N;;;;;
+A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;;
+A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;;
+A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;;
+A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;;
+A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;;
+A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;;
+A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;;
+A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;;
+A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;;
+A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;;
+A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;;
+A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;;
+A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;;
+A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;;
+A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;;
+A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;;
+A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;;
+A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;;
+A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;;
+A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;;
+A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;;
+A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;;
+A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;;
+A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;;
+A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;;
+A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;;
+A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;;
+A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;;
+A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;;
+A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;;
+A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;;
+A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;;
+A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;;
+A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;;
+A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;;
+A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;;
+A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;;
+A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;;
+A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;;
+A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;;
+A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;;
+A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;;
+A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;;
+A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;;
+A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;;
+A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;;
+A4D0;LISU LETTER BA;Lo;0;L;;;;;N;;;;;
+A4D1;LISU LETTER PA;Lo;0;L;;;;;N;;;;;
+A4D2;LISU LETTER PHA;Lo;0;L;;;;;N;;;;;
+A4D3;LISU LETTER DA;Lo;0;L;;;;;N;;;;;
+A4D4;LISU LETTER TA;Lo;0;L;;;;;N;;;;;
+A4D5;LISU LETTER THA;Lo;0;L;;;;;N;;;;;
+A4D6;LISU LETTER GA;Lo;0;L;;;;;N;;;;;
+A4D7;LISU LETTER KA;Lo;0;L;;;;;N;;;;;
+A4D8;LISU LETTER KHA;Lo;0;L;;;;;N;;;;;
+A4D9;LISU LETTER JA;Lo;0;L;;;;;N;;;;;
+A4DA;LISU LETTER CA;Lo;0;L;;;;;N;;;;;
+A4DB;LISU LETTER CHA;Lo;0;L;;;;;N;;;;;
+A4DC;LISU LETTER DZA;Lo;0;L;;;;;N;;;;;
+A4DD;LISU LETTER TSA;Lo;0;L;;;;;N;;;;;
+A4DE;LISU LETTER TSHA;Lo;0;L;;;;;N;;;;;
+A4DF;LISU LETTER MA;Lo;0;L;;;;;N;;;;;
+A4E0;LISU LETTER NA;Lo;0;L;;;;;N;;;;;
+A4E1;LISU LETTER LA;Lo;0;L;;;;;N;;;;;
+A4E2;LISU LETTER SA;Lo;0;L;;;;;N;;;;;
+A4E3;LISU LETTER ZHA;Lo;0;L;;;;;N;;;;;
+A4E4;LISU LETTER ZA;Lo;0;L;;;;;N;;;;;
+A4E5;LISU LETTER NGA;Lo;0;L;;;;;N;;;;;
+A4E6;LISU LETTER HA;Lo;0;L;;;;;N;;;;;
+A4E7;LISU LETTER XA;Lo;0;L;;;;;N;;;;;
+A4E8;LISU LETTER HHA;Lo;0;L;;;;;N;;;;;
+A4E9;LISU LETTER FA;Lo;0;L;;;;;N;;;;;
+A4EA;LISU LETTER WA;Lo;0;L;;;;;N;;;;;
+A4EB;LISU LETTER SHA;Lo;0;L;;;;;N;;;;;
+A4EC;LISU LETTER YA;Lo;0;L;;;;;N;;;;;
+A4ED;LISU LETTER GHA;Lo;0;L;;;;;N;;;;;
+A4EE;LISU LETTER A;Lo;0;L;;;;;N;;;;;
+A4EF;LISU LETTER AE;Lo;0;L;;;;;N;;;;;
+A4F0;LISU LETTER E;Lo;0;L;;;;;N;;;;;
+A4F1;LISU LETTER EU;Lo;0;L;;;;;N;;;;;
+A4F2;LISU LETTER I;Lo;0;L;;;;;N;;;;;
+A4F3;LISU LETTER O;Lo;0;L;;;;;N;;;;;
+A4F4;LISU LETTER U;Lo;0;L;;;;;N;;;;;
+A4F5;LISU LETTER UE;Lo;0;L;;;;;N;;;;;
+A4F6;LISU LETTER UH;Lo;0;L;;;;;N;;;;;
+A4F7;LISU LETTER OE;Lo;0;L;;;;;N;;;;;
+A4F8;LISU LETTER TONE MYA TI;Lm;0;L;;;;;N;;;;;
+A4F9;LISU LETTER TONE NA PO;Lm;0;L;;;;;N;;;;;
+A4FA;LISU LETTER TONE MYA CYA;Lm;0;L;;;;;N;;;;;
+A4FB;LISU LETTER TONE MYA BO;Lm;0;L;;;;;N;;;;;
+A4FC;LISU LETTER TONE MYA NA;Lm;0;L;;;;;N;;;;;
+A4FD;LISU LETTER TONE MYA JEU;Lm;0;L;;;;;N;;;;;
+A4FE;LISU PUNCTUATION COMMA;Po;0;L;;;;;N;;;;;
+A4FF;LISU PUNCTUATION FULL STOP;Po;0;L;;;;;N;;;;;
+A500;VAI SYLLABLE EE;Lo;0;L;;;;;N;;;;;
+A501;VAI SYLLABLE EEN;Lo;0;L;;;;;N;;;;;
+A502;VAI SYLLABLE HEE;Lo;0;L;;;;;N;;;;;
+A503;VAI SYLLABLE WEE;Lo;0;L;;;;;N;;;;;
+A504;VAI SYLLABLE WEEN;Lo;0;L;;;;;N;;;;;
+A505;VAI SYLLABLE PEE;Lo;0;L;;;;;N;;;;;
+A506;VAI SYLLABLE BHEE;Lo;0;L;;;;;N;;;;;
+A507;VAI SYLLABLE BEE;Lo;0;L;;;;;N;;;;;
+A508;VAI SYLLABLE MBEE;Lo;0;L;;;;;N;;;;;
+A509;VAI SYLLABLE KPEE;Lo;0;L;;;;;N;;;;;
+A50A;VAI SYLLABLE MGBEE;Lo;0;L;;;;;N;;;;;
+A50B;VAI SYLLABLE GBEE;Lo;0;L;;;;;N;;;;;
+A50C;VAI SYLLABLE FEE;Lo;0;L;;;;;N;;;;;
+A50D;VAI SYLLABLE VEE;Lo;0;L;;;;;N;;;;;
+A50E;VAI SYLLABLE TEE;Lo;0;L;;;;;N;;;;;
+A50F;VAI SYLLABLE THEE;Lo;0;L;;;;;N;;;;;
+A510;VAI SYLLABLE DHEE;Lo;0;L;;;;;N;;;;;
+A511;VAI SYLLABLE DHHEE;Lo;0;L;;;;;N;;;;;
+A512;VAI SYLLABLE LEE;Lo;0;L;;;;;N;;;;;
+A513;VAI SYLLABLE REE;Lo;0;L;;;;;N;;;;;
+A514;VAI SYLLABLE DEE;Lo;0;L;;;;;N;;;;;
+A515;VAI SYLLABLE NDEE;Lo;0;L;;;;;N;;;;;
+A516;VAI SYLLABLE SEE;Lo;0;L;;;;;N;;;;;
+A517;VAI SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;
+A518;VAI SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;
+A519;VAI SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;
+A51A;VAI SYLLABLE CEE;Lo;0;L;;;;;N;;;;;
+A51B;VAI SYLLABLE JEE;Lo;0;L;;;;;N;;;;;
+A51C;VAI SYLLABLE NJEE;Lo;0;L;;;;;N;;;;;
+A51D;VAI SYLLABLE YEE;Lo;0;L;;;;;N;;;;;
+A51E;VAI SYLLABLE KEE;Lo;0;L;;;;;N;;;;;
+A51F;VAI SYLLABLE NGGEE;Lo;0;L;;;;;N;;;;;
+A520;VAI SYLLABLE GEE;Lo;0;L;;;;;N;;;;;
+A521;VAI SYLLABLE MEE;Lo;0;L;;;;;N;;;;;
+A522;VAI SYLLABLE NEE;Lo;0;L;;;;;N;;;;;
+A523;VAI SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;
+A524;VAI SYLLABLE I;Lo;0;L;;;;;N;;;;;
+A525;VAI SYLLABLE IN;Lo;0;L;;;;;N;;;;;
+A526;VAI SYLLABLE HI;Lo;0;L;;;;;N;;;;;
+A527;VAI SYLLABLE HIN;Lo;0;L;;;;;N;;;;;
+A528;VAI SYLLABLE WI;Lo;0;L;;;;;N;;;;;
+A529;VAI SYLLABLE WIN;Lo;0;L;;;;;N;;;;;
+A52A;VAI SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+A52B;VAI SYLLABLE BHI;Lo;0;L;;;;;N;;;;;
+A52C;VAI SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+A52D;VAI SYLLABLE MBI;Lo;0;L;;;;;N;;;;;
+A52E;VAI SYLLABLE KPI;Lo;0;L;;;;;N;;;;;
+A52F;VAI SYLLABLE MGBI;Lo;0;L;;;;;N;;;;;
+A530;VAI SYLLABLE GBI;Lo;0;L;;;;;N;;;;;
+A531;VAI SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+A532;VAI SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+A533;VAI SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+A534;VAI SYLLABLE THI;Lo;0;L;;;;;N;;;;;
+A535;VAI SYLLABLE DHI;Lo;0;L;;;;;N;;;;;
+A536;VAI SYLLABLE DHHI;Lo;0;L;;;;;N;;;;;
+A537;VAI SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+A538;VAI SYLLABLE RI;Lo;0;L;;;;;N;;;;;
+A539;VAI SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+A53A;VAI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;
+A53B;VAI SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+A53C;VAI SYLLABLE SHI;Lo;0;L;;;;;N;;;;;
+A53D;VAI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+A53E;VAI SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;
+A53F;VAI SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+A540;VAI SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+A541;VAI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;
+A542;VAI SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+A543;VAI SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+A544;VAI SYLLABLE NGGI;Lo;0;L;;;;;N;;;;;
+A545;VAI SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+A546;VAI SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+A547;VAI SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+A548;VAI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+A549;VAI SYLLABLE A;Lo;0;L;;;;;N;;;;;
+A54A;VAI SYLLABLE AN;Lo;0;L;;;;;N;;;;;
+A54B;VAI SYLLABLE NGAN;Lo;0;L;;;;;N;;;;;
+A54C;VAI SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+A54D;VAI SYLLABLE HAN;Lo;0;L;;;;;N;;;;;
+A54E;VAI SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+A54F;VAI SYLLABLE WAN;Lo;0;L;;;;;N;;;;;
+A550;VAI SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+A551;VAI SYLLABLE BHA;Lo;0;L;;;;;N;;;;;
+A552;VAI SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+A553;VAI SYLLABLE MBA;Lo;0;L;;;;;N;;;;;
+A554;VAI SYLLABLE KPA;Lo;0;L;;;;;N;;;;;
+A555;VAI SYLLABLE KPAN;Lo;0;L;;;;;N;;;;;
+A556;VAI SYLLABLE MGBA;Lo;0;L;;;;;N;;;;;
+A557;VAI SYLLABLE GBA;Lo;0;L;;;;;N;;;;;
+A558;VAI SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+A559;VAI SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+A55A;VAI SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+A55B;VAI SYLLABLE THA;Lo;0;L;;;;;N;;;;;
+A55C;VAI SYLLABLE DHA;Lo;0;L;;;;;N;;;;;
+A55D;VAI SYLLABLE DHHA;Lo;0;L;;;;;N;;;;;
+A55E;VAI SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+A55F;VAI SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+A560;VAI SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+A561;VAI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;
+A562;VAI SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+A563;VAI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+A564;VAI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+A565;VAI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+A566;VAI SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+A567;VAI SYLLABLE JA;Lo;0;L;;;;;N;;;;;
+A568;VAI SYLLABLE NJA;Lo;0;L;;;;;N;;;;;
+A569;VAI SYLLABLE YA;Lo;0;L;;;;;N;;;;;
+A56A;VAI SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+A56B;VAI SYLLABLE KAN;Lo;0;L;;;;;N;;;;;
+A56C;VAI SYLLABLE NGGA;Lo;0;L;;;;;N;;;;;
+A56D;VAI SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+A56E;VAI SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+A56F;VAI SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+A570;VAI SYLLABLE NYA;Lo;0;L;;;;;N;;;;;
+A571;VAI SYLLABLE OO;Lo;0;L;;;;;N;;;;;
+A572;VAI SYLLABLE OON;Lo;0;L;;;;;N;;;;;
+A573;VAI SYLLABLE HOO;Lo;0;L;;;;;N;;;;;
+A574;VAI SYLLABLE WOO;Lo;0;L;;;;;N;;;;;
+A575;VAI SYLLABLE WOON;Lo;0;L;;;;;N;;;;;
+A576;VAI SYLLABLE POO;Lo;0;L;;;;;N;;;;;
+A577;VAI SYLLABLE BHOO;Lo;0;L;;;;;N;;;;;
+A578;VAI SYLLABLE BOO;Lo;0;L;;;;;N;;;;;
+A579;VAI SYLLABLE MBOO;Lo;0;L;;;;;N;;;;;
+A57A;VAI SYLLABLE KPOO;Lo;0;L;;;;;N;;;;;
+A57B;VAI SYLLABLE MGBOO;Lo;0;L;;;;;N;;;;;
+A57C;VAI SYLLABLE GBOO;Lo;0;L;;;;;N;;;;;
+A57D;VAI SYLLABLE FOO;Lo;0;L;;;;;N;;;;;
+A57E;VAI SYLLABLE VOO;Lo;0;L;;;;;N;;;;;
+A57F;VAI SYLLABLE TOO;Lo;0;L;;;;;N;;;;;
+A580;VAI SYLLABLE THOO;Lo;0;L;;;;;N;;;;;
+A581;VAI SYLLABLE DHOO;Lo;0;L;;;;;N;;;;;
+A582;VAI SYLLABLE DHHOO;Lo;0;L;;;;;N;;;;;
+A583;VAI SYLLABLE LOO;Lo;0;L;;;;;N;;;;;
+A584;VAI SYLLABLE ROO;Lo;0;L;;;;;N;;;;;
+A585;VAI SYLLABLE DOO;Lo;0;L;;;;;N;;;;;
+A586;VAI SYLLABLE NDOO;Lo;0;L;;;;;N;;;;;
+A587;VAI SYLLABLE SOO;Lo;0;L;;;;;N;;;;;
+A588;VAI SYLLABLE SHOO;Lo;0;L;;;;;N;;;;;
+A589;VAI SYLLABLE ZOO;Lo;0;L;;;;;N;;;;;
+A58A;VAI SYLLABLE ZHOO;Lo;0;L;;;;;N;;;;;
+A58B;VAI SYLLABLE COO;Lo;0;L;;;;;N;;;;;
+A58C;VAI SYLLABLE JOO;Lo;0;L;;;;;N;;;;;
+A58D;VAI SYLLABLE NJOO;Lo;0;L;;;;;N;;;;;
+A58E;VAI SYLLABLE YOO;Lo;0;L;;;;;N;;;;;
+A58F;VAI SYLLABLE KOO;Lo;0;L;;;;;N;;;;;
+A590;VAI SYLLABLE NGGOO;Lo;0;L;;;;;N;;;;;
+A591;VAI SYLLABLE GOO;Lo;0;L;;;;;N;;;;;
+A592;VAI SYLLABLE MOO;Lo;0;L;;;;;N;;;;;
+A593;VAI SYLLABLE NOO;Lo;0;L;;;;;N;;;;;
+A594;VAI SYLLABLE NYOO;Lo;0;L;;;;;N;;;;;
+A595;VAI SYLLABLE U;Lo;0;L;;;;;N;;;;;
+A596;VAI SYLLABLE UN;Lo;0;L;;;;;N;;;;;
+A597;VAI SYLLABLE HU;Lo;0;L;;;;;N;;;;;
+A598;VAI SYLLABLE HUN;Lo;0;L;;;;;N;;;;;
+A599;VAI SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+A59A;VAI SYLLABLE WUN;Lo;0;L;;;;;N;;;;;
+A59B;VAI SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+A59C;VAI SYLLABLE BHU;Lo;0;L;;;;;N;;;;;
+A59D;VAI SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+A59E;VAI SYLLABLE MBU;Lo;0;L;;;;;N;;;;;
+A59F;VAI SYLLABLE KPU;Lo;0;L;;;;;N;;;;;
+A5A0;VAI SYLLABLE MGBU;Lo;0;L;;;;;N;;;;;
+A5A1;VAI SYLLABLE GBU;Lo;0;L;;;;;N;;;;;
+A5A2;VAI SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+A5A3;VAI SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+A5A4;VAI SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+A5A5;VAI SYLLABLE THU;Lo;0;L;;;;;N;;;;;
+A5A6;VAI SYLLABLE DHU;Lo;0;L;;;;;N;;;;;
+A5A7;VAI SYLLABLE DHHU;Lo;0;L;;;;;N;;;;;
+A5A8;VAI SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+A5A9;VAI SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+A5AA;VAI SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+A5AB;VAI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;
+A5AC;VAI SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+A5AD;VAI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+A5AE;VAI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+A5AF;VAI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+A5B0;VAI SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+A5B1;VAI SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+A5B2;VAI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;
+A5B3;VAI SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+A5B4;VAI SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+A5B5;VAI SYLLABLE NGGU;Lo;0;L;;;;;N;;;;;
+A5B6;VAI SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+A5B7;VAI SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+A5B8;VAI SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+A5B9;VAI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+A5BA;VAI SYLLABLE O;Lo;0;L;;;;;N;;;;;
+A5BB;VAI SYLLABLE ON;Lo;0;L;;;;;N;;;;;
+A5BC;VAI SYLLABLE NGON;Lo;0;L;;;;;N;;;;;
+A5BD;VAI SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+A5BE;VAI SYLLABLE HON;Lo;0;L;;;;;N;;;;;
+A5BF;VAI SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+A5C0;VAI SYLLABLE WON;Lo;0;L;;;;;N;;;;;
+A5C1;VAI SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+A5C2;VAI SYLLABLE BHO;Lo;0;L;;;;;N;;;;;
+A5C3;VAI SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+A5C4;VAI SYLLABLE MBO;Lo;0;L;;;;;N;;;;;
+A5C5;VAI SYLLABLE KPO;Lo;0;L;;;;;N;;;;;
+A5C6;VAI SYLLABLE MGBO;Lo;0;L;;;;;N;;;;;
+A5C7;VAI SYLLABLE GBO;Lo;0;L;;;;;N;;;;;
+A5C8;VAI SYLLABLE GBON;Lo;0;L;;;;;N;;;;;
+A5C9;VAI SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+A5CA;VAI SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+A5CB;VAI SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+A5CC;VAI SYLLABLE THO;Lo;0;L;;;;;N;;;;;
+A5CD;VAI SYLLABLE DHO;Lo;0;L;;;;;N;;;;;
+A5CE;VAI SYLLABLE DHHO;Lo;0;L;;;;;N;;;;;
+A5CF;VAI SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+A5D0;VAI SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+A5D1;VAI SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+A5D2;VAI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;
+A5D3;VAI SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+A5D4;VAI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+A5D5;VAI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+A5D6;VAI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+A5D7;VAI SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+A5D8;VAI SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+A5D9;VAI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;
+A5DA;VAI SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+A5DB;VAI SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+A5DC;VAI SYLLABLE NGGO;Lo;0;L;;;;;N;;;;;
+A5DD;VAI SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+A5DE;VAI SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+A5DF;VAI SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+A5E0;VAI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+A5E1;VAI SYLLABLE E;Lo;0;L;;;;;N;;;;;
+A5E2;VAI SYLLABLE EN;Lo;0;L;;;;;N;;;;;
+A5E3;VAI SYLLABLE NGEN;Lo;0;L;;;;;N;;;;;
+A5E4;VAI SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+A5E5;VAI SYLLABLE HEN;Lo;0;L;;;;;N;;;;;
+A5E6;VAI SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+A5E7;VAI SYLLABLE WEN;Lo;0;L;;;;;N;;;;;
+A5E8;VAI SYLLABLE PE;Lo;0;L;;;;;N;;;;;
+A5E9;VAI SYLLABLE BHE;Lo;0;L;;;;;N;;;;;
+A5EA;VAI SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+A5EB;VAI SYLLABLE MBE;Lo;0;L;;;;;N;;;;;
+A5EC;VAI SYLLABLE KPE;Lo;0;L;;;;;N;;;;;
+A5ED;VAI SYLLABLE KPEN;Lo;0;L;;;;;N;;;;;
+A5EE;VAI SYLLABLE MGBE;Lo;0;L;;;;;N;;;;;
+A5EF;VAI SYLLABLE GBE;Lo;0;L;;;;;N;;;;;
+A5F0;VAI SYLLABLE GBEN;Lo;0;L;;;;;N;;;;;
+A5F1;VAI SYLLABLE FE;Lo;0;L;;;;;N;;;;;
+A5F2;VAI SYLLABLE VE;Lo;0;L;;;;;N;;;;;
+A5F3;VAI SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+A5F4;VAI SYLLABLE THE;Lo;0;L;;;;;N;;;;;
+A5F5;VAI SYLLABLE DHE;Lo;0;L;;;;;N;;;;;
+A5F6;VAI SYLLABLE DHHE;Lo;0;L;;;;;N;;;;;
+A5F7;VAI SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+A5F8;VAI SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+A5F9;VAI SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+A5FA;VAI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;
+A5FB;VAI SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+A5FC;VAI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+A5FD;VAI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+A5FE;VAI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+A5FF;VAI SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+A600;VAI SYLLABLE JE;Lo;0;L;;;;;N;;;;;
+A601;VAI SYLLABLE NJE;Lo;0;L;;;;;N;;;;;
+A602;VAI SYLLABLE YE;Lo;0;L;;;;;N;;;;;
+A603;VAI SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+A604;VAI SYLLABLE NGGE;Lo;0;L;;;;;N;;;;;
+A605;VAI SYLLABLE NGGEN;Lo;0;L;;;;;N;;;;;
+A606;VAI SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+A607;VAI SYLLABLE GEN;Lo;0;L;;;;;N;;;;;
+A608;VAI SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+A609;VAI SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+A60A;VAI SYLLABLE NYE;Lo;0;L;;;;;N;;;;;
+A60B;VAI SYLLABLE NG;Lo;0;L;;;;;N;;;;;
+A60C;VAI SYLLABLE LENGTHENER;Lm;0;L;;;;;N;;;;;
+A60D;VAI COMMA;Po;0;ON;;;;;N;;;;;
+A60E;VAI FULL STOP;Po;0;ON;;;;;N;;;;;
+A60F;VAI QUESTION MARK;Po;0;ON;;;;;N;;;;;
+A610;VAI SYLLABLE NDOLE FA;Lo;0;L;;;;;N;;;;;
+A611;VAI SYLLABLE NDOLE KA;Lo;0;L;;;;;N;;;;;
+A612;VAI SYLLABLE NDOLE SOO;Lo;0;L;;;;;N;;;;;
+A613;VAI SYMBOL FEENG;Lo;0;L;;;;;N;;;;;
+A614;VAI SYMBOL KEENG;Lo;0;L;;;;;N;;;;;
+A615;VAI SYMBOL TING;Lo;0;L;;;;;N;;;;;
+A616;VAI SYMBOL NII;Lo;0;L;;;;;N;;;;;
+A617;VAI SYMBOL BANG;Lo;0;L;;;;;N;;;;;
+A618;VAI SYMBOL FAA;Lo;0;L;;;;;N;;;;;
+A619;VAI SYMBOL TAA;Lo;0;L;;;;;N;;;;;
+A61A;VAI SYMBOL DANG;Lo;0;L;;;;;N;;;;;
+A61B;VAI SYMBOL DOONG;Lo;0;L;;;;;N;;;;;
+A61C;VAI SYMBOL KUNG;Lo;0;L;;;;;N;;;;;
+A61D;VAI SYMBOL TONG;Lo;0;L;;;;;N;;;;;
+A61E;VAI SYMBOL DO-O;Lo;0;L;;;;;N;;;;;
+A61F;VAI SYMBOL JONG;Lo;0;L;;;;;N;;;;;
+A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+A62A;VAI SYLLABLE NDOLE MA;Lo;0;L;;;;;N;;;;;
+A62B;VAI SYLLABLE NDOLE DO;Lo;0;L;;;;;N;;;;;
+A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
+A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
+A642;CYRILLIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;A643;
+A643;CYRILLIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;A642;;A642
+A644;CYRILLIC CAPITAL LETTER REVERSED DZE;Lu;0;L;;;;;N;;;;A645;
+A645;CYRILLIC SMALL LETTER REVERSED DZE;Ll;0;L;;;;;N;;;A644;;A644
+A646;CYRILLIC CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;A647;
+A647;CYRILLIC SMALL LETTER IOTA;Ll;0;L;;;;;N;;;A646;;A646
+A648;CYRILLIC CAPITAL LETTER DJERV;Lu;0;L;;;;;N;;;;A649;
+A649;CYRILLIC SMALL LETTER DJERV;Ll;0;L;;;;;N;;;A648;;A648
+A64A;CYRILLIC CAPITAL LETTER MONOGRAPH UK;Lu;0;L;;;;;N;;;;A64B;
+A64B;CYRILLIC SMALL LETTER MONOGRAPH UK;Ll;0;L;;;;;N;;;A64A;;A64A
+A64C;CYRILLIC CAPITAL LETTER BROAD OMEGA;Lu;0;L;;;;;N;;;;A64D;
+A64D;CYRILLIC SMALL LETTER BROAD OMEGA;Ll;0;L;;;;;N;;;A64C;;A64C
+A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
+A64F;CYRILLIC SMALL LETTER NEUTRAL YER;Ll;0;L;;;;;N;;;A64E;;A64E
+A650;CYRILLIC CAPITAL LETTER YERU WITH BACK YER;Lu;0;L;;;;;N;;;;A651;
+A651;CYRILLIC SMALL LETTER YERU WITH BACK YER;Ll;0;L;;;;;N;;;A650;;A650
+A652;CYRILLIC CAPITAL LETTER IOTIFIED YAT;Lu;0;L;;;;;N;;;;A653;
+A653;CYRILLIC SMALL LETTER IOTIFIED YAT;Ll;0;L;;;;;N;;;A652;;A652
+A654;CYRILLIC CAPITAL LETTER REVERSED YU;Lu;0;L;;;;;N;;;;A655;
+A655;CYRILLIC SMALL LETTER REVERSED YU;Ll;0;L;;;;;N;;;A654;;A654
+A656;CYRILLIC CAPITAL LETTER IOTIFIED A;Lu;0;L;;;;;N;;;;A657;
+A657;CYRILLIC SMALL LETTER IOTIFIED A;Ll;0;L;;;;;N;;;A656;;A656
+A658;CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A659;
+A659;CYRILLIC SMALL LETTER CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A658;;A658
+A65A;CYRILLIC CAPITAL LETTER BLENDED YUS;Lu;0;L;;;;;N;;;;A65B;
+A65B;CYRILLIC SMALL LETTER BLENDED YUS;Ll;0;L;;;;;N;;;A65A;;A65A
+A65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D;
+A65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C
+A65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F;
+A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
+A660;CYRILLIC CAPITAL LETTER REVERSED TSE;Lu;0;L;;;;;N;;;;A661;
+A661;CYRILLIC SMALL LETTER REVERSED TSE;Ll;0;L;;;;;N;;;A660;;A660
+A662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663;
+A663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662
+A664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665;
+A665;CYRILLIC SMALL LETTER SOFT EL;Ll;0;L;;;;;N;;;A664;;A664
+A666;CYRILLIC CAPITAL LETTER SOFT EM;Lu;0;L;;;;;N;;;;A667;
+A667;CYRILLIC SMALL LETTER SOFT EM;Ll;0;L;;;;;N;;;A666;;A666
+A668;CYRILLIC CAPITAL LETTER MONOCULAR O;Lu;0;L;;;;;N;;;;A669;
+A669;CYRILLIC SMALL LETTER MONOCULAR O;Ll;0;L;;;;;N;;;A668;;A668
+A66A;CYRILLIC CAPITAL LETTER BINOCULAR O;Lu;0;L;;;;;N;;;;A66B;
+A66B;CYRILLIC SMALL LETTER BINOCULAR O;Ll;0;L;;;;;N;;;A66A;;A66A
+A66C;CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O;Lu;0;L;;;;;N;;;;A66D;
+A66D;CYRILLIC SMALL LETTER DOUBLE MONOCULAR O;Ll;0;L;;;;;N;;;A66C;;A66C
+A66E;CYRILLIC LETTER MULTIOCULAR O;Lo;0;L;;;;;N;;;;;
+A66F;COMBINING CYRILLIC VZMET;Mn;230;NSM;;;;;N;;;;;
+A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+A673;SLAVONIC ASTERISK;Po;0;ON;;;;;N;;;;;
+A674;COMBINING CYRILLIC LETTER UKRAINIAN IE;Mn;230;NSM;;;;;N;;;;;
+A675;COMBINING CYRILLIC LETTER I;Mn;230;NSM;;;;;N;;;;;
+A676;COMBINING CYRILLIC LETTER YI;Mn;230;NSM;;;;;N;;;;;
+A677;COMBINING CYRILLIC LETTER U;Mn;230;NSM;;;;;N;;;;;
+A678;COMBINING CYRILLIC LETTER HARD SIGN;Mn;230;NSM;;;;;N;;;;;
+A679;COMBINING CYRILLIC LETTER YERU;Mn;230;NSM;;;;;N;;;;;
+A67A;COMBINING CYRILLIC LETTER SOFT SIGN;Mn;230;NSM;;;;;N;;;;;
+A67B;COMBINING CYRILLIC LETTER OMEGA;Mn;230;NSM;;;;;N;;;;;
+A67C;COMBINING CYRILLIC KAVYKA;Mn;230;NSM;;;;;N;;;;;
+A67D;COMBINING CYRILLIC PAYEROK;Mn;230;NSM;;;;;N;;;;;
+A67E;CYRILLIC KAVYKA;Po;0;ON;;;;;N;;;;;
+A67F;CYRILLIC PAYEROK;Lm;0;ON;;;;;N;;;;;
+A680;CYRILLIC CAPITAL LETTER DWE;Lu;0;L;;;;;N;;;;A681;
+A681;CYRILLIC SMALL LETTER DWE;Ll;0;L;;;;;N;;;A680;;A680
+A682;CYRILLIC CAPITAL LETTER DZWE;Lu;0;L;;;;;N;;;;A683;
+A683;CYRILLIC SMALL LETTER DZWE;Ll;0;L;;;;;N;;;A682;;A682
+A684;CYRILLIC CAPITAL LETTER ZHWE;Lu;0;L;;;;;N;;;;A685;
+A685;CYRILLIC SMALL LETTER ZHWE;Ll;0;L;;;;;N;;;A684;;A684
+A686;CYRILLIC CAPITAL LETTER CCHE;Lu;0;L;;;;;N;;;;A687;
+A687;CYRILLIC SMALL LETTER CCHE;Ll;0;L;;;;;N;;;A686;;A686
+A688;CYRILLIC CAPITAL LETTER DZZE;Lu;0;L;;;;;N;;;;A689;
+A689;CYRILLIC SMALL LETTER DZZE;Ll;0;L;;;;;N;;;A688;;A688
+A68A;CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK;Lu;0;L;;;;;N;;;;A68B;
+A68B;CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;A68A;;A68A
+A68C;CYRILLIC CAPITAL LETTER TWE;Lu;0;L;;;;;N;;;;A68D;
+A68D;CYRILLIC SMALL LETTER TWE;Ll;0;L;;;;;N;;;A68C;;A68C
+A68E;CYRILLIC CAPITAL LETTER TSWE;Lu;0;L;;;;;N;;;;A68F;
+A68F;CYRILLIC SMALL LETTER TSWE;Ll;0;L;;;;;N;;;A68E;;A68E
+A690;CYRILLIC CAPITAL LETTER TSSE;Lu;0;L;;;;;N;;;;A691;
+A691;CYRILLIC SMALL LETTER TSSE;Ll;0;L;;;;;N;;;A690;;A690
+A692;CYRILLIC CAPITAL LETTER TCHE;Lu;0;L;;;;;N;;;;A693;
+A693;CYRILLIC SMALL LETTER TCHE;Ll;0;L;;;;;N;;;A692;;A692
+A694;CYRILLIC CAPITAL LETTER HWE;Lu;0;L;;;;;N;;;;A695;
+A695;CYRILLIC SMALL LETTER HWE;Ll;0;L;;;;;N;;;A694;;A694
+A696;CYRILLIC CAPITAL LETTER SHWE;Lu;0;L;;;;;N;;;;A697;
+A697;CYRILLIC SMALL LETTER SHWE;Ll;0;L;;;;;N;;;A696;;A696
+A698;CYRILLIC CAPITAL LETTER DOUBLE O;Lu;0;L;;;;;N;;;;A699;
+A699;CYRILLIC SMALL LETTER DOUBLE O;Ll;0;L;;;;;N;;;A698;;A698
+A69A;CYRILLIC CAPITAL LETTER CROSSED O;Lu;0;L;;;;;N;;;;A69B;
+A69B;CYRILLIC SMALL LETTER CROSSED O;Ll;0;L;;;;;N;;;A69A;;A69A
+A69C;MODIFIER LETTER CYRILLIC HARD SIGN;Lm;0;L;<super> 044A;;;;N;;;;;
+A69D;MODIFIER LETTER CYRILLIC SOFT SIGN;Lm;0;L;<super> 044C;;;;N;;;;;
+A69E;COMBINING CYRILLIC LETTER EF;Mn;230;NSM;;;;;N;;;;;
+A69F;COMBINING CYRILLIC LETTER IOTIFIED E;Mn;230;NSM;;;;;N;;;;;
+A6A0;BAMUM LETTER A;Lo;0;L;;;;;N;;;;;
+A6A1;BAMUM LETTER KA;Lo;0;L;;;;;N;;;;;
+A6A2;BAMUM LETTER U;Lo;0;L;;;;;N;;;;;
+A6A3;BAMUM LETTER KU;Lo;0;L;;;;;N;;;;;
+A6A4;BAMUM LETTER EE;Lo;0;L;;;;;N;;;;;
+A6A5;BAMUM LETTER REE;Lo;0;L;;;;;N;;;;;
+A6A6;BAMUM LETTER TAE;Lo;0;L;;;;;N;;;;;
+A6A7;BAMUM LETTER O;Lo;0;L;;;;;N;;;;;
+A6A8;BAMUM LETTER NYI;Lo;0;L;;;;;N;;;;;
+A6A9;BAMUM LETTER I;Lo;0;L;;;;;N;;;;;
+A6AA;BAMUM LETTER LA;Lo;0;L;;;;;N;;;;;
+A6AB;BAMUM LETTER PA;Lo;0;L;;;;;N;;;;;
+A6AC;BAMUM LETTER RII;Lo;0;L;;;;;N;;;;;
+A6AD;BAMUM LETTER RIEE;Lo;0;L;;;;;N;;;;;
+A6AE;BAMUM LETTER LEEEE;Lo;0;L;;;;;N;;;;;
+A6AF;BAMUM LETTER MEEEE;Lo;0;L;;;;;N;;;;;
+A6B0;BAMUM LETTER TAA;Lo;0;L;;;;;N;;;;;
+A6B1;BAMUM LETTER NDAA;Lo;0;L;;;;;N;;;;;
+A6B2;BAMUM LETTER NJAEM;Lo;0;L;;;;;N;;;;;
+A6B3;BAMUM LETTER M;Lo;0;L;;;;;N;;;;;
+A6B4;BAMUM LETTER SUU;Lo;0;L;;;;;N;;;;;
+A6B5;BAMUM LETTER MU;Lo;0;L;;;;;N;;;;;
+A6B6;BAMUM LETTER SHII;Lo;0;L;;;;;N;;;;;
+A6B7;BAMUM LETTER SI;Lo;0;L;;;;;N;;;;;
+A6B8;BAMUM LETTER SHEUX;Lo;0;L;;;;;N;;;;;
+A6B9;BAMUM LETTER SEUX;Lo;0;L;;;;;N;;;;;
+A6BA;BAMUM LETTER KYEE;Lo;0;L;;;;;N;;;;;
+A6BB;BAMUM LETTER KET;Lo;0;L;;;;;N;;;;;
+A6BC;BAMUM LETTER NUAE;Lo;0;L;;;;;N;;;;;
+A6BD;BAMUM LETTER NU;Lo;0;L;;;;;N;;;;;
+A6BE;BAMUM LETTER NJUAE;Lo;0;L;;;;;N;;;;;
+A6BF;BAMUM LETTER YOQ;Lo;0;L;;;;;N;;;;;
+A6C0;BAMUM LETTER SHU;Lo;0;L;;;;;N;;;;;
+A6C1;BAMUM LETTER YUQ;Lo;0;L;;;;;N;;;;;
+A6C2;BAMUM LETTER YA;Lo;0;L;;;;;N;;;;;
+A6C3;BAMUM LETTER NSHA;Lo;0;L;;;;;N;;;;;
+A6C4;BAMUM LETTER KEUX;Lo;0;L;;;;;N;;;;;
+A6C5;BAMUM LETTER PEUX;Lo;0;L;;;;;N;;;;;
+A6C6;BAMUM LETTER NJEE;Lo;0;L;;;;;N;;;;;
+A6C7;BAMUM LETTER NTEE;Lo;0;L;;;;;N;;;;;
+A6C8;BAMUM LETTER PUE;Lo;0;L;;;;;N;;;;;
+A6C9;BAMUM LETTER WUE;Lo;0;L;;;;;N;;;;;
+A6CA;BAMUM LETTER PEE;Lo;0;L;;;;;N;;;;;
+A6CB;BAMUM LETTER FEE;Lo;0;L;;;;;N;;;;;
+A6CC;BAMUM LETTER RU;Lo;0;L;;;;;N;;;;;
+A6CD;BAMUM LETTER LU;Lo;0;L;;;;;N;;;;;
+A6CE;BAMUM LETTER MI;Lo;0;L;;;;;N;;;;;
+A6CF;BAMUM LETTER NI;Lo;0;L;;;;;N;;;;;
+A6D0;BAMUM LETTER REUX;Lo;0;L;;;;;N;;;;;
+A6D1;BAMUM LETTER RAE;Lo;0;L;;;;;N;;;;;
+A6D2;BAMUM LETTER KEN;Lo;0;L;;;;;N;;;;;
+A6D3;BAMUM LETTER NGKWAEN;Lo;0;L;;;;;N;;;;;
+A6D4;BAMUM LETTER NGGA;Lo;0;L;;;;;N;;;;;
+A6D5;BAMUM LETTER NGA;Lo;0;L;;;;;N;;;;;
+A6D6;BAMUM LETTER SHO;Lo;0;L;;;;;N;;;;;
+A6D7;BAMUM LETTER PUAE;Lo;0;L;;;;;N;;;;;
+A6D8;BAMUM LETTER FU;Lo;0;L;;;;;N;;;;;
+A6D9;BAMUM LETTER FOM;Lo;0;L;;;;;N;;;;;
+A6DA;BAMUM LETTER WA;Lo;0;L;;;;;N;;;;;
+A6DB;BAMUM LETTER NA;Lo;0;L;;;;;N;;;;;
+A6DC;BAMUM LETTER LI;Lo;0;L;;;;;N;;;;;
+A6DD;BAMUM LETTER PI;Lo;0;L;;;;;N;;;;;
+A6DE;BAMUM LETTER LOQ;Lo;0;L;;;;;N;;;;;
+A6DF;BAMUM LETTER KO;Lo;0;L;;;;;N;;;;;
+A6E0;BAMUM LETTER MBEN;Lo;0;L;;;;;N;;;;;
+A6E1;BAMUM LETTER REN;Lo;0;L;;;;;N;;;;;
+A6E2;BAMUM LETTER MEN;Lo;0;L;;;;;N;;;;;
+A6E3;BAMUM LETTER MA;Lo;0;L;;;;;N;;;;;
+A6E4;BAMUM LETTER TI;Lo;0;L;;;;;N;;;;;
+A6E5;BAMUM LETTER KI;Lo;0;L;;;;;N;;;;;
+A6E6;BAMUM LETTER MO;Nl;0;L;;;;1;N;;;;;
+A6E7;BAMUM LETTER MBAA;Nl;0;L;;;;2;N;;;;;
+A6E8;BAMUM LETTER TET;Nl;0;L;;;;3;N;;;;;
+A6E9;BAMUM LETTER KPA;Nl;0;L;;;;4;N;;;;;
+A6EA;BAMUM LETTER TEN;Nl;0;L;;;;5;N;;;;;
+A6EB;BAMUM LETTER NTUU;Nl;0;L;;;;6;N;;;;;
+A6EC;BAMUM LETTER SAMBA;Nl;0;L;;;;7;N;;;;;
+A6ED;BAMUM LETTER FAAMAE;Nl;0;L;;;;8;N;;;;;
+A6EE;BAMUM LETTER KOVUU;Nl;0;L;;;;9;N;;;;;
+A6EF;BAMUM LETTER KOGHOM;Nl;0;L;;;;0;N;;;;;
+A6F0;BAMUM COMBINING MARK KOQNDON;Mn;230;NSM;;;;;N;;;;;
+A6F1;BAMUM COMBINING MARK TUKWENTIS;Mn;230;NSM;;;;;N;;;;;
+A6F2;BAMUM NJAEMLI;Po;0;L;;;;;N;;;;;
+A6F3;BAMUM FULL STOP;Po;0;L;;;;;N;;;;;
+A6F4;BAMUM COLON;Po;0;L;;;;;N;;;;;
+A6F5;BAMUM COMMA;Po;0;L;;;;;N;;;;;
+A6F6;BAMUM SEMICOLON;Po;0;L;;;;;N;;;;;
+A6F7;BAMUM QUESTION MARK;Po;0;L;;;;;N;;;;;
+A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;;
+A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;;
+A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;;
+A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;;
+A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;;
+A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;;
+A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;;
+A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;;
+A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A717;MODIFIER LETTER DOT VERTICAL BAR;Lm;0;ON;;;;;N;;;;;
+A718;MODIFIER LETTER DOT SLASH;Lm;0;ON;;;;;N;;;;;
+A719;MODIFIER LETTER DOT HORIZONTAL BAR;Lm;0;ON;;;;;N;;;;;
+A71A;MODIFIER LETTER LOWER RIGHT CORNER ANGLE;Lm;0;ON;;;;;N;;;;;
+A71B;MODIFIER LETTER RAISED UP ARROW;Lm;0;ON;;;;;N;;;;;
+A71C;MODIFIER LETTER RAISED DOWN ARROW;Lm;0;ON;;;;;N;;;;;
+A71D;MODIFIER LETTER RAISED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;
+A71E;MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;
+A71F;MODIFIER LETTER LOW INVERTED EXCLAMATION MARK;Lm;0;ON;;;;;N;;;;;
+A720;MODIFIER LETTER STRESS AND HIGH TONE;Sk;0;ON;;;;;N;;;;;
+A721;MODIFIER LETTER STRESS AND LOW TONE;Sk;0;ON;;;;;N;;;;;
+A722;LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF;Lu;0;L;;;;;N;;;;A723;
+A723;LATIN SMALL LETTER EGYPTOLOGICAL ALEF;Ll;0;L;;;;;N;;;A722;;A722
+A724;LATIN CAPITAL LETTER EGYPTOLOGICAL AIN;Lu;0;L;;;;;N;;;;A725;
+A725;LATIN SMALL LETTER EGYPTOLOGICAL AIN;Ll;0;L;;;;;N;;;A724;;A724
+A726;LATIN CAPITAL LETTER HENG;Lu;0;L;;;;;N;;;;A727;
+A727;LATIN SMALL LETTER HENG;Ll;0;L;;;;;N;;;A726;;A726
+A728;LATIN CAPITAL LETTER TZ;Lu;0;L;;;;;N;;;;A729;
+A729;LATIN SMALL LETTER TZ;Ll;0;L;;;;;N;;;A728;;A728
+A72A;LATIN CAPITAL LETTER TRESILLO;Lu;0;L;;;;;N;;;;A72B;
+A72B;LATIN SMALL LETTER TRESILLO;Ll;0;L;;;;;N;;;A72A;;A72A
+A72C;LATIN CAPITAL LETTER CUATRILLO;Lu;0;L;;;;;N;;;;A72D;
+A72D;LATIN SMALL LETTER CUATRILLO;Ll;0;L;;;;;N;;;A72C;;A72C
+A72E;LATIN CAPITAL LETTER CUATRILLO WITH COMMA;Lu;0;L;;;;;N;;;;A72F;
+A72F;LATIN SMALL LETTER CUATRILLO WITH COMMA;Ll;0;L;;;;;N;;;A72E;;A72E
+A730;LATIN LETTER SMALL CAPITAL F;Ll;0;L;;;;;N;;;;;
+A731;LATIN LETTER SMALL CAPITAL S;Ll;0;L;;;;;N;;;;;
+A732;LATIN CAPITAL LETTER AA;Lu;0;L;;;;;N;;;;A733;
+A733;LATIN SMALL LETTER AA;Ll;0;L;;;;;N;;;A732;;A732
+A734;LATIN CAPITAL LETTER AO;Lu;0;L;;;;;N;;;;A735;
+A735;LATIN SMALL LETTER AO;Ll;0;L;;;;;N;;;A734;;A734
+A736;LATIN CAPITAL LETTER AU;Lu;0;L;;;;;N;;;;A737;
+A737;LATIN SMALL LETTER AU;Ll;0;L;;;;;N;;;A736;;A736
+A738;LATIN CAPITAL LETTER AV;Lu;0;L;;;;;N;;;;A739;
+A739;LATIN SMALL LETTER AV;Ll;0;L;;;;;N;;;A738;;A738
+A73A;LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR;Lu;0;L;;;;;N;;;;A73B;
+A73B;LATIN SMALL LETTER AV WITH HORIZONTAL BAR;Ll;0;L;;;;;N;;;A73A;;A73A
+A73C;LATIN CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;A73D;
+A73D;LATIN SMALL LETTER AY;Ll;0;L;;;;;N;;;A73C;;A73C
+A73E;LATIN CAPITAL LETTER REVERSED C WITH DOT;Lu;0;L;;;;;N;;;;A73F;
+A73F;LATIN SMALL LETTER REVERSED C WITH DOT;Ll;0;L;;;;;N;;;A73E;;A73E
+A740;LATIN CAPITAL LETTER K WITH STROKE;Lu;0;L;;;;;N;;;;A741;
+A741;LATIN SMALL LETTER K WITH STROKE;Ll;0;L;;;;;N;;;A740;;A740
+A742;LATIN CAPITAL LETTER K WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A743;
+A743;LATIN SMALL LETTER K WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A742;;A742
+A744;LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A745;
+A745;LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE;Ll;0;L;;;;;N;;;A744;;A744
+A746;LATIN CAPITAL LETTER BROKEN L;Lu;0;L;;;;;N;;;;A747;
+A747;LATIN SMALL LETTER BROKEN L;Ll;0;L;;;;;N;;;A746;;A746
+A748;LATIN CAPITAL LETTER L WITH HIGH STROKE;Lu;0;L;;;;;N;;;;A749;
+A749;LATIN SMALL LETTER L WITH HIGH STROKE;Ll;0;L;;;;;N;;;A748;;A748
+A74A;LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY;Lu;0;L;;;;;N;;;;A74B;
+A74B;LATIN SMALL LETTER O WITH LONG STROKE OVERLAY;Ll;0;L;;;;;N;;;A74A;;A74A
+A74C;LATIN CAPITAL LETTER O WITH LOOP;Lu;0;L;;;;;N;;;;A74D;
+A74D;LATIN SMALL LETTER O WITH LOOP;Ll;0;L;;;;;N;;;A74C;;A74C
+A74E;LATIN CAPITAL LETTER OO;Lu;0;L;;;;;N;;;;A74F;
+A74F;LATIN SMALL LETTER OO;Ll;0;L;;;;;N;;;A74E;;A74E
+A750;LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A751;
+A751;LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A750;;A750
+A752;LATIN CAPITAL LETTER P WITH FLOURISH;Lu;0;L;;;;;N;;;;A753;
+A753;LATIN SMALL LETTER P WITH FLOURISH;Ll;0;L;;;;;N;;;A752;;A752
+A754;LATIN CAPITAL LETTER P WITH SQUIRREL TAIL;Lu;0;L;;;;;N;;;;A755;
+A755;LATIN SMALL LETTER P WITH SQUIRREL TAIL;Ll;0;L;;;;;N;;;A754;;A754
+A756;LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A757;
+A757;LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A756;;A756
+A758;LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A759;
+A759;LATIN SMALL LETTER Q WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A758;;A758
+A75A;LATIN CAPITAL LETTER R ROTUNDA;Lu;0;L;;;;;N;;;;A75B;
+A75B;LATIN SMALL LETTER R ROTUNDA;Ll;0;L;;;;;N;;;A75A;;A75A
+A75C;LATIN CAPITAL LETTER RUM ROTUNDA;Lu;0;L;;;;;N;;;;A75D;
+A75D;LATIN SMALL LETTER RUM ROTUNDA;Ll;0;L;;;;;N;;;A75C;;A75C
+A75E;LATIN CAPITAL LETTER V WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A75F;
+A75F;LATIN SMALL LETTER V WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A75E;;A75E
+A760;LATIN CAPITAL LETTER VY;Lu;0;L;;;;;N;;;;A761;
+A761;LATIN SMALL LETTER VY;Ll;0;L;;;;;N;;;A760;;A760
+A762;LATIN CAPITAL LETTER VISIGOTHIC Z;Lu;0;L;;;;;N;;;;A763;
+A763;LATIN SMALL LETTER VISIGOTHIC Z;Ll;0;L;;;;;N;;;A762;;A762
+A764;LATIN CAPITAL LETTER THORN WITH STROKE;Lu;0;L;;;;;N;;;;A765;
+A765;LATIN SMALL LETTER THORN WITH STROKE;Ll;0;L;;;;;N;;;A764;;A764
+A766;LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER;Lu;0;L;;;;;N;;;;A767;
+A767;LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER;Ll;0;L;;;;;N;;;A766;;A766
+A768;LATIN CAPITAL LETTER VEND;Lu;0;L;;;;;N;;;;A769;
+A769;LATIN SMALL LETTER VEND;Ll;0;L;;;;;N;;;A768;;A768
+A76A;LATIN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;A76B;
+A76B;LATIN SMALL LETTER ET;Ll;0;L;;;;;N;;;A76A;;A76A
+A76C;LATIN CAPITAL LETTER IS;Lu;0;L;;;;;N;;;;A76D;
+A76D;LATIN SMALL LETTER IS;Ll;0;L;;;;;N;;;A76C;;A76C
+A76E;LATIN CAPITAL LETTER CON;Lu;0;L;;;;;N;;;;A76F;
+A76F;LATIN SMALL LETTER CON;Ll;0;L;;;;;N;;;A76E;;A76E
+A770;MODIFIER LETTER US;Lm;0;L;<super> A76F;;;;N;;;;;
+A771;LATIN SMALL LETTER DUM;Ll;0;L;;;;;N;;;;;
+A772;LATIN SMALL LETTER LUM;Ll;0;L;;;;;N;;;;;
+A773;LATIN SMALL LETTER MUM;Ll;0;L;;;;;N;;;;;
+A774;LATIN SMALL LETTER NUM;Ll;0;L;;;;;N;;;;;
+A775;LATIN SMALL LETTER RUM;Ll;0;L;;;;;N;;;;;
+A776;LATIN LETTER SMALL CAPITAL RUM;Ll;0;L;;;;;N;;;;;
+A777;LATIN SMALL LETTER TUM;Ll;0;L;;;;;N;;;;;
+A778;LATIN SMALL LETTER UM;Ll;0;L;;;;;N;;;;;
+A779;LATIN CAPITAL LETTER INSULAR D;Lu;0;L;;;;;N;;;;A77A;
+A77A;LATIN SMALL LETTER INSULAR D;Ll;0;L;;;;;N;;;A779;;A779
+A77B;LATIN CAPITAL LETTER INSULAR F;Lu;0;L;;;;;N;;;;A77C;
+A77C;LATIN SMALL LETTER INSULAR F;Ll;0;L;;;;;N;;;A77B;;A77B
+A77D;LATIN CAPITAL LETTER INSULAR G;Lu;0;L;;;;;N;;;;1D79;
+A77E;LATIN CAPITAL LETTER TURNED INSULAR G;Lu;0;L;;;;;N;;;;A77F;
+A77F;LATIN SMALL LETTER TURNED INSULAR G;Ll;0;L;;;;;N;;;A77E;;A77E
+A780;LATIN CAPITAL LETTER TURNED L;Lu;0;L;;;;;N;;;;A781;
+A781;LATIN SMALL LETTER TURNED L;Ll;0;L;;;;;N;;;A780;;A780
+A782;LATIN CAPITAL LETTER INSULAR R;Lu;0;L;;;;;N;;;;A783;
+A783;LATIN SMALL LETTER INSULAR R;Ll;0;L;;;;;N;;;A782;;A782
+A784;LATIN CAPITAL LETTER INSULAR S;Lu;0;L;;;;;N;;;;A785;
+A785;LATIN SMALL LETTER INSULAR S;Ll;0;L;;;;;N;;;A784;;A784
+A786;LATIN CAPITAL LETTER INSULAR T;Lu;0;L;;;;;N;;;;A787;
+A787;LATIN SMALL LETTER INSULAR T;Ll;0;L;;;;;N;;;A786;;A786
+A788;MODIFIER LETTER LOW CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;;;;;
+A789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;;
+A78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;;
+A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C;
+A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B
+A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265;
+A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;;
+A78F;LATIN LETTER SINOLOGICAL DOT;Lo;0;L;;;;;N;;;;;
+A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791;
+A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790
+A792;LATIN CAPITAL LETTER C WITH BAR;Lu;0;L;;;;;N;;;;A793;
+A793;LATIN SMALL LETTER C WITH BAR;Ll;0;L;;;;;N;;;A792;;A792
+A794;LATIN SMALL LETTER C WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+A795;LATIN SMALL LETTER H WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+A796;LATIN CAPITAL LETTER B WITH FLOURISH;Lu;0;L;;;;;N;;;;A797;
+A797;LATIN SMALL LETTER B WITH FLOURISH;Ll;0;L;;;;;N;;;A796;;A796
+A798;LATIN CAPITAL LETTER F WITH STROKE;Lu;0;L;;;;;N;;;;A799;
+A799;LATIN SMALL LETTER F WITH STROKE;Ll;0;L;;;;;N;;;A798;;A798
+A79A;LATIN CAPITAL LETTER VOLAPUK AE;Lu;0;L;;;;;N;;;;A79B;
+A79B;LATIN SMALL LETTER VOLAPUK AE;Ll;0;L;;;;;N;;;A79A;;A79A
+A79C;LATIN CAPITAL LETTER VOLAPUK OE;Lu;0;L;;;;;N;;;;A79D;
+A79D;LATIN SMALL LETTER VOLAPUK OE;Ll;0;L;;;;;N;;;A79C;;A79C
+A79E;LATIN CAPITAL LETTER VOLAPUK UE;Lu;0;L;;;;;N;;;;A79F;
+A79F;LATIN SMALL LETTER VOLAPUK UE;Ll;0;L;;;;;N;;;A79E;;A79E
+A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1;
+A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0
+A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3;
+A7A3;LATIN SMALL LETTER K WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A2;;A7A2
+A7A4;LATIN CAPITAL LETTER N WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A5;
+A7A5;LATIN SMALL LETTER N WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A4;;A7A4
+A7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7;
+A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6
+A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9;
+A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8
+A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266;
+A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C;
+A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261;
+A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C;
+A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A;
+A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E;
+A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287;
+A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D;
+A7B3;LATIN CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;AB53;
+A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5;
+A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4
+A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7;
+A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6
+A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;;
+A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;;
+A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;;
+A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;;
+A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;;
+A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;;
+A7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;;
+A7FE;LATIN EPIGRAPHIC LETTER I LONGA;Lo;0;L;;;;;N;;;;;
+A7FF;LATIN EPIGRAPHIC LETTER ARCHAIC M;Lo;0;L;;;;;N;;;;;
+A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;;
+A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;;
+A802;SYLOTI NAGRI SIGN DVISVARA;Mn;0;NSM;;;;;N;;;;;
+A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;;
+A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;;
+A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;;
+A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;;
+A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;;
+A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;;
+A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;;
+A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;;
+A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;;
+A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;;
+A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;;
+A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;;
+A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;;
+A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;;
+A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;;
+A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;;
+A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;;
+A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;;
+A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;;
+A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;;
+A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;;
+A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;;
+A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;;
+A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;;
+A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;;
+A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;;
+A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;;
+A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;;
+A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;;
+A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;;
+A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;;
+A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;;
+A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;;
+A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;;
+A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;;
+A830;NORTH INDIC FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;;
+A831;NORTH INDIC FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;;
+A832;NORTH INDIC FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;;
+A833;NORTH INDIC FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;;
+A834;NORTH INDIC FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;;
+A835;NORTH INDIC FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;;
+A836;NORTH INDIC QUARTER MARK;So;0;L;;;;;N;;;;;
+A837;NORTH INDIC PLACEHOLDER MARK;So;0;L;;;;;N;;;;;
+A838;NORTH INDIC RUPEE MARK;Sc;0;ET;;;;;N;;;;;
+A839;NORTH INDIC QUANTITY MARK;So;0;ET;;;;;N;;;;;
+A840;PHAGS-PA LETTER KA;Lo;0;L;;;;;N;;;;;
+A841;PHAGS-PA LETTER KHA;Lo;0;L;;;;;N;;;;;
+A842;PHAGS-PA LETTER GA;Lo;0;L;;;;;N;;;;;
+A843;PHAGS-PA LETTER NGA;Lo;0;L;;;;;N;;;;;
+A844;PHAGS-PA LETTER CA;Lo;0;L;;;;;N;;;;;
+A845;PHAGS-PA LETTER CHA;Lo;0;L;;;;;N;;;;;
+A846;PHAGS-PA LETTER JA;Lo;0;L;;;;;N;;;;;
+A847;PHAGS-PA LETTER NYA;Lo;0;L;;;;;N;;;;;
+A848;PHAGS-PA LETTER TA;Lo;0;L;;;;;N;;;;;
+A849;PHAGS-PA LETTER THA;Lo;0;L;;;;;N;;;;;
+A84A;PHAGS-PA LETTER DA;Lo;0;L;;;;;N;;;;;
+A84B;PHAGS-PA LETTER NA;Lo;0;L;;;;;N;;;;;
+A84C;PHAGS-PA LETTER PA;Lo;0;L;;;;;N;;;;;
+A84D;PHAGS-PA LETTER PHA;Lo;0;L;;;;;N;;;;;
+A84E;PHAGS-PA LETTER BA;Lo;0;L;;;;;N;;;;;
+A84F;PHAGS-PA LETTER MA;Lo;0;L;;;;;N;;;;;
+A850;PHAGS-PA LETTER TSA;Lo;0;L;;;;;N;;;;;
+A851;PHAGS-PA LETTER TSHA;Lo;0;L;;;;;N;;;;;
+A852;PHAGS-PA LETTER DZA;Lo;0;L;;;;;N;;;;;
+A853;PHAGS-PA LETTER WA;Lo;0;L;;;;;N;;;;;
+A854;PHAGS-PA LETTER ZHA;Lo;0;L;;;;;N;;;;;
+A855;PHAGS-PA LETTER ZA;Lo;0;L;;;;;N;;;;;
+A856;PHAGS-PA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+A857;PHAGS-PA LETTER YA;Lo;0;L;;;;;N;;;;;
+A858;PHAGS-PA LETTER RA;Lo;0;L;;;;;N;;;;;
+A859;PHAGS-PA LETTER LA;Lo;0;L;;;;;N;;;;;
+A85A;PHAGS-PA LETTER SHA;Lo;0;L;;;;;N;;;;;
+A85B;PHAGS-PA LETTER SA;Lo;0;L;;;;;N;;;;;
+A85C;PHAGS-PA LETTER HA;Lo;0;L;;;;;N;;;;;
+A85D;PHAGS-PA LETTER A;Lo;0;L;;;;;N;;;;;
+A85E;PHAGS-PA LETTER I;Lo;0;L;;;;;N;;;;;
+A85F;PHAGS-PA LETTER U;Lo;0;L;;;;;N;;;;;
+A860;PHAGS-PA LETTER E;Lo;0;L;;;;;N;;;;;
+A861;PHAGS-PA LETTER O;Lo;0;L;;;;;N;;;;;
+A862;PHAGS-PA LETTER QA;Lo;0;L;;;;;N;;;;;
+A863;PHAGS-PA LETTER XA;Lo;0;L;;;;;N;;;;;
+A864;PHAGS-PA LETTER FA;Lo;0;L;;;;;N;;;;;
+A865;PHAGS-PA LETTER GGA;Lo;0;L;;;;;N;;;;;
+A866;PHAGS-PA LETTER EE;Lo;0;L;;;;;N;;;;;
+A867;PHAGS-PA SUBJOINED LETTER WA;Lo;0;L;;;;;N;;;;;
+A868;PHAGS-PA SUBJOINED LETTER YA;Lo;0;L;;;;;N;;;;;
+A869;PHAGS-PA LETTER TTA;Lo;0;L;;;;;N;;;;;
+A86A;PHAGS-PA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+A86B;PHAGS-PA LETTER DDA;Lo;0;L;;;;;N;;;;;
+A86C;PHAGS-PA LETTER NNA;Lo;0;L;;;;;N;;;;;
+A86D;PHAGS-PA LETTER ALTERNATE YA;Lo;0;L;;;;;N;;;;;
+A86E;PHAGS-PA LETTER VOICELESS SHA;Lo;0;L;;;;;N;;;;;
+A86F;PHAGS-PA LETTER VOICED HA;Lo;0;L;;;;;N;;;;;
+A870;PHAGS-PA LETTER ASPIRATED FA;Lo;0;L;;;;;N;;;;;
+A871;PHAGS-PA SUBJOINED LETTER RA;Lo;0;L;;;;;N;;;;;
+A872;PHAGS-PA SUPERFIXED LETTER RA;Lo;0;L;;;;;N;;;;;
+A873;PHAGS-PA LETTER CANDRABINDU;Lo;0;L;;;;;N;;;;;
+A874;PHAGS-PA SINGLE HEAD MARK;Po;0;ON;;;;;N;;;;;
+A875;PHAGS-PA DOUBLE HEAD MARK;Po;0;ON;;;;;N;;;;;
+A876;PHAGS-PA MARK SHAD;Po;0;ON;;;;;N;;;;;
+A877;PHAGS-PA MARK DOUBLE SHAD;Po;0;ON;;;;;N;;;;;
+A880;SAURASHTRA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+A881;SAURASHTRA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+A882;SAURASHTRA LETTER A;Lo;0;L;;;;;N;;;;;
+A883;SAURASHTRA LETTER AA;Lo;0;L;;;;;N;;;;;
+A884;SAURASHTRA LETTER I;Lo;0;L;;;;;N;;;;;
+A885;SAURASHTRA LETTER II;Lo;0;L;;;;;N;;;;;
+A886;SAURASHTRA LETTER U;Lo;0;L;;;;;N;;;;;
+A887;SAURASHTRA LETTER UU;Lo;0;L;;;;;N;;;;;
+A888;SAURASHTRA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+A889;SAURASHTRA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+A88A;SAURASHTRA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+A88B;SAURASHTRA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+A88C;SAURASHTRA LETTER E;Lo;0;L;;;;;N;;;;;
+A88D;SAURASHTRA LETTER EE;Lo;0;L;;;;;N;;;;;
+A88E;SAURASHTRA LETTER AI;Lo;0;L;;;;;N;;;;;
+A88F;SAURASHTRA LETTER O;Lo;0;L;;;;;N;;;;;
+A890;SAURASHTRA LETTER OO;Lo;0;L;;;;;N;;;;;
+A891;SAURASHTRA LETTER AU;Lo;0;L;;;;;N;;;;;
+A892;SAURASHTRA LETTER KA;Lo;0;L;;;;;N;;;;;
+A893;SAURASHTRA LETTER KHA;Lo;0;L;;;;;N;;;;;
+A894;SAURASHTRA LETTER GA;Lo;0;L;;;;;N;;;;;
+A895;SAURASHTRA LETTER GHA;Lo;0;L;;;;;N;;;;;
+A896;SAURASHTRA LETTER NGA;Lo;0;L;;;;;N;;;;;
+A897;SAURASHTRA LETTER CA;Lo;0;L;;;;;N;;;;;
+A898;SAURASHTRA LETTER CHA;Lo;0;L;;;;;N;;;;;
+A899;SAURASHTRA LETTER JA;Lo;0;L;;;;;N;;;;;
+A89A;SAURASHTRA LETTER JHA;Lo;0;L;;;;;N;;;;;
+A89B;SAURASHTRA LETTER NYA;Lo;0;L;;;;;N;;;;;
+A89C;SAURASHTRA LETTER TTA;Lo;0;L;;;;;N;;;;;
+A89D;SAURASHTRA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+A89E;SAURASHTRA LETTER DDA;Lo;0;L;;;;;N;;;;;
+A89F;SAURASHTRA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+A8A0;SAURASHTRA LETTER NNA;Lo;0;L;;;;;N;;;;;
+A8A1;SAURASHTRA LETTER TA;Lo;0;L;;;;;N;;;;;
+A8A2;SAURASHTRA LETTER THA;Lo;0;L;;;;;N;;;;;
+A8A3;SAURASHTRA LETTER DA;Lo;0;L;;;;;N;;;;;
+A8A4;SAURASHTRA LETTER DHA;Lo;0;L;;;;;N;;;;;
+A8A5;SAURASHTRA LETTER NA;Lo;0;L;;;;;N;;;;;
+A8A6;SAURASHTRA LETTER PA;Lo;0;L;;;;;N;;;;;
+A8A7;SAURASHTRA LETTER PHA;Lo;0;L;;;;;N;;;;;
+A8A8;SAURASHTRA LETTER BA;Lo;0;L;;;;;N;;;;;
+A8A9;SAURASHTRA LETTER BHA;Lo;0;L;;;;;N;;;;;
+A8AA;SAURASHTRA LETTER MA;Lo;0;L;;;;;N;;;;;
+A8AB;SAURASHTRA LETTER YA;Lo;0;L;;;;;N;;;;;
+A8AC;SAURASHTRA LETTER RA;Lo;0;L;;;;;N;;;;;
+A8AD;SAURASHTRA LETTER LA;Lo;0;L;;;;;N;;;;;
+A8AE;SAURASHTRA LETTER VA;Lo;0;L;;;;;N;;;;;
+A8AF;SAURASHTRA LETTER SHA;Lo;0;L;;;;;N;;;;;
+A8B0;SAURASHTRA LETTER SSA;Lo;0;L;;;;;N;;;;;
+A8B1;SAURASHTRA LETTER SA;Lo;0;L;;;;;N;;;;;
+A8B2;SAURASHTRA LETTER HA;Lo;0;L;;;;;N;;;;;
+A8B3;SAURASHTRA LETTER LLA;Lo;0;L;;;;;N;;;;;
+A8B4;SAURASHTRA CONSONANT SIGN HAARU;Mc;0;L;;;;;N;;;;;
+A8B5;SAURASHTRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+A8B6;SAURASHTRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+A8B7;SAURASHTRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+A8B8;SAURASHTRA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+A8B9;SAURASHTRA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+A8BA;SAURASHTRA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+A8BB;SAURASHTRA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+A8BC;SAURASHTRA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;;
+A8BD;SAURASHTRA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;;
+A8BE;SAURASHTRA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+A8BF;SAURASHTRA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+A8C0;SAURASHTRA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+A8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;;
+A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+A8E0;COMBINING DEVANAGARI DIGIT ZERO;Mn;230;NSM;;;;;N;;;;;
+A8E1;COMBINING DEVANAGARI DIGIT ONE;Mn;230;NSM;;;;;N;;;;;
+A8E2;COMBINING DEVANAGARI DIGIT TWO;Mn;230;NSM;;;;;N;;;;;
+A8E3;COMBINING DEVANAGARI DIGIT THREE;Mn;230;NSM;;;;;N;;;;;
+A8E4;COMBINING DEVANAGARI DIGIT FOUR;Mn;230;NSM;;;;;N;;;;;
+A8E5;COMBINING DEVANAGARI DIGIT FIVE;Mn;230;NSM;;;;;N;;;;;
+A8E6;COMBINING DEVANAGARI DIGIT SIX;Mn;230;NSM;;;;;N;;;;;
+A8E7;COMBINING DEVANAGARI DIGIT SEVEN;Mn;230;NSM;;;;;N;;;;;
+A8E8;COMBINING DEVANAGARI DIGIT EIGHT;Mn;230;NSM;;;;;N;;;;;
+A8E9;COMBINING DEVANAGARI DIGIT NINE;Mn;230;NSM;;;;;N;;;;;
+A8EA;COMBINING DEVANAGARI LETTER A;Mn;230;NSM;;;;;N;;;;;
+A8EB;COMBINING DEVANAGARI LETTER U;Mn;230;NSM;;;;;N;;;;;
+A8EC;COMBINING DEVANAGARI LETTER KA;Mn;230;NSM;;;;;N;;;;;
+A8ED;COMBINING DEVANAGARI LETTER NA;Mn;230;NSM;;;;;N;;;;;
+A8EE;COMBINING DEVANAGARI LETTER PA;Mn;230;NSM;;;;;N;;;;;
+A8EF;COMBINING DEVANAGARI LETTER RA;Mn;230;NSM;;;;;N;;;;;
+A8F0;COMBINING DEVANAGARI LETTER VI;Mn;230;NSM;;;;;N;;;;;
+A8F1;COMBINING DEVANAGARI SIGN AVAGRAHA;Mn;230;NSM;;;;;N;;;;;
+A8F2;DEVANAGARI SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;;
+A8F3;DEVANAGARI SIGN CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;;
+A8F4;DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA;Lo;0;L;;;;;N;;;;;
+A8F5;DEVANAGARI SIGN CANDRABINDU TWO;Lo;0;L;;;;;N;;;;;
+A8F6;DEVANAGARI SIGN CANDRABINDU THREE;Lo;0;L;;;;;N;;;;;
+A8F7;DEVANAGARI SIGN CANDRABINDU AVAGRAHA;Lo;0;L;;;;;N;;;;;
+A8F8;DEVANAGARI SIGN PUSHPIKA;Po;0;L;;;;;N;;;;;
+A8F9;DEVANAGARI GAP FILLER;Po;0;L;;;;;N;;;;;
+A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;;
+A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;;
+A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
+A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;;
+A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+A90A;KAYAH LI LETTER KA;Lo;0;L;;;;;N;;;;;
+A90B;KAYAH LI LETTER KHA;Lo;0;L;;;;;N;;;;;
+A90C;KAYAH LI LETTER GA;Lo;0;L;;;;;N;;;;;
+A90D;KAYAH LI LETTER NGA;Lo;0;L;;;;;N;;;;;
+A90E;KAYAH LI LETTER SA;Lo;0;L;;;;;N;;;;;
+A90F;KAYAH LI LETTER SHA;Lo;0;L;;;;;N;;;;;
+A910;KAYAH LI LETTER ZA;Lo;0;L;;;;;N;;;;;
+A911;KAYAH LI LETTER NYA;Lo;0;L;;;;;N;;;;;
+A912;KAYAH LI LETTER TA;Lo;0;L;;;;;N;;;;;
+A913;KAYAH LI LETTER HTA;Lo;0;L;;;;;N;;;;;
+A914;KAYAH LI LETTER NA;Lo;0;L;;;;;N;;;;;
+A915;KAYAH LI LETTER PA;Lo;0;L;;;;;N;;;;;
+A916;KAYAH LI LETTER PHA;Lo;0;L;;;;;N;;;;;
+A917;KAYAH LI LETTER MA;Lo;0;L;;;;;N;;;;;
+A918;KAYAH LI LETTER DA;Lo;0;L;;;;;N;;;;;
+A919;KAYAH LI LETTER BA;Lo;0;L;;;;;N;;;;;
+A91A;KAYAH LI LETTER RA;Lo;0;L;;;;;N;;;;;
+A91B;KAYAH LI LETTER YA;Lo;0;L;;;;;N;;;;;
+A91C;KAYAH LI LETTER LA;Lo;0;L;;;;;N;;;;;
+A91D;KAYAH LI LETTER WA;Lo;0;L;;;;;N;;;;;
+A91E;KAYAH LI LETTER THA;Lo;0;L;;;;;N;;;;;
+A91F;KAYAH LI LETTER HA;Lo;0;L;;;;;N;;;;;
+A920;KAYAH LI LETTER VA;Lo;0;L;;;;;N;;;;;
+A921;KAYAH LI LETTER CA;Lo;0;L;;;;;N;;;;;
+A922;KAYAH LI LETTER A;Lo;0;L;;;;;N;;;;;
+A923;KAYAH LI LETTER OE;Lo;0;L;;;;;N;;;;;
+A924;KAYAH LI LETTER I;Lo;0;L;;;;;N;;;;;
+A925;KAYAH LI LETTER OO;Lo;0;L;;;;;N;;;;;
+A926;KAYAH LI VOWEL UE;Mn;0;NSM;;;;;N;;;;;
+A927;KAYAH LI VOWEL E;Mn;0;NSM;;;;;N;;;;;
+A928;KAYAH LI VOWEL U;Mn;0;NSM;;;;;N;;;;;
+A929;KAYAH LI VOWEL EE;Mn;0;NSM;;;;;N;;;;;
+A92A;KAYAH LI VOWEL O;Mn;0;NSM;;;;;N;;;;;
+A92B;KAYAH LI TONE PLOPHU;Mn;220;NSM;;;;;N;;;;;
+A92C;KAYAH LI TONE CALYA;Mn;220;NSM;;;;;N;;;;;
+A92D;KAYAH LI TONE CALYA PLOPHU;Mn;220;NSM;;;;;N;;;;;
+A92E;KAYAH LI SIGN CWI;Po;0;L;;;;;N;;;;;
+A92F;KAYAH LI SIGN SHYA;Po;0;L;;;;;N;;;;;
+A930;REJANG LETTER KA;Lo;0;L;;;;;N;;;;;
+A931;REJANG LETTER GA;Lo;0;L;;;;;N;;;;;
+A932;REJANG LETTER NGA;Lo;0;L;;;;;N;;;;;
+A933;REJANG LETTER TA;Lo;0;L;;;;;N;;;;;
+A934;REJANG LETTER DA;Lo;0;L;;;;;N;;;;;
+A935;REJANG LETTER NA;Lo;0;L;;;;;N;;;;;
+A936;REJANG LETTER PA;Lo;0;L;;;;;N;;;;;
+A937;REJANG LETTER BA;Lo;0;L;;;;;N;;;;;
+A938;REJANG LETTER MA;Lo;0;L;;;;;N;;;;;
+A939;REJANG LETTER CA;Lo;0;L;;;;;N;;;;;
+A93A;REJANG LETTER JA;Lo;0;L;;;;;N;;;;;
+A93B;REJANG LETTER NYA;Lo;0;L;;;;;N;;;;;
+A93C;REJANG LETTER SA;Lo;0;L;;;;;N;;;;;
+A93D;REJANG LETTER RA;Lo;0;L;;;;;N;;;;;
+A93E;REJANG LETTER LA;Lo;0;L;;;;;N;;;;;
+A93F;REJANG LETTER YA;Lo;0;L;;;;;N;;;;;
+A940;REJANG LETTER WA;Lo;0;L;;;;;N;;;;;
+A941;REJANG LETTER HA;Lo;0;L;;;;;N;;;;;
+A942;REJANG LETTER MBA;Lo;0;L;;;;;N;;;;;
+A943;REJANG LETTER NGGA;Lo;0;L;;;;;N;;;;;
+A944;REJANG LETTER NDA;Lo;0;L;;;;;N;;;;;
+A945;REJANG LETTER NYJA;Lo;0;L;;;;;N;;;;;
+A946;REJANG LETTER A;Lo;0;L;;;;;N;;;;;
+A947;REJANG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+A948;REJANG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+A949;REJANG VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+A94A;REJANG VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+A94B;REJANG VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+A94C;REJANG VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+A94D;REJANG VOWEL SIGN EU;Mn;0;NSM;;;;;N;;;;;
+A94E;REJANG VOWEL SIGN EA;Mn;0;NSM;;;;;N;;;;;
+A94F;REJANG CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;;
+A950;REJANG CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;;
+A951;REJANG CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;;
+A952;REJANG CONSONANT SIGN H;Mc;0;L;;;;;N;;;;;
+A953;REJANG VIRAMA;Mc;9;L;;;;;N;;;;;
+A95F;REJANG SECTION MARK;Po;0;L;;;;;N;;;;;
+A960;HANGUL CHOSEONG TIKEUT-MIEUM;Lo;0;L;;;;;N;;;;;
+A961;HANGUL CHOSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;
+A962;HANGUL CHOSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;;
+A963;HANGUL CHOSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;;
+A964;HANGUL CHOSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;;;;
+A965;HANGUL CHOSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+A966;HANGUL CHOSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;
+A967;HANGUL CHOSEONG RIEUL-SSANGTIKEUT;Lo;0;L;;;;;N;;;;;
+A968;HANGUL CHOSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;;;;
+A969;HANGUL CHOSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;;;;
+A96A;HANGUL CHOSEONG RIEUL-SSANGPIEUP;Lo;0;L;;;;;N;;;;;
+A96B;HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+A96C;HANGUL CHOSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;;;;
+A96D;HANGUL CHOSEONG RIEUL-CIEUC;Lo;0;L;;;;;N;;;;;
+A96E;HANGUL CHOSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+A96F;HANGUL CHOSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+A970;HANGUL CHOSEONG MIEUM-TIKEUT;Lo;0;L;;;;;N;;;;;
+A971;HANGUL CHOSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+A972;HANGUL CHOSEONG PIEUP-SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+A973;HANGUL CHOSEONG PIEUP-KHIEUKH;Lo;0;L;;;;;N;;;;;
+A974;HANGUL CHOSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+A975;HANGUL CHOSEONG SSANGSIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+A976;HANGUL CHOSEONG IEUNG-RIEUL;Lo;0;L;;;;;N;;;;;
+A977;HANGUL CHOSEONG IEUNG-HIEUH;Lo;0;L;;;;;N;;;;;
+A978;HANGUL CHOSEONG SSANGCIEUC-HIEUH;Lo;0;L;;;;;N;;;;;
+A979;HANGUL CHOSEONG SSANGTHIEUTH;Lo;0;L;;;;;N;;;;;
+A97A;HANGUL CHOSEONG PHIEUPH-HIEUH;Lo;0;L;;;;;N;;;;;
+A97B;HANGUL CHOSEONG HIEUH-SIOS;Lo;0;L;;;;;N;;;;;
+A97C;HANGUL CHOSEONG SSANGYEORINHIEUH;Lo;0;L;;;;;N;;;;;
+A980;JAVANESE SIGN PANYANGGA;Mn;0;NSM;;;;;N;;;;;
+A981;JAVANESE SIGN CECAK;Mn;0;NSM;;;;;N;;;;;
+A982;JAVANESE SIGN LAYAR;Mn;0;NSM;;;;;N;;;;;
+A983;JAVANESE SIGN WIGNYAN;Mc;0;L;;;;;N;;;;;
+A984;JAVANESE LETTER A;Lo;0;L;;;;;N;;;;;
+A985;JAVANESE LETTER I KAWI;Lo;0;L;;;;;N;;;;;
+A986;JAVANESE LETTER I;Lo;0;L;;;;;N;;;;;
+A987;JAVANESE LETTER II;Lo;0;L;;;;;N;;;;;
+A988;JAVANESE LETTER U;Lo;0;L;;;;;N;;;;;
+A989;JAVANESE LETTER PA CEREK;Lo;0;L;;;;;N;;;;;
+A98A;JAVANESE LETTER NGA LELET;Lo;0;L;;;;;N;;;;;
+A98B;JAVANESE LETTER NGA LELET RASWADI;Lo;0;L;;;;;N;;;;;
+A98C;JAVANESE LETTER E;Lo;0;L;;;;;N;;;;;
+A98D;JAVANESE LETTER AI;Lo;0;L;;;;;N;;;;;
+A98E;JAVANESE LETTER O;Lo;0;L;;;;;N;;;;;
+A98F;JAVANESE LETTER KA;Lo;0;L;;;;;N;;;;;
+A990;JAVANESE LETTER KA SASAK;Lo;0;L;;;;;N;;;;;
+A991;JAVANESE LETTER KA MURDA;Lo;0;L;;;;;N;;;;;
+A992;JAVANESE LETTER GA;Lo;0;L;;;;;N;;;;;
+A993;JAVANESE LETTER GA MURDA;Lo;0;L;;;;;N;;;;;
+A994;JAVANESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+A995;JAVANESE LETTER CA;Lo;0;L;;;;;N;;;;;
+A996;JAVANESE LETTER CA MURDA;Lo;0;L;;;;;N;;;;;
+A997;JAVANESE LETTER JA;Lo;0;L;;;;;N;;;;;
+A998;JAVANESE LETTER NYA MURDA;Lo;0;L;;;;;N;;;;;
+A999;JAVANESE LETTER JA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+A99A;JAVANESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+A99B;JAVANESE LETTER TTA;Lo;0;L;;;;;N;;;;;
+A99C;JAVANESE LETTER TTA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+A99D;JAVANESE LETTER DDA;Lo;0;L;;;;;N;;;;;
+A99E;JAVANESE LETTER DDA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+A99F;JAVANESE LETTER NA MURDA;Lo;0;L;;;;;N;;;;;
+A9A0;JAVANESE LETTER TA;Lo;0;L;;;;;N;;;;;
+A9A1;JAVANESE LETTER TA MURDA;Lo;0;L;;;;;N;;;;;
+A9A2;JAVANESE LETTER DA;Lo;0;L;;;;;N;;;;;
+A9A3;JAVANESE LETTER DA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+A9A4;JAVANESE LETTER NA;Lo;0;L;;;;;N;;;;;
+A9A5;JAVANESE LETTER PA;Lo;0;L;;;;;N;;;;;
+A9A6;JAVANESE LETTER PA MURDA;Lo;0;L;;;;;N;;;;;
+A9A7;JAVANESE LETTER BA;Lo;0;L;;;;;N;;;;;
+A9A8;JAVANESE LETTER BA MURDA;Lo;0;L;;;;;N;;;;;
+A9A9;JAVANESE LETTER MA;Lo;0;L;;;;;N;;;;;
+A9AA;JAVANESE LETTER YA;Lo;0;L;;;;;N;;;;;
+A9AB;JAVANESE LETTER RA;Lo;0;L;;;;;N;;;;;
+A9AC;JAVANESE LETTER RA AGUNG;Lo;0;L;;;;;N;;;;;
+A9AD;JAVANESE LETTER LA;Lo;0;L;;;;;N;;;;;
+A9AE;JAVANESE LETTER WA;Lo;0;L;;;;;N;;;;;
+A9AF;JAVANESE LETTER SA MURDA;Lo;0;L;;;;;N;;;;;
+A9B0;JAVANESE LETTER SA MAHAPRANA;Lo;0;L;;;;;N;;;;;
+A9B1;JAVANESE LETTER SA;Lo;0;L;;;;;N;;;;;
+A9B2;JAVANESE LETTER HA;Lo;0;L;;;;;N;;;;;
+A9B3;JAVANESE SIGN CECAK TELU;Mn;7;NSM;;;;;N;;;;;
+A9B4;JAVANESE VOWEL SIGN TARUNG;Mc;0;L;;;;;N;;;;;
+A9B5;JAVANESE VOWEL SIGN TOLONG;Mc;0;L;;;;;N;;;;;
+A9B6;JAVANESE VOWEL SIGN WULU;Mn;0;NSM;;;;;N;;;;;
+A9B7;JAVANESE VOWEL SIGN WULU MELIK;Mn;0;NSM;;;;;N;;;;;
+A9B8;JAVANESE VOWEL SIGN SUKU;Mn;0;NSM;;;;;N;;;;;
+A9B9;JAVANESE VOWEL SIGN SUKU MENDUT;Mn;0;NSM;;;;;N;;;;;
+A9BA;JAVANESE VOWEL SIGN TALING;Mc;0;L;;;;;N;;;;;
+A9BB;JAVANESE VOWEL SIGN DIRGA MURE;Mc;0;L;;;;;N;;;;;
+A9BC;JAVANESE VOWEL SIGN PEPET;Mn;0;NSM;;;;;N;;;;;
+A9BD;JAVANESE CONSONANT SIGN KERET;Mc;0;L;;;;;N;;;;;
+A9BE;JAVANESE CONSONANT SIGN PENGKAL;Mc;0;L;;;;;N;;;;;
+A9BF;JAVANESE CONSONANT SIGN CAKRA;Mc;0;L;;;;;N;;;;;
+A9C0;JAVANESE PANGKON;Mc;9;L;;;;;N;;;;;
+A9C1;JAVANESE LEFT RERENGGAN;Po;0;L;;;;;N;;;;;
+A9C2;JAVANESE RIGHT RERENGGAN;Po;0;L;;;;;N;;;;;
+A9C3;JAVANESE PADA ANDAP;Po;0;L;;;;;N;;;;;
+A9C4;JAVANESE PADA MADYA;Po;0;L;;;;;N;;;;;
+A9C5;JAVANESE PADA LUHUR;Po;0;L;;;;;N;;;;;
+A9C6;JAVANESE PADA WINDU;Po;0;L;;;;;N;;;;;
+A9C7;JAVANESE PADA PANGKAT;Po;0;L;;;;;N;;;;;
+A9C8;JAVANESE PADA LINGSA;Po;0;L;;;;;N;;;;;
+A9C9;JAVANESE PADA LUNGSI;Po;0;L;;;;;N;;;;;
+A9CA;JAVANESE PADA ADEG;Po;0;L;;;;;N;;;;;
+A9CB;JAVANESE PADA ADEG ADEG;Po;0;L;;;;;N;;;;;
+A9CC;JAVANESE PADA PISELEH;Po;0;L;;;;;N;;;;;
+A9CD;JAVANESE TURNED PADA PISELEH;Po;0;L;;;;;N;;;;;
+A9CF;JAVANESE PANGRANGKEP;Lm;0;L;;;;;N;;;;;
+A9D0;JAVANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+A9D1;JAVANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+A9D2;JAVANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+A9D3;JAVANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+A9D4;JAVANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+A9D5;JAVANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+A9D6;JAVANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+A9D7;JAVANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+A9D8;JAVANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+A9D9;JAVANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+A9DE;JAVANESE PADA TIRTA TUMETES;Po;0;L;;;;;N;;;;;
+A9DF;JAVANESE PADA ISEN-ISEN;Po;0;L;;;;;N;;;;;
+A9E0;MYANMAR LETTER SHAN GHA;Lo;0;L;;;;;N;;;;;
+A9E1;MYANMAR LETTER SHAN CHA;Lo;0;L;;;;;N;;;;;
+A9E2;MYANMAR LETTER SHAN JHA;Lo;0;L;;;;;N;;;;;
+A9E3;MYANMAR LETTER SHAN NNA;Lo;0;L;;;;;N;;;;;
+A9E4;MYANMAR LETTER SHAN BHA;Lo;0;L;;;;;N;;;;;
+A9E5;MYANMAR SIGN SHAN SAW;Mn;0;NSM;;;;;N;;;;;
+A9E6;MYANMAR MODIFIER LETTER SHAN REDUPLICATION;Lm;0;L;;;;;N;;;;;
+A9E7;MYANMAR LETTER TAI LAING NYA;Lo;0;L;;;;;N;;;;;
+A9E8;MYANMAR LETTER TAI LAING FA;Lo;0;L;;;;;N;;;;;
+A9E9;MYANMAR LETTER TAI LAING GA;Lo;0;L;;;;;N;;;;;
+A9EA;MYANMAR LETTER TAI LAING GHA;Lo;0;L;;;;;N;;;;;
+A9EB;MYANMAR LETTER TAI LAING JA;Lo;0;L;;;;;N;;;;;
+A9EC;MYANMAR LETTER TAI LAING JHA;Lo;0;L;;;;;N;;;;;
+A9ED;MYANMAR LETTER TAI LAING DDA;Lo;0;L;;;;;N;;;;;
+A9EE;MYANMAR LETTER TAI LAING DDHA;Lo;0;L;;;;;N;;;;;
+A9EF;MYANMAR LETTER TAI LAING NNA;Lo;0;L;;;;;N;;;;;
+A9F0;MYANMAR TAI LAING DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+A9F1;MYANMAR TAI LAING DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+A9F2;MYANMAR TAI LAING DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+A9F3;MYANMAR TAI LAING DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+A9F4;MYANMAR TAI LAING DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+A9F5;MYANMAR TAI LAING DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+A9F6;MYANMAR TAI LAING DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+A9F7;MYANMAR TAI LAING DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+A9F8;MYANMAR TAI LAING DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+A9F9;MYANMAR TAI LAING DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+A9FA;MYANMAR LETTER TAI LAING LLA;Lo;0;L;;;;;N;;;;;
+A9FB;MYANMAR LETTER TAI LAING DA;Lo;0;L;;;;;N;;;;;
+A9FC;MYANMAR LETTER TAI LAING DHA;Lo;0;L;;;;;N;;;;;
+A9FD;MYANMAR LETTER TAI LAING BA;Lo;0;L;;;;;N;;;;;
+A9FE;MYANMAR LETTER TAI LAING BHA;Lo;0;L;;;;;N;;;;;
+AA00;CHAM LETTER A;Lo;0;L;;;;;N;;;;;
+AA01;CHAM LETTER I;Lo;0;L;;;;;N;;;;;
+AA02;CHAM LETTER U;Lo;0;L;;;;;N;;;;;
+AA03;CHAM LETTER E;Lo;0;L;;;;;N;;;;;
+AA04;CHAM LETTER AI;Lo;0;L;;;;;N;;;;;
+AA05;CHAM LETTER O;Lo;0;L;;;;;N;;;;;
+AA06;CHAM LETTER KA;Lo;0;L;;;;;N;;;;;
+AA07;CHAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+AA08;CHAM LETTER GA;Lo;0;L;;;;;N;;;;;
+AA09;CHAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+AA0A;CHAM LETTER NGUE;Lo;0;L;;;;;N;;;;;
+AA0B;CHAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+AA0C;CHAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+AA0D;CHAM LETTER CHHA;Lo;0;L;;;;;N;;;;;
+AA0E;CHAM LETTER JA;Lo;0;L;;;;;N;;;;;
+AA0F;CHAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+AA10;CHAM LETTER NHUE;Lo;0;L;;;;;N;;;;;
+AA11;CHAM LETTER NHA;Lo;0;L;;;;;N;;;;;
+AA12;CHAM LETTER NHJA;Lo;0;L;;;;;N;;;;;
+AA13;CHAM LETTER TA;Lo;0;L;;;;;N;;;;;
+AA14;CHAM LETTER THA;Lo;0;L;;;;;N;;;;;
+AA15;CHAM LETTER DA;Lo;0;L;;;;;N;;;;;
+AA16;CHAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+AA17;CHAM LETTER NUE;Lo;0;L;;;;;N;;;;;
+AA18;CHAM LETTER NA;Lo;0;L;;;;;N;;;;;
+AA19;CHAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+AA1A;CHAM LETTER PA;Lo;0;L;;;;;N;;;;;
+AA1B;CHAM LETTER PPA;Lo;0;L;;;;;N;;;;;
+AA1C;CHAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+AA1D;CHAM LETTER BA;Lo;0;L;;;;;N;;;;;
+AA1E;CHAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+AA1F;CHAM LETTER MUE;Lo;0;L;;;;;N;;;;;
+AA20;CHAM LETTER MA;Lo;0;L;;;;;N;;;;;
+AA21;CHAM LETTER BBA;Lo;0;L;;;;;N;;;;;
+AA22;CHAM LETTER YA;Lo;0;L;;;;;N;;;;;
+AA23;CHAM LETTER RA;Lo;0;L;;;;;N;;;;;
+AA24;CHAM LETTER LA;Lo;0;L;;;;;N;;;;;
+AA25;CHAM LETTER VA;Lo;0;L;;;;;N;;;;;
+AA26;CHAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+AA27;CHAM LETTER SA;Lo;0;L;;;;;N;;;;;
+AA28;CHAM LETTER HA;Lo;0;L;;;;;N;;;;;
+AA29;CHAM VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+AA2A;CHAM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+AA2B;CHAM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+AA2C;CHAM VOWEL SIGN EI;Mn;0;NSM;;;;;N;;;;;
+AA2D;CHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+AA2E;CHAM VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
+AA2F;CHAM VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+AA30;CHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+AA31;CHAM VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+AA32;CHAM VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+AA33;CHAM CONSONANT SIGN YA;Mc;0;L;;;;;N;;;;;
+AA34;CHAM CONSONANT SIGN RA;Mc;0;L;;;;;N;;;;;
+AA35;CHAM CONSONANT SIGN LA;Mn;0;NSM;;;;;N;;;;;
+AA36;CHAM CONSONANT SIGN WA;Mn;0;NSM;;;;;N;;;;;
+AA40;CHAM LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+AA41;CHAM LETTER FINAL G;Lo;0;L;;;;;N;;;;;
+AA42;CHAM LETTER FINAL NG;Lo;0;L;;;;;N;;;;;
+AA43;CHAM CONSONANT SIGN FINAL NG;Mn;0;NSM;;;;;N;;;;;
+AA44;CHAM LETTER FINAL CH;Lo;0;L;;;;;N;;;;;
+AA45;CHAM LETTER FINAL T;Lo;0;L;;;;;N;;;;;
+AA46;CHAM LETTER FINAL N;Lo;0;L;;;;;N;;;;;
+AA47;CHAM LETTER FINAL P;Lo;0;L;;;;;N;;;;;
+AA48;CHAM LETTER FINAL Y;Lo;0;L;;;;;N;;;;;
+AA49;CHAM LETTER FINAL R;Lo;0;L;;;;;N;;;;;
+AA4A;CHAM LETTER FINAL L;Lo;0;L;;;;;N;;;;;
+AA4B;CHAM LETTER FINAL SS;Lo;0;L;;;;;N;;;;;
+AA4C;CHAM CONSONANT SIGN FINAL M;Mn;0;NSM;;;;;N;;;;;
+AA4D;CHAM CONSONANT SIGN FINAL H;Mc;0;L;;;;;N;;;;;
+AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+AA5C;CHAM PUNCTUATION SPIRAL;Po;0;L;;;;;N;;;;;
+AA5D;CHAM PUNCTUATION DANDA;Po;0;L;;;;;N;;;;;
+AA5E;CHAM PUNCTUATION DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+AA5F;CHAM PUNCTUATION TRIPLE DANDA;Po;0;L;;;;;N;;;;;
+AA60;MYANMAR LETTER KHAMTI GA;Lo;0;L;;;;;N;;;;;
+AA61;MYANMAR LETTER KHAMTI CA;Lo;0;L;;;;;N;;;;;
+AA62;MYANMAR LETTER KHAMTI CHA;Lo;0;L;;;;;N;;;;;
+AA63;MYANMAR LETTER KHAMTI JA;Lo;0;L;;;;;N;;;;;
+AA64;MYANMAR LETTER KHAMTI JHA;Lo;0;L;;;;;N;;;;;
+AA65;MYANMAR LETTER KHAMTI NYA;Lo;0;L;;;;;N;;;;;
+AA66;MYANMAR LETTER KHAMTI TTA;Lo;0;L;;;;;N;;;;;
+AA67;MYANMAR LETTER KHAMTI TTHA;Lo;0;L;;;;;N;;;;;
+AA68;MYANMAR LETTER KHAMTI DDA;Lo;0;L;;;;;N;;;;;
+AA69;MYANMAR LETTER KHAMTI DDHA;Lo;0;L;;;;;N;;;;;
+AA6A;MYANMAR LETTER KHAMTI DHA;Lo;0;L;;;;;N;;;;;
+AA6B;MYANMAR LETTER KHAMTI NA;Lo;0;L;;;;;N;;;;;
+AA6C;MYANMAR LETTER KHAMTI SA;Lo;0;L;;;;;N;;;;;
+AA6D;MYANMAR LETTER KHAMTI HA;Lo;0;L;;;;;N;;;;;
+AA6E;MYANMAR LETTER KHAMTI HHA;Lo;0;L;;;;;N;;;;;
+AA6F;MYANMAR LETTER KHAMTI FA;Lo;0;L;;;;;N;;;;;
+AA70;MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION;Lm;0;L;;;;;N;;;;;
+AA71;MYANMAR LETTER KHAMTI XA;Lo;0;L;;;;;N;;;;;
+AA72;MYANMAR LETTER KHAMTI ZA;Lo;0;L;;;;;N;;;;;
+AA73;MYANMAR LETTER KHAMTI RA;Lo;0;L;;;;;N;;;;;
+AA74;MYANMAR LOGOGRAM KHAMTI OAY;Lo;0;L;;;;;N;;;;;
+AA75;MYANMAR LOGOGRAM KHAMTI QN;Lo;0;L;;;;;N;;;;;
+AA76;MYANMAR LOGOGRAM KHAMTI HM;Lo;0;L;;;;;N;;;;;
+AA77;MYANMAR SYMBOL AITON EXCLAMATION;So;0;L;;;;;N;;;;;
+AA78;MYANMAR SYMBOL AITON ONE;So;0;L;;;;;N;;;;;
+AA79;MYANMAR SYMBOL AITON TWO;So;0;L;;;;;N;;;;;
+AA7A;MYANMAR LETTER AITON RA;Lo;0;L;;;;;N;;;;;
+AA7B;MYANMAR SIGN PAO KAREN TONE;Mc;0;L;;;;;N;;;;;
+AA7C;MYANMAR SIGN TAI LAING TONE-2;Mn;0;NSM;;;;;N;;;;;
+AA7D;MYANMAR SIGN TAI LAING TONE-5;Mc;0;L;;;;;N;;;;;
+AA7E;MYANMAR LETTER SHWE PALAUNG CHA;Lo;0;L;;;;;N;;;;;
+AA7F;MYANMAR LETTER SHWE PALAUNG SHA;Lo;0;L;;;;;N;;;;;
+AA80;TAI VIET LETTER LOW KO;Lo;0;L;;;;;N;;;;;
+AA81;TAI VIET LETTER HIGH KO;Lo;0;L;;;;;N;;;;;
+AA82;TAI VIET LETTER LOW KHO;Lo;0;L;;;;;N;;;;;
+AA83;TAI VIET LETTER HIGH KHO;Lo;0;L;;;;;N;;;;;
+AA84;TAI VIET LETTER LOW KHHO;Lo;0;L;;;;;N;;;;;
+AA85;TAI VIET LETTER HIGH KHHO;Lo;0;L;;;;;N;;;;;
+AA86;TAI VIET LETTER LOW GO;Lo;0;L;;;;;N;;;;;
+AA87;TAI VIET LETTER HIGH GO;Lo;0;L;;;;;N;;;;;
+AA88;TAI VIET LETTER LOW NGO;Lo;0;L;;;;;N;;;;;
+AA89;TAI VIET LETTER HIGH NGO;Lo;0;L;;;;;N;;;;;
+AA8A;TAI VIET LETTER LOW CO;Lo;0;L;;;;;N;;;;;
+AA8B;TAI VIET LETTER HIGH CO;Lo;0;L;;;;;N;;;;;
+AA8C;TAI VIET LETTER LOW CHO;Lo;0;L;;;;;N;;;;;
+AA8D;TAI VIET LETTER HIGH CHO;Lo;0;L;;;;;N;;;;;
+AA8E;TAI VIET LETTER LOW SO;Lo;0;L;;;;;N;;;;;
+AA8F;TAI VIET LETTER HIGH SO;Lo;0;L;;;;;N;;;;;
+AA90;TAI VIET LETTER LOW NYO;Lo;0;L;;;;;N;;;;;
+AA91;TAI VIET LETTER HIGH NYO;Lo;0;L;;;;;N;;;;;
+AA92;TAI VIET LETTER LOW DO;Lo;0;L;;;;;N;;;;;
+AA93;TAI VIET LETTER HIGH DO;Lo;0;L;;;;;N;;;;;
+AA94;TAI VIET LETTER LOW TO;Lo;0;L;;;;;N;;;;;
+AA95;TAI VIET LETTER HIGH TO;Lo;0;L;;;;;N;;;;;
+AA96;TAI VIET LETTER LOW THO;Lo;0;L;;;;;N;;;;;
+AA97;TAI VIET LETTER HIGH THO;Lo;0;L;;;;;N;;;;;
+AA98;TAI VIET LETTER LOW NO;Lo;0;L;;;;;N;;;;;
+AA99;TAI VIET LETTER HIGH NO;Lo;0;L;;;;;N;;;;;
+AA9A;TAI VIET LETTER LOW BO;Lo;0;L;;;;;N;;;;;
+AA9B;TAI VIET LETTER HIGH BO;Lo;0;L;;;;;N;;;;;
+AA9C;TAI VIET LETTER LOW PO;Lo;0;L;;;;;N;;;;;
+AA9D;TAI VIET LETTER HIGH PO;Lo;0;L;;;;;N;;;;;
+AA9E;TAI VIET LETTER LOW PHO;Lo;0;L;;;;;N;;;;;
+AA9F;TAI VIET LETTER HIGH PHO;Lo;0;L;;;;;N;;;;;
+AAA0;TAI VIET LETTER LOW FO;Lo;0;L;;;;;N;;;;;
+AAA1;TAI VIET LETTER HIGH FO;Lo;0;L;;;;;N;;;;;
+AAA2;TAI VIET LETTER LOW MO;Lo;0;L;;;;;N;;;;;
+AAA3;TAI VIET LETTER HIGH MO;Lo;0;L;;;;;N;;;;;
+AAA4;TAI VIET LETTER LOW YO;Lo;0;L;;;;;N;;;;;
+AAA5;TAI VIET LETTER HIGH YO;Lo;0;L;;;;;N;;;;;
+AAA6;TAI VIET LETTER LOW RO;Lo;0;L;;;;;N;;;;;
+AAA7;TAI VIET LETTER HIGH RO;Lo;0;L;;;;;N;;;;;
+AAA8;TAI VIET LETTER LOW LO;Lo;0;L;;;;;N;;;;;
+AAA9;TAI VIET LETTER HIGH LO;Lo;0;L;;;;;N;;;;;
+AAAA;TAI VIET LETTER LOW VO;Lo;0;L;;;;;N;;;;;
+AAAB;TAI VIET LETTER HIGH VO;Lo;0;L;;;;;N;;;;;
+AAAC;TAI VIET LETTER LOW HO;Lo;0;L;;;;;N;;;;;
+AAAD;TAI VIET LETTER HIGH HO;Lo;0;L;;;;;N;;;;;
+AAAE;TAI VIET LETTER LOW O;Lo;0;L;;;;;N;;;;;
+AAAF;TAI VIET LETTER HIGH O;Lo;0;L;;;;;N;;;;;
+AAB0;TAI VIET MAI KANG;Mn;230;NSM;;;;;N;;;;;
+AAB1;TAI VIET VOWEL AA;Lo;0;L;;;;;N;;;;;
+AAB2;TAI VIET VOWEL I;Mn;230;NSM;;;;;N;;;;;
+AAB3;TAI VIET VOWEL UE;Mn;230;NSM;;;;;N;;;;;
+AAB4;TAI VIET VOWEL U;Mn;220;NSM;;;;;N;;;;;
+AAB5;TAI VIET VOWEL E;Lo;0;L;;;;;N;;;;;
+AAB6;TAI VIET VOWEL O;Lo;0;L;;;;;N;;;;;
+AAB7;TAI VIET MAI KHIT;Mn;230;NSM;;;;;N;;;;;
+AAB8;TAI VIET VOWEL IA;Mn;230;NSM;;;;;N;;;;;
+AAB9;TAI VIET VOWEL UEA;Lo;0;L;;;;;N;;;;;
+AABA;TAI VIET VOWEL UA;Lo;0;L;;;;;N;;;;;
+AABB;TAI VIET VOWEL AUE;Lo;0;L;;;;;N;;;;;
+AABC;TAI VIET VOWEL AY;Lo;0;L;;;;;N;;;;;
+AABD;TAI VIET VOWEL AN;Lo;0;L;;;;;N;;;;;
+AABE;TAI VIET VOWEL AM;Mn;230;NSM;;;;;N;;;;;
+AABF;TAI VIET TONE MAI EK;Mn;230;NSM;;;;;N;;;;;
+AAC0;TAI VIET TONE MAI NUENG;Lo;0;L;;;;;N;;;;;
+AAC1;TAI VIET TONE MAI THO;Mn;230;NSM;;;;;N;;;;;
+AAC2;TAI VIET TONE MAI SONG;Lo;0;L;;;;;N;;;;;
+AADB;TAI VIET SYMBOL KON;Lo;0;L;;;;;N;;;;;
+AADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;;
+AADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;;
+AADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;;
+AADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;;
+AAE0;MEETEI MAYEK LETTER E;Lo;0;L;;;;;N;;;;;
+AAE1;MEETEI MAYEK LETTER O;Lo;0;L;;;;;N;;;;;
+AAE2;MEETEI MAYEK LETTER CHA;Lo;0;L;;;;;N;;;;;
+AAE3;MEETEI MAYEK LETTER NYA;Lo;0;L;;;;;N;;;;;
+AAE4;MEETEI MAYEK LETTER TTA;Lo;0;L;;;;;N;;;;;
+AAE5;MEETEI MAYEK LETTER TTHA;Lo;0;L;;;;;N;;;;;
+AAE6;MEETEI MAYEK LETTER DDA;Lo;0;L;;;;;N;;;;;
+AAE7;MEETEI MAYEK LETTER DDHA;Lo;0;L;;;;;N;;;;;
+AAE8;MEETEI MAYEK LETTER NNA;Lo;0;L;;;;;N;;;;;
+AAE9;MEETEI MAYEK LETTER SHA;Lo;0;L;;;;;N;;;;;
+AAEA;MEETEI MAYEK LETTER SSA;Lo;0;L;;;;;N;;;;;
+AAEB;MEETEI MAYEK VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+AAEC;MEETEI MAYEK VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+AAED;MEETEI MAYEK VOWEL SIGN AAI;Mn;0;NSM;;;;;N;;;;;
+AAEE;MEETEI MAYEK VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+AAEF;MEETEI MAYEK VOWEL SIGN AAU;Mc;0;L;;;;;N;;;;;
+AAF0;MEETEI MAYEK CHEIKHAN;Po;0;L;;;;;N;;;;;
+AAF1;MEETEI MAYEK AHANG KHUDAM;Po;0;L;;;;;N;;;;;
+AAF2;MEETEI MAYEK ANJI;Lo;0;L;;;;;N;;;;;
+AAF3;MEETEI MAYEK SYLLABLE REPETITION MARK;Lm;0;L;;;;;N;;;;;
+AAF4;MEETEI MAYEK WORD REPETITION MARK;Lm;0;L;;;;;N;;;;;
+AAF5;MEETEI MAYEK VOWEL SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+AAF6;MEETEI MAYEK VIRAMA;Mn;9;NSM;;;;;N;;;;;
+AB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;;
+AB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;;
+AB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;;
+AB04;ETHIOPIC SYLLABLE TTHEE;Lo;0;L;;;;;N;;;;;
+AB05;ETHIOPIC SYLLABLE TTHE;Lo;0;L;;;;;N;;;;;
+AB06;ETHIOPIC SYLLABLE TTHO;Lo;0;L;;;;;N;;;;;
+AB09;ETHIOPIC SYLLABLE DDHU;Lo;0;L;;;;;N;;;;;
+AB0A;ETHIOPIC SYLLABLE DDHI;Lo;0;L;;;;;N;;;;;
+AB0B;ETHIOPIC SYLLABLE DDHAA;Lo;0;L;;;;;N;;;;;
+AB0C;ETHIOPIC SYLLABLE DDHEE;Lo;0;L;;;;;N;;;;;
+AB0D;ETHIOPIC SYLLABLE DDHE;Lo;0;L;;;;;N;;;;;
+AB0E;ETHIOPIC SYLLABLE DDHO;Lo;0;L;;;;;N;;;;;
+AB11;ETHIOPIC SYLLABLE DZU;Lo;0;L;;;;;N;;;;;
+AB12;ETHIOPIC SYLLABLE DZI;Lo;0;L;;;;;N;;;;;
+AB13;ETHIOPIC SYLLABLE DZAA;Lo;0;L;;;;;N;;;;;
+AB14;ETHIOPIC SYLLABLE DZEE;Lo;0;L;;;;;N;;;;;
+AB15;ETHIOPIC SYLLABLE DZE;Lo;0;L;;;;;N;;;;;
+AB16;ETHIOPIC SYLLABLE DZO;Lo;0;L;;;;;N;;;;;
+AB20;ETHIOPIC SYLLABLE CCHHA;Lo;0;L;;;;;N;;;;;
+AB21;ETHIOPIC SYLLABLE CCHHU;Lo;0;L;;;;;N;;;;;
+AB22;ETHIOPIC SYLLABLE CCHHI;Lo;0;L;;;;;N;;;;;
+AB23;ETHIOPIC SYLLABLE CCHHAA;Lo;0;L;;;;;N;;;;;
+AB24;ETHIOPIC SYLLABLE CCHHEE;Lo;0;L;;;;;N;;;;;
+AB25;ETHIOPIC SYLLABLE CCHHE;Lo;0;L;;;;;N;;;;;
+AB26;ETHIOPIC SYLLABLE CCHHO;Lo;0;L;;;;;N;;;;;
+AB28;ETHIOPIC SYLLABLE BBA;Lo;0;L;;;;;N;;;;;
+AB29;ETHIOPIC SYLLABLE BBU;Lo;0;L;;;;;N;;;;;
+AB2A;ETHIOPIC SYLLABLE BBI;Lo;0;L;;;;;N;;;;;
+AB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;;
+AB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;;
+AB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;;
+AB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;;
+AB30;LATIN SMALL LETTER BARRED ALPHA;Ll;0;L;;;;;N;;;;;
+AB31;LATIN SMALL LETTER A REVERSED-SCHWA;Ll;0;L;;;;;N;;;;;
+AB32;LATIN SMALL LETTER BLACKLETTER E;Ll;0;L;;;;;N;;;;;
+AB33;LATIN SMALL LETTER BARRED E;Ll;0;L;;;;;N;;;;;
+AB34;LATIN SMALL LETTER E WITH FLOURISH;Ll;0;L;;;;;N;;;;;
+AB35;LATIN SMALL LETTER LENIS F;Ll;0;L;;;;;N;;;;;
+AB36;LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB37;LATIN SMALL LETTER L WITH INVERTED LAZY S;Ll;0;L;;;;;N;;;;;
+AB38;LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+AB39;LATIN SMALL LETTER L WITH MIDDLE RING;Ll;0;L;;;;;N;;;;;
+AB3A;LATIN SMALL LETTER M WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB3B;LATIN SMALL LETTER N WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB3C;LATIN SMALL LETTER ENG WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB3D;LATIN SMALL LETTER BLACKLETTER O;Ll;0;L;;;;;N;;;;;
+AB3E;LATIN SMALL LETTER BLACKLETTER O WITH STROKE;Ll;0;L;;;;;N;;;;;
+AB3F;LATIN SMALL LETTER OPEN O WITH STROKE;Ll;0;L;;;;;N;;;;;
+AB40;LATIN SMALL LETTER INVERTED OE;Ll;0;L;;;;;N;;;;;
+AB41;LATIN SMALL LETTER TURNED OE WITH STROKE;Ll;0;L;;;;;N;;;;;
+AB42;LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE;Ll;0;L;;;;;N;;;;;
+AB43;LATIN SMALL LETTER TURNED O OPEN-O;Ll;0;L;;;;;N;;;;;
+AB44;LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE;Ll;0;L;;;;;N;;;;;
+AB45;LATIN SMALL LETTER STIRRUP R;Ll;0;L;;;;;N;;;;;
+AB46;LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG;Ll;0;L;;;;;N;;;;;
+AB47;LATIN SMALL LETTER R WITHOUT HANDLE;Ll;0;L;;;;;N;;;;;
+AB48;LATIN SMALL LETTER DOUBLE R;Ll;0;L;;;;;N;;;;;
+AB49;LATIN SMALL LETTER R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB4A;LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL;Ll;0;L;;;;;N;;;;;
+AB4B;LATIN SMALL LETTER SCRIPT R;Ll;0;L;;;;;N;;;;;
+AB4C;LATIN SMALL LETTER SCRIPT R WITH RING;Ll;0;L;;;;;N;;;;;
+AB4D;LATIN SMALL LETTER BASELINE ESH;Ll;0;L;;;;;N;;;;;
+AB4E;LATIN SMALL LETTER U WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;
+AB4F;LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;
+AB50;LATIN SMALL LETTER UI;Ll;0;L;;;;;N;;;;;
+AB51;LATIN SMALL LETTER TURNED UI;Ll;0;L;;;;;N;;;;;
+AB52;LATIN SMALL LETTER U WITH LEFT HOOK;Ll;0;L;;;;;N;;;;;
+AB53;LATIN SMALL LETTER CHI;Ll;0;L;;;;;N;;;A7B3;;A7B3
+AB54;LATIN SMALL LETTER CHI WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;;
+AB55;LATIN SMALL LETTER CHI WITH LOW LEFT SERIF;Ll;0;L;;;;;N;;;;;
+AB56;LATIN SMALL LETTER X WITH LOW RIGHT RING;Ll;0;L;;;;;N;;;;;
+AB57;LATIN SMALL LETTER X WITH LONG LEFT LEG;Ll;0;L;;;;;N;;;;;
+AB58;LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING;Ll;0;L;;;;;N;;;;;
+AB59;LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF;Ll;0;L;;;;;N;;;;;
+AB5A;LATIN SMALL LETTER Y WITH SHORT RIGHT LEG;Ll;0;L;;;;;N;;;;;
+AB5B;MODIFIER BREVE WITH INVERTED BREVE;Sk;0;L;;;;;N;;;;;
+AB5C;MODIFIER LETTER SMALL HENG;Lm;0;L;<super> A727;;;;N;;;;;
+AB5D;MODIFIER LETTER SMALL L WITH INVERTED LAZY S;Lm;0;L;<super> AB37;;;;N;;;;;
+AB5E;MODIFIER LETTER SMALL L WITH MIDDLE TILDE;Lm;0;L;<super> 026B;;;;N;;;;;
+AB5F;MODIFIER LETTER SMALL U WITH LEFT HOOK;Lm;0;L;<super> AB52;;;;N;;;;;
+AB60;LATIN SMALL LETTER SAKHA YAT;Ll;0;L;;;;;N;;;;;
+AB61;LATIN SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;;;
+AB62;LATIN SMALL LETTER OPEN OE;Ll;0;L;;;;;N;;;;;
+AB63;LATIN SMALL LETTER UO;Ll;0;L;;;;;N;;;;;
+AB64;LATIN SMALL LETTER INVERTED ALPHA;Ll;0;L;;;;;N;;;;;
+AB65;GREEK LETTER SMALL CAPITAL OMEGA;Ll;0;L;;;;;N;;;;;
+AB70;CHEROKEE SMALL LETTER A;Ll;0;L;;;;;N;;;13A0;;13A0
+AB71;CHEROKEE SMALL LETTER E;Ll;0;L;;;;;N;;;13A1;;13A1
+AB72;CHEROKEE SMALL LETTER I;Ll;0;L;;;;;N;;;13A2;;13A2
+AB73;CHEROKEE SMALL LETTER O;Ll;0;L;;;;;N;;;13A3;;13A3
+AB74;CHEROKEE SMALL LETTER U;Ll;0;L;;;;;N;;;13A4;;13A4
+AB75;CHEROKEE SMALL LETTER V;Ll;0;L;;;;;N;;;13A5;;13A5
+AB76;CHEROKEE SMALL LETTER GA;Ll;0;L;;;;;N;;;13A6;;13A6
+AB77;CHEROKEE SMALL LETTER KA;Ll;0;L;;;;;N;;;13A7;;13A7
+AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8
+AB79;CHEROKEE SMALL LETTER GI;Ll;0;L;;;;;N;;;13A9;;13A9
+AB7A;CHEROKEE SMALL LETTER GO;Ll;0;L;;;;;N;;;13AA;;13AA
+AB7B;CHEROKEE SMALL LETTER GU;Ll;0;L;;;;;N;;;13AB;;13AB
+AB7C;CHEROKEE SMALL LETTER GV;Ll;0;L;;;;;N;;;13AC;;13AC
+AB7D;CHEROKEE SMALL LETTER HA;Ll;0;L;;;;;N;;;13AD;;13AD
+AB7E;CHEROKEE SMALL LETTER HE;Ll;0;L;;;;;N;;;13AE;;13AE
+AB7F;CHEROKEE SMALL LETTER HI;Ll;0;L;;;;;N;;;13AF;;13AF
+AB80;CHEROKEE SMALL LETTER HO;Ll;0;L;;;;;N;;;13B0;;13B0
+AB81;CHEROKEE SMALL LETTER HU;Ll;0;L;;;;;N;;;13B1;;13B1
+AB82;CHEROKEE SMALL LETTER HV;Ll;0;L;;;;;N;;;13B2;;13B2
+AB83;CHEROKEE SMALL LETTER LA;Ll;0;L;;;;;N;;;13B3;;13B3
+AB84;CHEROKEE SMALL LETTER LE;Ll;0;L;;;;;N;;;13B4;;13B4
+AB85;CHEROKEE SMALL LETTER LI;Ll;0;L;;;;;N;;;13B5;;13B5
+AB86;CHEROKEE SMALL LETTER LO;Ll;0;L;;;;;N;;;13B6;;13B6
+AB87;CHEROKEE SMALL LETTER LU;Ll;0;L;;;;;N;;;13B7;;13B7
+AB88;CHEROKEE SMALL LETTER LV;Ll;0;L;;;;;N;;;13B8;;13B8
+AB89;CHEROKEE SMALL LETTER MA;Ll;0;L;;;;;N;;;13B9;;13B9
+AB8A;CHEROKEE SMALL LETTER ME;Ll;0;L;;;;;N;;;13BA;;13BA
+AB8B;CHEROKEE SMALL LETTER MI;Ll;0;L;;;;;N;;;13BB;;13BB
+AB8C;CHEROKEE SMALL LETTER MO;Ll;0;L;;;;;N;;;13BC;;13BC
+AB8D;CHEROKEE SMALL LETTER MU;Ll;0;L;;;;;N;;;13BD;;13BD
+AB8E;CHEROKEE SMALL LETTER NA;Ll;0;L;;;;;N;;;13BE;;13BE
+AB8F;CHEROKEE SMALL LETTER HNA;Ll;0;L;;;;;N;;;13BF;;13BF
+AB90;CHEROKEE SMALL LETTER NAH;Ll;0;L;;;;;N;;;13C0;;13C0
+AB91;CHEROKEE SMALL LETTER NE;Ll;0;L;;;;;N;;;13C1;;13C1
+AB92;CHEROKEE SMALL LETTER NI;Ll;0;L;;;;;N;;;13C2;;13C2
+AB93;CHEROKEE SMALL LETTER NO;Ll;0;L;;;;;N;;;13C3;;13C3
+AB94;CHEROKEE SMALL LETTER NU;Ll;0;L;;;;;N;;;13C4;;13C4
+AB95;CHEROKEE SMALL LETTER NV;Ll;0;L;;;;;N;;;13C5;;13C5
+AB96;CHEROKEE SMALL LETTER QUA;Ll;0;L;;;;;N;;;13C6;;13C6
+AB97;CHEROKEE SMALL LETTER QUE;Ll;0;L;;;;;N;;;13C7;;13C7
+AB98;CHEROKEE SMALL LETTER QUI;Ll;0;L;;;;;N;;;13C8;;13C8
+AB99;CHEROKEE SMALL LETTER QUO;Ll;0;L;;;;;N;;;13C9;;13C9
+AB9A;CHEROKEE SMALL LETTER QUU;Ll;0;L;;;;;N;;;13CA;;13CA
+AB9B;CHEROKEE SMALL LETTER QUV;Ll;0;L;;;;;N;;;13CB;;13CB
+AB9C;CHEROKEE SMALL LETTER SA;Ll;0;L;;;;;N;;;13CC;;13CC
+AB9D;CHEROKEE SMALL LETTER S;Ll;0;L;;;;;N;;;13CD;;13CD
+AB9E;CHEROKEE SMALL LETTER SE;Ll;0;L;;;;;N;;;13CE;;13CE
+AB9F;CHEROKEE SMALL LETTER SI;Ll;0;L;;;;;N;;;13CF;;13CF
+ABA0;CHEROKEE SMALL LETTER SO;Ll;0;L;;;;;N;;;13D0;;13D0
+ABA1;CHEROKEE SMALL LETTER SU;Ll;0;L;;;;;N;;;13D1;;13D1
+ABA2;CHEROKEE SMALL LETTER SV;Ll;0;L;;;;;N;;;13D2;;13D2
+ABA3;CHEROKEE SMALL LETTER DA;Ll;0;L;;;;;N;;;13D3;;13D3
+ABA4;CHEROKEE SMALL LETTER TA;Ll;0;L;;;;;N;;;13D4;;13D4
+ABA5;CHEROKEE SMALL LETTER DE;Ll;0;L;;;;;N;;;13D5;;13D5
+ABA6;CHEROKEE SMALL LETTER TE;Ll;0;L;;;;;N;;;13D6;;13D6
+ABA7;CHEROKEE SMALL LETTER DI;Ll;0;L;;;;;N;;;13D7;;13D7
+ABA8;CHEROKEE SMALL LETTER TI;Ll;0;L;;;;;N;;;13D8;;13D8
+ABA9;CHEROKEE SMALL LETTER DO;Ll;0;L;;;;;N;;;13D9;;13D9
+ABAA;CHEROKEE SMALL LETTER DU;Ll;0;L;;;;;N;;;13DA;;13DA
+ABAB;CHEROKEE SMALL LETTER DV;Ll;0;L;;;;;N;;;13DB;;13DB
+ABAC;CHEROKEE SMALL LETTER DLA;Ll;0;L;;;;;N;;;13DC;;13DC
+ABAD;CHEROKEE SMALL LETTER TLA;Ll;0;L;;;;;N;;;13DD;;13DD
+ABAE;CHEROKEE SMALL LETTER TLE;Ll;0;L;;;;;N;;;13DE;;13DE
+ABAF;CHEROKEE SMALL LETTER TLI;Ll;0;L;;;;;N;;;13DF;;13DF
+ABB0;CHEROKEE SMALL LETTER TLO;Ll;0;L;;;;;N;;;13E0;;13E0
+ABB1;CHEROKEE SMALL LETTER TLU;Ll;0;L;;;;;N;;;13E1;;13E1
+ABB2;CHEROKEE SMALL LETTER TLV;Ll;0;L;;;;;N;;;13E2;;13E2
+ABB3;CHEROKEE SMALL LETTER TSA;Ll;0;L;;;;;N;;;13E3;;13E3
+ABB4;CHEROKEE SMALL LETTER TSE;Ll;0;L;;;;;N;;;13E4;;13E4
+ABB5;CHEROKEE SMALL LETTER TSI;Ll;0;L;;;;;N;;;13E5;;13E5
+ABB6;CHEROKEE SMALL LETTER TSO;Ll;0;L;;;;;N;;;13E6;;13E6
+ABB7;CHEROKEE SMALL LETTER TSU;Ll;0;L;;;;;N;;;13E7;;13E7
+ABB8;CHEROKEE SMALL LETTER TSV;Ll;0;L;;;;;N;;;13E8;;13E8
+ABB9;CHEROKEE SMALL LETTER WA;Ll;0;L;;;;;N;;;13E9;;13E9
+ABBA;CHEROKEE SMALL LETTER WE;Ll;0;L;;;;;N;;;13EA;;13EA
+ABBB;CHEROKEE SMALL LETTER WI;Ll;0;L;;;;;N;;;13EB;;13EB
+ABBC;CHEROKEE SMALL LETTER WO;Ll;0;L;;;;;N;;;13EC;;13EC
+ABBD;CHEROKEE SMALL LETTER WU;Ll;0;L;;;;;N;;;13ED;;13ED
+ABBE;CHEROKEE SMALL LETTER WV;Ll;0;L;;;;;N;;;13EE;;13EE
+ABBF;CHEROKEE SMALL LETTER YA;Ll;0;L;;;;;N;;;13EF;;13EF
+ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;;
+ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;;
+ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;;
+ABC3;MEETEI MAYEK LETTER MIT;Lo;0;L;;;;;N;;;;;
+ABC4;MEETEI MAYEK LETTER PA;Lo;0;L;;;;;N;;;;;
+ABC5;MEETEI MAYEK LETTER NA;Lo;0;L;;;;;N;;;;;
+ABC6;MEETEI MAYEK LETTER CHIL;Lo;0;L;;;;;N;;;;;
+ABC7;MEETEI MAYEK LETTER TIL;Lo;0;L;;;;;N;;;;;
+ABC8;MEETEI MAYEK LETTER KHOU;Lo;0;L;;;;;N;;;;;
+ABC9;MEETEI MAYEK LETTER NGOU;Lo;0;L;;;;;N;;;;;
+ABCA;MEETEI MAYEK LETTER THOU;Lo;0;L;;;;;N;;;;;
+ABCB;MEETEI MAYEK LETTER WAI;Lo;0;L;;;;;N;;;;;
+ABCC;MEETEI MAYEK LETTER YANG;Lo;0;L;;;;;N;;;;;
+ABCD;MEETEI MAYEK LETTER HUK;Lo;0;L;;;;;N;;;;;
+ABCE;MEETEI MAYEK LETTER UN;Lo;0;L;;;;;N;;;;;
+ABCF;MEETEI MAYEK LETTER I;Lo;0;L;;;;;N;;;;;
+ABD0;MEETEI MAYEK LETTER PHAM;Lo;0;L;;;;;N;;;;;
+ABD1;MEETEI MAYEK LETTER ATIYA;Lo;0;L;;;;;N;;;;;
+ABD2;MEETEI MAYEK LETTER GOK;Lo;0;L;;;;;N;;;;;
+ABD3;MEETEI MAYEK LETTER JHAM;Lo;0;L;;;;;N;;;;;
+ABD4;MEETEI MAYEK LETTER RAI;Lo;0;L;;;;;N;;;;;
+ABD5;MEETEI MAYEK LETTER BA;Lo;0;L;;;;;N;;;;;
+ABD6;MEETEI MAYEK LETTER JIL;Lo;0;L;;;;;N;;;;;
+ABD7;MEETEI MAYEK LETTER DIL;Lo;0;L;;;;;N;;;;;
+ABD8;MEETEI MAYEK LETTER GHOU;Lo;0;L;;;;;N;;;;;
+ABD9;MEETEI MAYEK LETTER DHOU;Lo;0;L;;;;;N;;;;;
+ABDA;MEETEI MAYEK LETTER BHAM;Lo;0;L;;;;;N;;;;;
+ABDB;MEETEI MAYEK LETTER KOK LONSUM;Lo;0;L;;;;;N;;;;;
+ABDC;MEETEI MAYEK LETTER LAI LONSUM;Lo;0;L;;;;;N;;;;;
+ABDD;MEETEI MAYEK LETTER MIT LONSUM;Lo;0;L;;;;;N;;;;;
+ABDE;MEETEI MAYEK LETTER PA LONSUM;Lo;0;L;;;;;N;;;;;
+ABDF;MEETEI MAYEK LETTER NA LONSUM;Lo;0;L;;;;;N;;;;;
+ABE0;MEETEI MAYEK LETTER TIL LONSUM;Lo;0;L;;;;;N;;;;;
+ABE1;MEETEI MAYEK LETTER NGOU LONSUM;Lo;0;L;;;;;N;;;;;
+ABE2;MEETEI MAYEK LETTER I LONSUM;Lo;0;L;;;;;N;;;;;
+ABE3;MEETEI MAYEK VOWEL SIGN ONAP;Mc;0;L;;;;;N;;;;;
+ABE4;MEETEI MAYEK VOWEL SIGN INAP;Mc;0;L;;;;;N;;;;;
+ABE5;MEETEI MAYEK VOWEL SIGN ANAP;Mn;0;NSM;;;;;N;;;;;
+ABE6;MEETEI MAYEK VOWEL SIGN YENAP;Mc;0;L;;;;;N;;;;;
+ABE7;MEETEI MAYEK VOWEL SIGN SOUNAP;Mc;0;L;;;;;N;;;;;
+ABE8;MEETEI MAYEK VOWEL SIGN UNAP;Mn;0;NSM;;;;;N;;;;;
+ABE9;MEETEI MAYEK VOWEL SIGN CHEINAP;Mc;0;L;;;;;N;;;;;
+ABEA;MEETEI MAYEK VOWEL SIGN NUNG;Mc;0;L;;;;;N;;;;;
+ABEB;MEETEI MAYEK CHEIKHEI;Po;0;L;;;;;N;;;;;
+ABEC;MEETEI MAYEK LUM IYEK;Mc;0;L;;;;;N;;;;;
+ABED;MEETEI MAYEK APUN IYEK;Mn;9;NSM;;;;;N;;;;;
+ABF0;MEETEI MAYEK DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+ABF1;MEETEI MAYEK DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+ABF2;MEETEI MAYEK DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+ABF3;MEETEI MAYEK DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+ABF4;MEETEI MAYEK DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+ABF5;MEETEI MAYEK DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+ABF6;MEETEI MAYEK DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+ABF7;MEETEI MAYEK DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+ABF8;MEETEI MAYEK DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+ABF9;MEETEI MAYEK DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;;
+D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;;
+D7B0;HANGUL JUNGSEONG O-YEO;Lo;0;L;;;;;N;;;;;
+D7B1;HANGUL JUNGSEONG O-O-I;Lo;0;L;;;;;N;;;;;
+D7B2;HANGUL JUNGSEONG YO-A;Lo;0;L;;;;;N;;;;;
+D7B3;HANGUL JUNGSEONG YO-AE;Lo;0;L;;;;;N;;;;;
+D7B4;HANGUL JUNGSEONG YO-EO;Lo;0;L;;;;;N;;;;;
+D7B5;HANGUL JUNGSEONG U-YEO;Lo;0;L;;;;;N;;;;;
+D7B6;HANGUL JUNGSEONG U-I-I;Lo;0;L;;;;;N;;;;;
+D7B7;HANGUL JUNGSEONG YU-AE;Lo;0;L;;;;;N;;;;;
+D7B8;HANGUL JUNGSEONG YU-O;Lo;0;L;;;;;N;;;;;
+D7B9;HANGUL JUNGSEONG EU-A;Lo;0;L;;;;;N;;;;;
+D7BA;HANGUL JUNGSEONG EU-EO;Lo;0;L;;;;;N;;;;;
+D7BB;HANGUL JUNGSEONG EU-E;Lo;0;L;;;;;N;;;;;
+D7BC;HANGUL JUNGSEONG EU-O;Lo;0;L;;;;;N;;;;;
+D7BD;HANGUL JUNGSEONG I-YA-O;Lo;0;L;;;;;N;;;;;
+D7BE;HANGUL JUNGSEONG I-YAE;Lo;0;L;;;;;N;;;;;
+D7BF;HANGUL JUNGSEONG I-YEO;Lo;0;L;;;;;N;;;;;
+D7C0;HANGUL JUNGSEONG I-YE;Lo;0;L;;;;;N;;;;;
+D7C1;HANGUL JUNGSEONG I-O-I;Lo;0;L;;;;;N;;;;;
+D7C2;HANGUL JUNGSEONG I-YO;Lo;0;L;;;;;N;;;;;
+D7C3;HANGUL JUNGSEONG I-YU;Lo;0;L;;;;;N;;;;;
+D7C4;HANGUL JUNGSEONG I-I;Lo;0;L;;;;;N;;;;;
+D7C5;HANGUL JUNGSEONG ARAEA-A;Lo;0;L;;;;;N;;;;;
+D7C6;HANGUL JUNGSEONG ARAEA-E;Lo;0;L;;;;;N;;;;;
+D7CB;HANGUL JONGSEONG NIEUN-RIEUL;Lo;0;L;;;;;N;;;;;
+D7CC;HANGUL JONGSEONG NIEUN-CHIEUCH;Lo;0;L;;;;;N;;;;;
+D7CD;HANGUL JONGSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;;;;
+D7CE;HANGUL JONGSEONG SSANGTIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;
+D7CF;HANGUL JONGSEONG TIKEUT-PIEUP;Lo;0;L;;;;;N;;;;;
+D7D0;HANGUL JONGSEONG TIKEUT-SIOS;Lo;0;L;;;;;N;;;;;
+D7D1;HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+D7D2;HANGUL JONGSEONG TIKEUT-CIEUC;Lo;0;L;;;;;N;;;;;
+D7D3;HANGUL JONGSEONG TIKEUT-CHIEUCH;Lo;0;L;;;;;N;;;;;
+D7D4;HANGUL JONGSEONG TIKEUT-THIEUTH;Lo;0;L;;;;;N;;;;;
+D7D5;HANGUL JONGSEONG RIEUL-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+D7D6;HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH;Lo;0;L;;;;;N;;;;;
+D7D7;HANGUL JONGSEONG SSANGRIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+D7D8;HANGUL JONGSEONG RIEUL-MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;
+D7D9;HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+D7DA;HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+D7DB;HANGUL JONGSEONG RIEUL-YESIEUNG;Lo;0;L;;;;;N;;;;;
+D7DC;HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH;Lo;0;L;;;;;N;;;;;
+D7DD;HANGUL JONGSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;
+D7DE;HANGUL JONGSEONG MIEUM-NIEUN;Lo;0;L;;;;;N;;;;;
+D7DF;HANGUL JONGSEONG MIEUM-SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+D7E0;HANGUL JONGSEONG SSANGMIEUM;Lo;0;L;;;;;N;;;;;
+D7E1;HANGUL JONGSEONG MIEUM-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+D7E2;HANGUL JONGSEONG MIEUM-CIEUC;Lo;0;L;;;;;N;;;;;
+D7E3;HANGUL JONGSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+D7E4;HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH;Lo;0;L;;;;;N;;;;;
+D7E5;HANGUL JONGSEONG PIEUP-MIEUM;Lo;0;L;;;;;N;;;;;
+D7E6;HANGUL JONGSEONG SSANGPIEUP;Lo;0;L;;;;;N;;;;;
+D7E7;HANGUL JONGSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+D7E8;HANGUL JONGSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;
+D7E9;HANGUL JONGSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;
+D7EA;HANGUL JONGSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;
+D7EB;HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+D7EC;HANGUL JONGSEONG SSANGSIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+D7ED;HANGUL JONGSEONG SSANGSIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+D7EE;HANGUL JONGSEONG SIOS-PANSIOS;Lo;0;L;;;;;N;;;;;
+D7EF;HANGUL JONGSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+D7F0;HANGUL JONGSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;
+D7F1;HANGUL JONGSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+D7F2;HANGUL JONGSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;
+D7F3;HANGUL JONGSEONG PANSIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+D7F4;HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+D7F5;HANGUL JONGSEONG YESIEUNG-MIEUM;Lo;0;L;;;;;N;;;;;
+D7F6;HANGUL JONGSEONG YESIEUNG-HIEUH;Lo;0;L;;;;;N;;;;;
+D7F7;HANGUL JONGSEONG CIEUC-PIEUP;Lo;0;L;;;;;N;;;;;
+D7F8;HANGUL JONGSEONG CIEUC-SSANGPIEUP;Lo;0;L;;;;;N;;;;;
+D7F9;HANGUL JONGSEONG SSANGCIEUC;Lo;0;L;;;;;N;;;;;
+D7FA;HANGUL JONGSEONG PHIEUPH-SIOS;Lo;0;L;;;;;N;;;;;
+D7FB;HANGUL JONGSEONG PHIEUPH-THIEUTH;Lo;0;L;;;;;N;;;;;
+D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+E000;<Private Use, First>;Co;0;L;;;;;N;;;;;
+F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;;
+F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;;
+F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;;
+F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;;
+F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;;
+F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;;
+F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;;
+F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;;
+F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;;
+F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;;
+F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;;
+F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;;
+F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;;
+F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;;
+F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;;
+F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;;
+F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;;
+F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;;
+F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;;
+F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;;
+F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;;
+F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;;
+F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;;
+F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;;
+F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;;
+F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;;
+F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;;
+F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;;
+F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;;
+F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;;
+F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;;
+F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;;
+F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;;
+F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;;
+F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;;
+F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;;
+F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;;
+F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;;
+F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;;
+F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;;
+F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;;
+F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;;
+F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;;
+F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;;
+F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;;
+F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;;
+F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;;
+F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;;
+F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;;
+F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;;
+F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;;
+F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;;
+F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;;
+F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;;
+F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;;
+F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;;
+F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;;
+F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;;
+F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;;
+F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;;
+F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;;
+F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;;
+F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;;
+F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;;
+F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;;
+F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;;
+F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;;
+F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;;
+F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;;
+F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;;
+F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;;
+F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;;
+F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;;
+F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;;
+F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;;
+F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;;
+F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;;
+F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;;
+F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;;
+F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;;
+F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;;
+F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;;
+F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;;
+F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;;
+F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;;
+F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;;
+F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;;
+F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;;
+F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;;
+F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;;
+F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;;
+F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;;
+F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;;
+F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;;
+F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;;
+F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;;
+F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;;
+F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;;
+F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;;
+F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;;
+F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;;
+F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;;
+F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;;
+F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;;
+F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;;
+F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;;
+F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;;
+F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;;
+F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;3;N;;;;;
+F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;;
+F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;;
+F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;;
+F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;;
+F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;;
+F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;;
+F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;;
+F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;10;N;;;;;
+F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;;
+F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;;
+F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;;
+F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;;
+F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;2;N;;;;;
+F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;;
+F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;;
+F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;;
+F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;;
+F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;;
+F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;;
+F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;;
+F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;;
+F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;;
+F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;;
+F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;;
+F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;;
+F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;;
+F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;;
+F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;;
+F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;;
+F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;;
+F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;;
+F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;;
+F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;;
+F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;;
+F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;;
+F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;;
+F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;;
+F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;;
+F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;;
+F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;;
+F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;;
+F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;;
+F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;;
+F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;;
+F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;;
+F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;;
+F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;;
+F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;;
+F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;;
+F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;;
+F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;;
+F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;;
+F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;;
+F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;;
+F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;;
+F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;;
+F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;;
+F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;;
+F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;;
+F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;;
+F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;;
+F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;;
+F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;;
+F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;;
+F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;;
+F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;;
+F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;;
+F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;;
+F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;;
+F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;;
+F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;0;N;;;;;
+F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;;
+F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;;
+F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;;
+F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;;
+F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;;
+F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;;
+F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;;
+F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;;
+F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;;
+F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;;
+F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;;
+F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;;
+F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;;
+F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;;
+F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;;
+F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;;
+F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;;
+F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;;
+F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;;
+F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;;
+F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;;
+F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;;
+F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;;
+F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;;
+F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;;
+F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;;
+F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;;
+F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;;
+F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;;
+F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;;
+F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;6;N;;;;;
+F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;;
+F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;6;N;;;;;
+F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;;
+F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;;
+F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;;
+F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;;
+F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;;
+F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;;
+F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;;
+F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;;
+F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;;
+F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;;
+F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;;
+F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;;
+F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;;
+F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;;
+F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;;
+F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;;
+F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;;
+F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;;
+F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;;
+F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;;
+F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;;
+F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;;
+F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;;
+F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;;
+F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;;
+F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;;
+F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;;
+F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;;
+F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;;
+F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;;
+F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;;
+F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;;
+F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;;
+F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;;
+F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;;
+F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;;
+F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;;
+F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;;
+F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;;
+F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;;
+F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;;
+F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;10;N;;;;;
+F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;;
+F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;;
+FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;;
+FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;;
+FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;;
+FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;;
+FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;;
+FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;;
+FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;;
+FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;;
+FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;;
+FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;;
+FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;;
+FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;;
+FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;;
+FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;;
+FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;;
+FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;;
+FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;;
+FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;;
+FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;;
+FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;;
+FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;;
+FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;;
+FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;;
+FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;;
+FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;;
+FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;;
+FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;;
+FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;;
+FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;;
+FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;;
+FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;;
+FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;;;;
+FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;;
+FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;;
+FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;;
+FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;;;;
+FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;;
+FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;;
+FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;;
+FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;;
+FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;;
+FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;;
+FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;;
+FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;;
+FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;;
+FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;;
+FA2E;CJK COMPATIBILITY IDEOGRAPH-FA2E;Lo;0;L;90DE;;;;N;;;;;
+FA2F;CJK COMPATIBILITY IDEOGRAPH-FA2F;Lo;0;L;96B7;;;;N;;;;;
+FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;;
+FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;;
+FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;;
+FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;;
+FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;;
+FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;;
+FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;;
+FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;;
+FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;;
+FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;;
+FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;;
+FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;;
+FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;;
+FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;;
+FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;;
+FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;;
+FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;;
+FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;;
+FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;;
+FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;;
+FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;;
+FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;;
+FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;;
+FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;;
+FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;;
+FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;;
+FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;;
+FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;;
+FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;;
+FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;;
+FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;;
+FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;;
+FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;;
+FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;;
+FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;;
+FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;;
+FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;;
+FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;;
+FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;;
+FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;;
+FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;;
+FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;;
+FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;;
+FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;;
+FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;;
+FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;;
+FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;;
+FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;;
+FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;;
+FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;;
+FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;;
+FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;;
+FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;;
+FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;;
+FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;;
+FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;;
+FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;;
+FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;;
+FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;;
+FA6B;CJK COMPATIBILITY IDEOGRAPH-FA6B;Lo;0;L;6075;;;;N;;;;;
+FA6C;CJK COMPATIBILITY IDEOGRAPH-FA6C;Lo;0;L;242EE;;;;N;;;;;
+FA6D;CJK COMPATIBILITY IDEOGRAPH-FA6D;Lo;0;L;8218;;;;N;;;;;
+FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;;
+FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;;
+FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;;
+FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;;
+FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;;
+FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;;
+FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;;
+FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;;
+FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;;
+FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;;
+FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;;
+FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;;
+FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;;
+FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;;
+FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;;
+FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;;
+FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;;
+FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;;
+FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;;
+FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;;
+FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;;
+FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;;
+FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;;
+FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;;
+FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;;
+FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;;
+FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;;
+FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;;
+FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;;
+FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;;
+FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;;
+FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;;
+FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;;
+FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;;
+FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;;
+FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;;
+FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;;
+FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;;
+FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;;
+FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;;
+FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;;
+FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;;
+FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;;
+FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;;
+FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;;
+FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;;
+FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;;
+FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;;
+FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;;
+FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;;
+FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;;
+FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;;
+FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;;
+FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;;
+FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;;
+FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;;
+FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;;
+FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;;
+FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;;
+FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;;
+FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;;
+FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;;
+FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;;
+FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;;
+FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;;
+FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;;
+FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;;
+FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;;
+FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;;
+FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;;
+FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;;
+FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;;
+FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;;
+FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;;
+FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;;
+FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;;
+FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;;
+FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;;
+FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;;
+FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;;
+FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;;
+FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;;
+FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;;
+FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;;
+FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;;
+FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;;
+FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;;
+FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;;
+FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;;
+FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;;
+FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;;
+FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;;
+FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;;
+FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;;
+FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;;
+FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;;
+FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;;
+FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;;
+FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;;
+FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;;
+FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;;
+FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;;
+FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;;
+FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;;
+FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;;
+FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;;
+FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;;
+FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;;
+FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;;
+FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;;
+FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;;
+FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;;
+FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;;
+FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;;
+FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;;
+FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;;
+FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;;
+FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;;
+FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;;
+FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;;
+FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;;
+FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;;
+FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;;
+FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;;
+FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;;
+FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;;
+FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;;
+FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;;
+FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;;
+FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;;
+FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;;
+FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;;
+FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;;
+FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;;
+FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;;
+FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;;
+FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;;
+FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;;
+FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;;
+FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;;
+FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;;
+FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;;
+FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;;
+FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;;
+FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;;
+FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;;
+FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;;
+FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;;
+FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;;
+FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;;
+FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;;
+FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;;
+FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;;
+FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;;
+FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;;
+FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;;
+FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;;
+FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;;
+FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;;
+FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;;
+FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;;
+FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;;
+FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;;
+FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;;
+FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;;
+FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;;
+FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;;
+FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;;
+FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;;
+FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;;
+FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;;
+FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;;
+FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;;
+FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;;
+FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;;
+FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;;
+FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;;
+FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;;
+FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;;
+FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;;
+FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;;
+FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;;
+FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;;
+FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;;
+FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;;
+FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;;
+FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;;
+FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;;
+FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;;
+FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;;
+FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;;
+FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;;
+FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;;
+FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;;
+FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;;
+FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;;
+FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;;
+FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;;
+FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;;
+FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;;
+FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;;
+FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;;
+FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;;
+FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;;
+FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;;
+FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;;
+FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;;
+FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;;
+FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;;
+FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;;
+FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;;
+FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;;
+FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;;
+FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;;
+FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;;
+FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;;
+FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;;
+FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;;
+FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;;
+FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;;
+FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;;
+FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;;
+FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;;
+FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;;
+FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;;
+FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;;
+FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;;
+FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;;
+FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;;
+FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;;
+FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;;
+FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;;
+FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;;
+FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;;
+FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;;
+FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;;
+FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;;
+FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;;
+FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;;
+FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;;
+FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;;
+FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;;
+FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;;
+FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;;
+FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;;
+FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;;
+FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;;
+FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;;
+FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;;
+FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;;
+FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;;
+FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;;
+FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;;
+FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;;
+FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;;
+FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;;
+FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;;
+FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;;
+FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;;
+FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;;
+FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;;
+FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;;
+FBB2;ARABIC SYMBOL DOT ABOVE;Sk;0;AL;;;;;N;;;;;
+FBB3;ARABIC SYMBOL DOT BELOW;Sk;0;AL;;;;;N;;;;;
+FBB4;ARABIC SYMBOL TWO DOTS ABOVE;Sk;0;AL;;;;;N;;;;;
+FBB5;ARABIC SYMBOL TWO DOTS BELOW;Sk;0;AL;;;;;N;;;;;
+FBB6;ARABIC SYMBOL THREE DOTS ABOVE;Sk;0;AL;;;;;N;;;;;
+FBB7;ARABIC SYMBOL THREE DOTS BELOW;Sk;0;AL;;;;;N;;;;;
+FBB8;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE;Sk;0;AL;;;;;N;;;;;
+FBB9;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW;Sk;0;AL;;;;;N;;;;;
+FBBA;ARABIC SYMBOL FOUR DOTS ABOVE;Sk;0;AL;;;;;N;;;;;
+FBBB;ARABIC SYMBOL FOUR DOTS BELOW;Sk;0;AL;;;;;N;;;;;
+FBBC;ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW;Sk;0;AL;;;;;N;;;;;
+FBBD;ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE;Sk;0;AL;;;;;N;;;;;
+FBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;;
+FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;;
+FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;;
+FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;;
+FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;;
+FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;;
+FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;;
+FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;;
+FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;;
+FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;;
+FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;;
+FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;;
+FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;;
+FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;;
+FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;;
+FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;;
+FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;;
+FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;;
+FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;;
+FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;;
+FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;;
+FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;;
+FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;;
+FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;;
+FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;;
+FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;;
+FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;;
+FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;;
+FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;;
+FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;;
+FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;;
+FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;;
+FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;;
+FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;;
+FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;;
+FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;;
+FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;;
+FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;;
+FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;;
+FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;;
+FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;;
+FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;;
+FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;;
+FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;;
+FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;;
+FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;;
+FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;;
+FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;;
+FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;;
+FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;;
+FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;;
+FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;;
+FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;;
+FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;;
+FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;;
+FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;;
+FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;;
+FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;;
+FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;;
+FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;;
+FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;;
+FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;;
+FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;;
+FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;;
+FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;;
+FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;;
+FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;;
+FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;;
+FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;;
+FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;;
+FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;;
+FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;;
+FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;;
+FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;;
+FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;;
+FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;;
+FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;;
+FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;;
+FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;;
+FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;;
+FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;;
+FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;;
+FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;;
+FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;;
+FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;;
+FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;;
+FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;;
+FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;;
+FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;;
+FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;;
+FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;;
+FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;;
+FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;;
+FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;;
+FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;;
+FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;;
+FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;;
+FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;;
+FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;;
+FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;;
+FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;;
+FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;;
+FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;;
+FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;;
+FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;;
+FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;;
+FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;;
+FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;;
+FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;;
+FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;;
+FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;;
+FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;;
+FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;;
+FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;;
+FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;;
+FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;;
+FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;;
+FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;;
+FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;;
+FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;;
+FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;;
+FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;;
+FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;;
+FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;;
+FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;;
+FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;;
+FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;;
+FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;;
+FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;;
+FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;;
+FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;;
+FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;;
+FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;;
+FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;;
+FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;;
+FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;;
+FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;;
+FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;;
+FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;;
+FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;;
+FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;;
+FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;;
+FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;;
+FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;;
+FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;;
+FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;;
+FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;;
+FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;;
+FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;;
+FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;;
+FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;;
+FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;;
+FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;;
+FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;;
+FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;;
+FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;;
+FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;;
+FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;;
+FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;;
+FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;;
+FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;;
+FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;;
+FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;;
+FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;;
+FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;;
+FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;;
+FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;;
+FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;;
+FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;;
+FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;;
+FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;;
+FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;;
+FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;;
+FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;;
+FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;;
+FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;;
+FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;;
+FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;;
+FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;;
+FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;;
+FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;;
+FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;;
+FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;;
+FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;;
+FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;;
+FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;;
+FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;;
+FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;;
+FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;;
+FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;;
+FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;;
+FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;;
+FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;;
+FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;;
+FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;;
+FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;;
+FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;;
+FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;;
+FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;;
+FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;;
+FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;;
+FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;;
+FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;;
+FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;;
+FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;;
+FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;;
+FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;;
+FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;;
+FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;;
+FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;;
+FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;;
+FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;;
+FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;;
+FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;;
+FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;;
+FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;;
+FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;;
+FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;;
+FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;;
+FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;;
+FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;;
+FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;;
+FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;;
+FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;;
+FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;;
+FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;;
+FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;;
+FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;;
+FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;;
+FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;;
+FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;;
+FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;;
+FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;;
+FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;;
+FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;;
+FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;;
+FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;;
+FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;;
+FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;;
+FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;;
+FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;;
+FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;;
+FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;;
+FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;;
+FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;;
+FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;;
+FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;;
+FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;;
+FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;;
+FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;;
+FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;;
+FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;;
+FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;;
+FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;;
+FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;;
+FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;;
+FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;;
+FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;;
+FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;;
+FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;;
+FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;;
+FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;;
+FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;;
+FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;;
+FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;;
+FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;;
+FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;;
+FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;;
+FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;;
+FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;;
+FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;;
+FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;;
+FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;;
+FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;;
+FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;;
+FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;;
+FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;;
+FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;;
+FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;;
+FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;;
+FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;;
+FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;;
+FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;;
+FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;;
+FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;;
+FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;;
+FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;;
+FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;;
+FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;;
+FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;;
+FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;;
+FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;;
+FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;;
+FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;;
+FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;;
+FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;;
+FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;;
+FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;;
+FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;;
+FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;;
+FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;;
+FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;;
+FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;;
+FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;;
+FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;;
+FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;;
+FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;;
+FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;;
+FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;;
+FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;;
+FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;;
+FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;;
+FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;;
+FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;;
+FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;;
+FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;;
+FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;;
+FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;;
+FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;;
+FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;;
+FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;;
+FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;;
+FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;;
+FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;;
+FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;;
+FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;;
+FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;;
+FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;;
+FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;;
+FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;;
+FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;;
+FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;;
+FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;;
+FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;;
+FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;;
+FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;;
+FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;;
+FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;;
+FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;;
+FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;;
+FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;;
+FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;;
+FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;;
+FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;;
+FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;;
+FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;;
+FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;;
+FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;;
+FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;;
+FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;;
+FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;;
+FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;;
+FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;;
+FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;;
+FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;;
+FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;;
+FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;;
+FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;;
+FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;;
+FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;;
+FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;;
+FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;;
+FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;;
+FD3E;ORNATE LEFT PARENTHESIS;Pe;0;ON;;;;;N;;;;;
+FD3F;ORNATE RIGHT PARENTHESIS;Ps;0;ON;;;;;N;;;;;
+FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;;
+FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;;
+FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;;
+FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;;
+FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;;
+FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;;
+FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;;
+FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;;
+FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;;
+FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;;
+FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;;
+FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;;
+FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;;
+FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;;
+FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;;
+FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;;
+FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;;
+FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;;
+FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;;
+FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;;
+FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;;
+FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;;
+FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;;
+FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;;
+FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;;
+FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;;
+FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;;
+FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;;
+FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;;
+FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;;
+FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;;
+FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;;
+FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;;
+FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;;
+FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;;
+FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;;
+FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;;
+FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;;
+FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;;
+FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;;
+FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;;
+FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;;
+FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;;
+FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;;
+FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;;
+FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;;
+FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;;
+FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;;
+FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;;
+FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;;
+FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;;
+FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;;
+FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;;
+FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;;
+FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;;
+FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;;
+FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;;
+FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;;
+FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;;
+FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;;
+FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;;
+FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;;
+FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;;
+FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;;
+FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;;
+FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;;
+FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;;
+FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;;
+FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;;
+FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;;
+FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;;
+FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;;
+FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;;
+FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;;
+FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;;
+FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;;
+FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;;
+FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;;
+FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;;
+FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;;
+FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;;
+FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;;
+FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;;
+FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;;
+FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;;
+FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;;
+FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;;
+FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;;
+FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;;
+FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;;
+FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;;
+FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;;
+FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;;
+FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;;
+FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;;
+FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;;
+FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;;
+FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;;
+FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;;
+FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;;
+FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;;
+FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;;
+FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;;
+FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;;
+FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;;
+FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;;
+FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;;
+FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;;
+FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;;
+FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;;
+FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;;
+FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;;
+FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;;
+FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;;
+FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;;
+FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;;
+FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;;
+FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;;
+FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;;
+FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;;
+FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;;
+FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;;
+FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;;
+FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;;
+FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;;
+FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;;
+FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;;
+FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;;
+FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;;
+FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;;
+FDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;;
+FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;;
+FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;;
+FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;;
+FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;;
+FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;;
+FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;;
+FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;;
+FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;;
+FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;;
+FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;;
+FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;;
+FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;;
+FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;;
+FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;;
+FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;;
+FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;;
+FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;;
+FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;;
+FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;;
+FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;;
+FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;;
+FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;;
+FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;;
+FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;;
+FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;;
+FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;;
+FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;;
+FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE24;COMBINING MACRON LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE25;COMBINING MACRON RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE26;COMBINING CONJOINING MACRON;Mn;230;NSM;;;;;N;;;;;
+FE27;COMBINING LIGATURE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE28;COMBINING LIGATURE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE29;COMBINING TILDE LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE2A;COMBINING TILDE RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE2B;COMBINING MACRON LEFT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE2C;COMBINING MACRON RIGHT HALF BELOW;Mn;220;NSM;;;;;N;;;;;
+FE2D;COMBINING CONJOINING MACRON BELOW;Mn;220;NSM;;;;;N;;;;;
+FE2E;COMBINING CYRILLIC TITLO LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE2F;COMBINING CYRILLIC TITLO RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;;
+FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;;
+FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;;
+FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;;
+FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;;
+FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;;
+FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;;
+FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;;
+FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;;
+FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;;
+FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;;
+FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;;
+FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;;
+FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;;
+FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;;
+FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;;
+FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;;
+FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;;
+FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;;
+FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;;
+FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;;
+FE45;SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;;
+FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;;
+FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;;
+FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;;
+FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;;
+FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;;
+FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;;
+FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;;
+FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;;
+FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;;
+FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;;
+FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;;
+FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;;
+FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;;
+FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;;
+FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;;
+FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;;
+FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;Y;SMALL OPENING PARENTHESIS;;;;
+FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;Y;SMALL CLOSING PARENTHESIS;;;;
+FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;Y;SMALL OPENING CURLY BRACKET;;;;
+FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;Y;SMALL CLOSING CURLY BRACKET;;;;
+FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;Y;SMALL OPENING TORTOISE SHELL BRACKET;;;;
+FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;Y;SMALL CLOSING TORTOISE SHELL BRACKET;;;;
+FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;;
+FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;;
+FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;;
+FE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;;
+FE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;;
+FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;Y;;;;;
+FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;Y;;;;;
+FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;;
+FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;;
+FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;;
+FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;;
+FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;;
+FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;;
+FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;;
+FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;;
+FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;;
+FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;;
+FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;;
+FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;;
+FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;;
+FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;;
+FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;;
+FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;;
+FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;;
+FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;;
+FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;;
+FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;;
+FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;;
+FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;;
+FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;;
+FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;;
+FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;;
+FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;;
+FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;;
+FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;;
+FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;;
+FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;;
+FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;;
+FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;;
+FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;;
+FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;;
+FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;;
+FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;;
+FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;;
+FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;;
+FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;;
+FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;;
+FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;;
+FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;;
+FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;;
+FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;;
+FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;;
+FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;;
+FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;;
+FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;;
+FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;;
+FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;;
+FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;;
+FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;;
+FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;;
+FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;;
+FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;;
+FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;;
+FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;;
+FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;;
+FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;;
+FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;;
+FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;;
+FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;;
+FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;;
+FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;;
+FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;;
+FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;;
+FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;;
+FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;;
+FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;;
+FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;;
+FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;;
+FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;;
+FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;;
+FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;;
+FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;;
+FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;;
+FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;;
+FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;;
+FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;;
+FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;;
+FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;;
+FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;;
+FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;;
+FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;;
+FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;;
+FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;;
+FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;;
+FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;;
+FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;;
+FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;;
+FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;;
+FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;;
+FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;;
+FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;;
+FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;;
+FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;;
+FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;;
+FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;;
+FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;;
+FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;;
+FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;;
+FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;;
+FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;;
+FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;;
+FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;;
+FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;;
+FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;;
+FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;;
+FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;;
+FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;;
+FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;;
+FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;;
+FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;;
+FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;;
+FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;;
+FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;;
+FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;;
+FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;;
+FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;;
+FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;;
+FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;;
+FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;;
+FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;;
+FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;;
+FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;;
+FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;;
+FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;;
+FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;;
+FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;;
+FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;;
+FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;;
+FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;;
+FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;;
+FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;;
+FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;;
+FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;;
+FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;;
+FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;;
+FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;;
+FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
+FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;;
+FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;;
+FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;;
+FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;;
+FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;;
+FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;;
+FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;;
+FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;;
+FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;;
+FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;;
+FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;;
+FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;;
+FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;;
+FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;;
+FF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;;
+FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
+FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;
+FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;
+FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;
+FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;
+FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;
+FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;
+FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;
+FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;
+FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;;
+FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;;
+FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;;
+FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;;
+FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;;
+FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;;
+FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;;
+FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;;
+FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41;
+FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42;
+FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43;
+FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44;
+FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45;
+FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46;
+FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47;
+FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48;
+FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49;
+FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A;
+FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B;
+FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C;
+FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D;
+FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E;
+FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F;
+FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50;
+FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51;
+FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52;
+FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53;
+FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54;
+FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55;
+FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56;
+FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57;
+FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58;
+FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59;
+FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A;
+FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;;
+FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;;
+FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;;
+FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;;
+FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;;
+FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;;
+FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21
+FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22
+FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23
+FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24
+FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25
+FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26
+FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27
+FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28
+FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29
+FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A
+FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B
+FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C
+FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D
+FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E
+FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F
+FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30
+FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31
+FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32
+FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33
+FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34
+FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35
+FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36
+FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37
+FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38
+FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39
+FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A
+FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;;
+FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;;
+FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;;
+FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;;
+FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;;;;
+FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;;;;
+FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;;
+FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;;
+FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;;
+FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;;
+FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;;
+FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;;
+FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;;
+FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;;
+FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;;
+FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;;
+FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;;
+FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;;
+FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;;
+FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;;
+FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;;
+FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;;
+FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;;
+FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;;
+FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;;
+FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;;
+FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;;
+FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;;
+FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;;
+FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;;
+FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;;
+FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;;
+FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;;
+FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;;
+FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;;
+FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;;
+FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;;
+FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;;
+FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;;
+FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;;
+FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;;
+FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;;
+FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;;
+FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;;
+FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;;
+FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;;
+FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;;
+FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;;
+FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;;
+FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;;
+FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;;
+FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;;
+FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;;
+FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;;
+FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;;
+FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;;
+FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;;
+FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;;
+FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;;
+FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;;
+FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;;
+FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;;
+FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;;
+FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;;
+FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;;
+FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;;
+FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;;
+FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;;;;
+FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;;;;
+FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;;
+FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;;
+FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;;
+FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
+FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;;
+FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;;
+FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;;
+FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;;
+FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;;
+FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;;
+FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;;
+FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;;
+FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;;
+FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;;
+FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;;
+FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;;
+FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;;
+FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;;
+FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;;
+FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;;
+FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;;
+FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;;
+FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;;
+FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;;
+FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;;
+FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;;
+FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;;
+FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;;
+FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;;
+FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;;
+FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;;
+FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;;
+FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;;
+FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;;
+FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;;
+FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;;
+FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;;
+FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;;
+FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;;
+FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;;
+FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;;
+FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;;
+FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;;
+FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;;
+FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;;
+FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;;
+FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;;
+FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;;
+FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;;
+FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;;
+FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;;
+FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
+FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;;
+FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;;
+FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;;
+FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;;;;
+FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;;
+FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;;
+FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;;
+FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;;
+FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;;
+FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;;
+FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;;
+FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;;
+FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;;
+FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;;
+FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;;
+FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;;
+FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;;
+FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;;
+10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;;
+10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;;
+10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;;
+10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;;
+10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;;
+10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;;
+10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;;
+10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;;
+10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;;
+1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;;
+1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;;
+1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;;
+1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;;
+1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;;
+10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;;
+10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;;
+10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;;
+10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;;
+10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;;
+10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;;
+10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;;
+10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;;
+10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;;
+10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;;
+1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;;
+1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;;
+1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;;
+1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;;
+1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;;
+1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;;
+10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;;
+10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;;
+10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;;
+10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;;
+10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;;
+10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;;
+10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;;
+10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;;
+10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;;
+1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;;
+1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;;
+1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;;
+1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;;
+1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;;
+1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;;
+10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;;
+10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;;
+10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;;
+10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;;
+10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;;
+10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;;
+10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;;
+10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;;
+10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;;
+10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;;
+1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;;
+1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;;
+1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;;
+1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;;
+10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;;
+10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;;
+10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;;
+10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;;
+10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;;
+10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;;
+10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;;
+10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;;
+10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;;
+10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;;
+1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;;
+1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;;
+1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;;
+1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;;
+10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;;
+10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;;
+10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;;
+10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;;
+10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;;
+10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;;
+10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;;
+10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;;
+10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;;
+10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;;
+1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;;
+1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;;
+1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;;
+1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;;
+10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;;
+10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;;
+10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;;
+10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;;
+10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;;
+10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;;
+10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;;
+10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;;
+10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;;
+10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;;
+1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;;
+1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;;
+1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;;
+1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;;
+1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;;
+1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;;
+10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;;
+10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;;
+10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;;
+10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;;
+10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;;
+10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;;
+10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;;
+10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;;
+10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;;
+10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;;
+1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;;
+1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;;
+1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;;
+1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;;
+1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;;
+1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;;
+100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;;
+100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;;
+100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;;
+100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;;
+100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;;
+100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;;
+100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;;
+100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;;
+100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;;
+100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;;
+100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;;
+100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;;
+100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;;
+100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;;
+100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;;
+100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;;
+100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;;
+100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;;
+100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;;
+100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;;
+100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;;
+100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;;
+100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;;
+100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;;
+100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;;
+100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;;
+100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;;
+100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;;
+100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;;
+100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;;
+100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;;
+100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;;
+100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;;
+100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;;
+100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;;
+100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;;
+100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;;
+100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;;
+100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;;
+100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;;
+100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;;
+100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;;;;
+100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;;
+100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;;;;
+100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;;
+100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;;
+100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;;
+100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;;
+100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;;
+100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;;
+100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;;
+100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;;
+100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;;
+100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;;
+100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;;
+100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;;
+100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;;
+100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;;
+100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;;
+100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;;
+100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;;
+100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;;
+100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;;
+100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;;
+100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;;
+100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;;
+100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;;
+100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;;
+100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;;
+100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;;
+100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;;
+100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;;
+100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;;
+100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;;
+100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;;
+100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;;
+100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;;
+100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;;
+100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;;
+100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;;
+100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;;
+100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;;
+100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;;
+100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;;
+100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;;
+100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;;
+100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;;
+100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;;
+100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;;
+100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;;
+100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;;
+10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;;
+10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;;
+10102;AEGEAN CHECK MARK;Po;0;L;;;;;N;;;;;
+10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;;
+10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;;
+10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;;
+1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;;
+1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;;
+1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;;
+1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;;
+1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;;
+1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;;
+10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;;
+10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;;
+10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;;
+10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;;
+1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;;
+1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;;
+1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;;
+1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;;
+1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;;
+10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;;
+10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;;
+10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;;
+10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;;
+10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;;
+10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;;
+10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;;
+10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;;
+10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;;
+1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;;
+1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;;
+1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;;
+1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;;
+1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;;
+10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;;
+10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;;
+10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;;
+10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;;
+10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;;
+10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;;
+1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;;
+10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;;
+10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;;
+10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;;
+10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;;
+10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;;
+10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;;
+10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;;
+1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;;
+1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;;
+1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;;
+1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;;
+1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;;
+1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;;
+10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;;
+10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;;
+10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;;
+10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;;
+10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;;
+10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;;
+10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;;
+10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;;
+10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;;
+10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;;
+10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;;
+10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;;
+10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;;
+10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;;
+1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;;
+1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;;
+10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;;
+10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;;
+10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;;
+10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;;
+10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;;
+10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;;
+10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;;
+1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;;
+1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;;
+1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;;
+1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;;
+10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;;
+10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;;
+10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;;
+10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;;
+10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;;
+10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;;
+10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;;
+10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;;
+1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;;
+1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;;
+1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;;
+1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;;
+1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;;
+10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;;
+10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;;
+10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;;
+10193;ROMAN SEXTULA SIGN;So;0;ON;;;;;N;;;;;
+10194;ROMAN DIMIDIA SEXTULA SIGN;So;0;ON;;;;;N;;;;;
+10195;ROMAN SILIQUA SIGN;So;0;ON;;;;;N;;;;;
+10196;ROMAN DENARIUS SIGN;So;0;ON;;;;;N;;;;;
+10197;ROMAN QUINARIUS SIGN;So;0;ON;;;;;N;;;;;
+10198;ROMAN SESTERTIUS SIGN;So;0;ON;;;;;N;;;;;
+10199;ROMAN DUPONDIUS SIGN;So;0;ON;;;;;N;;;;;
+1019A;ROMAN AS SIGN;So;0;ON;;;;;N;;;;;
+1019B;ROMAN CENTURIAL SIGN;So;0;ON;;;;;N;;;;;
+101A0;GREEK SYMBOL TAU RHO;So;0;ON;;;;;N;;;;;
+101D0;PHAISTOS DISC SIGN PEDESTRIAN;So;0;L;;;;;N;;;;;
+101D1;PHAISTOS DISC SIGN PLUMED HEAD;So;0;L;;;;;N;;;;;
+101D2;PHAISTOS DISC SIGN TATTOOED HEAD;So;0;L;;;;;N;;;;;
+101D3;PHAISTOS DISC SIGN CAPTIVE;So;0;L;;;;;N;;;;;
+101D4;PHAISTOS DISC SIGN CHILD;So;0;L;;;;;N;;;;;
+101D5;PHAISTOS DISC SIGN WOMAN;So;0;L;;;;;N;;;;;
+101D6;PHAISTOS DISC SIGN HELMET;So;0;L;;;;;N;;;;;
+101D7;PHAISTOS DISC SIGN GAUNTLET;So;0;L;;;;;N;;;;;
+101D8;PHAISTOS DISC SIGN TIARA;So;0;L;;;;;N;;;;;
+101D9;PHAISTOS DISC SIGN ARROW;So;0;L;;;;;N;;;;;
+101DA;PHAISTOS DISC SIGN BOW;So;0;L;;;;;N;;;;;
+101DB;PHAISTOS DISC SIGN SHIELD;So;0;L;;;;;N;;;;;
+101DC;PHAISTOS DISC SIGN CLUB;So;0;L;;;;;N;;;;;
+101DD;PHAISTOS DISC SIGN MANACLES;So;0;L;;;;;N;;;;;
+101DE;PHAISTOS DISC SIGN MATTOCK;So;0;L;;;;;N;;;;;
+101DF;PHAISTOS DISC SIGN SAW;So;0;L;;;;;N;;;;;
+101E0;PHAISTOS DISC SIGN LID;So;0;L;;;;;N;;;;;
+101E1;PHAISTOS DISC SIGN BOOMERANG;So;0;L;;;;;N;;;;;
+101E2;PHAISTOS DISC SIGN CARPENTRY PLANE;So;0;L;;;;;N;;;;;
+101E3;PHAISTOS DISC SIGN DOLIUM;So;0;L;;;;;N;;;;;
+101E4;PHAISTOS DISC SIGN COMB;So;0;L;;;;;N;;;;;
+101E5;PHAISTOS DISC SIGN SLING;So;0;L;;;;;N;;;;;
+101E6;PHAISTOS DISC SIGN COLUMN;So;0;L;;;;;N;;;;;
+101E7;PHAISTOS DISC SIGN BEEHIVE;So;0;L;;;;;N;;;;;
+101E8;PHAISTOS DISC SIGN SHIP;So;0;L;;;;;N;;;;;
+101E9;PHAISTOS DISC SIGN HORN;So;0;L;;;;;N;;;;;
+101EA;PHAISTOS DISC SIGN HIDE;So;0;L;;;;;N;;;;;
+101EB;PHAISTOS DISC SIGN BULLS LEG;So;0;L;;;;;N;;;;;
+101EC;PHAISTOS DISC SIGN CAT;So;0;L;;;;;N;;;;;
+101ED;PHAISTOS DISC SIGN RAM;So;0;L;;;;;N;;;;;
+101EE;PHAISTOS DISC SIGN EAGLE;So;0;L;;;;;N;;;;;
+101EF;PHAISTOS DISC SIGN DOVE;So;0;L;;;;;N;;;;;
+101F0;PHAISTOS DISC SIGN TUNNY;So;0;L;;;;;N;;;;;
+101F1;PHAISTOS DISC SIGN BEE;So;0;L;;;;;N;;;;;
+101F2;PHAISTOS DISC SIGN PLANE TREE;So;0;L;;;;;N;;;;;
+101F3;PHAISTOS DISC SIGN VINE;So;0;L;;;;;N;;;;;
+101F4;PHAISTOS DISC SIGN PAPYRUS;So;0;L;;;;;N;;;;;
+101F5;PHAISTOS DISC SIGN ROSETTE;So;0;L;;;;;N;;;;;
+101F6;PHAISTOS DISC SIGN LILY;So;0;L;;;;;N;;;;;
+101F7;PHAISTOS DISC SIGN OX BACK;So;0;L;;;;;N;;;;;
+101F8;PHAISTOS DISC SIGN FLUTE;So;0;L;;;;;N;;;;;
+101F9;PHAISTOS DISC SIGN GRATER;So;0;L;;;;;N;;;;;
+101FA;PHAISTOS DISC SIGN STRAINER;So;0;L;;;;;N;;;;;
+101FB;PHAISTOS DISC SIGN SMALL AXE;So;0;L;;;;;N;;;;;
+101FC;PHAISTOS DISC SIGN WAVY BAND;So;0;L;;;;;N;;;;;
+101FD;PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE;Mn;220;NSM;;;;;N;;;;;
+10280;LYCIAN LETTER A;Lo;0;L;;;;;N;;;;;
+10281;LYCIAN LETTER E;Lo;0;L;;;;;N;;;;;
+10282;LYCIAN LETTER B;Lo;0;L;;;;;N;;;;;
+10283;LYCIAN LETTER BH;Lo;0;L;;;;;N;;;;;
+10284;LYCIAN LETTER G;Lo;0;L;;;;;N;;;;;
+10285;LYCIAN LETTER D;Lo;0;L;;;;;N;;;;;
+10286;LYCIAN LETTER I;Lo;0;L;;;;;N;;;;;
+10287;LYCIAN LETTER W;Lo;0;L;;;;;N;;;;;
+10288;LYCIAN LETTER Z;Lo;0;L;;;;;N;;;;;
+10289;LYCIAN LETTER TH;Lo;0;L;;;;;N;;;;;
+1028A;LYCIAN LETTER J;Lo;0;L;;;;;N;;;;;
+1028B;LYCIAN LETTER K;Lo;0;L;;;;;N;;;;;
+1028C;LYCIAN LETTER Q;Lo;0;L;;;;;N;;;;;
+1028D;LYCIAN LETTER L;Lo;0;L;;;;;N;;;;;
+1028E;LYCIAN LETTER M;Lo;0;L;;;;;N;;;;;
+1028F;LYCIAN LETTER N;Lo;0;L;;;;;N;;;;;
+10290;LYCIAN LETTER MM;Lo;0;L;;;;;N;;;;;
+10291;LYCIAN LETTER NN;Lo;0;L;;;;;N;;;;;
+10292;LYCIAN LETTER U;Lo;0;L;;;;;N;;;;;
+10293;LYCIAN LETTER P;Lo;0;L;;;;;N;;;;;
+10294;LYCIAN LETTER KK;Lo;0;L;;;;;N;;;;;
+10295;LYCIAN LETTER R;Lo;0;L;;;;;N;;;;;
+10296;LYCIAN LETTER S;Lo;0;L;;;;;N;;;;;
+10297;LYCIAN LETTER T;Lo;0;L;;;;;N;;;;;
+10298;LYCIAN LETTER TT;Lo;0;L;;;;;N;;;;;
+10299;LYCIAN LETTER AN;Lo;0;L;;;;;N;;;;;
+1029A;LYCIAN LETTER EN;Lo;0;L;;;;;N;;;;;
+1029B;LYCIAN LETTER H;Lo;0;L;;;;;N;;;;;
+1029C;LYCIAN LETTER X;Lo;0;L;;;;;N;;;;;
+102A0;CARIAN LETTER A;Lo;0;L;;;;;N;;;;;
+102A1;CARIAN LETTER P2;Lo;0;L;;;;;N;;;;;
+102A2;CARIAN LETTER D;Lo;0;L;;;;;N;;;;;
+102A3;CARIAN LETTER L;Lo;0;L;;;;;N;;;;;
+102A4;CARIAN LETTER UUU;Lo;0;L;;;;;N;;;;;
+102A5;CARIAN LETTER R;Lo;0;L;;;;;N;;;;;
+102A6;CARIAN LETTER LD;Lo;0;L;;;;;N;;;;;
+102A7;CARIAN LETTER A2;Lo;0;L;;;;;N;;;;;
+102A8;CARIAN LETTER Q;Lo;0;L;;;;;N;;;;;
+102A9;CARIAN LETTER B;Lo;0;L;;;;;N;;;;;
+102AA;CARIAN LETTER M;Lo;0;L;;;;;N;;;;;
+102AB;CARIAN LETTER O;Lo;0;L;;;;;N;;;;;
+102AC;CARIAN LETTER D2;Lo;0;L;;;;;N;;;;;
+102AD;CARIAN LETTER T;Lo;0;L;;;;;N;;;;;
+102AE;CARIAN LETTER SH;Lo;0;L;;;;;N;;;;;
+102AF;CARIAN LETTER SH2;Lo;0;L;;;;;N;;;;;
+102B0;CARIAN LETTER S;Lo;0;L;;;;;N;;;;;
+102B1;CARIAN LETTER C-18;Lo;0;L;;;;;N;;;;;
+102B2;CARIAN LETTER U;Lo;0;L;;;;;N;;;;;
+102B3;CARIAN LETTER NN;Lo;0;L;;;;;N;;;;;
+102B4;CARIAN LETTER X;Lo;0;L;;;;;N;;;;;
+102B5;CARIAN LETTER N;Lo;0;L;;;;;N;;;;;
+102B6;CARIAN LETTER TT2;Lo;0;L;;;;;N;;;;;
+102B7;CARIAN LETTER P;Lo;0;L;;;;;N;;;;;
+102B8;CARIAN LETTER SS;Lo;0;L;;;;;N;;;;;
+102B9;CARIAN LETTER I;Lo;0;L;;;;;N;;;;;
+102BA;CARIAN LETTER E;Lo;0;L;;;;;N;;;;;
+102BB;CARIAN LETTER UUUU;Lo;0;L;;;;;N;;;;;
+102BC;CARIAN LETTER K;Lo;0;L;;;;;N;;;;;
+102BD;CARIAN LETTER K2;Lo;0;L;;;;;N;;;;;
+102BE;CARIAN LETTER ND;Lo;0;L;;;;;N;;;;;
+102BF;CARIAN LETTER UU;Lo;0;L;;;;;N;;;;;
+102C0;CARIAN LETTER G;Lo;0;L;;;;;N;;;;;
+102C1;CARIAN LETTER G2;Lo;0;L;;;;;N;;;;;
+102C2;CARIAN LETTER ST;Lo;0;L;;;;;N;;;;;
+102C3;CARIAN LETTER ST2;Lo;0;L;;;;;N;;;;;
+102C4;CARIAN LETTER NG;Lo;0;L;;;;;N;;;;;
+102C5;CARIAN LETTER II;Lo;0;L;;;;;N;;;;;
+102C6;CARIAN LETTER C-39;Lo;0;L;;;;;N;;;;;
+102C7;CARIAN LETTER TT;Lo;0;L;;;;;N;;;;;
+102C8;CARIAN LETTER UUU2;Lo;0;L;;;;;N;;;;;
+102C9;CARIAN LETTER RR;Lo;0;L;;;;;N;;;;;
+102CA;CARIAN LETTER MB;Lo;0;L;;;;;N;;;;;
+102CB;CARIAN LETTER MB2;Lo;0;L;;;;;N;;;;;
+102CC;CARIAN LETTER MB3;Lo;0;L;;;;;N;;;;;
+102CD;CARIAN LETTER MB4;Lo;0;L;;;;;N;;;;;
+102CE;CARIAN LETTER LD2;Lo;0;L;;;;;N;;;;;
+102CF;CARIAN LETTER E2;Lo;0;L;;;;;N;;;;;
+102D0;CARIAN LETTER UUU3;Lo;0;L;;;;;N;;;;;
+102E0;COPTIC EPACT THOUSANDS MARK;Mn;220;NSM;;;;;N;;;;;
+102E1;COPTIC EPACT DIGIT ONE;No;0;EN;;;;1;N;;;;;
+102E2;COPTIC EPACT DIGIT TWO;No;0;EN;;;;2;N;;;;;
+102E3;COPTIC EPACT DIGIT THREE;No;0;EN;;;;3;N;;;;;
+102E4;COPTIC EPACT DIGIT FOUR;No;0;EN;;;;4;N;;;;;
+102E5;COPTIC EPACT DIGIT FIVE;No;0;EN;;;;5;N;;;;;
+102E6;COPTIC EPACT DIGIT SIX;No;0;EN;;;;6;N;;;;;
+102E7;COPTIC EPACT DIGIT SEVEN;No;0;EN;;;;7;N;;;;;
+102E8;COPTIC EPACT DIGIT EIGHT;No;0;EN;;;;8;N;;;;;
+102E9;COPTIC EPACT DIGIT NINE;No;0;EN;;;;9;N;;;;;
+102EA;COPTIC EPACT NUMBER TEN;No;0;EN;;;;10;N;;;;;
+102EB;COPTIC EPACT NUMBER TWENTY;No;0;EN;;;;20;N;;;;;
+102EC;COPTIC EPACT NUMBER THIRTY;No;0;EN;;;;30;N;;;;;
+102ED;COPTIC EPACT NUMBER FORTY;No;0;EN;;;;40;N;;;;;
+102EE;COPTIC EPACT NUMBER FIFTY;No;0;EN;;;;50;N;;;;;
+102EF;COPTIC EPACT NUMBER SIXTY;No;0;EN;;;;60;N;;;;;
+102F0;COPTIC EPACT NUMBER SEVENTY;No;0;EN;;;;70;N;;;;;
+102F1;COPTIC EPACT NUMBER EIGHTY;No;0;EN;;;;80;N;;;;;
+102F2;COPTIC EPACT NUMBER NINETY;No;0;EN;;;;90;N;;;;;
+102F3;COPTIC EPACT NUMBER ONE HUNDRED;No;0;EN;;;;100;N;;;;;
+102F4;COPTIC EPACT NUMBER TWO HUNDRED;No;0;EN;;;;200;N;;;;;
+102F5;COPTIC EPACT NUMBER THREE HUNDRED;No;0;EN;;;;300;N;;;;;
+102F6;COPTIC EPACT NUMBER FOUR HUNDRED;No;0;EN;;;;400;N;;;;;
+102F7;COPTIC EPACT NUMBER FIVE HUNDRED;No;0;EN;;;;500;N;;;;;
+102F8;COPTIC EPACT NUMBER SIX HUNDRED;No;0;EN;;;;600;N;;;;;
+102F9;COPTIC EPACT NUMBER SEVEN HUNDRED;No;0;EN;;;;700;N;;;;;
+102FA;COPTIC EPACT NUMBER EIGHT HUNDRED;No;0;EN;;;;800;N;;;;;
+102FB;COPTIC EPACT NUMBER NINE HUNDRED;No;0;EN;;;;900;N;;;;;
+10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;;
+10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;;
+10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;;
+10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;;
+10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;;
+10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;;
+10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;;
+10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;;
+10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;;
+10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;;
+1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;;
+1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;;
+1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;;
+1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;;
+1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;;
+1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;;;;
+10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;;
+10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;;
+10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;;
+10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;;
+10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;;
+10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;;
+10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;;
+10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;;;;
+10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;;
+10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;;
+1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;;
+1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;;;;
+1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;;;;
+1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;;;;
+1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;;;;
+1031F;OLD ITALIC LETTER ESS;Lo;0;L;;;;;N;;;;;
+10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;;
+10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;
+10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;
+10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;
+10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;
+10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;
+10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;;
+10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;;
+10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;;
+10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;;
+10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;;
+10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;;
+10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;;
+1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;;
+1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;;
+1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;;
+1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;;
+1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;;
+1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;;
+10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;;
+10341;GOTHIC LETTER NINETY;Nl;0;L;;;;90;N;;;;;
+10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;;
+10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;;
+10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;;
+10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;;
+10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;;
+10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;;
+10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;;
+10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;;
+1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;;
+10350;OLD PERMIC LETTER AN;Lo;0;L;;;;;N;;;;;
+10351;OLD PERMIC LETTER BUR;Lo;0;L;;;;;N;;;;;
+10352;OLD PERMIC LETTER GAI;Lo;0;L;;;;;N;;;;;
+10353;OLD PERMIC LETTER DOI;Lo;0;L;;;;;N;;;;;
+10354;OLD PERMIC LETTER E;Lo;0;L;;;;;N;;;;;
+10355;OLD PERMIC LETTER ZHOI;Lo;0;L;;;;;N;;;;;
+10356;OLD PERMIC LETTER DZHOI;Lo;0;L;;;;;N;;;;;
+10357;OLD PERMIC LETTER ZATA;Lo;0;L;;;;;N;;;;;
+10358;OLD PERMIC LETTER DZITA;Lo;0;L;;;;;N;;;;;
+10359;OLD PERMIC LETTER I;Lo;0;L;;;;;N;;;;;
+1035A;OLD PERMIC LETTER KOKE;Lo;0;L;;;;;N;;;;;
+1035B;OLD PERMIC LETTER LEI;Lo;0;L;;;;;N;;;;;
+1035C;OLD PERMIC LETTER MENOE;Lo;0;L;;;;;N;;;;;
+1035D;OLD PERMIC LETTER NENOE;Lo;0;L;;;;;N;;;;;
+1035E;OLD PERMIC LETTER VOOI;Lo;0;L;;;;;N;;;;;
+1035F;OLD PERMIC LETTER PEEI;Lo;0;L;;;;;N;;;;;
+10360;OLD PERMIC LETTER REI;Lo;0;L;;;;;N;;;;;
+10361;OLD PERMIC LETTER SII;Lo;0;L;;;;;N;;;;;
+10362;OLD PERMIC LETTER TAI;Lo;0;L;;;;;N;;;;;
+10363;OLD PERMIC LETTER U;Lo;0;L;;;;;N;;;;;
+10364;OLD PERMIC LETTER CHERY;Lo;0;L;;;;;N;;;;;
+10365;OLD PERMIC LETTER SHOOI;Lo;0;L;;;;;N;;;;;
+10366;OLD PERMIC LETTER SHCHOOI;Lo;0;L;;;;;N;;;;;
+10367;OLD PERMIC LETTER YRY;Lo;0;L;;;;;N;;;;;
+10368;OLD PERMIC LETTER YERU;Lo;0;L;;;;;N;;;;;
+10369;OLD PERMIC LETTER O;Lo;0;L;;;;;N;;;;;
+1036A;OLD PERMIC LETTER OO;Lo;0;L;;;;;N;;;;;
+1036B;OLD PERMIC LETTER EF;Lo;0;L;;;;;N;;;;;
+1036C;OLD PERMIC LETTER HA;Lo;0;L;;;;;N;;;;;
+1036D;OLD PERMIC LETTER TSIU;Lo;0;L;;;;;N;;;;;
+1036E;OLD PERMIC LETTER VER;Lo;0;L;;;;;N;;;;;
+1036F;OLD PERMIC LETTER YER;Lo;0;L;;;;;N;;;;;
+10370;OLD PERMIC LETTER YERI;Lo;0;L;;;;;N;;;;;
+10371;OLD PERMIC LETTER YAT;Lo;0;L;;;;;N;;;;;
+10372;OLD PERMIC LETTER IE;Lo;0;L;;;;;N;;;;;
+10373;OLD PERMIC LETTER YU;Lo;0;L;;;;;N;;;;;
+10374;OLD PERMIC LETTER YA;Lo;0;L;;;;;N;;;;;
+10375;OLD PERMIC LETTER IA;Lo;0;L;;;;;N;;;;;
+10376;COMBINING OLD PERMIC LETTER AN;Mn;230;NSM;;;;;N;;;;;
+10377;COMBINING OLD PERMIC LETTER DOI;Mn;230;NSM;;;;;N;;;;;
+10378;COMBINING OLD PERMIC LETTER ZATA;Mn;230;NSM;;;;;N;;;;;
+10379;COMBINING OLD PERMIC LETTER NENOE;Mn;230;NSM;;;;;N;;;;;
+1037A;COMBINING OLD PERMIC LETTER SII;Mn;230;NSM;;;;;N;;;;;
+10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;;
+10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;;
+10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;;
+10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;;
+10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;;
+10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;;
+10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;;
+10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;;
+10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;;
+10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;;
+1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;;
+1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;;
+1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;;
+1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;;
+1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;;
+1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;;
+10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;;
+10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;;
+10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;;
+10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;;
+10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;;
+10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;;
+10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;;
+10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;;
+10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;;
+10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;;
+1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;;
+1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;;
+1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;;
+1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;;
+1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;;
+103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;;
+103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;;
+103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;;
+103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;;
+103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;;
+103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;;
+103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;;
+103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;;
+103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;;
+103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;;
+103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;;
+103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;;
+103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;;
+103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;;
+103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;;
+103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;;
+103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;;
+103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;;
+103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;;
+103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;;
+103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;;
+103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;;
+103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;;
+103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;;
+103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;;
+103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;;
+103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;;
+103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;;
+103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;;
+103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;;
+103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;;
+103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;;
+103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;;
+103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;;
+103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;;
+103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;;
+103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;;
+103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;;
+103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;;
+103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;;
+103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;;
+103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;;
+103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;;
+103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;;
+103D0;OLD PERSIAN WORD DIVIDER;Po;0;L;;;;;N;;;;;
+103D1;OLD PERSIAN NUMBER ONE;Nl;0;L;;;;1;N;;;;;
+103D2;OLD PERSIAN NUMBER TWO;Nl;0;L;;;;2;N;;;;;
+103D3;OLD PERSIAN NUMBER TEN;Nl;0;L;;;;10;N;;;;;
+103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;L;;;;20;N;;;;;
+103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;L;;;;100;N;;;;;
+10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429;
+10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A;
+10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B;
+10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C;
+10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D;
+10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E;
+10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F;
+10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430;
+10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431;
+1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432;
+1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433;
+1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434;
+1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435;
+1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436;
+1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437;
+10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438;
+10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439;
+10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A;
+10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B;
+10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C;
+10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D;
+10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E;
+10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F;
+10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440;
+10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441;
+1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442;
+1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443;
+1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444;
+1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445;
+1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446;
+1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447;
+10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448;
+10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449;
+10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A;
+10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B;
+10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C;
+10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D;
+10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E;
+10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401
+1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402
+1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403
+1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404
+1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405
+1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406
+1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407
+10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408
+10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409
+10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A
+10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B
+10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C
+10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D
+10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E
+10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F
+10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410
+10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411
+1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412
+1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413
+1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414
+1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415
+1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416
+1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417
+10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418
+10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419
+10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A
+10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B
+10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C
+10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D
+10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E
+10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F
+10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420
+10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421
+1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422
+1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423
+1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424
+1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425
+1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426
+1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;;
+10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;;
+10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;;
+10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;;
+10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;;
+10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;;
+10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;;
+10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;;
+10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;;
+1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;;
+1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;;
+1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;;
+1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;;
+1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;;
+1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;;
+10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;;
+10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;;
+10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;;
+10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;;
+10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;;
+10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;;
+10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;;
+10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;;
+10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;;
+10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;;
+1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;;
+1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;;
+1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;;
+1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;;
+1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;;
+1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;;
+10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;;
+10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;;
+10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;;
+10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;;
+10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;;
+10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;;
+10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;;
+10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;;
+10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;;
+10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;;
+1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;;
+1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;;
+1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;;
+1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;;
+1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;;
+1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;;
+10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;;
+10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;;
+10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;;
+10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;;
+10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;;
+10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;;
+10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;;
+10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;;
+10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;;
+1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;;
+1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;;
+1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;;
+1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;;
+1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;;
+10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;;
+10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;;
+10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;;
+10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;;
+10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;;
+10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;;
+10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;;
+10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;;
+10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;;
+10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;;
+1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;;
+1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;;
+1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;;
+1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;;
+104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8;
+104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9;
+104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA;
+104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB;
+104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC;
+104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD;
+104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE;
+104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF;
+104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0;
+104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1;
+104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2;
+104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3;
+104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4;
+104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5;
+104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6;
+104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7;
+104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8;
+104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9;
+104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA;
+104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB;
+104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC;
+104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED;
+104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE;
+104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF;
+104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0;
+104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1;
+104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2;
+104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3;
+104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4;
+104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5;
+104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6;
+104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7;
+104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8;
+104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9;
+104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA;
+104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB;
+104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0
+104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1
+104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2
+104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3
+104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4
+104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5
+104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6
+104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7
+104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8
+104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9
+104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA
+104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB
+104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC
+104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD
+104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE
+104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF
+104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0
+104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1
+104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2
+104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3
+104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4
+104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5
+104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6
+104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7
+104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8
+104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9
+104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA
+104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB
+104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC
+104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD
+104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE
+104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF
+104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0
+104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1
+104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2
+104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3
+10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;;
+10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;;
+10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;;
+10503;ELBASAN LETTER CHE;Lo;0;L;;;;;N;;;;;
+10504;ELBASAN LETTER DE;Lo;0;L;;;;;N;;;;;
+10505;ELBASAN LETTER NDE;Lo;0;L;;;;;N;;;;;
+10506;ELBASAN LETTER DHE;Lo;0;L;;;;;N;;;;;
+10507;ELBASAN LETTER EI;Lo;0;L;;;;;N;;;;;
+10508;ELBASAN LETTER E;Lo;0;L;;;;;N;;;;;
+10509;ELBASAN LETTER FE;Lo;0;L;;;;;N;;;;;
+1050A;ELBASAN LETTER GE;Lo;0;L;;;;;N;;;;;
+1050B;ELBASAN LETTER GJE;Lo;0;L;;;;;N;;;;;
+1050C;ELBASAN LETTER HE;Lo;0;L;;;;;N;;;;;
+1050D;ELBASAN LETTER I;Lo;0;L;;;;;N;;;;;
+1050E;ELBASAN LETTER JE;Lo;0;L;;;;;N;;;;;
+1050F;ELBASAN LETTER KE;Lo;0;L;;;;;N;;;;;
+10510;ELBASAN LETTER LE;Lo;0;L;;;;;N;;;;;
+10511;ELBASAN LETTER LLE;Lo;0;L;;;;;N;;;;;
+10512;ELBASAN LETTER ME;Lo;0;L;;;;;N;;;;;
+10513;ELBASAN LETTER NE;Lo;0;L;;;;;N;;;;;
+10514;ELBASAN LETTER NA;Lo;0;L;;;;;N;;;;;
+10515;ELBASAN LETTER NJE;Lo;0;L;;;;;N;;;;;
+10516;ELBASAN LETTER O;Lo;0;L;;;;;N;;;;;
+10517;ELBASAN LETTER PE;Lo;0;L;;;;;N;;;;;
+10518;ELBASAN LETTER QE;Lo;0;L;;;;;N;;;;;
+10519;ELBASAN LETTER RE;Lo;0;L;;;;;N;;;;;
+1051A;ELBASAN LETTER RRE;Lo;0;L;;;;;N;;;;;
+1051B;ELBASAN LETTER SE;Lo;0;L;;;;;N;;;;;
+1051C;ELBASAN LETTER SHE;Lo;0;L;;;;;N;;;;;
+1051D;ELBASAN LETTER TE;Lo;0;L;;;;;N;;;;;
+1051E;ELBASAN LETTER THE;Lo;0;L;;;;;N;;;;;
+1051F;ELBASAN LETTER U;Lo;0;L;;;;;N;;;;;
+10520;ELBASAN LETTER VE;Lo;0;L;;;;;N;;;;;
+10521;ELBASAN LETTER XE;Lo;0;L;;;;;N;;;;;
+10522;ELBASAN LETTER Y;Lo;0;L;;;;;N;;;;;
+10523;ELBASAN LETTER ZE;Lo;0;L;;;;;N;;;;;
+10524;ELBASAN LETTER ZHE;Lo;0;L;;;;;N;;;;;
+10525;ELBASAN LETTER GHE;Lo;0;L;;;;;N;;;;;
+10526;ELBASAN LETTER GHAMMA;Lo;0;L;;;;;N;;;;;
+10527;ELBASAN LETTER KHE;Lo;0;L;;;;;N;;;;;
+10530;CAUCASIAN ALBANIAN LETTER ALT;Lo;0;L;;;;;N;;;;;
+10531;CAUCASIAN ALBANIAN LETTER BET;Lo;0;L;;;;;N;;;;;
+10532;CAUCASIAN ALBANIAN LETTER GIM;Lo;0;L;;;;;N;;;;;
+10533;CAUCASIAN ALBANIAN LETTER DAT;Lo;0;L;;;;;N;;;;;
+10534;CAUCASIAN ALBANIAN LETTER EB;Lo;0;L;;;;;N;;;;;
+10535;CAUCASIAN ALBANIAN LETTER ZARL;Lo;0;L;;;;;N;;;;;
+10536;CAUCASIAN ALBANIAN LETTER EYN;Lo;0;L;;;;;N;;;;;
+10537;CAUCASIAN ALBANIAN LETTER ZHIL;Lo;0;L;;;;;N;;;;;
+10538;CAUCASIAN ALBANIAN LETTER TAS;Lo;0;L;;;;;N;;;;;
+10539;CAUCASIAN ALBANIAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+1053A;CAUCASIAN ALBANIAN LETTER YOWD;Lo;0;L;;;;;N;;;;;
+1053B;CAUCASIAN ALBANIAN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+1053C;CAUCASIAN ALBANIAN LETTER IRB;Lo;0;L;;;;;N;;;;;
+1053D;CAUCASIAN ALBANIAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+1053E;CAUCASIAN ALBANIAN LETTER LAN;Lo;0;L;;;;;N;;;;;
+1053F;CAUCASIAN ALBANIAN LETTER INYA;Lo;0;L;;;;;N;;;;;
+10540;CAUCASIAN ALBANIAN LETTER XEYN;Lo;0;L;;;;;N;;;;;
+10541;CAUCASIAN ALBANIAN LETTER DYAN;Lo;0;L;;;;;N;;;;;
+10542;CAUCASIAN ALBANIAN LETTER CAR;Lo;0;L;;;;;N;;;;;
+10543;CAUCASIAN ALBANIAN LETTER JHOX;Lo;0;L;;;;;N;;;;;
+10544;CAUCASIAN ALBANIAN LETTER KAR;Lo;0;L;;;;;N;;;;;
+10545;CAUCASIAN ALBANIAN LETTER LYIT;Lo;0;L;;;;;N;;;;;
+10546;CAUCASIAN ALBANIAN LETTER HEYT;Lo;0;L;;;;;N;;;;;
+10547;CAUCASIAN ALBANIAN LETTER QAY;Lo;0;L;;;;;N;;;;;
+10548;CAUCASIAN ALBANIAN LETTER AOR;Lo;0;L;;;;;N;;;;;
+10549;CAUCASIAN ALBANIAN LETTER CHOY;Lo;0;L;;;;;N;;;;;
+1054A;CAUCASIAN ALBANIAN LETTER CHI;Lo;0;L;;;;;N;;;;;
+1054B;CAUCASIAN ALBANIAN LETTER CYAY;Lo;0;L;;;;;N;;;;;
+1054C;CAUCASIAN ALBANIAN LETTER MAQ;Lo;0;L;;;;;N;;;;;
+1054D;CAUCASIAN ALBANIAN LETTER QAR;Lo;0;L;;;;;N;;;;;
+1054E;CAUCASIAN ALBANIAN LETTER NOWC;Lo;0;L;;;;;N;;;;;
+1054F;CAUCASIAN ALBANIAN LETTER DZYAY;Lo;0;L;;;;;N;;;;;
+10550;CAUCASIAN ALBANIAN LETTER SHAK;Lo;0;L;;;;;N;;;;;
+10551;CAUCASIAN ALBANIAN LETTER JAYN;Lo;0;L;;;;;N;;;;;
+10552;CAUCASIAN ALBANIAN LETTER ON;Lo;0;L;;;;;N;;;;;
+10553;CAUCASIAN ALBANIAN LETTER TYAY;Lo;0;L;;;;;N;;;;;
+10554;CAUCASIAN ALBANIAN LETTER FAM;Lo;0;L;;;;;N;;;;;
+10555;CAUCASIAN ALBANIAN LETTER DZAY;Lo;0;L;;;;;N;;;;;
+10556;CAUCASIAN ALBANIAN LETTER CHAT;Lo;0;L;;;;;N;;;;;
+10557;CAUCASIAN ALBANIAN LETTER PEN;Lo;0;L;;;;;N;;;;;
+10558;CAUCASIAN ALBANIAN LETTER GHEYS;Lo;0;L;;;;;N;;;;;
+10559;CAUCASIAN ALBANIAN LETTER RAT;Lo;0;L;;;;;N;;;;;
+1055A;CAUCASIAN ALBANIAN LETTER SEYK;Lo;0;L;;;;;N;;;;;
+1055B;CAUCASIAN ALBANIAN LETTER VEYZ;Lo;0;L;;;;;N;;;;;
+1055C;CAUCASIAN ALBANIAN LETTER TIWR;Lo;0;L;;;;;N;;;;;
+1055D;CAUCASIAN ALBANIAN LETTER SHOY;Lo;0;L;;;;;N;;;;;
+1055E;CAUCASIAN ALBANIAN LETTER IWN;Lo;0;L;;;;;N;;;;;
+1055F;CAUCASIAN ALBANIAN LETTER CYAW;Lo;0;L;;;;;N;;;;;
+10560;CAUCASIAN ALBANIAN LETTER CAYN;Lo;0;L;;;;;N;;;;;
+10561;CAUCASIAN ALBANIAN LETTER YAYD;Lo;0;L;;;;;N;;;;;
+10562;CAUCASIAN ALBANIAN LETTER PIWR;Lo;0;L;;;;;N;;;;;
+10563;CAUCASIAN ALBANIAN LETTER KIW;Lo;0;L;;;;;N;;;;;
+1056F;CAUCASIAN ALBANIAN CITATION MARK;Po;0;L;;;;;N;;;;;
+10600;LINEAR A SIGN AB001;Lo;0;L;;;;;N;;;;;
+10601;LINEAR A SIGN AB002;Lo;0;L;;;;;N;;;;;
+10602;LINEAR A SIGN AB003;Lo;0;L;;;;;N;;;;;
+10603;LINEAR A SIGN AB004;Lo;0;L;;;;;N;;;;;
+10604;LINEAR A SIGN AB005;Lo;0;L;;;;;N;;;;;
+10605;LINEAR A SIGN AB006;Lo;0;L;;;;;N;;;;;
+10606;LINEAR A SIGN AB007;Lo;0;L;;;;;N;;;;;
+10607;LINEAR A SIGN AB008;Lo;0;L;;;;;N;;;;;
+10608;LINEAR A SIGN AB009;Lo;0;L;;;;;N;;;;;
+10609;LINEAR A SIGN AB010;Lo;0;L;;;;;N;;;;;
+1060A;LINEAR A SIGN AB011;Lo;0;L;;;;;N;;;;;
+1060B;LINEAR A SIGN AB013;Lo;0;L;;;;;N;;;;;
+1060C;LINEAR A SIGN AB016;Lo;0;L;;;;;N;;;;;
+1060D;LINEAR A SIGN AB017;Lo;0;L;;;;;N;;;;;
+1060E;LINEAR A SIGN AB020;Lo;0;L;;;;;N;;;;;
+1060F;LINEAR A SIGN AB021;Lo;0;L;;;;;N;;;;;
+10610;LINEAR A SIGN AB021F;Lo;0;L;;;;;N;;;;;
+10611;LINEAR A SIGN AB021M;Lo;0;L;;;;;N;;;;;
+10612;LINEAR A SIGN AB022;Lo;0;L;;;;;N;;;;;
+10613;LINEAR A SIGN AB022F;Lo;0;L;;;;;N;;;;;
+10614;LINEAR A SIGN AB022M;Lo;0;L;;;;;N;;;;;
+10615;LINEAR A SIGN AB023;Lo;0;L;;;;;N;;;;;
+10616;LINEAR A SIGN AB023M;Lo;0;L;;;;;N;;;;;
+10617;LINEAR A SIGN AB024;Lo;0;L;;;;;N;;;;;
+10618;LINEAR A SIGN AB026;Lo;0;L;;;;;N;;;;;
+10619;LINEAR A SIGN AB027;Lo;0;L;;;;;N;;;;;
+1061A;LINEAR A SIGN AB028;Lo;0;L;;;;;N;;;;;
+1061B;LINEAR A SIGN A028B;Lo;0;L;;;;;N;;;;;
+1061C;LINEAR A SIGN AB029;Lo;0;L;;;;;N;;;;;
+1061D;LINEAR A SIGN AB030;Lo;0;L;;;;;N;;;;;
+1061E;LINEAR A SIGN AB031;Lo;0;L;;;;;N;;;;;
+1061F;LINEAR A SIGN AB034;Lo;0;L;;;;;N;;;;;
+10620;LINEAR A SIGN AB037;Lo;0;L;;;;;N;;;;;
+10621;LINEAR A SIGN AB038;Lo;0;L;;;;;N;;;;;
+10622;LINEAR A SIGN AB039;Lo;0;L;;;;;N;;;;;
+10623;LINEAR A SIGN AB040;Lo;0;L;;;;;N;;;;;
+10624;LINEAR A SIGN AB041;Lo;0;L;;;;;N;;;;;
+10625;LINEAR A SIGN AB044;Lo;0;L;;;;;N;;;;;
+10626;LINEAR A SIGN AB045;Lo;0;L;;;;;N;;;;;
+10627;LINEAR A SIGN AB046;Lo;0;L;;;;;N;;;;;
+10628;LINEAR A SIGN AB047;Lo;0;L;;;;;N;;;;;
+10629;LINEAR A SIGN AB048;Lo;0;L;;;;;N;;;;;
+1062A;LINEAR A SIGN AB049;Lo;0;L;;;;;N;;;;;
+1062B;LINEAR A SIGN AB050;Lo;0;L;;;;;N;;;;;
+1062C;LINEAR A SIGN AB051;Lo;0;L;;;;;N;;;;;
+1062D;LINEAR A SIGN AB053;Lo;0;L;;;;;N;;;;;
+1062E;LINEAR A SIGN AB054;Lo;0;L;;;;;N;;;;;
+1062F;LINEAR A SIGN AB055;Lo;0;L;;;;;N;;;;;
+10630;LINEAR A SIGN AB056;Lo;0;L;;;;;N;;;;;
+10631;LINEAR A SIGN AB057;Lo;0;L;;;;;N;;;;;
+10632;LINEAR A SIGN AB058;Lo;0;L;;;;;N;;;;;
+10633;LINEAR A SIGN AB059;Lo;0;L;;;;;N;;;;;
+10634;LINEAR A SIGN AB060;Lo;0;L;;;;;N;;;;;
+10635;LINEAR A SIGN AB061;Lo;0;L;;;;;N;;;;;
+10636;LINEAR A SIGN AB065;Lo;0;L;;;;;N;;;;;
+10637;LINEAR A SIGN AB066;Lo;0;L;;;;;N;;;;;
+10638;LINEAR A SIGN AB067;Lo;0;L;;;;;N;;;;;
+10639;LINEAR A SIGN AB069;Lo;0;L;;;;;N;;;;;
+1063A;LINEAR A SIGN AB070;Lo;0;L;;;;;N;;;;;
+1063B;LINEAR A SIGN AB073;Lo;0;L;;;;;N;;;;;
+1063C;LINEAR A SIGN AB074;Lo;0;L;;;;;N;;;;;
+1063D;LINEAR A SIGN AB076;Lo;0;L;;;;;N;;;;;
+1063E;LINEAR A SIGN AB077;Lo;0;L;;;;;N;;;;;
+1063F;LINEAR A SIGN AB078;Lo;0;L;;;;;N;;;;;
+10640;LINEAR A SIGN AB079;Lo;0;L;;;;;N;;;;;
+10641;LINEAR A SIGN AB080;Lo;0;L;;;;;N;;;;;
+10642;LINEAR A SIGN AB081;Lo;0;L;;;;;N;;;;;
+10643;LINEAR A SIGN AB082;Lo;0;L;;;;;N;;;;;
+10644;LINEAR A SIGN AB085;Lo;0;L;;;;;N;;;;;
+10645;LINEAR A SIGN AB086;Lo;0;L;;;;;N;;;;;
+10646;LINEAR A SIGN AB087;Lo;0;L;;;;;N;;;;;
+10647;LINEAR A SIGN A100-102;Lo;0;L;;;;;N;;;;;
+10648;LINEAR A SIGN AB118;Lo;0;L;;;;;N;;;;;
+10649;LINEAR A SIGN AB120;Lo;0;L;;;;;N;;;;;
+1064A;LINEAR A SIGN A120B;Lo;0;L;;;;;N;;;;;
+1064B;LINEAR A SIGN AB122;Lo;0;L;;;;;N;;;;;
+1064C;LINEAR A SIGN AB123;Lo;0;L;;;;;N;;;;;
+1064D;LINEAR A SIGN AB131A;Lo;0;L;;;;;N;;;;;
+1064E;LINEAR A SIGN AB131B;Lo;0;L;;;;;N;;;;;
+1064F;LINEAR A SIGN A131C;Lo;0;L;;;;;N;;;;;
+10650;LINEAR A SIGN AB164;Lo;0;L;;;;;N;;;;;
+10651;LINEAR A SIGN AB171;Lo;0;L;;;;;N;;;;;
+10652;LINEAR A SIGN AB180;Lo;0;L;;;;;N;;;;;
+10653;LINEAR A SIGN AB188;Lo;0;L;;;;;N;;;;;
+10654;LINEAR A SIGN AB191;Lo;0;L;;;;;N;;;;;
+10655;LINEAR A SIGN A301;Lo;0;L;;;;;N;;;;;
+10656;LINEAR A SIGN A302;Lo;0;L;;;;;N;;;;;
+10657;LINEAR A SIGN A303;Lo;0;L;;;;;N;;;;;
+10658;LINEAR A SIGN A304;Lo;0;L;;;;;N;;;;;
+10659;LINEAR A SIGN A305;Lo;0;L;;;;;N;;;;;
+1065A;LINEAR A SIGN A306;Lo;0;L;;;;;N;;;;;
+1065B;LINEAR A SIGN A307;Lo;0;L;;;;;N;;;;;
+1065C;LINEAR A SIGN A308;Lo;0;L;;;;;N;;;;;
+1065D;LINEAR A SIGN A309A;Lo;0;L;;;;;N;;;;;
+1065E;LINEAR A SIGN A309B;Lo;0;L;;;;;N;;;;;
+1065F;LINEAR A SIGN A309C;Lo;0;L;;;;;N;;;;;
+10660;LINEAR A SIGN A310;Lo;0;L;;;;;N;;;;;
+10661;LINEAR A SIGN A311;Lo;0;L;;;;;N;;;;;
+10662;LINEAR A SIGN A312;Lo;0;L;;;;;N;;;;;
+10663;LINEAR A SIGN A313A;Lo;0;L;;;;;N;;;;;
+10664;LINEAR A SIGN A313B;Lo;0;L;;;;;N;;;;;
+10665;LINEAR A SIGN A313C;Lo;0;L;;;;;N;;;;;
+10666;LINEAR A SIGN A314;Lo;0;L;;;;;N;;;;;
+10667;LINEAR A SIGN A315;Lo;0;L;;;;;N;;;;;
+10668;LINEAR A SIGN A316;Lo;0;L;;;;;N;;;;;
+10669;LINEAR A SIGN A317;Lo;0;L;;;;;N;;;;;
+1066A;LINEAR A SIGN A318;Lo;0;L;;;;;N;;;;;
+1066B;LINEAR A SIGN A319;Lo;0;L;;;;;N;;;;;
+1066C;LINEAR A SIGN A320;Lo;0;L;;;;;N;;;;;
+1066D;LINEAR A SIGN A321;Lo;0;L;;;;;N;;;;;
+1066E;LINEAR A SIGN A322;Lo;0;L;;;;;N;;;;;
+1066F;LINEAR A SIGN A323;Lo;0;L;;;;;N;;;;;
+10670;LINEAR A SIGN A324;Lo;0;L;;;;;N;;;;;
+10671;LINEAR A SIGN A325;Lo;0;L;;;;;N;;;;;
+10672;LINEAR A SIGN A326;Lo;0;L;;;;;N;;;;;
+10673;LINEAR A SIGN A327;Lo;0;L;;;;;N;;;;;
+10674;LINEAR A SIGN A328;Lo;0;L;;;;;N;;;;;
+10675;LINEAR A SIGN A329;Lo;0;L;;;;;N;;;;;
+10676;LINEAR A SIGN A330;Lo;0;L;;;;;N;;;;;
+10677;LINEAR A SIGN A331;Lo;0;L;;;;;N;;;;;
+10678;LINEAR A SIGN A332;Lo;0;L;;;;;N;;;;;
+10679;LINEAR A SIGN A333;Lo;0;L;;;;;N;;;;;
+1067A;LINEAR A SIGN A334;Lo;0;L;;;;;N;;;;;
+1067B;LINEAR A SIGN A335;Lo;0;L;;;;;N;;;;;
+1067C;LINEAR A SIGN A336;Lo;0;L;;;;;N;;;;;
+1067D;LINEAR A SIGN A337;Lo;0;L;;;;;N;;;;;
+1067E;LINEAR A SIGN A338;Lo;0;L;;;;;N;;;;;
+1067F;LINEAR A SIGN A339;Lo;0;L;;;;;N;;;;;
+10680;LINEAR A SIGN A340;Lo;0;L;;;;;N;;;;;
+10681;LINEAR A SIGN A341;Lo;0;L;;;;;N;;;;;
+10682;LINEAR A SIGN A342;Lo;0;L;;;;;N;;;;;
+10683;LINEAR A SIGN A343;Lo;0;L;;;;;N;;;;;
+10684;LINEAR A SIGN A344;Lo;0;L;;;;;N;;;;;
+10685;LINEAR A SIGN A345;Lo;0;L;;;;;N;;;;;
+10686;LINEAR A SIGN A346;Lo;0;L;;;;;N;;;;;
+10687;LINEAR A SIGN A347;Lo;0;L;;;;;N;;;;;
+10688;LINEAR A SIGN A348;Lo;0;L;;;;;N;;;;;
+10689;LINEAR A SIGN A349;Lo;0;L;;;;;N;;;;;
+1068A;LINEAR A SIGN A350;Lo;0;L;;;;;N;;;;;
+1068B;LINEAR A SIGN A351;Lo;0;L;;;;;N;;;;;
+1068C;LINEAR A SIGN A352;Lo;0;L;;;;;N;;;;;
+1068D;LINEAR A SIGN A353;Lo;0;L;;;;;N;;;;;
+1068E;LINEAR A SIGN A354;Lo;0;L;;;;;N;;;;;
+1068F;LINEAR A SIGN A355;Lo;0;L;;;;;N;;;;;
+10690;LINEAR A SIGN A356;Lo;0;L;;;;;N;;;;;
+10691;LINEAR A SIGN A357;Lo;0;L;;;;;N;;;;;
+10692;LINEAR A SIGN A358;Lo;0;L;;;;;N;;;;;
+10693;LINEAR A SIGN A359;Lo;0;L;;;;;N;;;;;
+10694;LINEAR A SIGN A360;Lo;0;L;;;;;N;;;;;
+10695;LINEAR A SIGN A361;Lo;0;L;;;;;N;;;;;
+10696;LINEAR A SIGN A362;Lo;0;L;;;;;N;;;;;
+10697;LINEAR A SIGN A363;Lo;0;L;;;;;N;;;;;
+10698;LINEAR A SIGN A364;Lo;0;L;;;;;N;;;;;
+10699;LINEAR A SIGN A365;Lo;0;L;;;;;N;;;;;
+1069A;LINEAR A SIGN A366;Lo;0;L;;;;;N;;;;;
+1069B;LINEAR A SIGN A367;Lo;0;L;;;;;N;;;;;
+1069C;LINEAR A SIGN A368;Lo;0;L;;;;;N;;;;;
+1069D;LINEAR A SIGN A369;Lo;0;L;;;;;N;;;;;
+1069E;LINEAR A SIGN A370;Lo;0;L;;;;;N;;;;;
+1069F;LINEAR A SIGN A371;Lo;0;L;;;;;N;;;;;
+106A0;LINEAR A SIGN A400-VAS;Lo;0;L;;;;;N;;;;;
+106A1;LINEAR A SIGN A401-VAS;Lo;0;L;;;;;N;;;;;
+106A2;LINEAR A SIGN A402-VAS;Lo;0;L;;;;;N;;;;;
+106A3;LINEAR A SIGN A403-VAS;Lo;0;L;;;;;N;;;;;
+106A4;LINEAR A SIGN A404-VAS;Lo;0;L;;;;;N;;;;;
+106A5;LINEAR A SIGN A405-VAS;Lo;0;L;;;;;N;;;;;
+106A6;LINEAR A SIGN A406-VAS;Lo;0;L;;;;;N;;;;;
+106A7;LINEAR A SIGN A407-VAS;Lo;0;L;;;;;N;;;;;
+106A8;LINEAR A SIGN A408-VAS;Lo;0;L;;;;;N;;;;;
+106A9;LINEAR A SIGN A409-VAS;Lo;0;L;;;;;N;;;;;
+106AA;LINEAR A SIGN A410-VAS;Lo;0;L;;;;;N;;;;;
+106AB;LINEAR A SIGN A411-VAS;Lo;0;L;;;;;N;;;;;
+106AC;LINEAR A SIGN A412-VAS;Lo;0;L;;;;;N;;;;;
+106AD;LINEAR A SIGN A413-VAS;Lo;0;L;;;;;N;;;;;
+106AE;LINEAR A SIGN A414-VAS;Lo;0;L;;;;;N;;;;;
+106AF;LINEAR A SIGN A415-VAS;Lo;0;L;;;;;N;;;;;
+106B0;LINEAR A SIGN A416-VAS;Lo;0;L;;;;;N;;;;;
+106B1;LINEAR A SIGN A417-VAS;Lo;0;L;;;;;N;;;;;
+106B2;LINEAR A SIGN A418-VAS;Lo;0;L;;;;;N;;;;;
+106B3;LINEAR A SIGN A501;Lo;0;L;;;;;N;;;;;
+106B4;LINEAR A SIGN A502;Lo;0;L;;;;;N;;;;;
+106B5;LINEAR A SIGN A503;Lo;0;L;;;;;N;;;;;
+106B6;LINEAR A SIGN A504;Lo;0;L;;;;;N;;;;;
+106B7;LINEAR A SIGN A505;Lo;0;L;;;;;N;;;;;
+106B8;LINEAR A SIGN A506;Lo;0;L;;;;;N;;;;;
+106B9;LINEAR A SIGN A508;Lo;0;L;;;;;N;;;;;
+106BA;LINEAR A SIGN A509;Lo;0;L;;;;;N;;;;;
+106BB;LINEAR A SIGN A510;Lo;0;L;;;;;N;;;;;
+106BC;LINEAR A SIGN A511;Lo;0;L;;;;;N;;;;;
+106BD;LINEAR A SIGN A512;Lo;0;L;;;;;N;;;;;
+106BE;LINEAR A SIGN A513;Lo;0;L;;;;;N;;;;;
+106BF;LINEAR A SIGN A515;Lo;0;L;;;;;N;;;;;
+106C0;LINEAR A SIGN A516;Lo;0;L;;;;;N;;;;;
+106C1;LINEAR A SIGN A520;Lo;0;L;;;;;N;;;;;
+106C2;LINEAR A SIGN A521;Lo;0;L;;;;;N;;;;;
+106C3;LINEAR A SIGN A523;Lo;0;L;;;;;N;;;;;
+106C4;LINEAR A SIGN A524;Lo;0;L;;;;;N;;;;;
+106C5;LINEAR A SIGN A525;Lo;0;L;;;;;N;;;;;
+106C6;LINEAR A SIGN A526;Lo;0;L;;;;;N;;;;;
+106C7;LINEAR A SIGN A527;Lo;0;L;;;;;N;;;;;
+106C8;LINEAR A SIGN A528;Lo;0;L;;;;;N;;;;;
+106C9;LINEAR A SIGN A529;Lo;0;L;;;;;N;;;;;
+106CA;LINEAR A SIGN A530;Lo;0;L;;;;;N;;;;;
+106CB;LINEAR A SIGN A531;Lo;0;L;;;;;N;;;;;
+106CC;LINEAR A SIGN A532;Lo;0;L;;;;;N;;;;;
+106CD;LINEAR A SIGN A534;Lo;0;L;;;;;N;;;;;
+106CE;LINEAR A SIGN A535;Lo;0;L;;;;;N;;;;;
+106CF;LINEAR A SIGN A536;Lo;0;L;;;;;N;;;;;
+106D0;LINEAR A SIGN A537;Lo;0;L;;;;;N;;;;;
+106D1;LINEAR A SIGN A538;Lo;0;L;;;;;N;;;;;
+106D2;LINEAR A SIGN A539;Lo;0;L;;;;;N;;;;;
+106D3;LINEAR A SIGN A540;Lo;0;L;;;;;N;;;;;
+106D4;LINEAR A SIGN A541;Lo;0;L;;;;;N;;;;;
+106D5;LINEAR A SIGN A542;Lo;0;L;;;;;N;;;;;
+106D6;LINEAR A SIGN A545;Lo;0;L;;;;;N;;;;;
+106D7;LINEAR A SIGN A547;Lo;0;L;;;;;N;;;;;
+106D8;LINEAR A SIGN A548;Lo;0;L;;;;;N;;;;;
+106D9;LINEAR A SIGN A549;Lo;0;L;;;;;N;;;;;
+106DA;LINEAR A SIGN A550;Lo;0;L;;;;;N;;;;;
+106DB;LINEAR A SIGN A551;Lo;0;L;;;;;N;;;;;
+106DC;LINEAR A SIGN A552;Lo;0;L;;;;;N;;;;;
+106DD;LINEAR A SIGN A553;Lo;0;L;;;;;N;;;;;
+106DE;LINEAR A SIGN A554;Lo;0;L;;;;;N;;;;;
+106DF;LINEAR A SIGN A555;Lo;0;L;;;;;N;;;;;
+106E0;LINEAR A SIGN A556;Lo;0;L;;;;;N;;;;;
+106E1;LINEAR A SIGN A557;Lo;0;L;;;;;N;;;;;
+106E2;LINEAR A SIGN A559;Lo;0;L;;;;;N;;;;;
+106E3;LINEAR A SIGN A563;Lo;0;L;;;;;N;;;;;
+106E4;LINEAR A SIGN A564;Lo;0;L;;;;;N;;;;;
+106E5;LINEAR A SIGN A565;Lo;0;L;;;;;N;;;;;
+106E6;LINEAR A SIGN A566;Lo;0;L;;;;;N;;;;;
+106E7;LINEAR A SIGN A568;Lo;0;L;;;;;N;;;;;
+106E8;LINEAR A SIGN A569;Lo;0;L;;;;;N;;;;;
+106E9;LINEAR A SIGN A570;Lo;0;L;;;;;N;;;;;
+106EA;LINEAR A SIGN A571;Lo;0;L;;;;;N;;;;;
+106EB;LINEAR A SIGN A572;Lo;0;L;;;;;N;;;;;
+106EC;LINEAR A SIGN A573;Lo;0;L;;;;;N;;;;;
+106ED;LINEAR A SIGN A574;Lo;0;L;;;;;N;;;;;
+106EE;LINEAR A SIGN A575;Lo;0;L;;;;;N;;;;;
+106EF;LINEAR A SIGN A576;Lo;0;L;;;;;N;;;;;
+106F0;LINEAR A SIGN A577;Lo;0;L;;;;;N;;;;;
+106F1;LINEAR A SIGN A578;Lo;0;L;;;;;N;;;;;
+106F2;LINEAR A SIGN A579;Lo;0;L;;;;;N;;;;;
+106F3;LINEAR A SIGN A580;Lo;0;L;;;;;N;;;;;
+106F4;LINEAR A SIGN A581;Lo;0;L;;;;;N;;;;;
+106F5;LINEAR A SIGN A582;Lo;0;L;;;;;N;;;;;
+106F6;LINEAR A SIGN A583;Lo;0;L;;;;;N;;;;;
+106F7;LINEAR A SIGN A584;Lo;0;L;;;;;N;;;;;
+106F8;LINEAR A SIGN A585;Lo;0;L;;;;;N;;;;;
+106F9;LINEAR A SIGN A586;Lo;0;L;;;;;N;;;;;
+106FA;LINEAR A SIGN A587;Lo;0;L;;;;;N;;;;;
+106FB;LINEAR A SIGN A588;Lo;0;L;;;;;N;;;;;
+106FC;LINEAR A SIGN A589;Lo;0;L;;;;;N;;;;;
+106FD;LINEAR A SIGN A591;Lo;0;L;;;;;N;;;;;
+106FE;LINEAR A SIGN A592;Lo;0;L;;;;;N;;;;;
+106FF;LINEAR A SIGN A594;Lo;0;L;;;;;N;;;;;
+10700;LINEAR A SIGN A595;Lo;0;L;;;;;N;;;;;
+10701;LINEAR A SIGN A596;Lo;0;L;;;;;N;;;;;
+10702;LINEAR A SIGN A598;Lo;0;L;;;;;N;;;;;
+10703;LINEAR A SIGN A600;Lo;0;L;;;;;N;;;;;
+10704;LINEAR A SIGN A601;Lo;0;L;;;;;N;;;;;
+10705;LINEAR A SIGN A602;Lo;0;L;;;;;N;;;;;
+10706;LINEAR A SIGN A603;Lo;0;L;;;;;N;;;;;
+10707;LINEAR A SIGN A604;Lo;0;L;;;;;N;;;;;
+10708;LINEAR A SIGN A606;Lo;0;L;;;;;N;;;;;
+10709;LINEAR A SIGN A608;Lo;0;L;;;;;N;;;;;
+1070A;LINEAR A SIGN A609;Lo;0;L;;;;;N;;;;;
+1070B;LINEAR A SIGN A610;Lo;0;L;;;;;N;;;;;
+1070C;LINEAR A SIGN A611;Lo;0;L;;;;;N;;;;;
+1070D;LINEAR A SIGN A612;Lo;0;L;;;;;N;;;;;
+1070E;LINEAR A SIGN A613;Lo;0;L;;;;;N;;;;;
+1070F;LINEAR A SIGN A614;Lo;0;L;;;;;N;;;;;
+10710;LINEAR A SIGN A615;Lo;0;L;;;;;N;;;;;
+10711;LINEAR A SIGN A616;Lo;0;L;;;;;N;;;;;
+10712;LINEAR A SIGN A617;Lo;0;L;;;;;N;;;;;
+10713;LINEAR A SIGN A618;Lo;0;L;;;;;N;;;;;
+10714;LINEAR A SIGN A619;Lo;0;L;;;;;N;;;;;
+10715;LINEAR A SIGN A620;Lo;0;L;;;;;N;;;;;
+10716;LINEAR A SIGN A621;Lo;0;L;;;;;N;;;;;
+10717;LINEAR A SIGN A622;Lo;0;L;;;;;N;;;;;
+10718;LINEAR A SIGN A623;Lo;0;L;;;;;N;;;;;
+10719;LINEAR A SIGN A624;Lo;0;L;;;;;N;;;;;
+1071A;LINEAR A SIGN A626;Lo;0;L;;;;;N;;;;;
+1071B;LINEAR A SIGN A627;Lo;0;L;;;;;N;;;;;
+1071C;LINEAR A SIGN A628;Lo;0;L;;;;;N;;;;;
+1071D;LINEAR A SIGN A629;Lo;0;L;;;;;N;;;;;
+1071E;LINEAR A SIGN A634;Lo;0;L;;;;;N;;;;;
+1071F;LINEAR A SIGN A637;Lo;0;L;;;;;N;;;;;
+10720;LINEAR A SIGN A638;Lo;0;L;;;;;N;;;;;
+10721;LINEAR A SIGN A640;Lo;0;L;;;;;N;;;;;
+10722;LINEAR A SIGN A642;Lo;0;L;;;;;N;;;;;
+10723;LINEAR A SIGN A643;Lo;0;L;;;;;N;;;;;
+10724;LINEAR A SIGN A644;Lo;0;L;;;;;N;;;;;
+10725;LINEAR A SIGN A645;Lo;0;L;;;;;N;;;;;
+10726;LINEAR A SIGN A646;Lo;0;L;;;;;N;;;;;
+10727;LINEAR A SIGN A648;Lo;0;L;;;;;N;;;;;
+10728;LINEAR A SIGN A649;Lo;0;L;;;;;N;;;;;
+10729;LINEAR A SIGN A651;Lo;0;L;;;;;N;;;;;
+1072A;LINEAR A SIGN A652;Lo;0;L;;;;;N;;;;;
+1072B;LINEAR A SIGN A653;Lo;0;L;;;;;N;;;;;
+1072C;LINEAR A SIGN A654;Lo;0;L;;;;;N;;;;;
+1072D;LINEAR A SIGN A655;Lo;0;L;;;;;N;;;;;
+1072E;LINEAR A SIGN A656;Lo;0;L;;;;;N;;;;;
+1072F;LINEAR A SIGN A657;Lo;0;L;;;;;N;;;;;
+10730;LINEAR A SIGN A658;Lo;0;L;;;;;N;;;;;
+10731;LINEAR A SIGN A659;Lo;0;L;;;;;N;;;;;
+10732;LINEAR A SIGN A660;Lo;0;L;;;;;N;;;;;
+10733;LINEAR A SIGN A661;Lo;0;L;;;;;N;;;;;
+10734;LINEAR A SIGN A662;Lo;0;L;;;;;N;;;;;
+10735;LINEAR A SIGN A663;Lo;0;L;;;;;N;;;;;
+10736;LINEAR A SIGN A664;Lo;0;L;;;;;N;;;;;
+10740;LINEAR A SIGN A701 A;Lo;0;L;;;;;N;;;;;
+10741;LINEAR A SIGN A702 B;Lo;0;L;;;;;N;;;;;
+10742;LINEAR A SIGN A703 D;Lo;0;L;;;;;N;;;;;
+10743;LINEAR A SIGN A704 E;Lo;0;L;;;;;N;;;;;
+10744;LINEAR A SIGN A705 F;Lo;0;L;;;;;N;;;;;
+10745;LINEAR A SIGN A706 H;Lo;0;L;;;;;N;;;;;
+10746;LINEAR A SIGN A707 J;Lo;0;L;;;;;N;;;;;
+10747;LINEAR A SIGN A708 K;Lo;0;L;;;;;N;;;;;
+10748;LINEAR A SIGN A709 L;Lo;0;L;;;;;N;;;;;
+10749;LINEAR A SIGN A709-2 L2;Lo;0;L;;;;;N;;;;;
+1074A;LINEAR A SIGN A709-3 L3;Lo;0;L;;;;;N;;;;;
+1074B;LINEAR A SIGN A709-4 L4;Lo;0;L;;;;;N;;;;;
+1074C;LINEAR A SIGN A709-6 L6;Lo;0;L;;;;;N;;;;;
+1074D;LINEAR A SIGN A710 W;Lo;0;L;;;;;N;;;;;
+1074E;LINEAR A SIGN A711 X;Lo;0;L;;;;;N;;;;;
+1074F;LINEAR A SIGN A712 Y;Lo;0;L;;;;;N;;;;;
+10750;LINEAR A SIGN A713 OMEGA;Lo;0;L;;;;;N;;;;;
+10751;LINEAR A SIGN A714 ABB;Lo;0;L;;;;;N;;;;;
+10752;LINEAR A SIGN A715 BB;Lo;0;L;;;;;N;;;;;
+10753;LINEAR A SIGN A717 DD;Lo;0;L;;;;;N;;;;;
+10754;LINEAR A SIGN A726 EYYY;Lo;0;L;;;;;N;;;;;
+10755;LINEAR A SIGN A732 JE;Lo;0;L;;;;;N;;;;;
+10760;LINEAR A SIGN A800;Lo;0;L;;;;;N;;;;;
+10761;LINEAR A SIGN A801;Lo;0;L;;;;;N;;;;;
+10762;LINEAR A SIGN A802;Lo;0;L;;;;;N;;;;;
+10763;LINEAR A SIGN A803;Lo;0;L;;;;;N;;;;;
+10764;LINEAR A SIGN A804;Lo;0;L;;;;;N;;;;;
+10765;LINEAR A SIGN A805;Lo;0;L;;;;;N;;;;;
+10766;LINEAR A SIGN A806;Lo;0;L;;;;;N;;;;;
+10767;LINEAR A SIGN A807;Lo;0;L;;;;;N;;;;;
+10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;;
+10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;;
+10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;;
+10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;;
+10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;;
+10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;;
+10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;;
+1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;;
+1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;;
+1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;;
+1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;;
+1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;;
+1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;;
+10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;;
+10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;;
+10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;;
+10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;;
+10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;;
+10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;;
+10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;;
+10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;;
+10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;;
+10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;;
+1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;;
+1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;;
+1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;;
+1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;;
+1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;;
+1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;;
+10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;;
+10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;;
+10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;;
+10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;;
+10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;;
+10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;;
+10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;;
+10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;;
+10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;;
+10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;;
+1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;;
+1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;;
+1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;;
+1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;;
+1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;;
+1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;;
+10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;;
+10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;;
+10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;;
+10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;;
+10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;;
+10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;;
+10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;;
+10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;;
+1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;;
+1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;;
+10840;IMPERIAL ARAMAIC LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10841;IMPERIAL ARAMAIC LETTER BETH;Lo;0;R;;;;;N;;;;;
+10842;IMPERIAL ARAMAIC LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10843;IMPERIAL ARAMAIC LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10844;IMPERIAL ARAMAIC LETTER HE;Lo;0;R;;;;;N;;;;;
+10845;IMPERIAL ARAMAIC LETTER WAW;Lo;0;R;;;;;N;;;;;
+10846;IMPERIAL ARAMAIC LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10847;IMPERIAL ARAMAIC LETTER HETH;Lo;0;R;;;;;N;;;;;
+10848;IMPERIAL ARAMAIC LETTER TETH;Lo;0;R;;;;;N;;;;;
+10849;IMPERIAL ARAMAIC LETTER YODH;Lo;0;R;;;;;N;;;;;
+1084A;IMPERIAL ARAMAIC LETTER KAPH;Lo;0;R;;;;;N;;;;;
+1084B;IMPERIAL ARAMAIC LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+1084C;IMPERIAL ARAMAIC LETTER MEM;Lo;0;R;;;;;N;;;;;
+1084D;IMPERIAL ARAMAIC LETTER NUN;Lo;0;R;;;;;N;;;;;
+1084E;IMPERIAL ARAMAIC LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+1084F;IMPERIAL ARAMAIC LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10850;IMPERIAL ARAMAIC LETTER PE;Lo;0;R;;;;;N;;;;;
+10851;IMPERIAL ARAMAIC LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10852;IMPERIAL ARAMAIC LETTER QOPH;Lo;0;R;;;;;N;;;;;
+10853;IMPERIAL ARAMAIC LETTER RESH;Lo;0;R;;;;;N;;;;;
+10854;IMPERIAL ARAMAIC LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10855;IMPERIAL ARAMAIC LETTER TAW;Lo;0;R;;;;;N;;;;;
+10857;IMPERIAL ARAMAIC SECTION SIGN;Po;0;R;;;;;N;;;;;
+10858;IMPERIAL ARAMAIC NUMBER ONE;No;0;R;;;;1;N;;;;;
+10859;IMPERIAL ARAMAIC NUMBER TWO;No;0;R;;;;2;N;;;;;
+1085A;IMPERIAL ARAMAIC NUMBER THREE;No;0;R;;;;3;N;;;;;
+1085B;IMPERIAL ARAMAIC NUMBER TEN;No;0;R;;;;10;N;;;;;
+1085C;IMPERIAL ARAMAIC NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+1085D;IMPERIAL ARAMAIC NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+1085E;IMPERIAL ARAMAIC NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+1085F;IMPERIAL ARAMAIC NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;;
+10860;PALMYRENE LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10861;PALMYRENE LETTER BETH;Lo;0;R;;;;;N;;;;;
+10862;PALMYRENE LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10863;PALMYRENE LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10864;PALMYRENE LETTER HE;Lo;0;R;;;;;N;;;;;
+10865;PALMYRENE LETTER WAW;Lo;0;R;;;;;N;;;;;
+10866;PALMYRENE LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10867;PALMYRENE LETTER HETH;Lo;0;R;;;;;N;;;;;
+10868;PALMYRENE LETTER TETH;Lo;0;R;;;;;N;;;;;
+10869;PALMYRENE LETTER YODH;Lo;0;R;;;;;N;;;;;
+1086A;PALMYRENE LETTER KAPH;Lo;0;R;;;;;N;;;;;
+1086B;PALMYRENE LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+1086C;PALMYRENE LETTER MEM;Lo;0;R;;;;;N;;;;;
+1086D;PALMYRENE LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+1086E;PALMYRENE LETTER NUN;Lo;0;R;;;;;N;;;;;
+1086F;PALMYRENE LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10870;PALMYRENE LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10871;PALMYRENE LETTER PE;Lo;0;R;;;;;N;;;;;
+10872;PALMYRENE LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10873;PALMYRENE LETTER QOPH;Lo;0;R;;;;;N;;;;;
+10874;PALMYRENE LETTER RESH;Lo;0;R;;;;;N;;;;;
+10875;PALMYRENE LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10876;PALMYRENE LETTER TAW;Lo;0;R;;;;;N;;;;;
+10877;PALMYRENE LEFT-POINTING FLEURON;So;0;R;;;;;N;;;;;
+10878;PALMYRENE RIGHT-POINTING FLEURON;So;0;R;;;;;N;;;;;
+10879;PALMYRENE NUMBER ONE;No;0;R;;;;1;N;;;;;
+1087A;PALMYRENE NUMBER TWO;No;0;R;;;;2;N;;;;;
+1087B;PALMYRENE NUMBER THREE;No;0;R;;;;3;N;;;;;
+1087C;PALMYRENE NUMBER FOUR;No;0;R;;;;4;N;;;;;
+1087D;PALMYRENE NUMBER FIVE;No;0;R;;;;5;N;;;;;
+1087E;PALMYRENE NUMBER TEN;No;0;R;;;;10;N;;;;;
+1087F;PALMYRENE NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10880;NABATAEAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;
+10881;NABATAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10882;NABATAEAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;;
+10883;NABATAEAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10884;NABATAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10885;NABATAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10886;NABATAEAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;;
+10887;NABATAEAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10888;NABATAEAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10889;NABATAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+1088A;NABATAEAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+1088B;NABATAEAN LETTER TETH;Lo;0;R;;;;;N;;;;;
+1088C;NABATAEAN LETTER FINAL YODH;Lo;0;R;;;;;N;;;;;
+1088D;NABATAEAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+1088E;NABATAEAN LETTER FINAL KAPH;Lo;0;R;;;;;N;;;;;
+1088F;NABATAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10890;NABATAEAN LETTER FINAL LAMEDH;Lo;0;R;;;;;N;;;;;
+10891;NABATAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10892;NABATAEAN LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;
+10893;NABATAEAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10894;NABATAEAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+10895;NABATAEAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10896;NABATAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10897;NABATAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10898;NABATAEAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10899;NABATAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+1089A;NABATAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;;
+1089B;NABATAEAN LETTER RESH;Lo;0;R;;;;;N;;;;;
+1089C;NABATAEAN LETTER FINAL SHIN;Lo;0;R;;;;;N;;;;;
+1089D;NABATAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+1089E;NABATAEAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+108A7;NABATAEAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+108A8;NABATAEAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+108A9;NABATAEAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+108AA;NABATAEAN NUMBER FOUR;No;0;R;;;;4;N;;;;;
+108AB;NABATAEAN CRUCIFORM NUMBER FOUR;No;0;R;;;;4;N;;;;;
+108AC;NABATAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+108AD;NABATAEAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+108AE;NABATAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+108AF;NABATAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+108E0;HATRAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+108E1;HATRAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+108E2;HATRAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+108E3;HATRAN LETTER DALETH-RESH;Lo;0;R;;;;;N;;;;;
+108E4;HATRAN LETTER HE;Lo;0;R;;;;;N;;;;;
+108E5;HATRAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+108E6;HATRAN LETTER ZAYN;Lo;0;R;;;;;N;;;;;
+108E7;HATRAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+108E8;HATRAN LETTER TETH;Lo;0;R;;;;;N;;;;;
+108E9;HATRAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+108EA;HATRAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+108EB;HATRAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+108EC;HATRAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+108ED;HATRAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+108EE;HATRAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+108EF;HATRAN LETTER AYN;Lo;0;R;;;;;N;;;;;
+108F0;HATRAN LETTER PE;Lo;0;R;;;;;N;;;;;
+108F1;HATRAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+108F2;HATRAN LETTER QOPH;Lo;0;R;;;;;N;;;;;
+108F4;HATRAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+108F5;HATRAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+108FB;HATRAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+108FC;HATRAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+108FD;HATRAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+108FE;HATRAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+108FF;HATRAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10900;PHOENICIAN LETTER ALF;Lo;0;R;;;;;N;;;;;
+10901;PHOENICIAN LETTER BET;Lo;0;R;;;;;N;;;;;
+10902;PHOENICIAN LETTER GAML;Lo;0;R;;;;;N;;;;;
+10903;PHOENICIAN LETTER DELT;Lo;0;R;;;;;N;;;;;
+10904;PHOENICIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10905;PHOENICIAN LETTER WAU;Lo;0;R;;;;;N;;;;;
+10906;PHOENICIAN LETTER ZAI;Lo;0;R;;;;;N;;;;;
+10907;PHOENICIAN LETTER HET;Lo;0;R;;;;;N;;;;;
+10908;PHOENICIAN LETTER TET;Lo;0;R;;;;;N;;;;;
+10909;PHOENICIAN LETTER YOD;Lo;0;R;;;;;N;;;;;
+1090A;PHOENICIAN LETTER KAF;Lo;0;R;;;;;N;;;;;
+1090B;PHOENICIAN LETTER LAMD;Lo;0;R;;;;;N;;;;;
+1090C;PHOENICIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+1090D;PHOENICIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+1090E;PHOENICIAN LETTER SEMK;Lo;0;R;;;;;N;;;;;
+1090F;PHOENICIAN LETTER AIN;Lo;0;R;;;;;N;;;;;
+10910;PHOENICIAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10911;PHOENICIAN LETTER SADE;Lo;0;R;;;;;N;;;;;
+10912;PHOENICIAN LETTER QOF;Lo;0;R;;;;;N;;;;;
+10913;PHOENICIAN LETTER ROSH;Lo;0;R;;;;;N;;;;;
+10914;PHOENICIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10915;PHOENICIAN LETTER TAU;Lo;0;R;;;;;N;;;;;
+10916;PHOENICIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10917;PHOENICIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10918;PHOENICIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10919;PHOENICIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+1091A;PHOENICIAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+1091B;PHOENICIAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+1091F;PHOENICIAN WORD SEPARATOR;Po;0;ON;;;;;N;;;;;
+10920;LYDIAN LETTER A;Lo;0;R;;;;;N;;;;;
+10921;LYDIAN LETTER B;Lo;0;R;;;;;N;;;;;
+10922;LYDIAN LETTER G;Lo;0;R;;;;;N;;;;;
+10923;LYDIAN LETTER D;Lo;0;R;;;;;N;;;;;
+10924;LYDIAN LETTER E;Lo;0;R;;;;;N;;;;;
+10925;LYDIAN LETTER V;Lo;0;R;;;;;N;;;;;
+10926;LYDIAN LETTER I;Lo;0;R;;;;;N;;;;;
+10927;LYDIAN LETTER Y;Lo;0;R;;;;;N;;;;;
+10928;LYDIAN LETTER K;Lo;0;R;;;;;N;;;;;
+10929;LYDIAN LETTER L;Lo;0;R;;;;;N;;;;;
+1092A;LYDIAN LETTER M;Lo;0;R;;;;;N;;;;;
+1092B;LYDIAN LETTER N;Lo;0;R;;;;;N;;;;;
+1092C;LYDIAN LETTER O;Lo;0;R;;;;;N;;;;;
+1092D;LYDIAN LETTER R;Lo;0;R;;;;;N;;;;;
+1092E;LYDIAN LETTER SS;Lo;0;R;;;;;N;;;;;
+1092F;LYDIAN LETTER T;Lo;0;R;;;;;N;;;;;
+10930;LYDIAN LETTER U;Lo;0;R;;;;;N;;;;;
+10931;LYDIAN LETTER F;Lo;0;R;;;;;N;;;;;
+10932;LYDIAN LETTER Q;Lo;0;R;;;;;N;;;;;
+10933;LYDIAN LETTER S;Lo;0;R;;;;;N;;;;;
+10934;LYDIAN LETTER TT;Lo;0;R;;;;;N;;;;;
+10935;LYDIAN LETTER AN;Lo;0;R;;;;;N;;;;;
+10936;LYDIAN LETTER EN;Lo;0;R;;;;;N;;;;;
+10937;LYDIAN LETTER LY;Lo;0;R;;;;;N;;;;;
+10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;;
+10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;;
+1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;;
+10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;;
+10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;;
+10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;;
+10983;MEROITIC HIEROGLYPHIC LETTER O;Lo;0;R;;;;;N;;;;;
+10984;MEROITIC HIEROGLYPHIC LETTER YA;Lo;0;R;;;;;N;;;;;
+10985;MEROITIC HIEROGLYPHIC LETTER WA;Lo;0;R;;;;;N;;;;;
+10986;MEROITIC HIEROGLYPHIC LETTER BA;Lo;0;R;;;;;N;;;;;
+10987;MEROITIC HIEROGLYPHIC LETTER BA-2;Lo;0;R;;;;;N;;;;;
+10988;MEROITIC HIEROGLYPHIC LETTER PA;Lo;0;R;;;;;N;;;;;
+10989;MEROITIC HIEROGLYPHIC LETTER MA;Lo;0;R;;;;;N;;;;;
+1098A;MEROITIC HIEROGLYPHIC LETTER NA;Lo;0;R;;;;;N;;;;;
+1098B;MEROITIC HIEROGLYPHIC LETTER NA-2;Lo;0;R;;;;;N;;;;;
+1098C;MEROITIC HIEROGLYPHIC LETTER NE;Lo;0;R;;;;;N;;;;;
+1098D;MEROITIC HIEROGLYPHIC LETTER NE-2;Lo;0;R;;;;;N;;;;;
+1098E;MEROITIC HIEROGLYPHIC LETTER RA;Lo;0;R;;;;;N;;;;;
+1098F;MEROITIC HIEROGLYPHIC LETTER RA-2;Lo;0;R;;;;;N;;;;;
+10990;MEROITIC HIEROGLYPHIC LETTER LA;Lo;0;R;;;;;N;;;;;
+10991;MEROITIC HIEROGLYPHIC LETTER KHA;Lo;0;R;;;;;N;;;;;
+10992;MEROITIC HIEROGLYPHIC LETTER HHA;Lo;0;R;;;;;N;;;;;
+10993;MEROITIC HIEROGLYPHIC LETTER SA;Lo;0;R;;;;;N;;;;;
+10994;MEROITIC HIEROGLYPHIC LETTER SA-2;Lo;0;R;;;;;N;;;;;
+10995;MEROITIC HIEROGLYPHIC LETTER SE;Lo;0;R;;;;;N;;;;;
+10996;MEROITIC HIEROGLYPHIC LETTER KA;Lo;0;R;;;;;N;;;;;
+10997;MEROITIC HIEROGLYPHIC LETTER QA;Lo;0;R;;;;;N;;;;;
+10998;MEROITIC HIEROGLYPHIC LETTER TA;Lo;0;R;;;;;N;;;;;
+10999;MEROITIC HIEROGLYPHIC LETTER TA-2;Lo;0;R;;;;;N;;;;;
+1099A;MEROITIC HIEROGLYPHIC LETTER TE;Lo;0;R;;;;;N;;;;;
+1099B;MEROITIC HIEROGLYPHIC LETTER TE-2;Lo;0;R;;;;;N;;;;;
+1099C;MEROITIC HIEROGLYPHIC LETTER TO;Lo;0;R;;;;;N;;;;;
+1099D;MEROITIC HIEROGLYPHIC LETTER DA;Lo;0;R;;;;;N;;;;;
+1099E;MEROITIC HIEROGLYPHIC SYMBOL VIDJ;Lo;0;R;;;;;N;;;;;
+1099F;MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2;Lo;0;R;;;;;N;;;;;
+109A0;MEROITIC CURSIVE LETTER A;Lo;0;R;;;;;N;;;;;
+109A1;MEROITIC CURSIVE LETTER E;Lo;0;R;;;;;N;;;;;
+109A2;MEROITIC CURSIVE LETTER I;Lo;0;R;;;;;N;;;;;
+109A3;MEROITIC CURSIVE LETTER O;Lo;0;R;;;;;N;;;;;
+109A4;MEROITIC CURSIVE LETTER YA;Lo;0;R;;;;;N;;;;;
+109A5;MEROITIC CURSIVE LETTER WA;Lo;0;R;;;;;N;;;;;
+109A6;MEROITIC CURSIVE LETTER BA;Lo;0;R;;;;;N;;;;;
+109A7;MEROITIC CURSIVE LETTER PA;Lo;0;R;;;;;N;;;;;
+109A8;MEROITIC CURSIVE LETTER MA;Lo;0;R;;;;;N;;;;;
+109A9;MEROITIC CURSIVE LETTER NA;Lo;0;R;;;;;N;;;;;
+109AA;MEROITIC CURSIVE LETTER NE;Lo;0;R;;;;;N;;;;;
+109AB;MEROITIC CURSIVE LETTER RA;Lo;0;R;;;;;N;;;;;
+109AC;MEROITIC CURSIVE LETTER LA;Lo;0;R;;;;;N;;;;;
+109AD;MEROITIC CURSIVE LETTER KHA;Lo;0;R;;;;;N;;;;;
+109AE;MEROITIC CURSIVE LETTER HHA;Lo;0;R;;;;;N;;;;;
+109AF;MEROITIC CURSIVE LETTER SA;Lo;0;R;;;;;N;;;;;
+109B0;MEROITIC CURSIVE LETTER ARCHAIC SA;Lo;0;R;;;;;N;;;;;
+109B1;MEROITIC CURSIVE LETTER SE;Lo;0;R;;;;;N;;;;;
+109B2;MEROITIC CURSIVE LETTER KA;Lo;0;R;;;;;N;;;;;
+109B3;MEROITIC CURSIVE LETTER QA;Lo;0;R;;;;;N;;;;;
+109B4;MEROITIC CURSIVE LETTER TA;Lo;0;R;;;;;N;;;;;
+109B5;MEROITIC CURSIVE LETTER TE;Lo;0;R;;;;;N;;;;;
+109B6;MEROITIC CURSIVE LETTER TO;Lo;0;R;;;;;N;;;;;
+109B7;MEROITIC CURSIVE LETTER DA;Lo;0;R;;;;;N;;;;;
+109BC;MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS;No;0;R;;;;11/12;N;;;;;
+109BD;MEROITIC CURSIVE FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;
+109BE;MEROITIC CURSIVE LOGOGRAM RMT;Lo;0;R;;;;;N;;;;;
+109BF;MEROITIC CURSIVE LOGOGRAM IMN;Lo;0;R;;;;;N;;;;;
+109C0;MEROITIC CURSIVE NUMBER ONE;No;0;R;;;;1;N;;;;;
+109C1;MEROITIC CURSIVE NUMBER TWO;No;0;R;;;;2;N;;;;;
+109C2;MEROITIC CURSIVE NUMBER THREE;No;0;R;;;;3;N;;;;;
+109C3;MEROITIC CURSIVE NUMBER FOUR;No;0;R;;;;4;N;;;;;
+109C4;MEROITIC CURSIVE NUMBER FIVE;No;0;R;;;;5;N;;;;;
+109C5;MEROITIC CURSIVE NUMBER SIX;No;0;R;;;;6;N;;;;;
+109C6;MEROITIC CURSIVE NUMBER SEVEN;No;0;R;;;;7;N;;;;;
+109C7;MEROITIC CURSIVE NUMBER EIGHT;No;0;R;;;;8;N;;;;;
+109C8;MEROITIC CURSIVE NUMBER NINE;No;0;R;;;;9;N;;;;;
+109C9;MEROITIC CURSIVE NUMBER TEN;No;0;R;;;;10;N;;;;;
+109CA;MEROITIC CURSIVE NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+109CB;MEROITIC CURSIVE NUMBER THIRTY;No;0;R;;;;30;N;;;;;
+109CC;MEROITIC CURSIVE NUMBER FORTY;No;0;R;;;;40;N;;;;;
+109CD;MEROITIC CURSIVE NUMBER FIFTY;No;0;R;;;;50;N;;;;;
+109CE;MEROITIC CURSIVE NUMBER SIXTY;No;0;R;;;;60;N;;;;;
+109CF;MEROITIC CURSIVE NUMBER SEVENTY;No;0;R;;;;70;N;;;;;
+109D2;MEROITIC CURSIVE NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+109D3;MEROITIC CURSIVE NUMBER TWO HUNDRED;No;0;R;;;;200;N;;;;;
+109D4;MEROITIC CURSIVE NUMBER THREE HUNDRED;No;0;R;;;;300;N;;;;;
+109D5;MEROITIC CURSIVE NUMBER FOUR HUNDRED;No;0;R;;;;400;N;;;;;
+109D6;MEROITIC CURSIVE NUMBER FIVE HUNDRED;No;0;R;;;;500;N;;;;;
+109D7;MEROITIC CURSIVE NUMBER SIX HUNDRED;No;0;R;;;;600;N;;;;;
+109D8;MEROITIC CURSIVE NUMBER SEVEN HUNDRED;No;0;R;;;;700;N;;;;;
+109D9;MEROITIC CURSIVE NUMBER EIGHT HUNDRED;No;0;R;;;;800;N;;;;;
+109DA;MEROITIC CURSIVE NUMBER NINE HUNDRED;No;0;R;;;;900;N;;;;;
+109DB;MEROITIC CURSIVE NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+109DC;MEROITIC CURSIVE NUMBER TWO THOUSAND;No;0;R;;;;2000;N;;;;;
+109DD;MEROITIC CURSIVE NUMBER THREE THOUSAND;No;0;R;;;;3000;N;;;;;
+109DE;MEROITIC CURSIVE NUMBER FOUR THOUSAND;No;0;R;;;;4000;N;;;;;
+109DF;MEROITIC CURSIVE NUMBER FIVE THOUSAND;No;0;R;;;;5000;N;;;;;
+109E0;MEROITIC CURSIVE NUMBER SIX THOUSAND;No;0;R;;;;6000;N;;;;;
+109E1;MEROITIC CURSIVE NUMBER SEVEN THOUSAND;No;0;R;;;;7000;N;;;;;
+109E2;MEROITIC CURSIVE NUMBER EIGHT THOUSAND;No;0;R;;;;8000;N;;;;;
+109E3;MEROITIC CURSIVE NUMBER NINE THOUSAND;No;0;R;;;;9000;N;;;;;
+109E4;MEROITIC CURSIVE NUMBER TEN THOUSAND;No;0;R;;;;10000;N;;;;;
+109E5;MEROITIC CURSIVE NUMBER TWENTY THOUSAND;No;0;R;;;;20000;N;;;;;
+109E6;MEROITIC CURSIVE NUMBER THIRTY THOUSAND;No;0;R;;;;30000;N;;;;;
+109E7;MEROITIC CURSIVE NUMBER FORTY THOUSAND;No;0;R;;;;40000;N;;;;;
+109E8;MEROITIC CURSIVE NUMBER FIFTY THOUSAND;No;0;R;;;;50000;N;;;;;
+109E9;MEROITIC CURSIVE NUMBER SIXTY THOUSAND;No;0;R;;;;60000;N;;;;;
+109EA;MEROITIC CURSIVE NUMBER SEVENTY THOUSAND;No;0;R;;;;70000;N;;;;;
+109EB;MEROITIC CURSIVE NUMBER EIGHTY THOUSAND;No;0;R;;;;80000;N;;;;;
+109EC;MEROITIC CURSIVE NUMBER NINETY THOUSAND;No;0;R;;;;90000;N;;;;;
+109ED;MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND;No;0;R;;;;100000;N;;;;;
+109EE;MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND;No;0;R;;;;200000;N;;;;;
+109EF;MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND;No;0;R;;;;300000;N;;;;;
+109F0;MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND;No;0;R;;;;400000;N;;;;;
+109F1;MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND;No;0;R;;;;500000;N;;;;;
+109F2;MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND;No;0;R;;;;600000;N;;;;;
+109F3;MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND;No;0;R;;;;700000;N;;;;;
+109F4;MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND;No;0;R;;;;800000;N;;;;;
+109F5;MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND;No;0;R;;;;900000;N;;;;;
+109F6;MEROITIC CURSIVE FRACTION ONE TWELFTH;No;0;R;;;;1/12;N;;;;;
+109F7;MEROITIC CURSIVE FRACTION TWO TWELFTHS;No;0;R;;;;2/12;N;;;;;
+109F8;MEROITIC CURSIVE FRACTION THREE TWELFTHS;No;0;R;;;;3/12;N;;;;;
+109F9;MEROITIC CURSIVE FRACTION FOUR TWELFTHS;No;0;R;;;;4/12;N;;;;;
+109FA;MEROITIC CURSIVE FRACTION FIVE TWELFTHS;No;0;R;;;;5/12;N;;;;;
+109FB;MEROITIC CURSIVE FRACTION SIX TWELFTHS;No;0;R;;;;6/12;N;;;;;
+109FC;MEROITIC CURSIVE FRACTION SEVEN TWELFTHS;No;0;R;;;;7/12;N;;;;;
+109FD;MEROITIC CURSIVE FRACTION EIGHT TWELFTHS;No;0;R;;;;8/12;N;;;;;
+109FE;MEROITIC CURSIVE FRACTION NINE TWELFTHS;No;0;R;;;;9/12;N;;;;;
+109FF;MEROITIC CURSIVE FRACTION TEN TWELFTHS;No;0;R;;;;10/12;N;;;;;
+10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;;
+10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;
+10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;;
+10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;;
+10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;;
+10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;;
+10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;;
+10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;;
+10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;;
+10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;;
+10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;;
+10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;;
+10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;;
+10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;;
+10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;;
+10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;;
+10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;;
+10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;;
+10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;;
+10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;;
+10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;;
+10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;;
+10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;;
+10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;;
+10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;;
+10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;;
+10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;;
+10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;;
+10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;;
+10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;;
+10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;;
+10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;;
+10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;;
+10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;
+10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;
+10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;
+10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;
+10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;
+10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;;
+10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;;
+10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;;
+10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;;
+10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;;
+10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
+10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;
+10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;
+10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;;
+10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;;
+10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;;
+10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;;
+10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;;
+10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;;
+10A60;OLD SOUTH ARABIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10A61;OLD SOUTH ARABIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10A62;OLD SOUTH ARABIAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10A63;OLD SOUTH ARABIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10A64;OLD SOUTH ARABIAN LETTER QOPH;Lo;0;R;;;;;N;;;;;
+10A65;OLD SOUTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10A66;OLD SOUTH ARABIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10A67;OLD SOUTH ARABIAN LETTER RESH;Lo;0;R;;;;;N;;;;;
+10A68;OLD SOUTH ARABIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10A69;OLD SOUTH ARABIAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10A6A;OLD SOUTH ARABIAN LETTER SAT;Lo;0;R;;;;;N;;;;;
+10A6B;OLD SOUTH ARABIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10A6C;OLD SOUTH ARABIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10A6D;OLD SOUTH ARABIAN LETTER KHETH;Lo;0;R;;;;;N;;;;;
+10A6E;OLD SOUTH ARABIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10A6F;OLD SOUTH ARABIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10A70;OLD SOUTH ARABIAN LETTER FE;Lo;0;R;;;;;N;;;;;
+10A71;OLD SOUTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;;
+10A72;OLD SOUTH ARABIAN LETTER AYN;Lo;0;R;;;;;N;;;;;
+10A73;OLD SOUTH ARABIAN LETTER DHADHE;Lo;0;R;;;;;N;;;;;
+10A74;OLD SOUTH ARABIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10A75;OLD SOUTH ARABIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10A76;OLD SOUTH ARABIAN LETTER GHAYN;Lo;0;R;;;;;N;;;;;
+10A77;OLD SOUTH ARABIAN LETTER TETH;Lo;0;R;;;;;N;;;;;
+10A78;OLD SOUTH ARABIAN LETTER ZAYN;Lo;0;R;;;;;N;;;;;
+10A79;OLD SOUTH ARABIAN LETTER DHALETH;Lo;0;R;;;;;N;;;;;
+10A7A;OLD SOUTH ARABIAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10A7B;OLD SOUTH ARABIAN LETTER THAW;Lo;0;R;;;;;N;;;;;
+10A7C;OLD SOUTH ARABIAN LETTER THETH;Lo;0;R;;;;;N;;;;;
+10A7D;OLD SOUTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10A7E;OLD SOUTH ARABIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;
+10A7F;OLD SOUTH ARABIAN NUMERIC INDICATOR;Po;0;R;;;;;N;;;;;
+10A80;OLD NORTH ARABIAN LETTER HEH;Lo;0;R;;;;;N;;;;;
+10A81;OLD NORTH ARABIAN LETTER LAM;Lo;0;R;;;;;N;;;;;
+10A82;OLD NORTH ARABIAN LETTER HAH;Lo;0;R;;;;;N;;;;;
+10A83;OLD NORTH ARABIAN LETTER MEEM;Lo;0;R;;;;;N;;;;;
+10A84;OLD NORTH ARABIAN LETTER QAF;Lo;0;R;;;;;N;;;;;
+10A85;OLD NORTH ARABIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10A86;OLD NORTH ARABIAN LETTER ES-2;Lo;0;R;;;;;N;;;;;
+10A87;OLD NORTH ARABIAN LETTER REH;Lo;0;R;;;;;N;;;;;
+10A88;OLD NORTH ARABIAN LETTER BEH;Lo;0;R;;;;;N;;;;;
+10A89;OLD NORTH ARABIAN LETTER TEH;Lo;0;R;;;;;N;;;;;
+10A8A;OLD NORTH ARABIAN LETTER ES-1;Lo;0;R;;;;;N;;;;;
+10A8B;OLD NORTH ARABIAN LETTER KAF;Lo;0;R;;;;;N;;;;;
+10A8C;OLD NORTH ARABIAN LETTER NOON;Lo;0;R;;;;;N;;;;;
+10A8D;OLD NORTH ARABIAN LETTER KHAH;Lo;0;R;;;;;N;;;;;
+10A8E;OLD NORTH ARABIAN LETTER SAD;Lo;0;R;;;;;N;;;;;
+10A8F;OLD NORTH ARABIAN LETTER ES-3;Lo;0;R;;;;;N;;;;;
+10A90;OLD NORTH ARABIAN LETTER FEH;Lo;0;R;;;;;N;;;;;
+10A91;OLD NORTH ARABIAN LETTER ALEF;Lo;0;R;;;;;N;;;;;
+10A92;OLD NORTH ARABIAN LETTER AIN;Lo;0;R;;;;;N;;;;;
+10A93;OLD NORTH ARABIAN LETTER DAD;Lo;0;R;;;;;N;;;;;
+10A94;OLD NORTH ARABIAN LETTER GEEM;Lo;0;R;;;;;N;;;;;
+10A95;OLD NORTH ARABIAN LETTER DAL;Lo;0;R;;;;;N;;;;;
+10A96;OLD NORTH ARABIAN LETTER GHAIN;Lo;0;R;;;;;N;;;;;
+10A97;OLD NORTH ARABIAN LETTER TAH;Lo;0;R;;;;;N;;;;;
+10A98;OLD NORTH ARABIAN LETTER ZAIN;Lo;0;R;;;;;N;;;;;
+10A99;OLD NORTH ARABIAN LETTER THAL;Lo;0;R;;;;;N;;;;;
+10A9A;OLD NORTH ARABIAN LETTER YEH;Lo;0;R;;;;;N;;;;;
+10A9B;OLD NORTH ARABIAN LETTER THEH;Lo;0;R;;;;;N;;;;;
+10A9C;OLD NORTH ARABIAN LETTER ZAH;Lo;0;R;;;;;N;;;;;
+10A9D;OLD NORTH ARABIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10A9E;OLD NORTH ARABIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10A9F;OLD NORTH ARABIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10AC0;MANICHAEAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10AC1;MANICHAEAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10AC2;MANICHAEAN LETTER BHETH;Lo;0;R;;;;;N;;;;;
+10AC3;MANICHAEAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10AC4;MANICHAEAN LETTER GHIMEL;Lo;0;R;;;;;N;;;;;
+10AC5;MANICHAEAN LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10AC6;MANICHAEAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10AC7;MANICHAEAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10AC8;MANICHAEAN SIGN UD;So;0;R;;;;;N;;;;;
+10AC9;MANICHAEAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10ACA;MANICHAEAN LETTER ZHAYIN;Lo;0;R;;;;;N;;;;;
+10ACB;MANICHAEAN LETTER JAYIN;Lo;0;R;;;;;N;;;;;
+10ACC;MANICHAEAN LETTER JHAYIN;Lo;0;R;;;;;N;;;;;
+10ACD;MANICHAEAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10ACE;MANICHAEAN LETTER TETH;Lo;0;R;;;;;N;;;;;
+10ACF;MANICHAEAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10AD0;MANICHAEAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10AD1;MANICHAEAN LETTER XAPH;Lo;0;R;;;;;N;;;;;
+10AD2;MANICHAEAN LETTER KHAPH;Lo;0;R;;;;;N;;;;;
+10AD3;MANICHAEAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10AD4;MANICHAEAN LETTER DHAMEDH;Lo;0;R;;;;;N;;;;;
+10AD5;MANICHAEAN LETTER THAMEDH;Lo;0;R;;;;;N;;;;;
+10AD6;MANICHAEAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10AD7;MANICHAEAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10AD8;MANICHAEAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10AD9;MANICHAEAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10ADA;MANICHAEAN LETTER AAYIN;Lo;0;R;;;;;N;;;;;
+10ADB;MANICHAEAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10ADC;MANICHAEAN LETTER FE;Lo;0;R;;;;;N;;;;;
+10ADD;MANICHAEAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10ADE;MANICHAEAN LETTER QOPH;Lo;0;R;;;;;N;;;;;
+10ADF;MANICHAEAN LETTER XOPH;Lo;0;R;;;;;N;;;;;
+10AE0;MANICHAEAN LETTER QHOPH;Lo;0;R;;;;;N;;;;;
+10AE1;MANICHAEAN LETTER RESH;Lo;0;R;;;;;N;;;;;
+10AE2;MANICHAEAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10AE3;MANICHAEAN LETTER SSHIN;Lo;0;R;;;;;N;;;;;
+10AE4;MANICHAEAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10AE5;MANICHAEAN ABBREVIATION MARK ABOVE;Mn;230;NSM;;;;;N;;;;;
+10AE6;MANICHAEAN ABBREVIATION MARK BELOW;Mn;220;NSM;;;;;N;;;;;
+10AEB;MANICHAEAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10AEC;MANICHAEAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+10AED;MANICHAEAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10AEE;MANICHAEAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10AEF;MANICHAEAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10AF0;MANICHAEAN PUNCTUATION STAR;Po;0;R;;;;;N;;;;;
+10AF1;MANICHAEAN PUNCTUATION FLEURON;Po;0;R;;;;;N;;;;;
+10AF2;MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT;Po;0;R;;;;;N;;;;;
+10AF3;MANICHAEAN PUNCTUATION DOT WITHIN DOT;Po;0;R;;;;;N;;;;;
+10AF4;MANICHAEAN PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
+10AF5;MANICHAEAN PUNCTUATION TWO DOTS;Po;0;R;;;;;N;;;;;
+10AF6;MANICHAEAN PUNCTUATION LINE FILLER;Po;0;R;;;;;N;;;;;
+10B00;AVESTAN LETTER A;Lo;0;R;;;;;N;;;;;
+10B01;AVESTAN LETTER AA;Lo;0;R;;;;;N;;;;;
+10B02;AVESTAN LETTER AO;Lo;0;R;;;;;N;;;;;
+10B03;AVESTAN LETTER AAO;Lo;0;R;;;;;N;;;;;
+10B04;AVESTAN LETTER AN;Lo;0;R;;;;;N;;;;;
+10B05;AVESTAN LETTER AAN;Lo;0;R;;;;;N;;;;;
+10B06;AVESTAN LETTER AE;Lo;0;R;;;;;N;;;;;
+10B07;AVESTAN LETTER AEE;Lo;0;R;;;;;N;;;;;
+10B08;AVESTAN LETTER E;Lo;0;R;;;;;N;;;;;
+10B09;AVESTAN LETTER EE;Lo;0;R;;;;;N;;;;;
+10B0A;AVESTAN LETTER O;Lo;0;R;;;;;N;;;;;
+10B0B;AVESTAN LETTER OO;Lo;0;R;;;;;N;;;;;
+10B0C;AVESTAN LETTER I;Lo;0;R;;;;;N;;;;;
+10B0D;AVESTAN LETTER II;Lo;0;R;;;;;N;;;;;
+10B0E;AVESTAN LETTER U;Lo;0;R;;;;;N;;;;;
+10B0F;AVESTAN LETTER UU;Lo;0;R;;;;;N;;;;;
+10B10;AVESTAN LETTER KE;Lo;0;R;;;;;N;;;;;
+10B11;AVESTAN LETTER XE;Lo;0;R;;;;;N;;;;;
+10B12;AVESTAN LETTER XYE;Lo;0;R;;;;;N;;;;;
+10B13;AVESTAN LETTER XVE;Lo;0;R;;;;;N;;;;;
+10B14;AVESTAN LETTER GE;Lo;0;R;;;;;N;;;;;
+10B15;AVESTAN LETTER GGE;Lo;0;R;;;;;N;;;;;
+10B16;AVESTAN LETTER GHE;Lo;0;R;;;;;N;;;;;
+10B17;AVESTAN LETTER CE;Lo;0;R;;;;;N;;;;;
+10B18;AVESTAN LETTER JE;Lo;0;R;;;;;N;;;;;
+10B19;AVESTAN LETTER TE;Lo;0;R;;;;;N;;;;;
+10B1A;AVESTAN LETTER THE;Lo;0;R;;;;;N;;;;;
+10B1B;AVESTAN LETTER DE;Lo;0;R;;;;;N;;;;;
+10B1C;AVESTAN LETTER DHE;Lo;0;R;;;;;N;;;;;
+10B1D;AVESTAN LETTER TTE;Lo;0;R;;;;;N;;;;;
+10B1E;AVESTAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10B1F;AVESTAN LETTER FE;Lo;0;R;;;;;N;;;;;
+10B20;AVESTAN LETTER BE;Lo;0;R;;;;;N;;;;;
+10B21;AVESTAN LETTER BHE;Lo;0;R;;;;;N;;;;;
+10B22;AVESTAN LETTER NGE;Lo;0;R;;;;;N;;;;;
+10B23;AVESTAN LETTER NGYE;Lo;0;R;;;;;N;;;;;
+10B24;AVESTAN LETTER NGVE;Lo;0;R;;;;;N;;;;;
+10B25;AVESTAN LETTER NE;Lo;0;R;;;;;N;;;;;
+10B26;AVESTAN LETTER NYE;Lo;0;R;;;;;N;;;;;
+10B27;AVESTAN LETTER NNE;Lo;0;R;;;;;N;;;;;
+10B28;AVESTAN LETTER ME;Lo;0;R;;;;;N;;;;;
+10B29;AVESTAN LETTER HME;Lo;0;R;;;;;N;;;;;
+10B2A;AVESTAN LETTER YYE;Lo;0;R;;;;;N;;;;;
+10B2B;AVESTAN LETTER YE;Lo;0;R;;;;;N;;;;;
+10B2C;AVESTAN LETTER VE;Lo;0;R;;;;;N;;;;;
+10B2D;AVESTAN LETTER RE;Lo;0;R;;;;;N;;;;;
+10B2E;AVESTAN LETTER LE;Lo;0;R;;;;;N;;;;;
+10B2F;AVESTAN LETTER SE;Lo;0;R;;;;;N;;;;;
+10B30;AVESTAN LETTER ZE;Lo;0;R;;;;;N;;;;;
+10B31;AVESTAN LETTER SHE;Lo;0;R;;;;;N;;;;;
+10B32;AVESTAN LETTER ZHE;Lo;0;R;;;;;N;;;;;
+10B33;AVESTAN LETTER SHYE;Lo;0;R;;;;;N;;;;;
+10B34;AVESTAN LETTER SSHE;Lo;0;R;;;;;N;;;;;
+10B35;AVESTAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10B39;AVESTAN ABBREVIATION MARK;Po;0;ON;;;;;N;;;;;
+10B3A;TINY TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B3B;SMALL TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B3C;LARGE TWO DOTS OVER ONE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B3D;LARGE ONE DOT OVER TWO DOTS PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B3E;LARGE TWO RINGS OVER ONE RING PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B3F;LARGE ONE RING OVER TWO RINGS PUNCTUATION;Po;0;ON;;;;;N;;;;;
+10B40;INSCRIPTIONAL PARTHIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10B41;INSCRIPTIONAL PARTHIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10B42;INSCRIPTIONAL PARTHIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10B43;INSCRIPTIONAL PARTHIAN LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10B44;INSCRIPTIONAL PARTHIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10B45;INSCRIPTIONAL PARTHIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10B46;INSCRIPTIONAL PARTHIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10B47;INSCRIPTIONAL PARTHIAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10B48;INSCRIPTIONAL PARTHIAN LETTER TETH;Lo;0;R;;;;;N;;;;;
+10B49;INSCRIPTIONAL PARTHIAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10B4A;INSCRIPTIONAL PARTHIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10B4B;INSCRIPTIONAL PARTHIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10B4C;INSCRIPTIONAL PARTHIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10B4D;INSCRIPTIONAL PARTHIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10B4E;INSCRIPTIONAL PARTHIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10B4F;INSCRIPTIONAL PARTHIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10B50;INSCRIPTIONAL PARTHIAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10B51;INSCRIPTIONAL PARTHIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10B52;INSCRIPTIONAL PARTHIAN LETTER QOPH;Lo;0;R;;;;;N;;;;;
+10B53;INSCRIPTIONAL PARTHIAN LETTER RESH;Lo;0;R;;;;;N;;;;;
+10B54;INSCRIPTIONAL PARTHIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10B55;INSCRIPTIONAL PARTHIAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10B58;INSCRIPTIONAL PARTHIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10B59;INSCRIPTIONAL PARTHIAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+10B5A;INSCRIPTIONAL PARTHIAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+10B5B;INSCRIPTIONAL PARTHIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10B5C;INSCRIPTIONAL PARTHIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10B5D;INSCRIPTIONAL PARTHIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10B5E;INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10B5F;INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10B60;INSCRIPTIONAL PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10B61;INSCRIPTIONAL PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;;
+10B62;INSCRIPTIONAL PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10B63;INSCRIPTIONAL PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10B64;INSCRIPTIONAL PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;;
+10B65;INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;;
+10B66;INSCRIPTIONAL PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10B67;INSCRIPTIONAL PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;;
+10B68;INSCRIPTIONAL PAHLAVI LETTER TETH;Lo;0;R;;;;;N;;;;;
+10B69;INSCRIPTIONAL PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;;
+10B6A;INSCRIPTIONAL PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10B6B;INSCRIPTIONAL PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10B6C;INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;;
+10B6D;INSCRIPTIONAL PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;;
+10B6E;INSCRIPTIONAL PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10B6F;INSCRIPTIONAL PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;;
+10B70;INSCRIPTIONAL PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10B71;INSCRIPTIONAL PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10B72;INSCRIPTIONAL PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;;
+10B78;INSCRIPTIONAL PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;;
+10B79;INSCRIPTIONAL PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;;
+10B7A;INSCRIPTIONAL PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;;
+10B7B;INSCRIPTIONAL PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10B7C;INSCRIPTIONAL PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;;
+10B7D;INSCRIPTIONAL PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10B7E;INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10B7F;INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10B80;PSALTER PAHLAVI LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10B81;PSALTER PAHLAVI LETTER BETH;Lo;0;R;;;;;N;;;;;
+10B82;PSALTER PAHLAVI LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10B83;PSALTER PAHLAVI LETTER DALETH;Lo;0;R;;;;;N;;;;;
+10B84;PSALTER PAHLAVI LETTER HE;Lo;0;R;;;;;N;;;;;
+10B85;PSALTER PAHLAVI LETTER WAW-AYIN-RESH;Lo;0;R;;;;;N;;;;;
+10B86;PSALTER PAHLAVI LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10B87;PSALTER PAHLAVI LETTER HETH;Lo;0;R;;;;;N;;;;;
+10B88;PSALTER PAHLAVI LETTER YODH;Lo;0;R;;;;;N;;;;;
+10B89;PSALTER PAHLAVI LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10B8A;PSALTER PAHLAVI LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10B8B;PSALTER PAHLAVI LETTER MEM-QOPH;Lo;0;R;;;;;N;;;;;
+10B8C;PSALTER PAHLAVI LETTER NUN;Lo;0;R;;;;;N;;;;;
+10B8D;PSALTER PAHLAVI LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10B8E;PSALTER PAHLAVI LETTER PE;Lo;0;R;;;;;N;;;;;
+10B8F;PSALTER PAHLAVI LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10B90;PSALTER PAHLAVI LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10B91;PSALTER PAHLAVI LETTER TAW;Lo;0;R;;;;;N;;;;;
+10B99;PSALTER PAHLAVI SECTION MARK;Po;0;R;;;;;N;;;;;
+10B9A;PSALTER PAHLAVI TURNED SECTION MARK;Po;0;R;;;;;N;;;;;
+10B9B;PSALTER PAHLAVI FOUR DOTS WITH CROSS;Po;0;R;;;;;N;;;;;
+10B9C;PSALTER PAHLAVI FOUR DOTS WITH DOT;Po;0;R;;;;;N;;;;;
+10BA9;PSALTER PAHLAVI NUMBER ONE;No;0;R;;;;1;N;;;;;
+10BAA;PSALTER PAHLAVI NUMBER TWO;No;0;R;;;;2;N;;;;;
+10BAB;PSALTER PAHLAVI NUMBER THREE;No;0;R;;;;3;N;;;;;
+10BAC;PSALTER PAHLAVI NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10BAD;PSALTER PAHLAVI NUMBER TEN;No;0;R;;;;10;N;;;;;
+10BAE;PSALTER PAHLAVI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10BAF;PSALTER PAHLAVI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10C00;OLD TURKIC LETTER ORKHON A;Lo;0;R;;;;;N;;;;;
+10C01;OLD TURKIC LETTER YENISEI A;Lo;0;R;;;;;N;;;;;
+10C02;OLD TURKIC LETTER YENISEI AE;Lo;0;R;;;;;N;;;;;
+10C03;OLD TURKIC LETTER ORKHON I;Lo;0;R;;;;;N;;;;;
+10C04;OLD TURKIC LETTER YENISEI I;Lo;0;R;;;;;N;;;;;
+10C05;OLD TURKIC LETTER YENISEI E;Lo;0;R;;;;;N;;;;;
+10C06;OLD TURKIC LETTER ORKHON O;Lo;0;R;;;;;N;;;;;
+10C07;OLD TURKIC LETTER ORKHON OE;Lo;0;R;;;;;N;;;;;
+10C08;OLD TURKIC LETTER YENISEI OE;Lo;0;R;;;;;N;;;;;
+10C09;OLD TURKIC LETTER ORKHON AB;Lo;0;R;;;;;N;;;;;
+10C0A;OLD TURKIC LETTER YENISEI AB;Lo;0;R;;;;;N;;;;;
+10C0B;OLD TURKIC LETTER ORKHON AEB;Lo;0;R;;;;;N;;;;;
+10C0C;OLD TURKIC LETTER YENISEI AEB;Lo;0;R;;;;;N;;;;;
+10C0D;OLD TURKIC LETTER ORKHON AG;Lo;0;R;;;;;N;;;;;
+10C0E;OLD TURKIC LETTER YENISEI AG;Lo;0;R;;;;;N;;;;;
+10C0F;OLD TURKIC LETTER ORKHON AEG;Lo;0;R;;;;;N;;;;;
+10C10;OLD TURKIC LETTER YENISEI AEG;Lo;0;R;;;;;N;;;;;
+10C11;OLD TURKIC LETTER ORKHON AD;Lo;0;R;;;;;N;;;;;
+10C12;OLD TURKIC LETTER YENISEI AD;Lo;0;R;;;;;N;;;;;
+10C13;OLD TURKIC LETTER ORKHON AED;Lo;0;R;;;;;N;;;;;
+10C14;OLD TURKIC LETTER ORKHON EZ;Lo;0;R;;;;;N;;;;;
+10C15;OLD TURKIC LETTER YENISEI EZ;Lo;0;R;;;;;N;;;;;
+10C16;OLD TURKIC LETTER ORKHON AY;Lo;0;R;;;;;N;;;;;
+10C17;OLD TURKIC LETTER YENISEI AY;Lo;0;R;;;;;N;;;;;
+10C18;OLD TURKIC LETTER ORKHON AEY;Lo;0;R;;;;;N;;;;;
+10C19;OLD TURKIC LETTER YENISEI AEY;Lo;0;R;;;;;N;;;;;
+10C1A;OLD TURKIC LETTER ORKHON AEK;Lo;0;R;;;;;N;;;;;
+10C1B;OLD TURKIC LETTER YENISEI AEK;Lo;0;R;;;;;N;;;;;
+10C1C;OLD TURKIC LETTER ORKHON OEK;Lo;0;R;;;;;N;;;;;
+10C1D;OLD TURKIC LETTER YENISEI OEK;Lo;0;R;;;;;N;;;;;
+10C1E;OLD TURKIC LETTER ORKHON AL;Lo;0;R;;;;;N;;;;;
+10C1F;OLD TURKIC LETTER YENISEI AL;Lo;0;R;;;;;N;;;;;
+10C20;OLD TURKIC LETTER ORKHON AEL;Lo;0;R;;;;;N;;;;;
+10C21;OLD TURKIC LETTER ORKHON ELT;Lo;0;R;;;;;N;;;;;
+10C22;OLD TURKIC LETTER ORKHON EM;Lo;0;R;;;;;N;;;;;
+10C23;OLD TURKIC LETTER ORKHON AN;Lo;0;R;;;;;N;;;;;
+10C24;OLD TURKIC LETTER ORKHON AEN;Lo;0;R;;;;;N;;;;;
+10C25;OLD TURKIC LETTER YENISEI AEN;Lo;0;R;;;;;N;;;;;
+10C26;OLD TURKIC LETTER ORKHON ENT;Lo;0;R;;;;;N;;;;;
+10C27;OLD TURKIC LETTER YENISEI ENT;Lo;0;R;;;;;N;;;;;
+10C28;OLD TURKIC LETTER ORKHON ENC;Lo;0;R;;;;;N;;;;;
+10C29;OLD TURKIC LETTER YENISEI ENC;Lo;0;R;;;;;N;;;;;
+10C2A;OLD TURKIC LETTER ORKHON ENY;Lo;0;R;;;;;N;;;;;
+10C2B;OLD TURKIC LETTER YENISEI ENY;Lo;0;R;;;;;N;;;;;
+10C2C;OLD TURKIC LETTER YENISEI ANG;Lo;0;R;;;;;N;;;;;
+10C2D;OLD TURKIC LETTER ORKHON ENG;Lo;0;R;;;;;N;;;;;
+10C2E;OLD TURKIC LETTER YENISEI AENG;Lo;0;R;;;;;N;;;;;
+10C2F;OLD TURKIC LETTER ORKHON EP;Lo;0;R;;;;;N;;;;;
+10C30;OLD TURKIC LETTER ORKHON OP;Lo;0;R;;;;;N;;;;;
+10C31;OLD TURKIC LETTER ORKHON IC;Lo;0;R;;;;;N;;;;;
+10C32;OLD TURKIC LETTER ORKHON EC;Lo;0;R;;;;;N;;;;;
+10C33;OLD TURKIC LETTER YENISEI EC;Lo;0;R;;;;;N;;;;;
+10C34;OLD TURKIC LETTER ORKHON AQ;Lo;0;R;;;;;N;;;;;
+10C35;OLD TURKIC LETTER YENISEI AQ;Lo;0;R;;;;;N;;;;;
+10C36;OLD TURKIC LETTER ORKHON IQ;Lo;0;R;;;;;N;;;;;
+10C37;OLD TURKIC LETTER YENISEI IQ;Lo;0;R;;;;;N;;;;;
+10C38;OLD TURKIC LETTER ORKHON OQ;Lo;0;R;;;;;N;;;;;
+10C39;OLD TURKIC LETTER YENISEI OQ;Lo;0;R;;;;;N;;;;;
+10C3A;OLD TURKIC LETTER ORKHON AR;Lo;0;R;;;;;N;;;;;
+10C3B;OLD TURKIC LETTER YENISEI AR;Lo;0;R;;;;;N;;;;;
+10C3C;OLD TURKIC LETTER ORKHON AER;Lo;0;R;;;;;N;;;;;
+10C3D;OLD TURKIC LETTER ORKHON AS;Lo;0;R;;;;;N;;;;;
+10C3E;OLD TURKIC LETTER ORKHON AES;Lo;0;R;;;;;N;;;;;
+10C3F;OLD TURKIC LETTER ORKHON ASH;Lo;0;R;;;;;N;;;;;
+10C40;OLD TURKIC LETTER YENISEI ASH;Lo;0;R;;;;;N;;;;;
+10C41;OLD TURKIC LETTER ORKHON ESH;Lo;0;R;;;;;N;;;;;
+10C42;OLD TURKIC LETTER YENISEI ESH;Lo;0;R;;;;;N;;;;;
+10C43;OLD TURKIC LETTER ORKHON AT;Lo;0;R;;;;;N;;;;;
+10C44;OLD TURKIC LETTER YENISEI AT;Lo;0;R;;;;;N;;;;;
+10C45;OLD TURKIC LETTER ORKHON AET;Lo;0;R;;;;;N;;;;;
+10C46;OLD TURKIC LETTER YENISEI AET;Lo;0;R;;;;;N;;;;;
+10C47;OLD TURKIC LETTER ORKHON OT;Lo;0;R;;;;;N;;;;;
+10C48;OLD TURKIC LETTER ORKHON BASH;Lo;0;R;;;;;N;;;;;
+10C80;OLD HUNGARIAN CAPITAL LETTER A;Lu;0;R;;;;;N;;;;10CC0;
+10C81;OLD HUNGARIAN CAPITAL LETTER AA;Lu;0;R;;;;;N;;;;10CC1;
+10C82;OLD HUNGARIAN CAPITAL LETTER EB;Lu;0;R;;;;;N;;;;10CC2;
+10C83;OLD HUNGARIAN CAPITAL LETTER AMB;Lu;0;R;;;;;N;;;;10CC3;
+10C84;OLD HUNGARIAN CAPITAL LETTER EC;Lu;0;R;;;;;N;;;;10CC4;
+10C85;OLD HUNGARIAN CAPITAL LETTER ENC;Lu;0;R;;;;;N;;;;10CC5;
+10C86;OLD HUNGARIAN CAPITAL LETTER ECS;Lu;0;R;;;;;N;;;;10CC6;
+10C87;OLD HUNGARIAN CAPITAL LETTER ED;Lu;0;R;;;;;N;;;;10CC7;
+10C88;OLD HUNGARIAN CAPITAL LETTER AND;Lu;0;R;;;;;N;;;;10CC8;
+10C89;OLD HUNGARIAN CAPITAL LETTER E;Lu;0;R;;;;;N;;;;10CC9;
+10C8A;OLD HUNGARIAN CAPITAL LETTER CLOSE E;Lu;0;R;;;;;N;;;;10CCA;
+10C8B;OLD HUNGARIAN CAPITAL LETTER EE;Lu;0;R;;;;;N;;;;10CCB;
+10C8C;OLD HUNGARIAN CAPITAL LETTER EF;Lu;0;R;;;;;N;;;;10CCC;
+10C8D;OLD HUNGARIAN CAPITAL LETTER EG;Lu;0;R;;;;;N;;;;10CCD;
+10C8E;OLD HUNGARIAN CAPITAL LETTER EGY;Lu;0;R;;;;;N;;;;10CCE;
+10C8F;OLD HUNGARIAN CAPITAL LETTER EH;Lu;0;R;;;;;N;;;;10CCF;
+10C90;OLD HUNGARIAN CAPITAL LETTER I;Lu;0;R;;;;;N;;;;10CD0;
+10C91;OLD HUNGARIAN CAPITAL LETTER II;Lu;0;R;;;;;N;;;;10CD1;
+10C92;OLD HUNGARIAN CAPITAL LETTER EJ;Lu;0;R;;;;;N;;;;10CD2;
+10C93;OLD HUNGARIAN CAPITAL LETTER EK;Lu;0;R;;;;;N;;;;10CD3;
+10C94;OLD HUNGARIAN CAPITAL LETTER AK;Lu;0;R;;;;;N;;;;10CD4;
+10C95;OLD HUNGARIAN CAPITAL LETTER UNK;Lu;0;R;;;;;N;;;;10CD5;
+10C96;OLD HUNGARIAN CAPITAL LETTER EL;Lu;0;R;;;;;N;;;;10CD6;
+10C97;OLD HUNGARIAN CAPITAL LETTER ELY;Lu;0;R;;;;;N;;;;10CD7;
+10C98;OLD HUNGARIAN CAPITAL LETTER EM;Lu;0;R;;;;;N;;;;10CD8;
+10C99;OLD HUNGARIAN CAPITAL LETTER EN;Lu;0;R;;;;;N;;;;10CD9;
+10C9A;OLD HUNGARIAN CAPITAL LETTER ENY;Lu;0;R;;;;;N;;;;10CDA;
+10C9B;OLD HUNGARIAN CAPITAL LETTER O;Lu;0;R;;;;;N;;;;10CDB;
+10C9C;OLD HUNGARIAN CAPITAL LETTER OO;Lu;0;R;;;;;N;;;;10CDC;
+10C9D;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE;Lu;0;R;;;;;N;;;;10CDD;
+10C9E;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE;Lu;0;R;;;;;N;;;;10CDE;
+10C9F;OLD HUNGARIAN CAPITAL LETTER OEE;Lu;0;R;;;;;N;;;;10CDF;
+10CA0;OLD HUNGARIAN CAPITAL LETTER EP;Lu;0;R;;;;;N;;;;10CE0;
+10CA1;OLD HUNGARIAN CAPITAL LETTER EMP;Lu;0;R;;;;;N;;;;10CE1;
+10CA2;OLD HUNGARIAN CAPITAL LETTER ER;Lu;0;R;;;;;N;;;;10CE2;
+10CA3;OLD HUNGARIAN CAPITAL LETTER SHORT ER;Lu;0;R;;;;;N;;;;10CE3;
+10CA4;OLD HUNGARIAN CAPITAL LETTER ES;Lu;0;R;;;;;N;;;;10CE4;
+10CA5;OLD HUNGARIAN CAPITAL LETTER ESZ;Lu;0;R;;;;;N;;;;10CE5;
+10CA6;OLD HUNGARIAN CAPITAL LETTER ET;Lu;0;R;;;;;N;;;;10CE6;
+10CA7;OLD HUNGARIAN CAPITAL LETTER ENT;Lu;0;R;;;;;N;;;;10CE7;
+10CA8;OLD HUNGARIAN CAPITAL LETTER ETY;Lu;0;R;;;;;N;;;;10CE8;
+10CA9;OLD HUNGARIAN CAPITAL LETTER ECH;Lu;0;R;;;;;N;;;;10CE9;
+10CAA;OLD HUNGARIAN CAPITAL LETTER U;Lu;0;R;;;;;N;;;;10CEA;
+10CAB;OLD HUNGARIAN CAPITAL LETTER UU;Lu;0;R;;;;;N;;;;10CEB;
+10CAC;OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE;Lu;0;R;;;;;N;;;;10CEC;
+10CAD;OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE;Lu;0;R;;;;;N;;;;10CED;
+10CAE;OLD HUNGARIAN CAPITAL LETTER EV;Lu;0;R;;;;;N;;;;10CEE;
+10CAF;OLD HUNGARIAN CAPITAL LETTER EZ;Lu;0;R;;;;;N;;;;10CEF;
+10CB0;OLD HUNGARIAN CAPITAL LETTER EZS;Lu;0;R;;;;;N;;;;10CF0;
+10CB1;OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN;Lu;0;R;;;;;N;;;;10CF1;
+10CB2;OLD HUNGARIAN CAPITAL LETTER US;Lu;0;R;;;;;N;;;;10CF2;
+10CC0;OLD HUNGARIAN SMALL LETTER A;Ll;0;R;;;;;N;;;10C80;;10C80
+10CC1;OLD HUNGARIAN SMALL LETTER AA;Ll;0;R;;;;;N;;;10C81;;10C81
+10CC2;OLD HUNGARIAN SMALL LETTER EB;Ll;0;R;;;;;N;;;10C82;;10C82
+10CC3;OLD HUNGARIAN SMALL LETTER AMB;Ll;0;R;;;;;N;;;10C83;;10C83
+10CC4;OLD HUNGARIAN SMALL LETTER EC;Ll;0;R;;;;;N;;;10C84;;10C84
+10CC5;OLD HUNGARIAN SMALL LETTER ENC;Ll;0;R;;;;;N;;;10C85;;10C85
+10CC6;OLD HUNGARIAN SMALL LETTER ECS;Ll;0;R;;;;;N;;;10C86;;10C86
+10CC7;OLD HUNGARIAN SMALL LETTER ED;Ll;0;R;;;;;N;;;10C87;;10C87
+10CC8;OLD HUNGARIAN SMALL LETTER AND;Ll;0;R;;;;;N;;;10C88;;10C88
+10CC9;OLD HUNGARIAN SMALL LETTER E;Ll;0;R;;;;;N;;;10C89;;10C89
+10CCA;OLD HUNGARIAN SMALL LETTER CLOSE E;Ll;0;R;;;;;N;;;10C8A;;10C8A
+10CCB;OLD HUNGARIAN SMALL LETTER EE;Ll;0;R;;;;;N;;;10C8B;;10C8B
+10CCC;OLD HUNGARIAN SMALL LETTER EF;Ll;0;R;;;;;N;;;10C8C;;10C8C
+10CCD;OLD HUNGARIAN SMALL LETTER EG;Ll;0;R;;;;;N;;;10C8D;;10C8D
+10CCE;OLD HUNGARIAN SMALL LETTER EGY;Ll;0;R;;;;;N;;;10C8E;;10C8E
+10CCF;OLD HUNGARIAN SMALL LETTER EH;Ll;0;R;;;;;N;;;10C8F;;10C8F
+10CD0;OLD HUNGARIAN SMALL LETTER I;Ll;0;R;;;;;N;;;10C90;;10C90
+10CD1;OLD HUNGARIAN SMALL LETTER II;Ll;0;R;;;;;N;;;10C91;;10C91
+10CD2;OLD HUNGARIAN SMALL LETTER EJ;Ll;0;R;;;;;N;;;10C92;;10C92
+10CD3;OLD HUNGARIAN SMALL LETTER EK;Ll;0;R;;;;;N;;;10C93;;10C93
+10CD4;OLD HUNGARIAN SMALL LETTER AK;Ll;0;R;;;;;N;;;10C94;;10C94
+10CD5;OLD HUNGARIAN SMALL LETTER UNK;Ll;0;R;;;;;N;;;10C95;;10C95
+10CD6;OLD HUNGARIAN SMALL LETTER EL;Ll;0;R;;;;;N;;;10C96;;10C96
+10CD7;OLD HUNGARIAN SMALL LETTER ELY;Ll;0;R;;;;;N;;;10C97;;10C97
+10CD8;OLD HUNGARIAN SMALL LETTER EM;Ll;0;R;;;;;N;;;10C98;;10C98
+10CD9;OLD HUNGARIAN SMALL LETTER EN;Ll;0;R;;;;;N;;;10C99;;10C99
+10CDA;OLD HUNGARIAN SMALL LETTER ENY;Ll;0;R;;;;;N;;;10C9A;;10C9A
+10CDB;OLD HUNGARIAN SMALL LETTER O;Ll;0;R;;;;;N;;;10C9B;;10C9B
+10CDC;OLD HUNGARIAN SMALL LETTER OO;Ll;0;R;;;;;N;;;10C9C;;10C9C
+10CDD;OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE;Ll;0;R;;;;;N;;;10C9D;;10C9D
+10CDE;OLD HUNGARIAN SMALL LETTER RUDIMENTA OE;Ll;0;R;;;;;N;;;10C9E;;10C9E
+10CDF;OLD HUNGARIAN SMALL LETTER OEE;Ll;0;R;;;;;N;;;10C9F;;10C9F
+10CE0;OLD HUNGARIAN SMALL LETTER EP;Ll;0;R;;;;;N;;;10CA0;;10CA0
+10CE1;OLD HUNGARIAN SMALL LETTER EMP;Ll;0;R;;;;;N;;;10CA1;;10CA1
+10CE2;OLD HUNGARIAN SMALL LETTER ER;Ll;0;R;;;;;N;;;10CA2;;10CA2
+10CE3;OLD HUNGARIAN SMALL LETTER SHORT ER;Ll;0;R;;;;;N;;;10CA3;;10CA3
+10CE4;OLD HUNGARIAN SMALL LETTER ES;Ll;0;R;;;;;N;;;10CA4;;10CA4
+10CE5;OLD HUNGARIAN SMALL LETTER ESZ;Ll;0;R;;;;;N;;;10CA5;;10CA5
+10CE6;OLD HUNGARIAN SMALL LETTER ET;Ll;0;R;;;;;N;;;10CA6;;10CA6
+10CE7;OLD HUNGARIAN SMALL LETTER ENT;Ll;0;R;;;;;N;;;10CA7;;10CA7
+10CE8;OLD HUNGARIAN SMALL LETTER ETY;Ll;0;R;;;;;N;;;10CA8;;10CA8
+10CE9;OLD HUNGARIAN SMALL LETTER ECH;Ll;0;R;;;;;N;;;10CA9;;10CA9
+10CEA;OLD HUNGARIAN SMALL LETTER U;Ll;0;R;;;;;N;;;10CAA;;10CAA
+10CEB;OLD HUNGARIAN SMALL LETTER UU;Ll;0;R;;;;;N;;;10CAB;;10CAB
+10CEC;OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE;Ll;0;R;;;;;N;;;10CAC;;10CAC
+10CED;OLD HUNGARIAN SMALL LETTER RUDIMENTA UE;Ll;0;R;;;;;N;;;10CAD;;10CAD
+10CEE;OLD HUNGARIAN SMALL LETTER EV;Ll;0;R;;;;;N;;;10CAE;;10CAE
+10CEF;OLD HUNGARIAN SMALL LETTER EZ;Ll;0;R;;;;;N;;;10CAF;;10CAF
+10CF0;OLD HUNGARIAN SMALL LETTER EZS;Ll;0;R;;;;;N;;;10CB0;;10CB0
+10CF1;OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN;Ll;0;R;;;;;N;;;10CB1;;10CB1
+10CF2;OLD HUNGARIAN SMALL LETTER US;Ll;0;R;;;;;N;;;10CB2;;10CB2
+10CFA;OLD HUNGARIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10CFB;OLD HUNGARIAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+10CFC;OLD HUNGARIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;
+10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;;
+10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;;
+10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;;
+10E63;RUMI DIGIT FOUR;No;0;AN;;;4;4;N;;;;;
+10E64;RUMI DIGIT FIVE;No;0;AN;;;5;5;N;;;;;
+10E65;RUMI DIGIT SIX;No;0;AN;;;6;6;N;;;;;
+10E66;RUMI DIGIT SEVEN;No;0;AN;;;7;7;N;;;;;
+10E67;RUMI DIGIT EIGHT;No;0;AN;;;8;8;N;;;;;
+10E68;RUMI DIGIT NINE;No;0;AN;;;9;9;N;;;;;
+10E69;RUMI NUMBER TEN;No;0;AN;;;;10;N;;;;;
+10E6A;RUMI NUMBER TWENTY;No;0;AN;;;;20;N;;;;;
+10E6B;RUMI NUMBER THIRTY;No;0;AN;;;;30;N;;;;;
+10E6C;RUMI NUMBER FORTY;No;0;AN;;;;40;N;;;;;
+10E6D;RUMI NUMBER FIFTY;No;0;AN;;;;50;N;;;;;
+10E6E;RUMI NUMBER SIXTY;No;0;AN;;;;60;N;;;;;
+10E6F;RUMI NUMBER SEVENTY;No;0;AN;;;;70;N;;;;;
+10E70;RUMI NUMBER EIGHTY;No;0;AN;;;;80;N;;;;;
+10E71;RUMI NUMBER NINETY;No;0;AN;;;;90;N;;;;;
+10E72;RUMI NUMBER ONE HUNDRED;No;0;AN;;;;100;N;;;;;
+10E73;RUMI NUMBER TWO HUNDRED;No;0;AN;;;;200;N;;;;;
+10E74;RUMI NUMBER THREE HUNDRED;No;0;AN;;;;300;N;;;;;
+10E75;RUMI NUMBER FOUR HUNDRED;No;0;AN;;;;400;N;;;;;
+10E76;RUMI NUMBER FIVE HUNDRED;No;0;AN;;;;500;N;;;;;
+10E77;RUMI NUMBER SIX HUNDRED;No;0;AN;;;;600;N;;;;;
+10E78;RUMI NUMBER SEVEN HUNDRED;No;0;AN;;;;700;N;;;;;
+10E79;RUMI NUMBER EIGHT HUNDRED;No;0;AN;;;;800;N;;;;;
+10E7A;RUMI NUMBER NINE HUNDRED;No;0;AN;;;;900;N;;;;;
+10E7B;RUMI FRACTION ONE HALF;No;0;AN;;;;1/2;N;;;;;
+10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;;
+10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;;
+10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;;
+11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
+11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11003;BRAHMI SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
+11004;BRAHMI SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+11005;BRAHMI LETTER A;Lo;0;L;;;;;N;;;;;
+11006;BRAHMI LETTER AA;Lo;0;L;;;;;N;;;;;
+11007;BRAHMI LETTER I;Lo;0;L;;;;;N;;;;;
+11008;BRAHMI LETTER II;Lo;0;L;;;;;N;;;;;
+11009;BRAHMI LETTER U;Lo;0;L;;;;;N;;;;;
+1100A;BRAHMI LETTER UU;Lo;0;L;;;;;N;;;;;
+1100B;BRAHMI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1100C;BRAHMI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1100D;BRAHMI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1100E;BRAHMI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1100F;BRAHMI LETTER E;Lo;0;L;;;;;N;;;;;
+11010;BRAHMI LETTER AI;Lo;0;L;;;;;N;;;;;
+11011;BRAHMI LETTER O;Lo;0;L;;;;;N;;;;;
+11012;BRAHMI LETTER AU;Lo;0;L;;;;;N;;;;;
+11013;BRAHMI LETTER KA;Lo;0;L;;;;;N;;;;;
+11014;BRAHMI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11015;BRAHMI LETTER GA;Lo;0;L;;;;;N;;;;;
+11016;BRAHMI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11017;BRAHMI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11018;BRAHMI LETTER CA;Lo;0;L;;;;;N;;;;;
+11019;BRAHMI LETTER CHA;Lo;0;L;;;;;N;;;;;
+1101A;BRAHMI LETTER JA;Lo;0;L;;;;;N;;;;;
+1101B;BRAHMI LETTER JHA;Lo;0;L;;;;;N;;;;;
+1101C;BRAHMI LETTER NYA;Lo;0;L;;;;;N;;;;;
+1101D;BRAHMI LETTER TTA;Lo;0;L;;;;;N;;;;;
+1101E;BRAHMI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1101F;BRAHMI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11020;BRAHMI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11021;BRAHMI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11022;BRAHMI LETTER TA;Lo;0;L;;;;;N;;;;;
+11023;BRAHMI LETTER THA;Lo;0;L;;;;;N;;;;;
+11024;BRAHMI LETTER DA;Lo;0;L;;;;;N;;;;;
+11025;BRAHMI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11026;BRAHMI LETTER NA;Lo;0;L;;;;;N;;;;;
+11027;BRAHMI LETTER PA;Lo;0;L;;;;;N;;;;;
+11028;BRAHMI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11029;BRAHMI LETTER BA;Lo;0;L;;;;;N;;;;;
+1102A;BRAHMI LETTER BHA;Lo;0;L;;;;;N;;;;;
+1102B;BRAHMI LETTER MA;Lo;0;L;;;;;N;;;;;
+1102C;BRAHMI LETTER YA;Lo;0;L;;;;;N;;;;;
+1102D;BRAHMI LETTER RA;Lo;0;L;;;;;N;;;;;
+1102E;BRAHMI LETTER LA;Lo;0;L;;;;;N;;;;;
+1102F;BRAHMI LETTER VA;Lo;0;L;;;;;N;;;;;
+11030;BRAHMI LETTER SHA;Lo;0;L;;;;;N;;;;;
+11031;BRAHMI LETTER SSA;Lo;0;L;;;;;N;;;;;
+11032;BRAHMI LETTER SA;Lo;0;L;;;;;N;;;;;
+11033;BRAHMI LETTER HA;Lo;0;L;;;;;N;;;;;
+11034;BRAHMI LETTER LLA;Lo;0;L;;;;;N;;;;;
+11035;BRAHMI LETTER OLD TAMIL LLLA;Lo;0;L;;;;;N;;;;;
+11036;BRAHMI LETTER OLD TAMIL RRA;Lo;0;L;;;;;N;;;;;
+11037;BRAHMI LETTER OLD TAMIL NNNA;Lo;0;L;;;;;N;;;;;
+11038;BRAHMI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+11039;BRAHMI VOWEL SIGN BHATTIPROLU AA;Mn;0;NSM;;;;;N;;;;;
+1103A;BRAHMI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1103B;BRAHMI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+1103C;BRAHMI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1103D;BRAHMI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1103E;BRAHMI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+1103F;BRAHMI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+11040;BRAHMI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+11041;BRAHMI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+11042;BRAHMI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11043;BRAHMI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11044;BRAHMI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11045;BRAHMI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+11046;BRAHMI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11047;BRAHMI DANDA;Po;0;L;;;;;N;;;;;
+11048;BRAHMI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+11049;BRAHMI PUNCTUATION DOT;Po;0;L;;;;;N;;;;;
+1104A;BRAHMI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;;
+1104B;BRAHMI PUNCTUATION LINE;Po;0;L;;;;;N;;;;;
+1104C;BRAHMI PUNCTUATION CRESCENT BAR;Po;0;L;;;;;N;;;;;
+1104D;BRAHMI PUNCTUATION LOTUS;Po;0;L;;;;;N;;;;;
+11052;BRAHMI NUMBER ONE;No;0;ON;;;1;1;N;;;;;
+11053;BRAHMI NUMBER TWO;No;0;ON;;;2;2;N;;;;;
+11054;BRAHMI NUMBER THREE;No;0;ON;;;3;3;N;;;;;
+11055;BRAHMI NUMBER FOUR;No;0;ON;;;4;4;N;;;;;
+11056;BRAHMI NUMBER FIVE;No;0;ON;;;5;5;N;;;;;
+11057;BRAHMI NUMBER SIX;No;0;ON;;;6;6;N;;;;;
+11058;BRAHMI NUMBER SEVEN;No;0;ON;;;7;7;N;;;;;
+11059;BRAHMI NUMBER EIGHT;No;0;ON;;;8;8;N;;;;;
+1105A;BRAHMI NUMBER NINE;No;0;ON;;;9;9;N;;;;;
+1105B;BRAHMI NUMBER TEN;No;0;ON;;;;10;N;;;;;
+1105C;BRAHMI NUMBER TWENTY;No;0;ON;;;;20;N;;;;;
+1105D;BRAHMI NUMBER THIRTY;No;0;ON;;;;30;N;;;;;
+1105E;BRAHMI NUMBER FORTY;No;0;ON;;;;40;N;;;;;
+1105F;BRAHMI NUMBER FIFTY;No;0;ON;;;;50;N;;;;;
+11060;BRAHMI NUMBER SIXTY;No;0;ON;;;;60;N;;;;;
+11061;BRAHMI NUMBER SEVENTY;No;0;ON;;;;70;N;;;;;
+11062;BRAHMI NUMBER EIGHTY;No;0;ON;;;;80;N;;;;;
+11063;BRAHMI NUMBER NINETY;No;0;ON;;;;90;N;;;;;
+11064;BRAHMI NUMBER ONE HUNDRED;No;0;ON;;;;100;N;;;;;
+11065;BRAHMI NUMBER ONE THOUSAND;No;0;ON;;;;1000;N;;;;;
+11066;BRAHMI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11067;BRAHMI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11068;BRAHMI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11069;BRAHMI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1106A;BRAHMI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1106B;BRAHMI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1106C;BRAHMI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1107F;BRAHMI NUMBER JOINER;Mn;9;NSM;;;;;N;;;;;
+11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11083;KAITHI LETTER A;Lo;0;L;;;;;N;;;;;
+11084;KAITHI LETTER AA;Lo;0;L;;;;;N;;;;;
+11085;KAITHI LETTER I;Lo;0;L;;;;;N;;;;;
+11086;KAITHI LETTER II;Lo;0;L;;;;;N;;;;;
+11087;KAITHI LETTER U;Lo;0;L;;;;;N;;;;;
+11088;KAITHI LETTER UU;Lo;0;L;;;;;N;;;;;
+11089;KAITHI LETTER E;Lo;0;L;;;;;N;;;;;
+1108A;KAITHI LETTER AI;Lo;0;L;;;;;N;;;;;
+1108B;KAITHI LETTER O;Lo;0;L;;;;;N;;;;;
+1108C;KAITHI LETTER AU;Lo;0;L;;;;;N;;;;;
+1108D;KAITHI LETTER KA;Lo;0;L;;;;;N;;;;;
+1108E;KAITHI LETTER KHA;Lo;0;L;;;;;N;;;;;
+1108F;KAITHI LETTER GA;Lo;0;L;;;;;N;;;;;
+11090;KAITHI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11091;KAITHI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11092;KAITHI LETTER CA;Lo;0;L;;;;;N;;;;;
+11093;KAITHI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11094;KAITHI LETTER JA;Lo;0;L;;;;;N;;;;;
+11095;KAITHI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11096;KAITHI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11097;KAITHI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11098;KAITHI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11099;KAITHI LETTER DDA;Lo;0;L;;;;;N;;;;;
+1109A;KAITHI LETTER DDDHA;Lo;0;L;11099 110BA;;;;N;;;;;
+1109B;KAITHI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1109C;KAITHI LETTER RHA;Lo;0;L;1109B 110BA;;;;N;;;;;
+1109D;KAITHI LETTER NNA;Lo;0;L;;;;;N;;;;;
+1109E;KAITHI LETTER TA;Lo;0;L;;;;;N;;;;;
+1109F;KAITHI LETTER THA;Lo;0;L;;;;;N;;;;;
+110A0;KAITHI LETTER DA;Lo;0;L;;;;;N;;;;;
+110A1;KAITHI LETTER DHA;Lo;0;L;;;;;N;;;;;
+110A2;KAITHI LETTER NA;Lo;0;L;;;;;N;;;;;
+110A3;KAITHI LETTER PA;Lo;0;L;;;;;N;;;;;
+110A4;KAITHI LETTER PHA;Lo;0;L;;;;;N;;;;;
+110A5;KAITHI LETTER BA;Lo;0;L;;;;;N;;;;;
+110A6;KAITHI LETTER BHA;Lo;0;L;;;;;N;;;;;
+110A7;KAITHI LETTER MA;Lo;0;L;;;;;N;;;;;
+110A8;KAITHI LETTER YA;Lo;0;L;;;;;N;;;;;
+110A9;KAITHI LETTER RA;Lo;0;L;;;;;N;;;;;
+110AA;KAITHI LETTER LA;Lo;0;L;;;;;N;;;;;
+110AB;KAITHI LETTER VA;Lo;0;L;110A5 110BA;;;;N;;;;;
+110AC;KAITHI LETTER SHA;Lo;0;L;;;;;N;;;;;
+110AD;KAITHI LETTER SSA;Lo;0;L;;;;;N;;;;;
+110AE;KAITHI LETTER SA;Lo;0;L;;;;;N;;;;;
+110AF;KAITHI LETTER HA;Lo;0;L;;;;;N;;;;;
+110B0;KAITHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+110B1;KAITHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+110B2;KAITHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+110B3;KAITHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+110B4;KAITHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+110B5;KAITHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+110B6;KAITHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+110B7;KAITHI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+110B8;KAITHI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+110B9;KAITHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+110BA;KAITHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+110BB;KAITHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+110BC;KAITHI ENUMERATION SIGN;Po;0;L;;;;;N;;;;;
+110BD;KAITHI NUMBER SIGN;Cf;0;L;;;;;N;;;;;
+110BE;KAITHI SECTION MARK;Po;0;L;;;;;N;;;;;
+110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;
+110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;;
+110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;;
+110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;;
+110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;;
+110D3;SORA SOMPENG LETTER CAH;Lo;0;L;;;;;N;;;;;
+110D4;SORA SOMPENG LETTER DAH;Lo;0;L;;;;;N;;;;;
+110D5;SORA SOMPENG LETTER GAH;Lo;0;L;;;;;N;;;;;
+110D6;SORA SOMPENG LETTER MAH;Lo;0;L;;;;;N;;;;;
+110D7;SORA SOMPENG LETTER NGAH;Lo;0;L;;;;;N;;;;;
+110D8;SORA SOMPENG LETTER LAH;Lo;0;L;;;;;N;;;;;
+110D9;SORA SOMPENG LETTER NAH;Lo;0;L;;;;;N;;;;;
+110DA;SORA SOMPENG LETTER VAH;Lo;0;L;;;;;N;;;;;
+110DB;SORA SOMPENG LETTER PAH;Lo;0;L;;;;;N;;;;;
+110DC;SORA SOMPENG LETTER YAH;Lo;0;L;;;;;N;;;;;
+110DD;SORA SOMPENG LETTER RAH;Lo;0;L;;;;;N;;;;;
+110DE;SORA SOMPENG LETTER HAH;Lo;0;L;;;;;N;;;;;
+110DF;SORA SOMPENG LETTER KAH;Lo;0;L;;;;;N;;;;;
+110E0;SORA SOMPENG LETTER JAH;Lo;0;L;;;;;N;;;;;
+110E1;SORA SOMPENG LETTER NYAH;Lo;0;L;;;;;N;;;;;
+110E2;SORA SOMPENG LETTER AH;Lo;0;L;;;;;N;;;;;
+110E3;SORA SOMPENG LETTER EEH;Lo;0;L;;;;;N;;;;;
+110E4;SORA SOMPENG LETTER IH;Lo;0;L;;;;;N;;;;;
+110E5;SORA SOMPENG LETTER UH;Lo;0;L;;;;;N;;;;;
+110E6;SORA SOMPENG LETTER OH;Lo;0;L;;;;;N;;;;;
+110E7;SORA SOMPENG LETTER EH;Lo;0;L;;;;;N;;;;;
+110E8;SORA SOMPENG LETTER MAE;Lo;0;L;;;;;N;;;;;
+110F0;SORA SOMPENG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+110F1;SORA SOMPENG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+110F2;SORA SOMPENG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+110F3;SORA SOMPENG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+110F4;SORA SOMPENG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+110F5;SORA SOMPENG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+110F6;SORA SOMPENG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+110F7;SORA SOMPENG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+110F8;SORA SOMPENG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+110F9;SORA SOMPENG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11100;CHAKMA SIGN CANDRABINDU;Mn;230;NSM;;;;;N;;;;;
+11101;CHAKMA SIGN ANUSVARA;Mn;230;NSM;;;;;N;;;;;
+11102;CHAKMA SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;
+11103;CHAKMA LETTER AA;Lo;0;L;;;;;N;;;;;
+11104;CHAKMA LETTER I;Lo;0;L;;;;;N;;;;;
+11105;CHAKMA LETTER U;Lo;0;L;;;;;N;;;;;
+11106;CHAKMA LETTER E;Lo;0;L;;;;;N;;;;;
+11107;CHAKMA LETTER KAA;Lo;0;L;;;;;N;;;;;
+11108;CHAKMA LETTER KHAA;Lo;0;L;;;;;N;;;;;
+11109;CHAKMA LETTER GAA;Lo;0;L;;;;;N;;;;;
+1110A;CHAKMA LETTER GHAA;Lo;0;L;;;;;N;;;;;
+1110B;CHAKMA LETTER NGAA;Lo;0;L;;;;;N;;;;;
+1110C;CHAKMA LETTER CAA;Lo;0;L;;;;;N;;;;;
+1110D;CHAKMA LETTER CHAA;Lo;0;L;;;;;N;;;;;
+1110E;CHAKMA LETTER JAA;Lo;0;L;;;;;N;;;;;
+1110F;CHAKMA LETTER JHAA;Lo;0;L;;;;;N;;;;;
+11110;CHAKMA LETTER NYAA;Lo;0;L;;;;;N;;;;;
+11111;CHAKMA LETTER TTAA;Lo;0;L;;;;;N;;;;;
+11112;CHAKMA LETTER TTHAA;Lo;0;L;;;;;N;;;;;
+11113;CHAKMA LETTER DDAA;Lo;0;L;;;;;N;;;;;
+11114;CHAKMA LETTER DDHAA;Lo;0;L;;;;;N;;;;;
+11115;CHAKMA LETTER NNAA;Lo;0;L;;;;;N;;;;;
+11116;CHAKMA LETTER TAA;Lo;0;L;;;;;N;;;;;
+11117;CHAKMA LETTER THAA;Lo;0;L;;;;;N;;;;;
+11118;CHAKMA LETTER DAA;Lo;0;L;;;;;N;;;;;
+11119;CHAKMA LETTER DHAA;Lo;0;L;;;;;N;;;;;
+1111A;CHAKMA LETTER NAA;Lo;0;L;;;;;N;;;;;
+1111B;CHAKMA LETTER PAA;Lo;0;L;;;;;N;;;;;
+1111C;CHAKMA LETTER PHAA;Lo;0;L;;;;;N;;;;;
+1111D;CHAKMA LETTER BAA;Lo;0;L;;;;;N;;;;;
+1111E;CHAKMA LETTER BHAA;Lo;0;L;;;;;N;;;;;
+1111F;CHAKMA LETTER MAA;Lo;0;L;;;;;N;;;;;
+11120;CHAKMA LETTER YYAA;Lo;0;L;;;;;N;;;;;
+11121;CHAKMA LETTER YAA;Lo;0;L;;;;;N;;;;;
+11122;CHAKMA LETTER RAA;Lo;0;L;;;;;N;;;;;
+11123;CHAKMA LETTER LAA;Lo;0;L;;;;;N;;;;;
+11124;CHAKMA LETTER WAA;Lo;0;L;;;;;N;;;;;
+11125;CHAKMA LETTER SAA;Lo;0;L;;;;;N;;;;;
+11126;CHAKMA LETTER HAA;Lo;0;L;;;;;N;;;;;
+11127;CHAKMA VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;
+11128;CHAKMA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11129;CHAKMA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+1112A;CHAKMA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1112B;CHAKMA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1112C;CHAKMA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1112D;CHAKMA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1112E;CHAKMA VOWEL SIGN O;Mn;0;NSM;11131 11127;;;;N;;;;;
+1112F;CHAKMA VOWEL SIGN AU;Mn;0;NSM;11132 11127;;;;N;;;;;
+11130;CHAKMA VOWEL SIGN OI;Mn;0;NSM;;;;;N;;;;;
+11131;CHAKMA O MARK;Mn;0;NSM;;;;;N;;;;;
+11132;CHAKMA AU MARK;Mn;0;NSM;;;;;N;;;;;
+11133;CHAKMA VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11134;CHAKMA MAAYYAA;Mn;9;NSM;;;;;N;;;;;
+11136;CHAKMA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11137;CHAKMA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11138;CHAKMA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11139;CHAKMA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1113A;CHAKMA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1113B;CHAKMA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1113C;CHAKMA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1113D;CHAKMA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1113E;CHAKMA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1113F;CHAKMA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11140;CHAKMA SECTION MARK;Po;0;L;;;;;N;;;;;
+11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;;
+11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;;
+11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;;
+11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;;
+11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;;
+11153;MAHAJANI LETTER E;Lo;0;L;;;;;N;;;;;
+11154;MAHAJANI LETTER O;Lo;0;L;;;;;N;;;;;
+11155;MAHAJANI LETTER KA;Lo;0;L;;;;;N;;;;;
+11156;MAHAJANI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11157;MAHAJANI LETTER GA;Lo;0;L;;;;;N;;;;;
+11158;MAHAJANI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11159;MAHAJANI LETTER CA;Lo;0;L;;;;;N;;;;;
+1115A;MAHAJANI LETTER CHA;Lo;0;L;;;;;N;;;;;
+1115B;MAHAJANI LETTER JA;Lo;0;L;;;;;N;;;;;
+1115C;MAHAJANI LETTER JHA;Lo;0;L;;;;;N;;;;;
+1115D;MAHAJANI LETTER NYA;Lo;0;L;;;;;N;;;;;
+1115E;MAHAJANI LETTER TTA;Lo;0;L;;;;;N;;;;;
+1115F;MAHAJANI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11160;MAHAJANI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11161;MAHAJANI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11162;MAHAJANI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11163;MAHAJANI LETTER TA;Lo;0;L;;;;;N;;;;;
+11164;MAHAJANI LETTER THA;Lo;0;L;;;;;N;;;;;
+11165;MAHAJANI LETTER DA;Lo;0;L;;;;;N;;;;;
+11166;MAHAJANI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11167;MAHAJANI LETTER NA;Lo;0;L;;;;;N;;;;;
+11168;MAHAJANI LETTER PA;Lo;0;L;;;;;N;;;;;
+11169;MAHAJANI LETTER PHA;Lo;0;L;;;;;N;;;;;
+1116A;MAHAJANI LETTER BA;Lo;0;L;;;;;N;;;;;
+1116B;MAHAJANI LETTER BHA;Lo;0;L;;;;;N;;;;;
+1116C;MAHAJANI LETTER MA;Lo;0;L;;;;;N;;;;;
+1116D;MAHAJANI LETTER RA;Lo;0;L;;;;;N;;;;;
+1116E;MAHAJANI LETTER LA;Lo;0;L;;;;;N;;;;;
+1116F;MAHAJANI LETTER VA;Lo;0;L;;;;;N;;;;;
+11170;MAHAJANI LETTER SA;Lo;0;L;;;;;N;;;;;
+11171;MAHAJANI LETTER HA;Lo;0;L;;;;;N;;;;;
+11172;MAHAJANI LETTER RRA;Lo;0;L;;;;;N;;;;;
+11173;MAHAJANI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+11174;MAHAJANI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+11175;MAHAJANI SECTION MARK;Po;0;L;;;;;N;;;;;
+11176;MAHAJANI LIGATURE SHRI;Lo;0;L;;;;;N;;;;;
+11180;SHARADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11181;SHARADA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11182;SHARADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11183;SHARADA LETTER A;Lo;0;L;;;;;N;;;;;
+11184;SHARADA LETTER AA;Lo;0;L;;;;;N;;;;;
+11185;SHARADA LETTER I;Lo;0;L;;;;;N;;;;;
+11186;SHARADA LETTER II;Lo;0;L;;;;;N;;;;;
+11187;SHARADA LETTER U;Lo;0;L;;;;;N;;;;;
+11188;SHARADA LETTER UU;Lo;0;L;;;;;N;;;;;
+11189;SHARADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1118A;SHARADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1118B;SHARADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1118C;SHARADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1118D;SHARADA LETTER E;Lo;0;L;;;;;N;;;;;
+1118E;SHARADA LETTER AI;Lo;0;L;;;;;N;;;;;
+1118F;SHARADA LETTER O;Lo;0;L;;;;;N;;;;;
+11190;SHARADA LETTER AU;Lo;0;L;;;;;N;;;;;
+11191;SHARADA LETTER KA;Lo;0;L;;;;;N;;;;;
+11192;SHARADA LETTER KHA;Lo;0;L;;;;;N;;;;;
+11193;SHARADA LETTER GA;Lo;0;L;;;;;N;;;;;
+11194;SHARADA LETTER GHA;Lo;0;L;;;;;N;;;;;
+11195;SHARADA LETTER NGA;Lo;0;L;;;;;N;;;;;
+11196;SHARADA LETTER CA;Lo;0;L;;;;;N;;;;;
+11197;SHARADA LETTER CHA;Lo;0;L;;;;;N;;;;;
+11198;SHARADA LETTER JA;Lo;0;L;;;;;N;;;;;
+11199;SHARADA LETTER JHA;Lo;0;L;;;;;N;;;;;
+1119A;SHARADA LETTER NYA;Lo;0;L;;;;;N;;;;;
+1119B;SHARADA LETTER TTA;Lo;0;L;;;;;N;;;;;
+1119C;SHARADA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1119D;SHARADA LETTER DDA;Lo;0;L;;;;;N;;;;;
+1119E;SHARADA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1119F;SHARADA LETTER NNA;Lo;0;L;;;;;N;;;;;
+111A0;SHARADA LETTER TA;Lo;0;L;;;;;N;;;;;
+111A1;SHARADA LETTER THA;Lo;0;L;;;;;N;;;;;
+111A2;SHARADA LETTER DA;Lo;0;L;;;;;N;;;;;
+111A3;SHARADA LETTER DHA;Lo;0;L;;;;;N;;;;;
+111A4;SHARADA LETTER NA;Lo;0;L;;;;;N;;;;;
+111A5;SHARADA LETTER PA;Lo;0;L;;;;;N;;;;;
+111A6;SHARADA LETTER PHA;Lo;0;L;;;;;N;;;;;
+111A7;SHARADA LETTER BA;Lo;0;L;;;;;N;;;;;
+111A8;SHARADA LETTER BHA;Lo;0;L;;;;;N;;;;;
+111A9;SHARADA LETTER MA;Lo;0;L;;;;;N;;;;;
+111AA;SHARADA LETTER YA;Lo;0;L;;;;;N;;;;;
+111AB;SHARADA LETTER RA;Lo;0;L;;;;;N;;;;;
+111AC;SHARADA LETTER LA;Lo;0;L;;;;;N;;;;;
+111AD;SHARADA LETTER LLA;Lo;0;L;;;;;N;;;;;
+111AE;SHARADA LETTER VA;Lo;0;L;;;;;N;;;;;
+111AF;SHARADA LETTER SHA;Lo;0;L;;;;;N;;;;;
+111B0;SHARADA LETTER SSA;Lo;0;L;;;;;N;;;;;
+111B1;SHARADA LETTER SA;Lo;0;L;;;;;N;;;;;
+111B2;SHARADA LETTER HA;Lo;0;L;;;;;N;;;;;
+111B3;SHARADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+111B4;SHARADA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+111B5;SHARADA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+111B6;SHARADA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+111B7;SHARADA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+111B8;SHARADA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+111B9;SHARADA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+111BA;SHARADA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+111BB;SHARADA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+111BC;SHARADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+111BD;SHARADA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+111BE;SHARADA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+111BF;SHARADA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+111C0;SHARADA SIGN VIRAMA;Mc;9;L;;;;;N;;;;;
+111C1;SHARADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+111C2;SHARADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;;
+111C3;SHARADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;;
+111C4;SHARADA OM;Lo;0;L;;;;;N;;;;;
+111C5;SHARADA DANDA;Po;0;L;;;;;N;;;;;
+111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;;
+111C9;SHARADA SANDHI MARK;Po;0;L;;;;;N;;;;;
+111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;;
+111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;;
+111CD;SHARADA SUTRA MARK;Po;0;L;;;;;N;;;;;
+111D0;SHARADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+111D1;SHARADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+111D2;SHARADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+111D3;SHARADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+111D4;SHARADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+111D5;SHARADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+111D6;SHARADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+111D7;SHARADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+111D8;SHARADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+111D9;SHARADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+111DA;SHARADA EKAM;Lo;0;L;;;;;N;;;;;
+111DB;SHARADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
+111DC;SHARADA HEADSTROKE;Lo;0;L;;;;;N;;;;;
+111DD;SHARADA CONTINUATION SIGN;Po;0;L;;;;;N;;;;;
+111DE;SHARADA SECTION MARK-1;Po;0;L;;;;;N;;;;;
+111DF;SHARADA SECTION MARK-2;Po;0;L;;;;;N;;;;;
+111E1;SINHALA ARCHAIC DIGIT ONE;No;0;L;;;;1;N;;;;;
+111E2;SINHALA ARCHAIC DIGIT TWO;No;0;L;;;;2;N;;;;;
+111E3;SINHALA ARCHAIC DIGIT THREE;No;0;L;;;;3;N;;;;;
+111E4;SINHALA ARCHAIC DIGIT FOUR;No;0;L;;;;4;N;;;;;
+111E5;SINHALA ARCHAIC DIGIT FIVE;No;0;L;;;;5;N;;;;;
+111E6;SINHALA ARCHAIC DIGIT SIX;No;0;L;;;;6;N;;;;;
+111E7;SINHALA ARCHAIC DIGIT SEVEN;No;0;L;;;;7;N;;;;;
+111E8;SINHALA ARCHAIC DIGIT EIGHT;No;0;L;;;;8;N;;;;;
+111E9;SINHALA ARCHAIC DIGIT NINE;No;0;L;;;;9;N;;;;;
+111EA;SINHALA ARCHAIC NUMBER TEN;No;0;L;;;;10;N;;;;;
+111EB;SINHALA ARCHAIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+111EC;SINHALA ARCHAIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+111ED;SINHALA ARCHAIC NUMBER FORTY;No;0;L;;;;40;N;;;;;
+111EE;SINHALA ARCHAIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+111EF;SINHALA ARCHAIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+111F0;SINHALA ARCHAIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+111F1;SINHALA ARCHAIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+111F2;SINHALA ARCHAIC NUMBER NINETY;No;0;L;;;;90;N;;;;;
+111F3;SINHALA ARCHAIC NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+111F4;SINHALA ARCHAIC NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+11200;KHOJKI LETTER A;Lo;0;L;;;;;N;;;;;
+11201;KHOJKI LETTER AA;Lo;0;L;;;;;N;;;;;
+11202;KHOJKI LETTER I;Lo;0;L;;;;;N;;;;;
+11203;KHOJKI LETTER U;Lo;0;L;;;;;N;;;;;
+11204;KHOJKI LETTER E;Lo;0;L;;;;;N;;;;;
+11205;KHOJKI LETTER AI;Lo;0;L;;;;;N;;;;;
+11206;KHOJKI LETTER O;Lo;0;L;;;;;N;;;;;
+11207;KHOJKI LETTER AU;Lo;0;L;;;;;N;;;;;
+11208;KHOJKI LETTER KA;Lo;0;L;;;;;N;;;;;
+11209;KHOJKI LETTER KHA;Lo;0;L;;;;;N;;;;;
+1120A;KHOJKI LETTER GA;Lo;0;L;;;;;N;;;;;
+1120B;KHOJKI LETTER GGA;Lo;0;L;;;;;N;;;;;
+1120C;KHOJKI LETTER GHA;Lo;0;L;;;;;N;;;;;
+1120D;KHOJKI LETTER NGA;Lo;0;L;;;;;N;;;;;
+1120E;KHOJKI LETTER CA;Lo;0;L;;;;;N;;;;;
+1120F;KHOJKI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11210;KHOJKI LETTER JA;Lo;0;L;;;;;N;;;;;
+11211;KHOJKI LETTER JJA;Lo;0;L;;;;;N;;;;;
+11213;KHOJKI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11214;KHOJKI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11215;KHOJKI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11216;KHOJKI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11217;KHOJKI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11218;KHOJKI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11219;KHOJKI LETTER TA;Lo;0;L;;;;;N;;;;;
+1121A;KHOJKI LETTER THA;Lo;0;L;;;;;N;;;;;
+1121B;KHOJKI LETTER DA;Lo;0;L;;;;;N;;;;;
+1121C;KHOJKI LETTER DDDA;Lo;0;L;;;;;N;;;;;
+1121D;KHOJKI LETTER DHA;Lo;0;L;;;;;N;;;;;
+1121E;KHOJKI LETTER NA;Lo;0;L;;;;;N;;;;;
+1121F;KHOJKI LETTER PA;Lo;0;L;;;;;N;;;;;
+11220;KHOJKI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11221;KHOJKI LETTER BA;Lo;0;L;;;;;N;;;;;
+11222;KHOJKI LETTER BBA;Lo;0;L;;;;;N;;;;;
+11223;KHOJKI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11224;KHOJKI LETTER MA;Lo;0;L;;;;;N;;;;;
+11225;KHOJKI LETTER YA;Lo;0;L;;;;;N;;;;;
+11226;KHOJKI LETTER RA;Lo;0;L;;;;;N;;;;;
+11227;KHOJKI LETTER LA;Lo;0;L;;;;;N;;;;;
+11228;KHOJKI LETTER VA;Lo;0;L;;;;;N;;;;;
+11229;KHOJKI LETTER SA;Lo;0;L;;;;;N;;;;;
+1122A;KHOJKI LETTER HA;Lo;0;L;;;;;N;;;;;
+1122B;KHOJKI LETTER LLA;Lo;0;L;;;;;N;;;;;
+1122C;KHOJKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1122D;KHOJKI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+1122E;KHOJKI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+1122F;KHOJKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11230;KHOJKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11231;KHOJKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11232;KHOJKI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+11233;KHOJKI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11234;KHOJKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11235;KHOJKI SIGN VIRAMA;Mc;9;L;;;;;N;;;;;
+11236;KHOJKI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+11237;KHOJKI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;;
+11238;KHOJKI DANDA;Po;0;L;;;;;N;;;;;
+11239;KHOJKI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+1123A;KHOJKI WORD SEPARATOR;Po;0;L;;;;;N;;;;;
+1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;;
+1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;
+1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;;
+11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;;
+11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;;
+11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;;
+11283;MULTANI LETTER E;Lo;0;L;;;;;N;;;;;
+11284;MULTANI LETTER KA;Lo;0;L;;;;;N;;;;;
+11285;MULTANI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11286;MULTANI LETTER GA;Lo;0;L;;;;;N;;;;;
+11288;MULTANI LETTER GHA;Lo;0;L;;;;;N;;;;;
+1128A;MULTANI LETTER CA;Lo;0;L;;;;;N;;;;;
+1128B;MULTANI LETTER CHA;Lo;0;L;;;;;N;;;;;
+1128C;MULTANI LETTER JA;Lo;0;L;;;;;N;;;;;
+1128D;MULTANI LETTER JJA;Lo;0;L;;;;;N;;;;;
+1128F;MULTANI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11290;MULTANI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11291;MULTANI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11292;MULTANI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11293;MULTANI LETTER DDDA;Lo;0;L;;;;;N;;;;;
+11294;MULTANI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11295;MULTANI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11296;MULTANI LETTER TA;Lo;0;L;;;;;N;;;;;
+11297;MULTANI LETTER THA;Lo;0;L;;;;;N;;;;;
+11298;MULTANI LETTER DA;Lo;0;L;;;;;N;;;;;
+11299;MULTANI LETTER DHA;Lo;0;L;;;;;N;;;;;
+1129A;MULTANI LETTER NA;Lo;0;L;;;;;N;;;;;
+1129B;MULTANI LETTER PA;Lo;0;L;;;;;N;;;;;
+1129C;MULTANI LETTER PHA;Lo;0;L;;;;;N;;;;;
+1129D;MULTANI LETTER BA;Lo;0;L;;;;;N;;;;;
+1129F;MULTANI LETTER BHA;Lo;0;L;;;;;N;;;;;
+112A0;MULTANI LETTER MA;Lo;0;L;;;;;N;;;;;
+112A1;MULTANI LETTER YA;Lo;0;L;;;;;N;;;;;
+112A2;MULTANI LETTER RA;Lo;0;L;;;;;N;;;;;
+112A3;MULTANI LETTER LA;Lo;0;L;;;;;N;;;;;
+112A4;MULTANI LETTER VA;Lo;0;L;;;;;N;;;;;
+112A5;MULTANI LETTER SA;Lo;0;L;;;;;N;;;;;
+112A6;MULTANI LETTER HA;Lo;0;L;;;;;N;;;;;
+112A7;MULTANI LETTER RRA;Lo;0;L;;;;;N;;;;;
+112A8;MULTANI LETTER RHA;Lo;0;L;;;;;N;;;;;
+112A9;MULTANI SECTION MARK;Po;0;L;;;;;N;;;;;
+112B0;KHUDAWADI LETTER A;Lo;0;L;;;;;N;;;;;
+112B1;KHUDAWADI LETTER AA;Lo;0;L;;;;;N;;;;;
+112B2;KHUDAWADI LETTER I;Lo;0;L;;;;;N;;;;;
+112B3;KHUDAWADI LETTER II;Lo;0;L;;;;;N;;;;;
+112B4;KHUDAWADI LETTER U;Lo;0;L;;;;;N;;;;;
+112B5;KHUDAWADI LETTER UU;Lo;0;L;;;;;N;;;;;
+112B6;KHUDAWADI LETTER E;Lo;0;L;;;;;N;;;;;
+112B7;KHUDAWADI LETTER AI;Lo;0;L;;;;;N;;;;;
+112B8;KHUDAWADI LETTER O;Lo;0;L;;;;;N;;;;;
+112B9;KHUDAWADI LETTER AU;Lo;0;L;;;;;N;;;;;
+112BA;KHUDAWADI LETTER KA;Lo;0;L;;;;;N;;;;;
+112BB;KHUDAWADI LETTER KHA;Lo;0;L;;;;;N;;;;;
+112BC;KHUDAWADI LETTER GA;Lo;0;L;;;;;N;;;;;
+112BD;KHUDAWADI LETTER GGA;Lo;0;L;;;;;N;;;;;
+112BE;KHUDAWADI LETTER GHA;Lo;0;L;;;;;N;;;;;
+112BF;KHUDAWADI LETTER NGA;Lo;0;L;;;;;N;;;;;
+112C0;KHUDAWADI LETTER CA;Lo;0;L;;;;;N;;;;;
+112C1;KHUDAWADI LETTER CHA;Lo;0;L;;;;;N;;;;;
+112C2;KHUDAWADI LETTER JA;Lo;0;L;;;;;N;;;;;
+112C3;KHUDAWADI LETTER JJA;Lo;0;L;;;;;N;;;;;
+112C4;KHUDAWADI LETTER JHA;Lo;0;L;;;;;N;;;;;
+112C5;KHUDAWADI LETTER NYA;Lo;0;L;;;;;N;;;;;
+112C6;KHUDAWADI LETTER TTA;Lo;0;L;;;;;N;;;;;
+112C7;KHUDAWADI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+112C8;KHUDAWADI LETTER DDA;Lo;0;L;;;;;N;;;;;
+112C9;KHUDAWADI LETTER DDDA;Lo;0;L;;;;;N;;;;;
+112CA;KHUDAWADI LETTER RRA;Lo;0;L;;;;;N;;;;;
+112CB;KHUDAWADI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+112CC;KHUDAWADI LETTER NNA;Lo;0;L;;;;;N;;;;;
+112CD;KHUDAWADI LETTER TA;Lo;0;L;;;;;N;;;;;
+112CE;KHUDAWADI LETTER THA;Lo;0;L;;;;;N;;;;;
+112CF;KHUDAWADI LETTER DA;Lo;0;L;;;;;N;;;;;
+112D0;KHUDAWADI LETTER DHA;Lo;0;L;;;;;N;;;;;
+112D1;KHUDAWADI LETTER NA;Lo;0;L;;;;;N;;;;;
+112D2;KHUDAWADI LETTER PA;Lo;0;L;;;;;N;;;;;
+112D3;KHUDAWADI LETTER PHA;Lo;0;L;;;;;N;;;;;
+112D4;KHUDAWADI LETTER BA;Lo;0;L;;;;;N;;;;;
+112D5;KHUDAWADI LETTER BBA;Lo;0;L;;;;;N;;;;;
+112D6;KHUDAWADI LETTER BHA;Lo;0;L;;;;;N;;;;;
+112D7;KHUDAWADI LETTER MA;Lo;0;L;;;;;N;;;;;
+112D8;KHUDAWADI LETTER YA;Lo;0;L;;;;;N;;;;;
+112D9;KHUDAWADI LETTER RA;Lo;0;L;;;;;N;;;;;
+112DA;KHUDAWADI LETTER LA;Lo;0;L;;;;;N;;;;;
+112DB;KHUDAWADI LETTER VA;Lo;0;L;;;;;N;;;;;
+112DC;KHUDAWADI LETTER SHA;Lo;0;L;;;;;N;;;;;
+112DD;KHUDAWADI LETTER SA;Lo;0;L;;;;;N;;;;;
+112DE;KHUDAWADI LETTER HA;Lo;0;L;;;;;N;;;;;
+112DF;KHUDAWADI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+112E0;KHUDAWADI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+112E1;KHUDAWADI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+112E2;KHUDAWADI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+112E3;KHUDAWADI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+112E4;KHUDAWADI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+112E5;KHUDAWADI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+112E6;KHUDAWADI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+112E7;KHUDAWADI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+112E8;KHUDAWADI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+112E9;KHUDAWADI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+112EA;KHUDAWADI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+112F0;KHUDAWADI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+112F1;KHUDAWADI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+112F2;KHUDAWADI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+112F3;KHUDAWADI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+112F4;KHUDAWADI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+112F5;KHUDAWADI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+112F6;KHUDAWADI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+112F7;KHUDAWADI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+112F8;KHUDAWADI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+112F9;KHUDAWADI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11300;GRANTHA SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;
+11301;GRANTHA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11302;GRANTHA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+11303;GRANTHA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11305;GRANTHA LETTER A;Lo;0;L;;;;;N;;;;;
+11306;GRANTHA LETTER AA;Lo;0;L;;;;;N;;;;;
+11307;GRANTHA LETTER I;Lo;0;L;;;;;N;;;;;
+11308;GRANTHA LETTER II;Lo;0;L;;;;;N;;;;;
+11309;GRANTHA LETTER U;Lo;0;L;;;;;N;;;;;
+1130A;GRANTHA LETTER UU;Lo;0;L;;;;;N;;;;;
+1130B;GRANTHA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1130C;GRANTHA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1130F;GRANTHA LETTER EE;Lo;0;L;;;;;N;;;;;
+11310;GRANTHA LETTER AI;Lo;0;L;;;;;N;;;;;
+11313;GRANTHA LETTER OO;Lo;0;L;;;;;N;;;;;
+11314;GRANTHA LETTER AU;Lo;0;L;;;;;N;;;;;
+11315;GRANTHA LETTER KA;Lo;0;L;;;;;N;;;;;
+11316;GRANTHA LETTER KHA;Lo;0;L;;;;;N;;;;;
+11317;GRANTHA LETTER GA;Lo;0;L;;;;;N;;;;;
+11318;GRANTHA LETTER GHA;Lo;0;L;;;;;N;;;;;
+11319;GRANTHA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1131A;GRANTHA LETTER CA;Lo;0;L;;;;;N;;;;;
+1131B;GRANTHA LETTER CHA;Lo;0;L;;;;;N;;;;;
+1131C;GRANTHA LETTER JA;Lo;0;L;;;;;N;;;;;
+1131D;GRANTHA LETTER JHA;Lo;0;L;;;;;N;;;;;
+1131E;GRANTHA LETTER NYA;Lo;0;L;;;;;N;;;;;
+1131F;GRANTHA LETTER TTA;Lo;0;L;;;;;N;;;;;
+11320;GRANTHA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11321;GRANTHA LETTER DDA;Lo;0;L;;;;;N;;;;;
+11322;GRANTHA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11323;GRANTHA LETTER NNA;Lo;0;L;;;;;N;;;;;
+11324;GRANTHA LETTER TA;Lo;0;L;;;;;N;;;;;
+11325;GRANTHA LETTER THA;Lo;0;L;;;;;N;;;;;
+11326;GRANTHA LETTER DA;Lo;0;L;;;;;N;;;;;
+11327;GRANTHA LETTER DHA;Lo;0;L;;;;;N;;;;;
+11328;GRANTHA LETTER NA;Lo;0;L;;;;;N;;;;;
+1132A;GRANTHA LETTER PA;Lo;0;L;;;;;N;;;;;
+1132B;GRANTHA LETTER PHA;Lo;0;L;;;;;N;;;;;
+1132C;GRANTHA LETTER BA;Lo;0;L;;;;;N;;;;;
+1132D;GRANTHA LETTER BHA;Lo;0;L;;;;;N;;;;;
+1132E;GRANTHA LETTER MA;Lo;0;L;;;;;N;;;;;
+1132F;GRANTHA LETTER YA;Lo;0;L;;;;;N;;;;;
+11330;GRANTHA LETTER RA;Lo;0;L;;;;;N;;;;;
+11332;GRANTHA LETTER LA;Lo;0;L;;;;;N;;;;;
+11333;GRANTHA LETTER LLA;Lo;0;L;;;;;N;;;;;
+11335;GRANTHA LETTER VA;Lo;0;L;;;;;N;;;;;
+11336;GRANTHA LETTER SHA;Lo;0;L;;;;;N;;;;;
+11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;;
+11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;;
+11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;;
+1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1133F;GRANTHA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11340;GRANTHA VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+11341;GRANTHA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+11342;GRANTHA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+11343;GRANTHA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+11344;GRANTHA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+11347;GRANTHA VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+11348;GRANTHA VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+1134B;GRANTHA VOWEL SIGN OO;Mc;0;L;11347 1133E;;;;N;;;;;
+1134C;GRANTHA VOWEL SIGN AU;Mc;0;L;11347 11357;;;;N;;;;;
+1134D;GRANTHA SIGN VIRAMA;Mc;9;L;;;;;N;;;;;
+11350;GRANTHA OM;Lo;0;L;;;;;N;;;;;
+11357;GRANTHA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+1135D;GRANTHA SIGN PLUTA;Lo;0;L;;;;;N;;;;;
+1135E;GRANTHA LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;
+1135F;GRANTHA LETTER VEDIC DOUBLE ANUSVARA;Lo;0;L;;;;;N;;;;;
+11360;GRANTHA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11361;GRANTHA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+11362;GRANTHA VOWEL SIGN VOCALIC L;Mc;0;L;;;;;N;;;;;
+11363;GRANTHA VOWEL SIGN VOCALIC LL;Mc;0;L;;;;;N;;;;;
+11366;COMBINING GRANTHA DIGIT ZERO;Mn;230;NSM;;;;;N;;;;;
+11367;COMBINING GRANTHA DIGIT ONE;Mn;230;NSM;;;;;N;;;;;
+11368;COMBINING GRANTHA DIGIT TWO;Mn;230;NSM;;;;;N;;;;;
+11369;COMBINING GRANTHA DIGIT THREE;Mn;230;NSM;;;;;N;;;;;
+1136A;COMBINING GRANTHA DIGIT FOUR;Mn;230;NSM;;;;;N;;;;;
+1136B;COMBINING GRANTHA DIGIT FIVE;Mn;230;NSM;;;;;N;;;;;
+1136C;COMBINING GRANTHA DIGIT SIX;Mn;230;NSM;;;;;N;;;;;
+11370;COMBINING GRANTHA LETTER A;Mn;230;NSM;;;;;N;;;;;
+11371;COMBINING GRANTHA LETTER KA;Mn;230;NSM;;;;;N;;;;;
+11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;;
+11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;;
+11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;;
+11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;;
+11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;;
+11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;;
+11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;;
+11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;;
+11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;;
+11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;;
+1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;;
+1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;;
+1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;;
+1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;;
+1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;;
+11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;;
+11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;;
+11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;;
+11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;;
+11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;;
+11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;;
+11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;;
+11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;;
+11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;;
+11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;;
+1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;;
+1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;;
+1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;;
+1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;;
+11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;;
+11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;;
+11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;;
+11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;;
+11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;;
+11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;;
+11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;;
+11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;;
+11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;;
+11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;;
+1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;;
+1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;;
+1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;;
+1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;;
+1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;;
+1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;;
+11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;;
+11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;;
+11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;;
+11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;;
+11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;;
+11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;;
+11449;NEWA OM;Lo;0;L;;;;;N;;;;;
+1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;;
+1144B;NEWA DANDA;Po;0;L;;;;;N;;;;;
+1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+1144D;NEWA COMMA;Po;0;L;;;;;N;;;;;
+1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;;
+1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;;
+1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;;
+11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;;
+11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;;
+11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;;
+11483;TIRHUTA LETTER I;Lo;0;L;;;;;N;;;;;
+11484;TIRHUTA LETTER II;Lo;0;L;;;;;N;;;;;
+11485;TIRHUTA LETTER U;Lo;0;L;;;;;N;;;;;
+11486;TIRHUTA LETTER UU;Lo;0;L;;;;;N;;;;;
+11487;TIRHUTA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+11488;TIRHUTA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11489;TIRHUTA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1148A;TIRHUTA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1148B;TIRHUTA LETTER E;Lo;0;L;;;;;N;;;;;
+1148C;TIRHUTA LETTER AI;Lo;0;L;;;;;N;;;;;
+1148D;TIRHUTA LETTER O;Lo;0;L;;;;;N;;;;;
+1148E;TIRHUTA LETTER AU;Lo;0;L;;;;;N;;;;;
+1148F;TIRHUTA LETTER KA;Lo;0;L;;;;;N;;;;;
+11490;TIRHUTA LETTER KHA;Lo;0;L;;;;;N;;;;;
+11491;TIRHUTA LETTER GA;Lo;0;L;;;;;N;;;;;
+11492;TIRHUTA LETTER GHA;Lo;0;L;;;;;N;;;;;
+11493;TIRHUTA LETTER NGA;Lo;0;L;;;;;N;;;;;
+11494;TIRHUTA LETTER CA;Lo;0;L;;;;;N;;;;;
+11495;TIRHUTA LETTER CHA;Lo;0;L;;;;;N;;;;;
+11496;TIRHUTA LETTER JA;Lo;0;L;;;;;N;;;;;
+11497;TIRHUTA LETTER JHA;Lo;0;L;;;;;N;;;;;
+11498;TIRHUTA LETTER NYA;Lo;0;L;;;;;N;;;;;
+11499;TIRHUTA LETTER TTA;Lo;0;L;;;;;N;;;;;
+1149A;TIRHUTA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1149B;TIRHUTA LETTER DDA;Lo;0;L;;;;;N;;;;;
+1149C;TIRHUTA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1149D;TIRHUTA LETTER NNA;Lo;0;L;;;;;N;;;;;
+1149E;TIRHUTA LETTER TA;Lo;0;L;;;;;N;;;;;
+1149F;TIRHUTA LETTER THA;Lo;0;L;;;;;N;;;;;
+114A0;TIRHUTA LETTER DA;Lo;0;L;;;;;N;;;;;
+114A1;TIRHUTA LETTER DHA;Lo;0;L;;;;;N;;;;;
+114A2;TIRHUTA LETTER NA;Lo;0;L;;;;;N;;;;;
+114A3;TIRHUTA LETTER PA;Lo;0;L;;;;;N;;;;;
+114A4;TIRHUTA LETTER PHA;Lo;0;L;;;;;N;;;;;
+114A5;TIRHUTA LETTER BA;Lo;0;L;;;;;N;;;;;
+114A6;TIRHUTA LETTER BHA;Lo;0;L;;;;;N;;;;;
+114A7;TIRHUTA LETTER MA;Lo;0;L;;;;;N;;;;;
+114A8;TIRHUTA LETTER YA;Lo;0;L;;;;;N;;;;;
+114A9;TIRHUTA LETTER RA;Lo;0;L;;;;;N;;;;;
+114AA;TIRHUTA LETTER LA;Lo;0;L;;;;;N;;;;;
+114AB;TIRHUTA LETTER VA;Lo;0;L;;;;;N;;;;;
+114AC;TIRHUTA LETTER SHA;Lo;0;L;;;;;N;;;;;
+114AD;TIRHUTA LETTER SSA;Lo;0;L;;;;;N;;;;;
+114AE;TIRHUTA LETTER SA;Lo;0;L;;;;;N;;;;;
+114AF;TIRHUTA LETTER HA;Lo;0;L;;;;;N;;;;;
+114B0;TIRHUTA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+114B1;TIRHUTA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+114B2;TIRHUTA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+114B3;TIRHUTA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+114B4;TIRHUTA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+114B5;TIRHUTA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+114B6;TIRHUTA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+114B7;TIRHUTA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+114B8;TIRHUTA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+114B9;TIRHUTA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+114BA;TIRHUTA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+114BB;TIRHUTA VOWEL SIGN AI;Mc;0;L;114B9 114BA;;;;N;;;;;
+114BC;TIRHUTA VOWEL SIGN O;Mc;0;L;114B9 114B0;;;;N;;;;;
+114BD;TIRHUTA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+114BE;TIRHUTA VOWEL SIGN AU;Mc;0;L;114B9 114BD;;;;N;;;;;
+114BF;TIRHUTA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+114C0;TIRHUTA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+114C1;TIRHUTA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+114C2;TIRHUTA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+114C3;TIRHUTA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+114C4;TIRHUTA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+114C5;TIRHUTA GVANG;Lo;0;L;;;;;N;;;;;
+114C6;TIRHUTA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+114C7;TIRHUTA OM;Lo;0;L;;;;;N;;;;;
+114D0;TIRHUTA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+114D1;TIRHUTA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+114D2;TIRHUTA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+114D3;TIRHUTA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+114D4;TIRHUTA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+114D5;TIRHUTA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+114D6;TIRHUTA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+114D7;TIRHUTA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+114D8;TIRHUTA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+114D9;TIRHUTA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11580;SIDDHAM LETTER A;Lo;0;L;;;;;N;;;;;
+11581;SIDDHAM LETTER AA;Lo;0;L;;;;;N;;;;;
+11582;SIDDHAM LETTER I;Lo;0;L;;;;;N;;;;;
+11583;SIDDHAM LETTER II;Lo;0;L;;;;;N;;;;;
+11584;SIDDHAM LETTER U;Lo;0;L;;;;;N;;;;;
+11585;SIDDHAM LETTER UU;Lo;0;L;;;;;N;;;;;
+11586;SIDDHAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+11587;SIDDHAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11588;SIDDHAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+11589;SIDDHAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1158A;SIDDHAM LETTER E;Lo;0;L;;;;;N;;;;;
+1158B;SIDDHAM LETTER AI;Lo;0;L;;;;;N;;;;;
+1158C;SIDDHAM LETTER O;Lo;0;L;;;;;N;;;;;
+1158D;SIDDHAM LETTER AU;Lo;0;L;;;;;N;;;;;
+1158E;SIDDHAM LETTER KA;Lo;0;L;;;;;N;;;;;
+1158F;SIDDHAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+11590;SIDDHAM LETTER GA;Lo;0;L;;;;;N;;;;;
+11591;SIDDHAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+11592;SIDDHAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+11593;SIDDHAM LETTER CA;Lo;0;L;;;;;N;;;;;
+11594;SIDDHAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+11595;SIDDHAM LETTER JA;Lo;0;L;;;;;N;;;;;
+11596;SIDDHAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+11597;SIDDHAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+11598;SIDDHAM LETTER TTA;Lo;0;L;;;;;N;;;;;
+11599;SIDDHAM LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1159A;SIDDHAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+1159B;SIDDHAM LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1159C;SIDDHAM LETTER NNA;Lo;0;L;;;;;N;;;;;
+1159D;SIDDHAM LETTER TA;Lo;0;L;;;;;N;;;;;
+1159E;SIDDHAM LETTER THA;Lo;0;L;;;;;N;;;;;
+1159F;SIDDHAM LETTER DA;Lo;0;L;;;;;N;;;;;
+115A0;SIDDHAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+115A1;SIDDHAM LETTER NA;Lo;0;L;;;;;N;;;;;
+115A2;SIDDHAM LETTER PA;Lo;0;L;;;;;N;;;;;
+115A3;SIDDHAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+115A4;SIDDHAM LETTER BA;Lo;0;L;;;;;N;;;;;
+115A5;SIDDHAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+115A6;SIDDHAM LETTER MA;Lo;0;L;;;;;N;;;;;
+115A7;SIDDHAM LETTER YA;Lo;0;L;;;;;N;;;;;
+115A8;SIDDHAM LETTER RA;Lo;0;L;;;;;N;;;;;
+115A9;SIDDHAM LETTER LA;Lo;0;L;;;;;N;;;;;
+115AA;SIDDHAM LETTER VA;Lo;0;L;;;;;N;;;;;
+115AB;SIDDHAM LETTER SHA;Lo;0;L;;;;;N;;;;;
+115AC;SIDDHAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+115AD;SIDDHAM LETTER SA;Lo;0;L;;;;;N;;;;;
+115AE;SIDDHAM LETTER HA;Lo;0;L;;;;;N;;;;;
+115AF;SIDDHAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+115B0;SIDDHAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+115B1;SIDDHAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+115B2;SIDDHAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+115B3;SIDDHAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+115B4;SIDDHAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+115B5;SIDDHAM VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+115B8;SIDDHAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+115B9;SIDDHAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+115BA;SIDDHAM VOWEL SIGN O;Mc;0;L;115B8 115AF;;;;N;;;;;
+115BB;SIDDHAM VOWEL SIGN AU;Mc;0;L;115B9 115AF;;;;N;;;;;
+115BC;SIDDHAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+115BD;SIDDHAM SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+115BE;SIDDHAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+115BF;SIDDHAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+115C0;SIDDHAM SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+115C1;SIDDHAM SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
+115C2;SIDDHAM DANDA;Po;0;L;;;;;N;;;;;
+115C3;SIDDHAM DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+115C4;SIDDHAM SEPARATOR DOT;Po;0;L;;;;;N;;;;;
+115C5;SIDDHAM SEPARATOR BAR;Po;0;L;;;;;N;;;;;
+115C6;SIDDHAM REPETITION MARK-1;Po;0;L;;;;;N;;;;;
+115C7;SIDDHAM REPETITION MARK-2;Po;0;L;;;;;N;;;;;
+115C8;SIDDHAM REPETITION MARK-3;Po;0;L;;;;;N;;;;;
+115C9;SIDDHAM END OF TEXT MARK;Po;0;L;;;;;N;;;;;
+115CA;SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS;Po;0;L;;;;;N;;;;;
+115CB;SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;;
+115CC;SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS;Po;0;L;;;;;N;;;;;
+115CD;SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115CE;SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115CF;SIDDHAM SECTION MARK DOUBLE RING;Po;0;L;;;;;N;;;;;
+115D0;SIDDHAM SECTION MARK DOUBLE RING WITH RAYS;Po;0;L;;;;;N;;;;;
+115D1;SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115D2;SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115D3;SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115D4;SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS;Po;0;L;;;;;N;;;;;
+115D5;SIDDHAM SECTION MARK WITH CIRCLES AND RAYS;Po;0;L;;;;;N;;;;;
+115D6;SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES;Po;0;L;;;;;N;;;;;
+115D7;SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES;Po;0;L;;;;;N;;;;;
+115D8;SIDDHAM LETTER THREE-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;;
+115D9;SIDDHAM LETTER TWO-CIRCLE ALTERNATE I;Lo;0;L;;;;;N;;;;;
+115DA;SIDDHAM LETTER TWO-CIRCLE ALTERNATE II;Lo;0;L;;;;;N;;;;;
+115DB;SIDDHAM LETTER ALTERNATE U;Lo;0;L;;;;;N;;;;;
+115DC;SIDDHAM VOWEL SIGN ALTERNATE U;Mn;0;NSM;;;;;N;;;;;
+115DD;SIDDHAM VOWEL SIGN ALTERNATE UU;Mn;0;NSM;;;;;N;;;;;
+11600;MODI LETTER A;Lo;0;L;;;;;N;;;;;
+11601;MODI LETTER AA;Lo;0;L;;;;;N;;;;;
+11602;MODI LETTER I;Lo;0;L;;;;;N;;;;;
+11603;MODI LETTER II;Lo;0;L;;;;;N;;;;;
+11604;MODI LETTER U;Lo;0;L;;;;;N;;;;;
+11605;MODI LETTER UU;Lo;0;L;;;;;N;;;;;
+11606;MODI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+11607;MODI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11608;MODI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+11609;MODI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1160A;MODI LETTER E;Lo;0;L;;;;;N;;;;;
+1160B;MODI LETTER AI;Lo;0;L;;;;;N;;;;;
+1160C;MODI LETTER O;Lo;0;L;;;;;N;;;;;
+1160D;MODI LETTER AU;Lo;0;L;;;;;N;;;;;
+1160E;MODI LETTER KA;Lo;0;L;;;;;N;;;;;
+1160F;MODI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11610;MODI LETTER GA;Lo;0;L;;;;;N;;;;;
+11611;MODI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11612;MODI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11613;MODI LETTER CA;Lo;0;L;;;;;N;;;;;
+11614;MODI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11615;MODI LETTER JA;Lo;0;L;;;;;N;;;;;
+11616;MODI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11617;MODI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11618;MODI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11619;MODI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+1161A;MODI LETTER DDA;Lo;0;L;;;;;N;;;;;
+1161B;MODI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+1161C;MODI LETTER NNA;Lo;0;L;;;;;N;;;;;
+1161D;MODI LETTER TA;Lo;0;L;;;;;N;;;;;
+1161E;MODI LETTER THA;Lo;0;L;;;;;N;;;;;
+1161F;MODI LETTER DA;Lo;0;L;;;;;N;;;;;
+11620;MODI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11621;MODI LETTER NA;Lo;0;L;;;;;N;;;;;
+11622;MODI LETTER PA;Lo;0;L;;;;;N;;;;;
+11623;MODI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11624;MODI LETTER BA;Lo;0;L;;;;;N;;;;;
+11625;MODI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11626;MODI LETTER MA;Lo;0;L;;;;;N;;;;;
+11627;MODI LETTER YA;Lo;0;L;;;;;N;;;;;
+11628;MODI LETTER RA;Lo;0;L;;;;;N;;;;;
+11629;MODI LETTER LA;Lo;0;L;;;;;N;;;;;
+1162A;MODI LETTER VA;Lo;0;L;;;;;N;;;;;
+1162B;MODI LETTER SHA;Lo;0;L;;;;;N;;;;;
+1162C;MODI LETTER SSA;Lo;0;L;;;;;N;;;;;
+1162D;MODI LETTER SA;Lo;0;L;;;;;N;;;;;
+1162E;MODI LETTER HA;Lo;0;L;;;;;N;;;;;
+1162F;MODI LETTER LLA;Lo;0;L;;;;;N;;;;;
+11630;MODI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11631;MODI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11632;MODI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+11633;MODI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11634;MODI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11635;MODI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11636;MODI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+11637;MODI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+11638;MODI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+11639;MODI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1163A;MODI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1163B;MODI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1163C;MODI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+1163D;MODI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1163E;MODI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+1163F;MODI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11640;MODI SIGN ARDHACANDRA;Mn;0;NSM;;;;;N;;;;;
+11641;MODI DANDA;Po;0;L;;;;;N;;;;;
+11642;MODI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+11643;MODI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+11644;MODI SIGN HUVA;Lo;0;L;;;;;N;;;;;
+11650;MODI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11651;MODI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11652;MODI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11653;MODI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11654;MODI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11655;MODI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11656;MODI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;
+11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;;
+11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;
+11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;
+11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;
+11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;
+11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;
+11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;;
+11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;
+11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;;
+1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;;
+1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;
+1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;;
+11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;;
+11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;;
+11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;;
+11683;TAKRI LETTER II;Lo;0;L;;;;;N;;;;;
+11684;TAKRI LETTER U;Lo;0;L;;;;;N;;;;;
+11685;TAKRI LETTER UU;Lo;0;L;;;;;N;;;;;
+11686;TAKRI LETTER E;Lo;0;L;;;;;N;;;;;
+11687;TAKRI LETTER AI;Lo;0;L;;;;;N;;;;;
+11688;TAKRI LETTER O;Lo;0;L;;;;;N;;;;;
+11689;TAKRI LETTER AU;Lo;0;L;;;;;N;;;;;
+1168A;TAKRI LETTER KA;Lo;0;L;;;;;N;;;;;
+1168B;TAKRI LETTER KHA;Lo;0;L;;;;;N;;;;;
+1168C;TAKRI LETTER GA;Lo;0;L;;;;;N;;;;;
+1168D;TAKRI LETTER GHA;Lo;0;L;;;;;N;;;;;
+1168E;TAKRI LETTER NGA;Lo;0;L;;;;;N;;;;;
+1168F;TAKRI LETTER CA;Lo;0;L;;;;;N;;;;;
+11690;TAKRI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11691;TAKRI LETTER JA;Lo;0;L;;;;;N;;;;;
+11692;TAKRI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11693;TAKRI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11694;TAKRI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11695;TAKRI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11696;TAKRI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11697;TAKRI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11698;TAKRI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11699;TAKRI LETTER TA;Lo;0;L;;;;;N;;;;;
+1169A;TAKRI LETTER THA;Lo;0;L;;;;;N;;;;;
+1169B;TAKRI LETTER DA;Lo;0;L;;;;;N;;;;;
+1169C;TAKRI LETTER DHA;Lo;0;L;;;;;N;;;;;
+1169D;TAKRI LETTER NA;Lo;0;L;;;;;N;;;;;
+1169E;TAKRI LETTER PA;Lo;0;L;;;;;N;;;;;
+1169F;TAKRI LETTER PHA;Lo;0;L;;;;;N;;;;;
+116A0;TAKRI LETTER BA;Lo;0;L;;;;;N;;;;;
+116A1;TAKRI LETTER BHA;Lo;0;L;;;;;N;;;;;
+116A2;TAKRI LETTER MA;Lo;0;L;;;;;N;;;;;
+116A3;TAKRI LETTER YA;Lo;0;L;;;;;N;;;;;
+116A4;TAKRI LETTER RA;Lo;0;L;;;;;N;;;;;
+116A5;TAKRI LETTER LA;Lo;0;L;;;;;N;;;;;
+116A6;TAKRI LETTER VA;Lo;0;L;;;;;N;;;;;
+116A7;TAKRI LETTER SHA;Lo;0;L;;;;;N;;;;;
+116A8;TAKRI LETTER SA;Lo;0;L;;;;;N;;;;;
+116A9;TAKRI LETTER HA;Lo;0;L;;;;;N;;;;;
+116AA;TAKRI LETTER RRA;Lo;0;L;;;;;N;;;;;
+116AB;TAKRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+116AC;TAKRI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+116AD;TAKRI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+116AE;TAKRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+116AF;TAKRI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+116B0;TAKRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+116B1;TAKRI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+116B2;TAKRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+116B3;TAKRI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+116B4;TAKRI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+116B5;TAKRI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+116B6;TAKRI SIGN VIRAMA;Mc;9;L;;;;;N;;;;;
+116B7;TAKRI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+116C0;TAKRI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+116C1;TAKRI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+116C2;TAKRI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+116C3;TAKRI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+116C4;TAKRI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+116C5;TAKRI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+116C6;TAKRI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+116C7;TAKRI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+116C8;TAKRI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+116C9;TAKRI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11700;AHOM LETTER KA;Lo;0;L;;;;;N;;;;;
+11701;AHOM LETTER KHA;Lo;0;L;;;;;N;;;;;
+11702;AHOM LETTER NGA;Lo;0;L;;;;;N;;;;;
+11703;AHOM LETTER NA;Lo;0;L;;;;;N;;;;;
+11704;AHOM LETTER TA;Lo;0;L;;;;;N;;;;;
+11705;AHOM LETTER ALTERNATE TA;Lo;0;L;;;;;N;;;;;
+11706;AHOM LETTER PA;Lo;0;L;;;;;N;;;;;
+11707;AHOM LETTER PHA;Lo;0;L;;;;;N;;;;;
+11708;AHOM LETTER BA;Lo;0;L;;;;;N;;;;;
+11709;AHOM LETTER MA;Lo;0;L;;;;;N;;;;;
+1170A;AHOM LETTER JA;Lo;0;L;;;;;N;;;;;
+1170B;AHOM LETTER CHA;Lo;0;L;;;;;N;;;;;
+1170C;AHOM LETTER THA;Lo;0;L;;;;;N;;;;;
+1170D;AHOM LETTER RA;Lo;0;L;;;;;N;;;;;
+1170E;AHOM LETTER LA;Lo;0;L;;;;;N;;;;;
+1170F;AHOM LETTER SA;Lo;0;L;;;;;N;;;;;
+11710;AHOM LETTER NYA;Lo;0;L;;;;;N;;;;;
+11711;AHOM LETTER HA;Lo;0;L;;;;;N;;;;;
+11712;AHOM LETTER A;Lo;0;L;;;;;N;;;;;
+11713;AHOM LETTER DA;Lo;0;L;;;;;N;;;;;
+11714;AHOM LETTER DHA;Lo;0;L;;;;;N;;;;;
+11715;AHOM LETTER GA;Lo;0;L;;;;;N;;;;;
+11716;AHOM LETTER ALTERNATE GA;Lo;0;L;;;;;N;;;;;
+11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;;
+11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;;
+11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;;
+1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;
+1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;;
+1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;;
+11720;AHOM VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+11721;AHOM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11722;AHOM VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11723;AHOM VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+11724;AHOM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11725;AHOM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11726;AHOM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+11727;AHOM VOWEL SIGN AW;Mn;0;NSM;;;;;N;;;;;
+11728;AHOM VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11729;AHOM VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1172A;AHOM VOWEL SIGN AM;Mn;0;NSM;;;;;N;;;;;
+1172B;AHOM SIGN KILLER;Mn;9;NSM;;;;;N;;;;;
+11730;AHOM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11731;AHOM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11732;AHOM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11733;AHOM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11734;AHOM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11735;AHOM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11736;AHOM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11737;AHOM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11738;AHOM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11739;AHOM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1173A;AHOM NUMBER TEN;No;0;L;;;;10;N;;;;;
+1173B;AHOM NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+1173C;AHOM SIGN SMALL SECTION;Po;0;L;;;;;N;;;;;
+1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;;
+1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;;
+1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;;
+118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0;
+118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1;
+118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2;
+118A3;WARANG CITI CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;118C3;
+118A4;WARANG CITI CAPITAL LETTER YA;Lu;0;L;;;;;N;;;;118C4;
+118A5;WARANG CITI CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;118C5;
+118A6;WARANG CITI CAPITAL LETTER II;Lu;0;L;;;;;N;;;;118C6;
+118A7;WARANG CITI CAPITAL LETTER UU;Lu;0;L;;;;;N;;;;118C7;
+118A8;WARANG CITI CAPITAL LETTER E;Lu;0;L;;;;;N;;;;118C8;
+118A9;WARANG CITI CAPITAL LETTER O;Lu;0;L;;;;;N;;;;118C9;
+118AA;WARANG CITI CAPITAL LETTER ANG;Lu;0;L;;;;;N;;;;118CA;
+118AB;WARANG CITI CAPITAL LETTER GA;Lu;0;L;;;;;N;;;;118CB;
+118AC;WARANG CITI CAPITAL LETTER KO;Lu;0;L;;;;;N;;;;118CC;
+118AD;WARANG CITI CAPITAL LETTER ENY;Lu;0;L;;;;;N;;;;118CD;
+118AE;WARANG CITI CAPITAL LETTER YUJ;Lu;0;L;;;;;N;;;;118CE;
+118AF;WARANG CITI CAPITAL LETTER UC;Lu;0;L;;;;;N;;;;118CF;
+118B0;WARANG CITI CAPITAL LETTER ENN;Lu;0;L;;;;;N;;;;118D0;
+118B1;WARANG CITI CAPITAL LETTER ODD;Lu;0;L;;;;;N;;;;118D1;
+118B2;WARANG CITI CAPITAL LETTER TTE;Lu;0;L;;;;;N;;;;118D2;
+118B3;WARANG CITI CAPITAL LETTER NUNG;Lu;0;L;;;;;N;;;;118D3;
+118B4;WARANG CITI CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;118D4;
+118B5;WARANG CITI CAPITAL LETTER AT;Lu;0;L;;;;;N;;;;118D5;
+118B6;WARANG CITI CAPITAL LETTER AM;Lu;0;L;;;;;N;;;;118D6;
+118B7;WARANG CITI CAPITAL LETTER BU;Lu;0;L;;;;;N;;;;118D7;
+118B8;WARANG CITI CAPITAL LETTER PU;Lu;0;L;;;;;N;;;;118D8;
+118B9;WARANG CITI CAPITAL LETTER HIYO;Lu;0;L;;;;;N;;;;118D9;
+118BA;WARANG CITI CAPITAL LETTER HOLO;Lu;0;L;;;;;N;;;;118DA;
+118BB;WARANG CITI CAPITAL LETTER HORR;Lu;0;L;;;;;N;;;;118DB;
+118BC;WARANG CITI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;118DC;
+118BD;WARANG CITI CAPITAL LETTER SSUU;Lu;0;L;;;;;N;;;;118DD;
+118BE;WARANG CITI CAPITAL LETTER SII;Lu;0;L;;;;;N;;;;118DE;
+118BF;WARANG CITI CAPITAL LETTER VIYO;Lu;0;L;;;;;N;;;;118DF;
+118C0;WARANG CITI SMALL LETTER NGAA;Ll;0;L;;;;;N;;;118A0;;118A0
+118C1;WARANG CITI SMALL LETTER A;Ll;0;L;;;;;N;;;118A1;;118A1
+118C2;WARANG CITI SMALL LETTER WI;Ll;0;L;;;;;N;;;118A2;;118A2
+118C3;WARANG CITI SMALL LETTER YU;Ll;0;L;;;;;N;;;118A3;;118A3
+118C4;WARANG CITI SMALL LETTER YA;Ll;0;L;;;;;N;;;118A4;;118A4
+118C5;WARANG CITI SMALL LETTER YO;Ll;0;L;;;;;N;;;118A5;;118A5
+118C6;WARANG CITI SMALL LETTER II;Ll;0;L;;;;;N;;;118A6;;118A6
+118C7;WARANG CITI SMALL LETTER UU;Ll;0;L;;;;;N;;;118A7;;118A7
+118C8;WARANG CITI SMALL LETTER E;Ll;0;L;;;;;N;;;118A8;;118A8
+118C9;WARANG CITI SMALL LETTER O;Ll;0;L;;;;;N;;;118A9;;118A9
+118CA;WARANG CITI SMALL LETTER ANG;Ll;0;L;;;;;N;;;118AA;;118AA
+118CB;WARANG CITI SMALL LETTER GA;Ll;0;L;;;;;N;;;118AB;;118AB
+118CC;WARANG CITI SMALL LETTER KO;Ll;0;L;;;;;N;;;118AC;;118AC
+118CD;WARANG CITI SMALL LETTER ENY;Ll;0;L;;;;;N;;;118AD;;118AD
+118CE;WARANG CITI SMALL LETTER YUJ;Ll;0;L;;;;;N;;;118AE;;118AE
+118CF;WARANG CITI SMALL LETTER UC;Ll;0;L;;;;;N;;;118AF;;118AF
+118D0;WARANG CITI SMALL LETTER ENN;Ll;0;L;;;;;N;;;118B0;;118B0
+118D1;WARANG CITI SMALL LETTER ODD;Ll;0;L;;;;;N;;;118B1;;118B1
+118D2;WARANG CITI SMALL LETTER TTE;Ll;0;L;;;;;N;;;118B2;;118B2
+118D3;WARANG CITI SMALL LETTER NUNG;Ll;0;L;;;;;N;;;118B3;;118B3
+118D4;WARANG CITI SMALL LETTER DA;Ll;0;L;;;;;N;;;118B4;;118B4
+118D5;WARANG CITI SMALL LETTER AT;Ll;0;L;;;;;N;;;118B5;;118B5
+118D6;WARANG CITI SMALL LETTER AM;Ll;0;L;;;;;N;;;118B6;;118B6
+118D7;WARANG CITI SMALL LETTER BU;Ll;0;L;;;;;N;;;118B7;;118B7
+118D8;WARANG CITI SMALL LETTER PU;Ll;0;L;;;;;N;;;118B8;;118B8
+118D9;WARANG CITI SMALL LETTER HIYO;Ll;0;L;;;;;N;;;118B9;;118B9
+118DA;WARANG CITI SMALL LETTER HOLO;Ll;0;L;;;;;N;;;118BA;;118BA
+118DB;WARANG CITI SMALL LETTER HORR;Ll;0;L;;;;;N;;;118BB;;118BB
+118DC;WARANG CITI SMALL LETTER HAR;Ll;0;L;;;;;N;;;118BC;;118BC
+118DD;WARANG CITI SMALL LETTER SSUU;Ll;0;L;;;;;N;;;118BD;;118BD
+118DE;WARANG CITI SMALL LETTER SII;Ll;0;L;;;;;N;;;118BE;;118BE
+118DF;WARANG CITI SMALL LETTER VIYO;Ll;0;L;;;;;N;;;118BF;;118BF
+118E0;WARANG CITI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+118E1;WARANG CITI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+118E2;WARANG CITI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+118E3;WARANG CITI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+118E4;WARANG CITI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+118E5;WARANG CITI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+118E6;WARANG CITI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+118E7;WARANG CITI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+118E8;WARANG CITI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+118E9;WARANG CITI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+118EA;WARANG CITI NUMBER TEN;No;0;L;;;;10;N;;;;;
+118EB;WARANG CITI NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+118EC;WARANG CITI NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+118ED;WARANG CITI NUMBER FORTY;No;0;L;;;;40;N;;;;;
+118EE;WARANG CITI NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+118EF;WARANG CITI NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+118F0;WARANG CITI NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;;
+118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;;
+11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;;
+11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;;
+11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;;
+11AC3;PAU CIN HAU LETTER MA;Lo;0;L;;;;;N;;;;;
+11AC4;PAU CIN HAU LETTER DA;Lo;0;L;;;;;N;;;;;
+11AC5;PAU CIN HAU LETTER ZA;Lo;0;L;;;;;N;;;;;
+11AC6;PAU CIN HAU LETTER VA;Lo;0;L;;;;;N;;;;;
+11AC7;PAU CIN HAU LETTER NGA;Lo;0;L;;;;;N;;;;;
+11AC8;PAU CIN HAU LETTER HA;Lo;0;L;;;;;N;;;;;
+11AC9;PAU CIN HAU LETTER GA;Lo;0;L;;;;;N;;;;;
+11ACA;PAU CIN HAU LETTER KHA;Lo;0;L;;;;;N;;;;;
+11ACB;PAU CIN HAU LETTER SA;Lo;0;L;;;;;N;;;;;
+11ACC;PAU CIN HAU LETTER BA;Lo;0;L;;;;;N;;;;;
+11ACD;PAU CIN HAU LETTER CA;Lo;0;L;;;;;N;;;;;
+11ACE;PAU CIN HAU LETTER TA;Lo;0;L;;;;;N;;;;;
+11ACF;PAU CIN HAU LETTER THA;Lo;0;L;;;;;N;;;;;
+11AD0;PAU CIN HAU LETTER NA;Lo;0;L;;;;;N;;;;;
+11AD1;PAU CIN HAU LETTER PHA;Lo;0;L;;;;;N;;;;;
+11AD2;PAU CIN HAU LETTER RA;Lo;0;L;;;;;N;;;;;
+11AD3;PAU CIN HAU LETTER FA;Lo;0;L;;;;;N;;;;;
+11AD4;PAU CIN HAU LETTER CHA;Lo;0;L;;;;;N;;;;;
+11AD5;PAU CIN HAU LETTER A;Lo;0;L;;;;;N;;;;;
+11AD6;PAU CIN HAU LETTER E;Lo;0;L;;;;;N;;;;;
+11AD7;PAU CIN HAU LETTER I;Lo;0;L;;;;;N;;;;;
+11AD8;PAU CIN HAU LETTER O;Lo;0;L;;;;;N;;;;;
+11AD9;PAU CIN HAU LETTER U;Lo;0;L;;;;;N;;;;;
+11ADA;PAU CIN HAU LETTER UA;Lo;0;L;;;;;N;;;;;
+11ADB;PAU CIN HAU LETTER IA;Lo;0;L;;;;;N;;;;;
+11ADC;PAU CIN HAU LETTER FINAL P;Lo;0;L;;;;;N;;;;;
+11ADD;PAU CIN HAU LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+11ADE;PAU CIN HAU LETTER FINAL T;Lo;0;L;;;;;N;;;;;
+11ADF;PAU CIN HAU LETTER FINAL M;Lo;0;L;;;;;N;;;;;
+11AE0;PAU CIN HAU LETTER FINAL N;Lo;0;L;;;;;N;;;;;
+11AE1;PAU CIN HAU LETTER FINAL L;Lo;0;L;;;;;N;;;;;
+11AE2;PAU CIN HAU LETTER FINAL W;Lo;0;L;;;;;N;;;;;
+11AE3;PAU CIN HAU LETTER FINAL NG;Lo;0;L;;;;;N;;;;;
+11AE4;PAU CIN HAU LETTER FINAL Y;Lo;0;L;;;;;N;;;;;
+11AE5;PAU CIN HAU RISING TONE LONG;Lo;0;L;;;;;N;;;;;
+11AE6;PAU CIN HAU RISING TONE;Lo;0;L;;;;;N;;;;;
+11AE7;PAU CIN HAU SANDHI GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+11AE8;PAU CIN HAU RISING TONE LONG FINAL;Lo;0;L;;;;;N;;;;;
+11AE9;PAU CIN HAU RISING TONE FINAL;Lo;0;L;;;;;N;;;;;
+11AEA;PAU CIN HAU SANDHI GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;;
+11AEB;PAU CIN HAU SANDHI TONE LONG;Lo;0;L;;;;;N;;;;;
+11AEC;PAU CIN HAU SANDHI TONE;Lo;0;L;;;;;N;;;;;
+11AED;PAU CIN HAU SANDHI TONE LONG FINAL;Lo;0;L;;;;;N;;;;;
+11AEE;PAU CIN HAU SANDHI TONE FINAL;Lo;0;L;;;;;N;;;;;
+11AEF;PAU CIN HAU MID-LEVEL TONE;Lo;0;L;;;;;N;;;;;
+11AF0;PAU CIN HAU GLOTTAL STOP VARIANT;Lo;0;L;;;;;N;;;;;
+11AF1;PAU CIN HAU MID-LEVEL TONE LONG FINAL;Lo;0;L;;;;;N;;;;;
+11AF2;PAU CIN HAU MID-LEVEL TONE FINAL;Lo;0;L;;;;;N;;;;;
+11AF3;PAU CIN HAU LOW-FALLING TONE LONG;Lo;0;L;;;;;N;;;;;
+11AF4;PAU CIN HAU LOW-FALLING TONE;Lo;0;L;;;;;N;;;;;
+11AF5;PAU CIN HAU GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;;
+11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;;
+11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;;
+11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;;
+11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;;
+11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;;
+11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;;
+11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;;
+11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;;
+11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;;
+11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;;
+11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;;
+11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;;
+11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;;
+11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;;
+11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;;
+11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;;
+11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;;
+11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;;
+11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;;
+11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;;
+11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;;
+11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;;
+11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;;
+11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;;
+11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;;
+11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;;
+11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;;
+11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;;
+11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;;
+11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;;
+11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;;
+11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;;
+11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;;
+11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;;
+11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;;
+11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;;
+11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;;
+11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;;
+11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;;
+11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;;
+11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;;
+11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;;
+11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;;
+11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;;
+11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;;
+11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;;
+11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;;
+11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;;
+11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;;
+11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;;
+11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;;
+11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;;
+11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;;
+11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;;
+11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;;
+11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;;
+11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;;
+11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;;
+11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;;
+11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;;
+11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;;
+11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;;
+11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;;
+11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;;
+11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;;
+11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;;
+11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;;
+11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;;
+11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;;
+11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;;
+11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;;
+11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;;
+11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;;
+11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;;
+11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;;
+11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;;
+11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;;
+11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;;
+11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;;
+11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;;
+11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;;
+11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;;
+11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;
+11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;
+11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;
+11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;
+11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;
+11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;
+11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;
+11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;
+11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;
+11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;
+11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;
+11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;
+11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;
+11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;
+11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;
+11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;
+11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;
+11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;
+11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;
+11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;;
+11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;
+11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;
+11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;;
+11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;;
+11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;
+11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;
+11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;
+11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;
+11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;
+11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;;
+12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;;
+12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;;
+12003;CUNEIFORM SIGN A TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12004;CUNEIFORM SIGN A TIMES HA;Lo;0;L;;;;;N;;;;;
+12005;CUNEIFORM SIGN A TIMES IGI;Lo;0;L;;;;;N;;;;;
+12006;CUNEIFORM SIGN A TIMES LAGAR GUNU;Lo;0;L;;;;;N;;;;;
+12007;CUNEIFORM SIGN A TIMES MUSH;Lo;0;L;;;;;N;;;;;
+12008;CUNEIFORM SIGN A TIMES SAG;Lo;0;L;;;;;N;;;;;
+12009;CUNEIFORM SIGN A2;Lo;0;L;;;;;N;;;;;
+1200A;CUNEIFORM SIGN AB;Lo;0;L;;;;;N;;;;;
+1200B;CUNEIFORM SIGN AB TIMES ASH2;Lo;0;L;;;;;N;;;;;
+1200C;CUNEIFORM SIGN AB TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;;
+1200D;CUNEIFORM SIGN AB TIMES GAL;Lo;0;L;;;;;N;;;;;
+1200E;CUNEIFORM SIGN AB TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1200F;CUNEIFORM SIGN AB TIMES HA;Lo;0;L;;;;;N;;;;;
+12010;CUNEIFORM SIGN AB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+12011;CUNEIFORM SIGN AB TIMES IMIN;Lo;0;L;;;;;N;;;;;
+12012;CUNEIFORM SIGN AB TIMES LAGAB;Lo;0;L;;;;;N;;;;;
+12013;CUNEIFORM SIGN AB TIMES SHESH;Lo;0;L;;;;;N;;;;;
+12014;CUNEIFORM SIGN AB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;
+12015;CUNEIFORM SIGN AB GUNU;Lo;0;L;;;;;N;;;;;
+12016;CUNEIFORM SIGN AB2;Lo;0;L;;;;;N;;;;;
+12017;CUNEIFORM SIGN AB2 TIMES BALAG;Lo;0;L;;;;;N;;;;;
+12018;CUNEIFORM SIGN AB2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12019;CUNEIFORM SIGN AB2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;
+1201A;CUNEIFORM SIGN AB2 TIMES SHA3;Lo;0;L;;;;;N;;;;;
+1201B;CUNEIFORM SIGN AB2 TIMES TAK4;Lo;0;L;;;;;N;;;;;
+1201C;CUNEIFORM SIGN AD;Lo;0;L;;;;;N;;;;;
+1201D;CUNEIFORM SIGN AK;Lo;0;L;;;;;N;;;;;
+1201E;CUNEIFORM SIGN AK TIMES ERIN2;Lo;0;L;;;;;N;;;;;
+1201F;CUNEIFORM SIGN AK TIMES SHITA PLUS GISH;Lo;0;L;;;;;N;;;;;
+12020;CUNEIFORM SIGN AL;Lo;0;L;;;;;N;;;;;
+12021;CUNEIFORM SIGN AL TIMES AL;Lo;0;L;;;;;N;;;;;
+12022;CUNEIFORM SIGN AL TIMES DIM2;Lo;0;L;;;;;N;;;;;
+12023;CUNEIFORM SIGN AL TIMES GISH;Lo;0;L;;;;;N;;;;;
+12024;CUNEIFORM SIGN AL TIMES HA;Lo;0;L;;;;;N;;;;;
+12025;CUNEIFORM SIGN AL TIMES KAD3;Lo;0;L;;;;;N;;;;;
+12026;CUNEIFORM SIGN AL TIMES KI;Lo;0;L;;;;;N;;;;;
+12027;CUNEIFORM SIGN AL TIMES SHE;Lo;0;L;;;;;N;;;;;
+12028;CUNEIFORM SIGN AL TIMES USH;Lo;0;L;;;;;N;;;;;
+12029;CUNEIFORM SIGN ALAN;Lo;0;L;;;;;N;;;;;
+1202A;CUNEIFORM SIGN ALEPH;Lo;0;L;;;;;N;;;;;
+1202B;CUNEIFORM SIGN AMAR;Lo;0;L;;;;;N;;;;;
+1202C;CUNEIFORM SIGN AMAR TIMES SHE;Lo;0;L;;;;;N;;;;;
+1202D;CUNEIFORM SIGN AN;Lo;0;L;;;;;N;;;;;
+1202E;CUNEIFORM SIGN AN OVER AN;Lo;0;L;;;;;N;;;;;
+1202F;CUNEIFORM SIGN AN THREE TIMES;Lo;0;L;;;;;N;;;;;
+12030;CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA;Lo;0;L;;;;;N;;;;;
+12031;CUNEIFORM SIGN AN PLUS NAGA SQUARED;Lo;0;L;;;;;N;;;;;
+12032;CUNEIFORM SIGN ANSHE;Lo;0;L;;;;;N;;;;;
+12033;CUNEIFORM SIGN APIN;Lo;0;L;;;;;N;;;;;
+12034;CUNEIFORM SIGN ARAD;Lo;0;L;;;;;N;;;;;
+12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;;
+12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;;
+12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;;
+12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;;N;;;;;
+12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;;N;;;;;
+1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;;
+1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;;
+1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;;
+1203D;CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;;
+1203E;CUNEIFORM SIGN ASH2;Lo;0;L;;;;;N;;;;;
+1203F;CUNEIFORM SIGN ASHGAB;Lo;0;L;;;;;N;;;;;
+12040;CUNEIFORM SIGN BA;Lo;0;L;;;;;N;;;;;
+12041;CUNEIFORM SIGN BAD;Lo;0;L;;;;;N;;;;;
+12042;CUNEIFORM SIGN BAG3;Lo;0;L;;;;;N;;;;;
+12043;CUNEIFORM SIGN BAHAR2;Lo;0;L;;;;;N;;;;;
+12044;CUNEIFORM SIGN BAL;Lo;0;L;;;;;N;;;;;
+12045;CUNEIFORM SIGN BAL OVER BAL;Lo;0;L;;;;;N;;;;;
+12046;CUNEIFORM SIGN BALAG;Lo;0;L;;;;;N;;;;;
+12047;CUNEIFORM SIGN BAR;Lo;0;L;;;;;N;;;;;
+12048;CUNEIFORM SIGN BARA2;Lo;0;L;;;;;N;;;;;
+12049;CUNEIFORM SIGN BI;Lo;0;L;;;;;N;;;;;
+1204A;CUNEIFORM SIGN BI TIMES A;Lo;0;L;;;;;N;;;;;
+1204B;CUNEIFORM SIGN BI TIMES GAR;Lo;0;L;;;;;N;;;;;
+1204C;CUNEIFORM SIGN BI TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+1204D;CUNEIFORM SIGN BU;Lo;0;L;;;;;N;;;;;
+1204E;CUNEIFORM SIGN BU OVER BU AB;Lo;0;L;;;;;N;;;;;
+1204F;CUNEIFORM SIGN BU OVER BU UN;Lo;0;L;;;;;N;;;;;
+12050;CUNEIFORM SIGN BU CROSSING BU;Lo;0;L;;;;;N;;;;;
+12051;CUNEIFORM SIGN BULUG;Lo;0;L;;;;;N;;;;;
+12052;CUNEIFORM SIGN BULUG OVER BULUG;Lo;0;L;;;;;N;;;;;
+12053;CUNEIFORM SIGN BUR;Lo;0;L;;;;;N;;;;;
+12054;CUNEIFORM SIGN BUR2;Lo;0;L;;;;;N;;;;;
+12055;CUNEIFORM SIGN DA;Lo;0;L;;;;;N;;;;;
+12056;CUNEIFORM SIGN DAG;Lo;0;L;;;;;N;;;;;
+12057;CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH;Lo;0;L;;;;;N;;;;;
+12058;CUNEIFORM SIGN DAG KISIM5 TIMES AMAR;Lo;0;L;;;;;N;;;;;
+12059;CUNEIFORM SIGN DAG KISIM5 TIMES BALAG;Lo;0;L;;;;;N;;;;;
+1205A;CUNEIFORM SIGN DAG KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;;
+1205B;CUNEIFORM SIGN DAG KISIM5 TIMES GA;Lo;0;L;;;;;N;;;;;
+1205C;CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH;Lo;0;L;;;;;N;;;;;
+1205D;CUNEIFORM SIGN DAG KISIM5 TIMES GI;Lo;0;L;;;;;N;;;;;
+1205E;CUNEIFORM SIGN DAG KISIM5 TIMES GIR2;Lo;0;L;;;;;N;;;;;
+1205F;CUNEIFORM SIGN DAG KISIM5 TIMES GUD;Lo;0;L;;;;;N;;;;;
+12060;CUNEIFORM SIGN DAG KISIM5 TIMES HA;Lo;0;L;;;;;N;;;;;
+12061;CUNEIFORM SIGN DAG KISIM5 TIMES IR;Lo;0;L;;;;;N;;;;;
+12062;CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU;Lo;0;L;;;;;N;;;;;
+12063;CUNEIFORM SIGN DAG KISIM5 TIMES KAK;Lo;0;L;;;;;N;;;;;
+12064;CUNEIFORM SIGN DAG KISIM5 TIMES LA;Lo;0;L;;;;;N;;;;;
+12065;CUNEIFORM SIGN DAG KISIM5 TIMES LU;Lo;0;L;;;;;N;;;;;
+12066;CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2;Lo;0;L;;;;;N;;;;;
+12067;CUNEIFORM SIGN DAG KISIM5 TIMES LUM;Lo;0;L;;;;;N;;;;;
+12068;CUNEIFORM SIGN DAG KISIM5 TIMES NE;Lo;0;L;;;;;N;;;;;
+12069;CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;;
+1206A;CUNEIFORM SIGN DAG KISIM5 TIMES SI;Lo;0;L;;;;;N;;;;;
+1206B;CUNEIFORM SIGN DAG KISIM5 TIMES TAK4;Lo;0;L;;;;;N;;;;;
+1206C;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2;Lo;0;L;;;;;N;;;;;
+1206D;CUNEIFORM SIGN DAG KISIM5 TIMES USH;Lo;0;L;;;;;N;;;;;
+1206E;CUNEIFORM SIGN DAM;Lo;0;L;;;;;N;;;;;
+1206F;CUNEIFORM SIGN DAR;Lo;0;L;;;;;N;;;;;
+12070;CUNEIFORM SIGN DARA3;Lo;0;L;;;;;N;;;;;
+12071;CUNEIFORM SIGN DARA4;Lo;0;L;;;;;N;;;;;
+12072;CUNEIFORM SIGN DI;Lo;0;L;;;;;N;;;;;
+12073;CUNEIFORM SIGN DIB;Lo;0;L;;;;;N;;;;;
+12074;CUNEIFORM SIGN DIM;Lo;0;L;;;;;N;;;;;
+12075;CUNEIFORM SIGN DIM TIMES SHE;Lo;0;L;;;;;N;;;;;
+12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;;
+12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;;
+12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;;
+12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;;N;;;;;
+1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;;
+1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;;
+1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;;
+1207D;CUNEIFORM SIGN DU SHESHIG;Lo;0;L;;;;;N;;;;;
+1207E;CUNEIFORM SIGN DUB;Lo;0;L;;;;;N;;;;;
+1207F;CUNEIFORM SIGN DUB TIMES ESH2;Lo;0;L;;;;;N;;;;;
+12080;CUNEIFORM SIGN DUB2;Lo;0;L;;;;;N;;;;;
+12081;CUNEIFORM SIGN DUG;Lo;0;L;;;;;N;;;;;
+12082;CUNEIFORM SIGN DUGUD;Lo;0;L;;;;;N;;;;;
+12083;CUNEIFORM SIGN DUH;Lo;0;L;;;;;N;;;;;
+12084;CUNEIFORM SIGN DUN;Lo;0;L;;;;;N;;;;;
+12085;CUNEIFORM SIGN DUN3;Lo;0;L;;;;;N;;;;;
+12086;CUNEIFORM SIGN DUN3 GUNU;Lo;0;L;;;;;N;;;;;
+12087;CUNEIFORM SIGN DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;
+12088;CUNEIFORM SIGN DUN4;Lo;0;L;;;;;N;;;;;
+12089;CUNEIFORM SIGN DUR2;Lo;0;L;;;;;N;;;;;
+1208A;CUNEIFORM SIGN E;Lo;0;L;;;;;N;;;;;
+1208B;CUNEIFORM SIGN E TIMES PAP;Lo;0;L;;;;;N;;;;;
+1208C;CUNEIFORM SIGN E OVER E NUN OVER NUN;Lo;0;L;;;;;N;;;;;
+1208D;CUNEIFORM SIGN E2;Lo;0;L;;;;;N;;;;;
+1208E;CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA;Lo;0;L;;;;;N;;;;;
+1208F;CUNEIFORM SIGN E2 TIMES GAR;Lo;0;L;;;;;N;;;;;
+12090;CUNEIFORM SIGN E2 TIMES MI;Lo;0;L;;;;;N;;;;;
+12091;CUNEIFORM SIGN E2 TIMES SAL;Lo;0;L;;;;;N;;;;;
+12092;CUNEIFORM SIGN E2 TIMES SHE;Lo;0;L;;;;;N;;;;;
+12093;CUNEIFORM SIGN E2 TIMES U;Lo;0;L;;;;;N;;;;;
+12094;CUNEIFORM SIGN EDIN;Lo;0;L;;;;;N;;;;;
+12095;CUNEIFORM SIGN EGIR;Lo;0;L;;;;;N;;;;;
+12096;CUNEIFORM SIGN EL;Lo;0;L;;;;;N;;;;;
+12097;CUNEIFORM SIGN EN;Lo;0;L;;;;;N;;;;;
+12098;CUNEIFORM SIGN EN TIMES GAN2;Lo;0;L;;;;;N;;;;;
+12099;CUNEIFORM SIGN EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1209A;CUNEIFORM SIGN EN TIMES ME;Lo;0;L;;;;;N;;;;;
+1209B;CUNEIFORM SIGN EN CROSSING EN;Lo;0;L;;;;;N;;;;;
+1209C;CUNEIFORM SIGN EN OPPOSING EN;Lo;0;L;;;;;N;;;;;
+1209D;CUNEIFORM SIGN EN SQUARED;Lo;0;L;;;;;N;;;;;
+1209E;CUNEIFORM SIGN EREN;Lo;0;L;;;;;N;;;;;
+1209F;CUNEIFORM SIGN ERIN2;Lo;0;L;;;;;N;;;;;
+120A0;CUNEIFORM SIGN ESH2;Lo;0;L;;;;;N;;;;;
+120A1;CUNEIFORM SIGN EZEN;Lo;0;L;;;;;N;;;;;
+120A2;CUNEIFORM SIGN EZEN TIMES A;Lo;0;L;;;;;N;;;;;
+120A3;CUNEIFORM SIGN EZEN TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;;
+120A4;CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL;Lo;0;L;;;;;N;;;;;
+120A5;CUNEIFORM SIGN EZEN TIMES AN;Lo;0;L;;;;;N;;;;;
+120A6;CUNEIFORM SIGN EZEN TIMES BAD;Lo;0;L;;;;;N;;;;;
+120A7;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU;Lo;0;L;;;;;N;;;;;
+120A8;CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;
+120A9;CUNEIFORM SIGN EZEN TIMES HA;Lo;0;L;;;;;N;;;;;
+120AA;CUNEIFORM SIGN EZEN TIMES HA GUNU;Lo;0;L;;;;;N;;;;;
+120AB;CUNEIFORM SIGN EZEN TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+120AC;CUNEIFORM SIGN EZEN TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+120AD;CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED;Lo;0;L;;;;;N;;;;;
+120AE;CUNEIFORM SIGN EZEN TIMES KU3;Lo;0;L;;;;;N;;;;;
+120AF;CUNEIFORM SIGN EZEN TIMES LA;Lo;0;L;;;;;N;;;;;
+120B0;CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL;Lo;0;L;;;;;N;;;;;
+120B1;CUNEIFORM SIGN EZEN TIMES LI;Lo;0;L;;;;;N;;;;;
+120B2;CUNEIFORM SIGN EZEN TIMES LU;Lo;0;L;;;;;N;;;;;
+120B3;CUNEIFORM SIGN EZEN TIMES U2;Lo;0;L;;;;;N;;;;;
+120B4;CUNEIFORM SIGN EZEN TIMES UD;Lo;0;L;;;;;N;;;;;
+120B5;CUNEIFORM SIGN GA;Lo;0;L;;;;;N;;;;;
+120B6;CUNEIFORM SIGN GA GUNU;Lo;0;L;;;;;N;;;;;
+120B7;CUNEIFORM SIGN GA2;Lo;0;L;;;;;N;;;;;
+120B8;CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;;
+120B9;CUNEIFORM SIGN GA2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;;
+120BA;CUNEIFORM SIGN GA2 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;;
+120BB;CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB;Lo;0;L;;;;;N;;;;;
+120BC;CUNEIFORM SIGN GA2 TIMES AN;Lo;0;L;;;;;N;;;;;
+120BD;CUNEIFORM SIGN GA2 TIMES ASH;Lo;0;L;;;;;N;;;;;
+120BE;CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL;Lo;0;L;;;;;N;;;;;
+120BF;CUNEIFORM SIGN GA2 TIMES BAD;Lo;0;L;;;;;N;;;;;
+120C0;CUNEIFORM SIGN GA2 TIMES BAR PLUS RA;Lo;0;L;;;;;N;;;;;
+120C1;CUNEIFORM SIGN GA2 TIMES BUR;Lo;0;L;;;;;N;;;;;
+120C2;CUNEIFORM SIGN GA2 TIMES BUR PLUS RA;Lo;0;L;;;;;N;;;;;
+120C3;CUNEIFORM SIGN GA2 TIMES DA;Lo;0;L;;;;;N;;;;;
+120C4;CUNEIFORM SIGN GA2 TIMES DI;Lo;0;L;;;;;N;;;;;
+120C5;CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE;Lo;0;L;;;;;N;;;;;
+120C6;CUNEIFORM SIGN GA2 TIMES DUB;Lo;0;L;;;;;N;;;;;
+120C7;CUNEIFORM SIGN GA2 TIMES EL;Lo;0;L;;;;;N;;;;;
+120C8;CUNEIFORM SIGN GA2 TIMES EL PLUS LA;Lo;0;L;;;;;N;;;;;
+120C9;CUNEIFORM SIGN GA2 TIMES EN;Lo;0;L;;;;;N;;;;;
+120CA;CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+120CB;CUNEIFORM SIGN GA2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+120CC;CUNEIFORM SIGN GA2 TIMES GAR;Lo;0;L;;;;;N;;;;;
+120CD;CUNEIFORM SIGN GA2 TIMES GI;Lo;0;L;;;;;N;;;;;
+120CE;CUNEIFORM SIGN GA2 TIMES GI4;Lo;0;L;;;;;N;;;;;
+120CF;CUNEIFORM SIGN GA2 TIMES GI4 PLUS A;Lo;0;L;;;;;N;;;;;
+120D0;CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU;Lo;0;L;;;;;N;;;;;
+120D1;CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2;Lo;0;L;;;;;N;;;;;
+120D2;CUNEIFORM SIGN GA2 TIMES HAL;Lo;0;L;;;;;N;;;;;
+120D3;CUNEIFORM SIGN GA2 TIMES HAL PLUS LA;Lo;0;L;;;;;N;;;;;
+120D4;CUNEIFORM SIGN GA2 TIMES HI PLUS LI;Lo;0;L;;;;;N;;;;;
+120D5;CUNEIFORM SIGN GA2 TIMES HUB2;Lo;0;L;;;;;N;;;;;
+120D6;CUNEIFORM SIGN GA2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+120D7;CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH;Lo;0;L;;;;;N;;;;;
+120D8;CUNEIFORM SIGN GA2 TIMES KAK;Lo;0;L;;;;;N;;;;;
+120D9;CUNEIFORM SIGN GA2 TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+120DA;CUNEIFORM SIGN GA2 TIMES KID;Lo;0;L;;;;;N;;;;;
+120DB;CUNEIFORM SIGN GA2 TIMES KID PLUS LAL;Lo;0;L;;;;;N;;;;;
+120DC;CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN;Lo;0;L;;;;;N;;;;;
+120DD;CUNEIFORM SIGN GA2 TIMES LA;Lo;0;L;;;;;N;;;;;
+120DE;CUNEIFORM SIGN GA2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;
+120DF;CUNEIFORM SIGN GA2 TIMES MI;Lo;0;L;;;;;N;;;;;
+120E0;CUNEIFORM SIGN GA2 TIMES NUN;Lo;0;L;;;;;N;;;;;
+120E1;CUNEIFORM SIGN GA2 TIMES NUN OVER NUN;Lo;0;L;;;;;N;;;;;
+120E2;CUNEIFORM SIGN GA2 TIMES PA;Lo;0;L;;;;;N;;;;;
+120E3;CUNEIFORM SIGN GA2 TIMES SAL;Lo;0;L;;;;;N;;;;;
+120E4;CUNEIFORM SIGN GA2 TIMES SAR;Lo;0;L;;;;;N;;;;;
+120E5;CUNEIFORM SIGN GA2 TIMES SHE;Lo;0;L;;;;;N;;;;;
+120E6;CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR;Lo;0;L;;;;;N;;;;;
+120E7;CUNEIFORM SIGN GA2 TIMES SHID;Lo;0;L;;;;;N;;;;;
+120E8;CUNEIFORM SIGN GA2 TIMES SUM;Lo;0;L;;;;;N;;;;;
+120E9;CUNEIFORM SIGN GA2 TIMES TAK4;Lo;0;L;;;;;N;;;;;
+120EA;CUNEIFORM SIGN GA2 TIMES U;Lo;0;L;;;;;N;;;;;
+120EB;CUNEIFORM SIGN GA2 TIMES UD;Lo;0;L;;;;;N;;;;;
+120EC;CUNEIFORM SIGN GA2 TIMES UD PLUS DU;Lo;0;L;;;;;N;;;;;
+120ED;CUNEIFORM SIGN GA2 OVER GA2;Lo;0;L;;;;;N;;;;;
+120EE;CUNEIFORM SIGN GABA;Lo;0;L;;;;;N;;;;;
+120EF;CUNEIFORM SIGN GABA CROSSING GABA;Lo;0;L;;;;;N;;;;;
+120F0;CUNEIFORM SIGN GAD;Lo;0;L;;;;;N;;;;;
+120F1;CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+120F2;CUNEIFORM SIGN GAL;Lo;0;L;;;;;N;;;;;
+120F3;CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+120F4;CUNEIFORM SIGN GALAM;Lo;0;L;;;;;N;;;;;
+120F5;CUNEIFORM SIGN GAM;Lo;0;L;;;;;N;;;;;
+120F6;CUNEIFORM SIGN GAN;Lo;0;L;;;;;N;;;;;
+120F7;CUNEIFORM SIGN GAN2;Lo;0;L;;;;;N;;;;;
+120F8;CUNEIFORM SIGN GAN2 TENU;Lo;0;L;;;;;N;;;;;
+120F9;CUNEIFORM SIGN GAN2 OVER GAN2;Lo;0;L;;;;;N;;;;;
+120FA;CUNEIFORM SIGN GAN2 CROSSING GAN2;Lo;0;L;;;;;N;;;;;
+120FB;CUNEIFORM SIGN GAR;Lo;0;L;;;;;N;;;;;
+120FC;CUNEIFORM SIGN GAR3;Lo;0;L;;;;;N;;;;;
+120FD;CUNEIFORM SIGN GASHAN;Lo;0;L;;;;;N;;;;;
+120FE;CUNEIFORM SIGN GESHTIN;Lo;0;L;;;;;N;;;;;
+120FF;CUNEIFORM SIGN GESHTIN TIMES KUR;Lo;0;L;;;;;N;;;;;
+12100;CUNEIFORM SIGN GI;Lo;0;L;;;;;N;;;;;
+12101;CUNEIFORM SIGN GI TIMES E;Lo;0;L;;;;;N;;;;;
+12102;CUNEIFORM SIGN GI TIMES U;Lo;0;L;;;;;N;;;;;
+12103;CUNEIFORM SIGN GI CROSSING GI;Lo;0;L;;;;;N;;;;;
+12104;CUNEIFORM SIGN GI4;Lo;0;L;;;;;N;;;;;
+12105;CUNEIFORM SIGN GI4 OVER GI4;Lo;0;L;;;;;N;;;;;
+12106;CUNEIFORM SIGN GI4 CROSSING GI4;Lo;0;L;;;;;N;;;;;
+12107;CUNEIFORM SIGN GIDIM;Lo;0;L;;;;;N;;;;;
+12108;CUNEIFORM SIGN GIR2;Lo;0;L;;;;;N;;;;;
+12109;CUNEIFORM SIGN GIR2 GUNU;Lo;0;L;;;;;N;;;;;
+1210A;CUNEIFORM SIGN GIR3;Lo;0;L;;;;;N;;;;;
+1210B;CUNEIFORM SIGN GIR3 TIMES A PLUS IGI;Lo;0;L;;;;;N;;;;;
+1210C;CUNEIFORM SIGN GIR3 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1210D;CUNEIFORM SIGN GIR3 TIMES IGI;Lo;0;L;;;;;N;;;;;
+1210E;CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI;Lo;0;L;;;;;N;;;;;
+1210F;CUNEIFORM SIGN GIR3 TIMES PA;Lo;0;L;;;;;N;;;;;
+12110;CUNEIFORM SIGN GISAL;Lo;0;L;;;;;N;;;;;
+12111;CUNEIFORM SIGN GISH;Lo;0;L;;;;;N;;;;;
+12112;CUNEIFORM SIGN GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;
+12113;CUNEIFORM SIGN GISH TIMES BAD;Lo;0;L;;;;;N;;;;;
+12114;CUNEIFORM SIGN GISH TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12115;CUNEIFORM SIGN GISH TENU;Lo;0;L;;;;;N;;;;;
+12116;CUNEIFORM SIGN GU;Lo;0;L;;;;;N;;;;;
+12117;CUNEIFORM SIGN GU CROSSING GU;Lo;0;L;;;;;N;;;;;
+12118;CUNEIFORM SIGN GU2;Lo;0;L;;;;;N;;;;;
+12119;CUNEIFORM SIGN GU2 TIMES KAK;Lo;0;L;;;;;N;;;;;
+1211A;CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+1211B;CUNEIFORM SIGN GU2 TIMES NUN;Lo;0;L;;;;;N;;;;;
+1211C;CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2;Lo;0;L;;;;;N;;;;;
+1211D;CUNEIFORM SIGN GU2 GUNU;Lo;0;L;;;;;N;;;;;
+1211E;CUNEIFORM SIGN GUD;Lo;0;L;;;;;N;;;;;
+1211F;CUNEIFORM SIGN GUD TIMES A PLUS KUR;Lo;0;L;;;;;N;;;;;
+12120;CUNEIFORM SIGN GUD TIMES KUR;Lo;0;L;;;;;N;;;;;
+12121;CUNEIFORM SIGN GUD OVER GUD LUGAL;Lo;0;L;;;;;N;;;;;
+12122;CUNEIFORM SIGN GUL;Lo;0;L;;;;;N;;;;;
+12123;CUNEIFORM SIGN GUM;Lo;0;L;;;;;N;;;;;
+12124;CUNEIFORM SIGN GUM TIMES SHE;Lo;0;L;;;;;N;;;;;
+12125;CUNEIFORM SIGN GUR;Lo;0;L;;;;;N;;;;;
+12126;CUNEIFORM SIGN GUR7;Lo;0;L;;;;;N;;;;;
+12127;CUNEIFORM SIGN GURUN;Lo;0;L;;;;;N;;;;;
+12128;CUNEIFORM SIGN GURUSH;Lo;0;L;;;;;N;;;;;
+12129;CUNEIFORM SIGN HA;Lo;0;L;;;;;N;;;;;
+1212A;CUNEIFORM SIGN HA TENU;Lo;0;L;;;;;N;;;;;
+1212B;CUNEIFORM SIGN HA GUNU;Lo;0;L;;;;;N;;;;;
+1212C;CUNEIFORM SIGN HAL;Lo;0;L;;;;;N;;;;;
+1212D;CUNEIFORM SIGN HI;Lo;0;L;;;;;N;;;;;
+1212E;CUNEIFORM SIGN HI TIMES ASH;Lo;0;L;;;;;N;;;;;
+1212F;CUNEIFORM SIGN HI TIMES ASH2;Lo;0;L;;;;;N;;;;;
+12130;CUNEIFORM SIGN HI TIMES BAD;Lo;0;L;;;;;N;;;;;
+12131;CUNEIFORM SIGN HI TIMES DISH;Lo;0;L;;;;;N;;;;;
+12132;CUNEIFORM SIGN HI TIMES GAD;Lo;0;L;;;;;N;;;;;
+12133;CUNEIFORM SIGN HI TIMES KIN;Lo;0;L;;;;;N;;;;;
+12134;CUNEIFORM SIGN HI TIMES NUN;Lo;0;L;;;;;N;;;;;
+12135;CUNEIFORM SIGN HI TIMES SHE;Lo;0;L;;;;;N;;;;;
+12136;CUNEIFORM SIGN HI TIMES U;Lo;0;L;;;;;N;;;;;
+12137;CUNEIFORM SIGN HU;Lo;0;L;;;;;N;;;;;
+12138;CUNEIFORM SIGN HUB2;Lo;0;L;;;;;N;;;;;
+12139;CUNEIFORM SIGN HUB2 TIMES AN;Lo;0;L;;;;;N;;;;;
+1213A;CUNEIFORM SIGN HUB2 TIMES HAL;Lo;0;L;;;;;N;;;;;
+1213B;CUNEIFORM SIGN HUB2 TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+1213C;CUNEIFORM SIGN HUB2 TIMES LISH;Lo;0;L;;;;;N;;;;;
+1213D;CUNEIFORM SIGN HUB2 TIMES UD;Lo;0;L;;;;;N;;;;;
+1213E;CUNEIFORM SIGN HUL2;Lo;0;L;;;;;N;;;;;
+1213F;CUNEIFORM SIGN I;Lo;0;L;;;;;N;;;;;
+12140;CUNEIFORM SIGN I A;Lo;0;L;;;;;N;;;;;
+12141;CUNEIFORM SIGN IB;Lo;0;L;;;;;N;;;;;
+12142;CUNEIFORM SIGN IDIM;Lo;0;L;;;;;N;;;;;
+12143;CUNEIFORM SIGN IDIM OVER IDIM BUR;Lo;0;L;;;;;N;;;;;
+12144;CUNEIFORM SIGN IDIM OVER IDIM SQUARED;Lo;0;L;;;;;N;;;;;
+12145;CUNEIFORM SIGN IG;Lo;0;L;;;;;N;;;;;
+12146;CUNEIFORM SIGN IGI;Lo;0;L;;;;;N;;;;;
+12147;CUNEIFORM SIGN IGI DIB;Lo;0;L;;;;;N;;;;;
+12148;CUNEIFORM SIGN IGI RI;Lo;0;L;;;;;N;;;;;
+12149;CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD;Lo;0;L;;;;;N;;;;;
+1214A;CUNEIFORM SIGN IGI GUNU;Lo;0;L;;;;;N;;;;;
+1214B;CUNEIFORM SIGN IL;Lo;0;L;;;;;N;;;;;
+1214C;CUNEIFORM SIGN IL TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1214D;CUNEIFORM SIGN IL2;Lo;0;L;;;;;N;;;;;
+1214E;CUNEIFORM SIGN IM;Lo;0;L;;;;;N;;;;;
+1214F;CUNEIFORM SIGN IM TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12150;CUNEIFORM SIGN IM CROSSING IM;Lo;0;L;;;;;N;;;;;
+12151;CUNEIFORM SIGN IM OPPOSING IM;Lo;0;L;;;;;N;;;;;
+12152;CUNEIFORM SIGN IM SQUARED;Lo;0;L;;;;;N;;;;;
+12153;CUNEIFORM SIGN IMIN;Lo;0;L;;;;;N;;;;;
+12154;CUNEIFORM SIGN IN;Lo;0;L;;;;;N;;;;;
+12155;CUNEIFORM SIGN IR;Lo;0;L;;;;;N;;;;;
+12156;CUNEIFORM SIGN ISH;Lo;0;L;;;;;N;;;;;
+12157;CUNEIFORM SIGN KA;Lo;0;L;;;;;N;;;;;
+12158;CUNEIFORM SIGN KA TIMES A;Lo;0;L;;;;;N;;;;;
+12159;CUNEIFORM SIGN KA TIMES AD;Lo;0;L;;;;;N;;;;;
+1215A;CUNEIFORM SIGN KA TIMES AD PLUS KU3;Lo;0;L;;;;;N;;;;;
+1215B;CUNEIFORM SIGN KA TIMES ASH2;Lo;0;L;;;;;N;;;;;
+1215C;CUNEIFORM SIGN KA TIMES BAD;Lo;0;L;;;;;N;;;;;
+1215D;CUNEIFORM SIGN KA TIMES BALAG;Lo;0;L;;;;;N;;;;;
+1215E;CUNEIFORM SIGN KA TIMES BAR;Lo;0;L;;;;;N;;;;;
+1215F;CUNEIFORM SIGN KA TIMES BI;Lo;0;L;;;;;N;;;;;
+12160;CUNEIFORM SIGN KA TIMES ERIN2;Lo;0;L;;;;;N;;;;;
+12161;CUNEIFORM SIGN KA TIMES ESH2;Lo;0;L;;;;;N;;;;;
+12162;CUNEIFORM SIGN KA TIMES GA;Lo;0;L;;;;;N;;;;;
+12163;CUNEIFORM SIGN KA TIMES GAL;Lo;0;L;;;;;N;;;;;
+12164;CUNEIFORM SIGN KA TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12165;CUNEIFORM SIGN KA TIMES GAR;Lo;0;L;;;;;N;;;;;
+12166;CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A;Lo;0;L;;;;;N;;;;;
+12167;CUNEIFORM SIGN KA TIMES GI;Lo;0;L;;;;;N;;;;;
+12168;CUNEIFORM SIGN KA TIMES GIR2;Lo;0;L;;;;;N;;;;;
+12169;CUNEIFORM SIGN KA TIMES GISH PLUS SAR;Lo;0;L;;;;;N;;;;;
+1216A;CUNEIFORM SIGN KA TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;
+1216B;CUNEIFORM SIGN KA TIMES GU;Lo;0;L;;;;;N;;;;;
+1216C;CUNEIFORM SIGN KA TIMES GUR7;Lo;0;L;;;;;N;;;;;
+1216D;CUNEIFORM SIGN KA TIMES IGI;Lo;0;L;;;;;N;;;;;
+1216E;CUNEIFORM SIGN KA TIMES IM;Lo;0;L;;;;;N;;;;;
+1216F;CUNEIFORM SIGN KA TIMES KAK;Lo;0;L;;;;;N;;;;;
+12170;CUNEIFORM SIGN KA TIMES KI;Lo;0;L;;;;;N;;;;;
+12171;CUNEIFORM SIGN KA TIMES KID;Lo;0;L;;;;;N;;;;;
+12172;CUNEIFORM SIGN KA TIMES LI;Lo;0;L;;;;;N;;;;;
+12173;CUNEIFORM SIGN KA TIMES LU;Lo;0;L;;;;;N;;;;;
+12174;CUNEIFORM SIGN KA TIMES ME;Lo;0;L;;;;;N;;;;;
+12175;CUNEIFORM SIGN KA TIMES ME PLUS DU;Lo;0;L;;;;;N;;;;;
+12176;CUNEIFORM SIGN KA TIMES ME PLUS GI;Lo;0;L;;;;;N;;;;;
+12177;CUNEIFORM SIGN KA TIMES ME PLUS TE;Lo;0;L;;;;;N;;;;;
+12178;CUNEIFORM SIGN KA TIMES MI;Lo;0;L;;;;;N;;;;;
+12179;CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ;Lo;0;L;;;;;N;;;;;
+1217A;CUNEIFORM SIGN KA TIMES NE;Lo;0;L;;;;;N;;;;;
+1217B;CUNEIFORM SIGN KA TIMES NUN;Lo;0;L;;;;;N;;;;;
+1217C;CUNEIFORM SIGN KA TIMES PI;Lo;0;L;;;;;N;;;;;
+1217D;CUNEIFORM SIGN KA TIMES RU;Lo;0;L;;;;;N;;;;;
+1217E;CUNEIFORM SIGN KA TIMES SA;Lo;0;L;;;;;N;;;;;
+1217F;CUNEIFORM SIGN KA TIMES SAR;Lo;0;L;;;;;N;;;;;
+12180;CUNEIFORM SIGN KA TIMES SHA;Lo;0;L;;;;;N;;;;;
+12181;CUNEIFORM SIGN KA TIMES SHE;Lo;0;L;;;;;N;;;;;
+12182;CUNEIFORM SIGN KA TIMES SHID;Lo;0;L;;;;;N;;;;;
+12183;CUNEIFORM SIGN KA TIMES SHU;Lo;0;L;;;;;N;;;;;
+12184;CUNEIFORM SIGN KA TIMES SIG;Lo;0;L;;;;;N;;;;;
+12185;CUNEIFORM SIGN KA TIMES SUHUR;Lo;0;L;;;;;N;;;;;
+12186;CUNEIFORM SIGN KA TIMES TAR;Lo;0;L;;;;;N;;;;;
+12187;CUNEIFORM SIGN KA TIMES U;Lo;0;L;;;;;N;;;;;
+12188;CUNEIFORM SIGN KA TIMES U2;Lo;0;L;;;;;N;;;;;
+12189;CUNEIFORM SIGN KA TIMES UD;Lo;0;L;;;;;N;;;;;
+1218A;CUNEIFORM SIGN KA TIMES UMUM TIMES PA;Lo;0;L;;;;;N;;;;;
+1218B;CUNEIFORM SIGN KA TIMES USH;Lo;0;L;;;;;N;;;;;
+1218C;CUNEIFORM SIGN KA TIMES ZI;Lo;0;L;;;;;N;;;;;
+1218D;CUNEIFORM SIGN KA2;Lo;0;L;;;;;N;;;;;
+1218E;CUNEIFORM SIGN KA2 CROSSING KA2;Lo;0;L;;;;;N;;;;;
+1218F;CUNEIFORM SIGN KAB;Lo;0;L;;;;;N;;;;;
+12190;CUNEIFORM SIGN KAD2;Lo;0;L;;;;;N;;;;;
+12191;CUNEIFORM SIGN KAD3;Lo;0;L;;;;;N;;;;;
+12192;CUNEIFORM SIGN KAD4;Lo;0;L;;;;;N;;;;;
+12193;CUNEIFORM SIGN KAD5;Lo;0;L;;;;;N;;;;;
+12194;CUNEIFORM SIGN KAD5 OVER KAD5;Lo;0;L;;;;;N;;;;;
+12195;CUNEIFORM SIGN KAK;Lo;0;L;;;;;N;;;;;
+12196;CUNEIFORM SIGN KAK TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+12197;CUNEIFORM SIGN KAL;Lo;0;L;;;;;N;;;;;
+12198;CUNEIFORM SIGN KAL TIMES BAD;Lo;0;L;;;;;N;;;;;
+12199;CUNEIFORM SIGN KAL CROSSING KAL;Lo;0;L;;;;;N;;;;;
+1219A;CUNEIFORM SIGN KAM2;Lo;0;L;;;;;N;;;;;
+1219B;CUNEIFORM SIGN KAM4;Lo;0;L;;;;;N;;;;;
+1219C;CUNEIFORM SIGN KASKAL;Lo;0;L;;;;;N;;;;;
+1219D;CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;;
+1219E;CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U;Lo;0;L;;;;;N;;;;;
+1219F;CUNEIFORM SIGN KESH2;Lo;0;L;;;;;N;;;;;
+121A0;CUNEIFORM SIGN KI;Lo;0;L;;;;;N;;;;;
+121A1;CUNEIFORM SIGN KI TIMES BAD;Lo;0;L;;;;;N;;;;;
+121A2;CUNEIFORM SIGN KI TIMES U;Lo;0;L;;;;;N;;;;;
+121A3;CUNEIFORM SIGN KI TIMES UD;Lo;0;L;;;;;N;;;;;
+121A4;CUNEIFORM SIGN KID;Lo;0;L;;;;;N;;;;;
+121A5;CUNEIFORM SIGN KIN;Lo;0;L;;;;;N;;;;;
+121A6;CUNEIFORM SIGN KISAL;Lo;0;L;;;;;N;;;;;
+121A7;CUNEIFORM SIGN KISH;Lo;0;L;;;;;N;;;;;
+121A8;CUNEIFORM SIGN KISIM5;Lo;0;L;;;;;N;;;;;
+121A9;CUNEIFORM SIGN KISIM5 OVER KISIM5;Lo;0;L;;;;;N;;;;;
+121AA;CUNEIFORM SIGN KU;Lo;0;L;;;;;N;;;;;
+121AB;CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2;Lo;0;L;;;;;N;;;;;
+121AC;CUNEIFORM SIGN KU3;Lo;0;L;;;;;N;;;;;
+121AD;CUNEIFORM SIGN KU4;Lo;0;L;;;;;N;;;;;
+121AE;CUNEIFORM SIGN KU4 VARIANT FORM;Lo;0;L;;;;;N;;;;;
+121AF;CUNEIFORM SIGN KU7;Lo;0;L;;;;;N;;;;;
+121B0;CUNEIFORM SIGN KUL;Lo;0;L;;;;;N;;;;;
+121B1;CUNEIFORM SIGN KUL GUNU;Lo;0;L;;;;;N;;;;;
+121B2;CUNEIFORM SIGN KUN;Lo;0;L;;;;;N;;;;;
+121B3;CUNEIFORM SIGN KUR;Lo;0;L;;;;;N;;;;;
+121B4;CUNEIFORM SIGN KUR OPPOSING KUR;Lo;0;L;;;;;N;;;;;
+121B5;CUNEIFORM SIGN KUSHU2;Lo;0;L;;;;;N;;;;;
+121B6;CUNEIFORM SIGN KWU318;Lo;0;L;;;;;N;;;;;
+121B7;CUNEIFORM SIGN LA;Lo;0;L;;;;;N;;;;;
+121B8;CUNEIFORM SIGN LAGAB;Lo;0;L;;;;;N;;;;;
+121B9;CUNEIFORM SIGN LAGAB TIMES A;Lo;0;L;;;;;N;;;;;
+121BA;CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA;Lo;0;L;;;;;N;;;;;
+121BB;CUNEIFORM SIGN LAGAB TIMES A PLUS GAR;Lo;0;L;;;;;N;;;;;
+121BC;CUNEIFORM SIGN LAGAB TIMES A PLUS LAL;Lo;0;L;;;;;N;;;;;
+121BD;CUNEIFORM SIGN LAGAB TIMES AL;Lo;0;L;;;;;N;;;;;
+121BE;CUNEIFORM SIGN LAGAB TIMES AN;Lo;0;L;;;;;N;;;;;
+121BF;CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU;Lo;0;L;;;;;N;;;;;
+121C0;CUNEIFORM SIGN LAGAB TIMES BAD;Lo;0;L;;;;;N;;;;;
+121C1;CUNEIFORM SIGN LAGAB TIMES BI;Lo;0;L;;;;;N;;;;;
+121C2;CUNEIFORM SIGN LAGAB TIMES DAR;Lo;0;L;;;;;N;;;;;
+121C3;CUNEIFORM SIGN LAGAB TIMES EN;Lo;0;L;;;;;N;;;;;
+121C4;CUNEIFORM SIGN LAGAB TIMES GA;Lo;0;L;;;;;N;;;;;
+121C5;CUNEIFORM SIGN LAGAB TIMES GAR;Lo;0;L;;;;;N;;;;;
+121C6;CUNEIFORM SIGN LAGAB TIMES GUD;Lo;0;L;;;;;N;;;;;
+121C7;CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD;Lo;0;L;;;;;N;;;;;
+121C8;CUNEIFORM SIGN LAGAB TIMES HA;Lo;0;L;;;;;N;;;;;
+121C9;CUNEIFORM SIGN LAGAB TIMES HAL;Lo;0;L;;;;;N;;;;;
+121CA;CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN;Lo;0;L;;;;;N;;;;;
+121CB;CUNEIFORM SIGN LAGAB TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+121CC;CUNEIFORM SIGN LAGAB TIMES IM;Lo;0;L;;;;;N;;;;;
+121CD;CUNEIFORM SIGN LAGAB TIMES IM PLUS HA;Lo;0;L;;;;;N;;;;;
+121CE;CUNEIFORM SIGN LAGAB TIMES IM PLUS LU;Lo;0;L;;;;;N;;;;;
+121CF;CUNEIFORM SIGN LAGAB TIMES KI;Lo;0;L;;;;;N;;;;;
+121D0;CUNEIFORM SIGN LAGAB TIMES KIN;Lo;0;L;;;;;N;;;;;
+121D1;CUNEIFORM SIGN LAGAB TIMES KU3;Lo;0;L;;;;;N;;;;;
+121D2;CUNEIFORM SIGN LAGAB TIMES KUL;Lo;0;L;;;;;N;;;;;
+121D3;CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A;Lo;0;L;;;;;N;;;;;
+121D4;CUNEIFORM SIGN LAGAB TIMES LAGAB;Lo;0;L;;;;;N;;;;;
+121D5;CUNEIFORM SIGN LAGAB TIMES LISH;Lo;0;L;;;;;N;;;;;
+121D6;CUNEIFORM SIGN LAGAB TIMES LU;Lo;0;L;;;;;N;;;;;
+121D7;CUNEIFORM SIGN LAGAB TIMES LUL;Lo;0;L;;;;;N;;;;;
+121D8;CUNEIFORM SIGN LAGAB TIMES ME;Lo;0;L;;;;;N;;;;;
+121D9;CUNEIFORM SIGN LAGAB TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;
+121DA;CUNEIFORM SIGN LAGAB TIMES MUSH;Lo;0;L;;;;;N;;;;;
+121DB;CUNEIFORM SIGN LAGAB TIMES NE;Lo;0;L;;;;;N;;;;;
+121DC;CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;;
+121DD;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2;Lo;0;L;;;;;N;;;;;
+121DE;CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU;Lo;0;L;;;;;N;;;;;
+121DF;CUNEIFORM SIGN LAGAB TIMES SHU2;Lo;0;L;;;;;N;;;;;
+121E0;CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2;Lo;0;L;;;;;N;;;;;
+121E1;CUNEIFORM SIGN LAGAB TIMES SUM;Lo;0;L;;;;;N;;;;;
+121E2;CUNEIFORM SIGN LAGAB TIMES TAG;Lo;0;L;;;;;N;;;;;
+121E3;CUNEIFORM SIGN LAGAB TIMES TAK4;Lo;0;L;;;;;N;;;;;
+121E4;CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA;Lo;0;L;;;;;N;;;;;
+121E5;CUNEIFORM SIGN LAGAB TIMES U;Lo;0;L;;;;;N;;;;;
+121E6;CUNEIFORM SIGN LAGAB TIMES U PLUS A;Lo;0;L;;;;;N;;;;;
+121E7;CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;
+121E8;CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;
+121E9;CUNEIFORM SIGN LAGAB TIMES UD;Lo;0;L;;;;;N;;;;;
+121EA;CUNEIFORM SIGN LAGAB TIMES USH;Lo;0;L;;;;;N;;;;;
+121EB;CUNEIFORM SIGN LAGAB SQUARED;Lo;0;L;;;;;N;;;;;
+121EC;CUNEIFORM SIGN LAGAR;Lo;0;L;;;;;N;;;;;
+121ED;CUNEIFORM SIGN LAGAR TIMES SHE;Lo;0;L;;;;;N;;;;;
+121EE;CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM;Lo;0;L;;;;;N;;;;;
+121EF;CUNEIFORM SIGN LAGAR GUNU;Lo;0;L;;;;;N;;;;;
+121F0;CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE;Lo;0;L;;;;;N;;;;;
+121F1;CUNEIFORM SIGN LAHSHU;Lo;0;L;;;;;N;;;;;
+121F2;CUNEIFORM SIGN LAL;Lo;0;L;;;;;N;;;;;
+121F3;CUNEIFORM SIGN LAL TIMES LAL;Lo;0;L;;;;;N;;;;;
+121F4;CUNEIFORM SIGN LAM;Lo;0;L;;;;;N;;;;;
+121F5;CUNEIFORM SIGN LAM TIMES KUR;Lo;0;L;;;;;N;;;;;
+121F6;CUNEIFORM SIGN LAM TIMES KUR PLUS RU;Lo;0;L;;;;;N;;;;;
+121F7;CUNEIFORM SIGN LI;Lo;0;L;;;;;N;;;;;
+121F8;CUNEIFORM SIGN LIL;Lo;0;L;;;;;N;;;;;
+121F9;CUNEIFORM SIGN LIMMU2;Lo;0;L;;;;;N;;;;;
+121FA;CUNEIFORM SIGN LISH;Lo;0;L;;;;;N;;;;;
+121FB;CUNEIFORM SIGN LU;Lo;0;L;;;;;N;;;;;
+121FC;CUNEIFORM SIGN LU TIMES BAD;Lo;0;L;;;;;N;;;;;
+121FD;CUNEIFORM SIGN LU2;Lo;0;L;;;;;N;;;;;
+121FE;CUNEIFORM SIGN LU2 TIMES AL;Lo;0;L;;;;;N;;;;;
+121FF;CUNEIFORM SIGN LU2 TIMES BAD;Lo;0;L;;;;;N;;;;;
+12200;CUNEIFORM SIGN LU2 TIMES ESH2;Lo;0;L;;;;;N;;;;;
+12201;CUNEIFORM SIGN LU2 TIMES ESH2 TENU;Lo;0;L;;;;;N;;;;;
+12202;CUNEIFORM SIGN LU2 TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12203;CUNEIFORM SIGN LU2 TIMES HI TIMES BAD;Lo;0;L;;;;;N;;;;;
+12204;CUNEIFORM SIGN LU2 TIMES IM;Lo;0;L;;;;;N;;;;;
+12205;CUNEIFORM SIGN LU2 TIMES KAD2;Lo;0;L;;;;;N;;;;;
+12206;CUNEIFORM SIGN LU2 TIMES KAD3;Lo;0;L;;;;;N;;;;;
+12207;CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH;Lo;0;L;;;;;N;;;;;
+12208;CUNEIFORM SIGN LU2 TIMES KI;Lo;0;L;;;;;N;;;;;
+12209;CUNEIFORM SIGN LU2 TIMES LA PLUS ASH;Lo;0;L;;;;;N;;;;;
+1220A;CUNEIFORM SIGN LU2 TIMES LAGAB;Lo;0;L;;;;;N;;;;;
+1220B;CUNEIFORM SIGN LU2 TIMES ME PLUS EN;Lo;0;L;;;;;N;;;;;
+1220C;CUNEIFORM SIGN LU2 TIMES NE;Lo;0;L;;;;;N;;;;;
+1220D;CUNEIFORM SIGN LU2 TIMES NU;Lo;0;L;;;;;N;;;;;
+1220E;CUNEIFORM SIGN LU2 TIMES SI PLUS ASH;Lo;0;L;;;;;N;;;;;
+1220F;CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU;Lo;0;L;;;;;N;;;;;
+12210;CUNEIFORM SIGN LU2 TIMES TUG2;Lo;0;L;;;;;N;;;;;
+12211;CUNEIFORM SIGN LU2 TENU;Lo;0;L;;;;;N;;;;;
+12212;CUNEIFORM SIGN LU2 CROSSING LU2;Lo;0;L;;;;;N;;;;;
+12213;CUNEIFORM SIGN LU2 OPPOSING LU2;Lo;0;L;;;;;N;;;;;
+12214;CUNEIFORM SIGN LU2 SQUARED;Lo;0;L;;;;;N;;;;;
+12215;CUNEIFORM SIGN LU2 SHESHIG;Lo;0;L;;;;;N;;;;;
+12216;CUNEIFORM SIGN LU3;Lo;0;L;;;;;N;;;;;
+12217;CUNEIFORM SIGN LUGAL;Lo;0;L;;;;;N;;;;;
+12218;CUNEIFORM SIGN LUGAL OVER LUGAL;Lo;0;L;;;;;N;;;;;
+12219;CUNEIFORM SIGN LUGAL OPPOSING LUGAL;Lo;0;L;;;;;N;;;;;
+1221A;CUNEIFORM SIGN LUGAL SHESHIG;Lo;0;L;;;;;N;;;;;
+1221B;CUNEIFORM SIGN LUH;Lo;0;L;;;;;N;;;;;
+1221C;CUNEIFORM SIGN LUL;Lo;0;L;;;;;N;;;;;
+1221D;CUNEIFORM SIGN LUM;Lo;0;L;;;;;N;;;;;
+1221E;CUNEIFORM SIGN LUM OVER LUM;Lo;0;L;;;;;N;;;;;
+1221F;CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+12220;CUNEIFORM SIGN MA;Lo;0;L;;;;;N;;;;;
+12221;CUNEIFORM SIGN MA TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12222;CUNEIFORM SIGN MA GUNU;Lo;0;L;;;;;N;;;;;
+12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;;
+12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;;
+12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;;
+12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;;N;;;;;
+12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;;
+12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;;
+12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;;
+1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;;
+1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;;N;;;;;
+1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;;
+1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;;
+1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;;
+1222F;CUNEIFORM SIGN MUG GUNU;Lo;0;L;;;;;N;;;;;
+12230;CUNEIFORM SIGN MUNSUB;Lo;0;L;;;;;N;;;;;
+12231;CUNEIFORM SIGN MURGU2;Lo;0;L;;;;;N;;;;;
+12232;CUNEIFORM SIGN MUSH;Lo;0;L;;;;;N;;;;;
+12233;CUNEIFORM SIGN MUSH TIMES A;Lo;0;L;;;;;N;;;;;
+12234;CUNEIFORM SIGN MUSH TIMES KUR;Lo;0;L;;;;;N;;;;;
+12235;CUNEIFORM SIGN MUSH TIMES ZA;Lo;0;L;;;;;N;;;;;
+12236;CUNEIFORM SIGN MUSH OVER MUSH;Lo;0;L;;;;;N;;;;;
+12237;CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA;Lo;0;L;;;;;N;;;;;
+12238;CUNEIFORM SIGN MUSH CROSSING MUSH;Lo;0;L;;;;;N;;;;;
+12239;CUNEIFORM SIGN MUSH3;Lo;0;L;;;;;N;;;;;
+1223A;CUNEIFORM SIGN MUSH3 TIMES A;Lo;0;L;;;;;N;;;;;
+1223B;CUNEIFORM SIGN MUSH3 TIMES A PLUS DI;Lo;0;L;;;;;N;;;;;
+1223C;CUNEIFORM SIGN MUSH3 TIMES DI;Lo;0;L;;;;;N;;;;;
+1223D;CUNEIFORM SIGN MUSH3 GUNU;Lo;0;L;;;;;N;;;;;
+1223E;CUNEIFORM SIGN NA;Lo;0;L;;;;;N;;;;;
+1223F;CUNEIFORM SIGN NA2;Lo;0;L;;;;;N;;;;;
+12240;CUNEIFORM SIGN NAGA;Lo;0;L;;;;;N;;;;;
+12241;CUNEIFORM SIGN NAGA INVERTED;Lo;0;L;;;;;N;;;;;
+12242;CUNEIFORM SIGN NAGA TIMES SHU TENU;Lo;0;L;;;;;N;;;;;
+12243;CUNEIFORM SIGN NAGA OPPOSING NAGA;Lo;0;L;;;;;N;;;;;
+12244;CUNEIFORM SIGN NAGAR;Lo;0;L;;;;;N;;;;;
+12245;CUNEIFORM SIGN NAM NUTILLU;Lo;0;L;;;;;N;;;;;
+12246;CUNEIFORM SIGN NAM;Lo;0;L;;;;;N;;;;;
+12247;CUNEIFORM SIGN NAM2;Lo;0;L;;;;;N;;;;;
+12248;CUNEIFORM SIGN NE;Lo;0;L;;;;;N;;;;;
+12249;CUNEIFORM SIGN NE TIMES A;Lo;0;L;;;;;N;;;;;
+1224A;CUNEIFORM SIGN NE TIMES UD;Lo;0;L;;;;;N;;;;;
+1224B;CUNEIFORM SIGN NE SHESHIG;Lo;0;L;;;;;N;;;;;
+1224C;CUNEIFORM SIGN NI;Lo;0;L;;;;;N;;;;;
+1224D;CUNEIFORM SIGN NI TIMES E;Lo;0;L;;;;;N;;;;;
+1224E;CUNEIFORM SIGN NI2;Lo;0;L;;;;;N;;;;;
+1224F;CUNEIFORM SIGN NIM;Lo;0;L;;;;;N;;;;;
+12250;CUNEIFORM SIGN NIM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12251;CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12252;CUNEIFORM SIGN NINDA2;Lo;0;L;;;;;N;;;;;
+12253;CUNEIFORM SIGN NINDA2 TIMES AN;Lo;0;L;;;;;N;;;;;
+12254;CUNEIFORM SIGN NINDA2 TIMES ASH;Lo;0;L;;;;;N;;;;;
+12255;CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH;Lo;0;L;;;;;N;;;;;
+12256;CUNEIFORM SIGN NINDA2 TIMES GUD;Lo;0;L;;;;;N;;;;;
+12257;CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU;Lo;0;L;;;;;N;;;;;
+12258;CUNEIFORM SIGN NINDA2 TIMES NE;Lo;0;L;;;;;N;;;;;
+12259;CUNEIFORM SIGN NINDA2 TIMES NUN;Lo;0;L;;;;;N;;;;;
+1225A;CUNEIFORM SIGN NINDA2 TIMES SHE;Lo;0;L;;;;;N;;;;;
+1225B;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN;Lo;0;L;;;;;N;;;;;
+1225C;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH;Lo;0;L;;;;;N;;;;;
+1225D;CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH;Lo;0;L;;;;;N;;;;;
+1225E;CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;
+1225F;CUNEIFORM SIGN NINDA2 TIMES USH;Lo;0;L;;;;;N;;;;;
+12260;CUNEIFORM SIGN NISAG;Lo;0;L;;;;;N;;;;;
+12261;CUNEIFORM SIGN NU;Lo;0;L;;;;;N;;;;;
+12262;CUNEIFORM SIGN NU11;Lo;0;L;;;;;N;;;;;
+12263;CUNEIFORM SIGN NUN;Lo;0;L;;;;;N;;;;;
+12264;CUNEIFORM SIGN NUN LAGAR TIMES GAR;Lo;0;L;;;;;N;;;;;
+12265;CUNEIFORM SIGN NUN LAGAR TIMES MASH;Lo;0;L;;;;;N;;;;;
+12266;CUNEIFORM SIGN NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;;
+12267;CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL;Lo;0;L;;;;;N;;;;;
+12268;CUNEIFORM SIGN NUN LAGAR TIMES USH;Lo;0;L;;;;;N;;;;;
+12269;CUNEIFORM SIGN NUN TENU;Lo;0;L;;;;;N;;;;;
+1226A;CUNEIFORM SIGN NUN OVER NUN;Lo;0;L;;;;;N;;;;;
+1226B;CUNEIFORM SIGN NUN CROSSING NUN;Lo;0;L;;;;;N;;;;;
+1226C;CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR;Lo;0;L;;;;;N;;;;;
+1226D;CUNEIFORM SIGN NUNUZ;Lo;0;L;;;;;N;;;;;
+1226E;CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB;Lo;0;L;;;;;N;;;;;
+1226F;CUNEIFORM SIGN NUNUZ AB2 TIMES BI;Lo;0;L;;;;;N;;;;;
+12270;CUNEIFORM SIGN NUNUZ AB2 TIMES DUG;Lo;0;L;;;;;N;;;;;
+12271;CUNEIFORM SIGN NUNUZ AB2 TIMES GUD;Lo;0;L;;;;;N;;;;;
+12272;CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+12273;CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3;Lo;0;L;;;;;N;;;;;
+12274;CUNEIFORM SIGN NUNUZ AB2 TIMES LA;Lo;0;L;;;;;N;;;;;
+12275;CUNEIFORM SIGN NUNUZ AB2 TIMES NE;Lo;0;L;;;;;N;;;;;
+12276;CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3;Lo;0;L;;;;;N;;;;;
+12277;CUNEIFORM SIGN NUNUZ AB2 TIMES U2;Lo;0;L;;;;;N;;;;;
+12278;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI;Lo;0;L;;;;;N;;;;;
+12279;CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U;Lo;0;L;;;;;N;;;;;
+1227A;CUNEIFORM SIGN PA;Lo;0;L;;;;;N;;;;;
+1227B;CUNEIFORM SIGN PAD;Lo;0;L;;;;;N;;;;;
+1227C;CUNEIFORM SIGN PAN;Lo;0;L;;;;;N;;;;;
+1227D;CUNEIFORM SIGN PAP;Lo;0;L;;;;;N;;;;;
+1227E;CUNEIFORM SIGN PESH2;Lo;0;L;;;;;N;;;;;
+1227F;CUNEIFORM SIGN PI;Lo;0;L;;;;;N;;;;;
+12280;CUNEIFORM SIGN PI TIMES A;Lo;0;L;;;;;N;;;;;
+12281;CUNEIFORM SIGN PI TIMES AB;Lo;0;L;;;;;N;;;;;
+12282;CUNEIFORM SIGN PI TIMES BI;Lo;0;L;;;;;N;;;;;
+12283;CUNEIFORM SIGN PI TIMES BU;Lo;0;L;;;;;N;;;;;
+12284;CUNEIFORM SIGN PI TIMES E;Lo;0;L;;;;;N;;;;;
+12285;CUNEIFORM SIGN PI TIMES I;Lo;0;L;;;;;N;;;;;
+12286;CUNEIFORM SIGN PI TIMES IB;Lo;0;L;;;;;N;;;;;
+12287;CUNEIFORM SIGN PI TIMES U;Lo;0;L;;;;;N;;;;;
+12288;CUNEIFORM SIGN PI TIMES U2;Lo;0;L;;;;;N;;;;;
+12289;CUNEIFORM SIGN PI CROSSING PI;Lo;0;L;;;;;N;;;;;
+1228A;CUNEIFORM SIGN PIRIG;Lo;0;L;;;;;N;;;;;
+1228B;CUNEIFORM SIGN PIRIG TIMES KAL;Lo;0;L;;;;;N;;;;;
+1228C;CUNEIFORM SIGN PIRIG TIMES UD;Lo;0;L;;;;;N;;;;;
+1228D;CUNEIFORM SIGN PIRIG TIMES ZA;Lo;0;L;;;;;N;;;;;
+1228E;CUNEIFORM SIGN PIRIG OPPOSING PIRIG;Lo;0;L;;;;;N;;;;;
+1228F;CUNEIFORM SIGN RA;Lo;0;L;;;;;N;;;;;
+12290;CUNEIFORM SIGN RAB;Lo;0;L;;;;;N;;;;;
+12291;CUNEIFORM SIGN RI;Lo;0;L;;;;;N;;;;;
+12292;CUNEIFORM SIGN RU;Lo;0;L;;;;;N;;;;;
+12293;CUNEIFORM SIGN SA;Lo;0;L;;;;;N;;;;;
+12294;CUNEIFORM SIGN SAG NUTILLU;Lo;0;L;;;;;N;;;;;
+12295;CUNEIFORM SIGN SAG;Lo;0;L;;;;;N;;;;;
+12296;CUNEIFORM SIGN SAG TIMES A;Lo;0;L;;;;;N;;;;;
+12297;CUNEIFORM SIGN SAG TIMES DU;Lo;0;L;;;;;N;;;;;
+12298;CUNEIFORM SIGN SAG TIMES DUB;Lo;0;L;;;;;N;;;;;
+12299;CUNEIFORM SIGN SAG TIMES HA;Lo;0;L;;;;;N;;;;;
+1229A;CUNEIFORM SIGN SAG TIMES KAK;Lo;0;L;;;;;N;;;;;
+1229B;CUNEIFORM SIGN SAG TIMES KUR;Lo;0;L;;;;;N;;;;;
+1229C;CUNEIFORM SIGN SAG TIMES LUM;Lo;0;L;;;;;N;;;;;
+1229D;CUNEIFORM SIGN SAG TIMES MI;Lo;0;L;;;;;N;;;;;
+1229E;CUNEIFORM SIGN SAG TIMES NUN;Lo;0;L;;;;;N;;;;;
+1229F;CUNEIFORM SIGN SAG TIMES SAL;Lo;0;L;;;;;N;;;;;
+122A0;CUNEIFORM SIGN SAG TIMES SHID;Lo;0;L;;;;;N;;;;;
+122A1;CUNEIFORM SIGN SAG TIMES TAB;Lo;0;L;;;;;N;;;;;
+122A2;CUNEIFORM SIGN SAG TIMES U2;Lo;0;L;;;;;N;;;;;
+122A3;CUNEIFORM SIGN SAG TIMES UB;Lo;0;L;;;;;N;;;;;
+122A4;CUNEIFORM SIGN SAG TIMES UM;Lo;0;L;;;;;N;;;;;
+122A5;CUNEIFORM SIGN SAG TIMES UR;Lo;0;L;;;;;N;;;;;
+122A6;CUNEIFORM SIGN SAG TIMES USH;Lo;0;L;;;;;N;;;;;
+122A7;CUNEIFORM SIGN SAG OVER SAG;Lo;0;L;;;;;N;;;;;
+122A8;CUNEIFORM SIGN SAG GUNU;Lo;0;L;;;;;N;;;;;
+122A9;CUNEIFORM SIGN SAL;Lo;0;L;;;;;N;;;;;
+122AA;CUNEIFORM SIGN SAL LAGAB TIMES ASH2;Lo;0;L;;;;;N;;;;;
+122AB;CUNEIFORM SIGN SANGA2;Lo;0;L;;;;;N;;;;;
+122AC;CUNEIFORM SIGN SAR;Lo;0;L;;;;;N;;;;;
+122AD;CUNEIFORM SIGN SHA;Lo;0;L;;;;;N;;;;;
+122AE;CUNEIFORM SIGN SHA3;Lo;0;L;;;;;N;;;;;
+122AF;CUNEIFORM SIGN SHA3 TIMES A;Lo;0;L;;;;;N;;;;;
+122B0;CUNEIFORM SIGN SHA3 TIMES BAD;Lo;0;L;;;;;N;;;;;
+122B1;CUNEIFORM SIGN SHA3 TIMES GISH;Lo;0;L;;;;;N;;;;;
+122B2;CUNEIFORM SIGN SHA3 TIMES NE;Lo;0;L;;;;;N;;;;;
+122B3;CUNEIFORM SIGN SHA3 TIMES SHU2;Lo;0;L;;;;;N;;;;;
+122B4;CUNEIFORM SIGN SHA3 TIMES TUR;Lo;0;L;;;;;N;;;;;
+122B5;CUNEIFORM SIGN SHA3 TIMES U;Lo;0;L;;;;;N;;;;;
+122B6;CUNEIFORM SIGN SHA3 TIMES U PLUS A;Lo;0;L;;;;;N;;;;;
+122B7;CUNEIFORM SIGN SHA6;Lo;0;L;;;;;N;;;;;
+122B8;CUNEIFORM SIGN SHAB6;Lo;0;L;;;;;N;;;;;
+122B9;CUNEIFORM SIGN SHAR2;Lo;0;L;;;;;N;;;;;
+122BA;CUNEIFORM SIGN SHE;Lo;0;L;;;;;N;;;;;
+122BB;CUNEIFORM SIGN SHE HU;Lo;0;L;;;;;N;;;;;
+122BC;CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+122BD;CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+122BE;CUNEIFORM SIGN SHEG9;Lo;0;L;;;;;N;;;;;
+122BF;CUNEIFORM SIGN SHEN;Lo;0;L;;;;;N;;;;;
+122C0;CUNEIFORM SIGN SHESH;Lo;0;L;;;;;N;;;;;
+122C1;CUNEIFORM SIGN SHESH2;Lo;0;L;;;;;N;;;;;
+122C2;CUNEIFORM SIGN SHESHLAM;Lo;0;L;;;;;N;;;;;
+122C3;CUNEIFORM SIGN SHID;Lo;0;L;;;;;N;;;;;
+122C4;CUNEIFORM SIGN SHID TIMES A;Lo;0;L;;;;;N;;;;;
+122C5;CUNEIFORM SIGN SHID TIMES IM;Lo;0;L;;;;;N;;;;;
+122C6;CUNEIFORM SIGN SHIM;Lo;0;L;;;;;N;;;;;
+122C7;CUNEIFORM SIGN SHIM TIMES A;Lo;0;L;;;;;N;;;;;
+122C8;CUNEIFORM SIGN SHIM TIMES BAL;Lo;0;L;;;;;N;;;;;
+122C9;CUNEIFORM SIGN SHIM TIMES BULUG;Lo;0;L;;;;;N;;;;;
+122CA;CUNEIFORM SIGN SHIM TIMES DIN;Lo;0;L;;;;;N;;;;;
+122CB;CUNEIFORM SIGN SHIM TIMES GAR;Lo;0;L;;;;;N;;;;;
+122CC;CUNEIFORM SIGN SHIM TIMES IGI;Lo;0;L;;;;;N;;;;;
+122CD;CUNEIFORM SIGN SHIM TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+122CE;CUNEIFORM SIGN SHIM TIMES KUSHU2;Lo;0;L;;;;;N;;;;;
+122CF;CUNEIFORM SIGN SHIM TIMES LUL;Lo;0;L;;;;;N;;;;;
+122D0;CUNEIFORM SIGN SHIM TIMES MUG;Lo;0;L;;;;;N;;;;;
+122D1;CUNEIFORM SIGN SHIM TIMES SAL;Lo;0;L;;;;;N;;;;;
+122D2;CUNEIFORM SIGN SHINIG;Lo;0;L;;;;;N;;;;;
+122D3;CUNEIFORM SIGN SHIR;Lo;0;L;;;;;N;;;;;
+122D4;CUNEIFORM SIGN SHIR TENU;Lo;0;L;;;;;N;;;;;
+122D5;CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR;Lo;0;L;;;;;N;;;;;
+122D6;CUNEIFORM SIGN SHITA;Lo;0;L;;;;;N;;;;;
+122D7;CUNEIFORM SIGN SHU;Lo;0;L;;;;;N;;;;;
+122D8;CUNEIFORM SIGN SHU OVER INVERTED SHU;Lo;0;L;;;;;N;;;;;
+122D9;CUNEIFORM SIGN SHU2;Lo;0;L;;;;;N;;;;;
+122DA;CUNEIFORM SIGN SHUBUR;Lo;0;L;;;;;N;;;;;
+122DB;CUNEIFORM SIGN SI;Lo;0;L;;;;;N;;;;;
+122DC;CUNEIFORM SIGN SI GUNU;Lo;0;L;;;;;N;;;;;
+122DD;CUNEIFORM SIGN SIG;Lo;0;L;;;;;N;;;;;
+122DE;CUNEIFORM SIGN SIG4;Lo;0;L;;;;;N;;;;;
+122DF;CUNEIFORM SIGN SIG4 OVER SIG4 SHU2;Lo;0;L;;;;;N;;;;;
+122E0;CUNEIFORM SIGN SIK2;Lo;0;L;;;;;N;;;;;
+122E1;CUNEIFORM SIGN SILA3;Lo;0;L;;;;;N;;;;;
+122E2;CUNEIFORM SIGN SU;Lo;0;L;;;;;N;;;;;
+122E3;CUNEIFORM SIGN SU OVER SU;Lo;0;L;;;;;N;;;;;
+122E4;CUNEIFORM SIGN SUD;Lo;0;L;;;;;N;;;;;
+122E5;CUNEIFORM SIGN SUD2;Lo;0;L;;;;;N;;;;;
+122E6;CUNEIFORM SIGN SUHUR;Lo;0;L;;;;;N;;;;;
+122E7;CUNEIFORM SIGN SUM;Lo;0;L;;;;;N;;;;;
+122E8;CUNEIFORM SIGN SUMASH;Lo;0;L;;;;;N;;;;;
+122E9;CUNEIFORM SIGN SUR;Lo;0;L;;;;;N;;;;;
+122EA;CUNEIFORM SIGN SUR9;Lo;0;L;;;;;N;;;;;
+122EB;CUNEIFORM SIGN TA;Lo;0;L;;;;;N;;;;;
+122EC;CUNEIFORM SIGN TA ASTERISK;Lo;0;L;;;;;N;;;;;
+122ED;CUNEIFORM SIGN TA TIMES HI;Lo;0;L;;;;;N;;;;;
+122EE;CUNEIFORM SIGN TA TIMES MI;Lo;0;L;;;;;N;;;;;
+122EF;CUNEIFORM SIGN TA GUNU;Lo;0;L;;;;;N;;;;;
+122F0;CUNEIFORM SIGN TAB;Lo;0;L;;;;;N;;;;;
+122F1;CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH;Lo;0;L;;;;;N;;;;;
+122F2;CUNEIFORM SIGN TAB SQUARED;Lo;0;L;;;;;N;;;;;
+122F3;CUNEIFORM SIGN TAG;Lo;0;L;;;;;N;;;;;
+122F4;CUNEIFORM SIGN TAG TIMES BI;Lo;0;L;;;;;N;;;;;
+122F5;CUNEIFORM SIGN TAG TIMES GUD;Lo;0;L;;;;;N;;;;;
+122F6;CUNEIFORM SIGN TAG TIMES SHE;Lo;0;L;;;;;N;;;;;
+122F7;CUNEIFORM SIGN TAG TIMES SHU;Lo;0;L;;;;;N;;;;;
+122F8;CUNEIFORM SIGN TAG TIMES TUG2;Lo;0;L;;;;;N;;;;;
+122F9;CUNEIFORM SIGN TAG TIMES UD;Lo;0;L;;;;;N;;;;;
+122FA;CUNEIFORM SIGN TAK4;Lo;0;L;;;;;N;;;;;
+122FB;CUNEIFORM SIGN TAR;Lo;0;L;;;;;N;;;;;
+122FC;CUNEIFORM SIGN TE;Lo;0;L;;;;;N;;;;;
+122FD;CUNEIFORM SIGN TE GUNU;Lo;0;L;;;;;N;;;;;
+122FE;CUNEIFORM SIGN TI;Lo;0;L;;;;;N;;;;;
+122FF;CUNEIFORM SIGN TI TENU;Lo;0;L;;;;;N;;;;;
+12300;CUNEIFORM SIGN TIL;Lo;0;L;;;;;N;;;;;
+12301;CUNEIFORM SIGN TIR;Lo;0;L;;;;;N;;;;;
+12302;CUNEIFORM SIGN TIR TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12303;CUNEIFORM SIGN TIR OVER TIR;Lo;0;L;;;;;N;;;;;
+12304;CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+12305;CUNEIFORM SIGN TU;Lo;0;L;;;;;N;;;;;
+12306;CUNEIFORM SIGN TUG2;Lo;0;L;;;;;N;;;;;
+12307;CUNEIFORM SIGN TUK;Lo;0;L;;;;;N;;;;;
+12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;;
+12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;;
+1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;;
+1230B;CUNEIFORM SIGN U;Lo;0;L;;;;;N;;;;;
+1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;;
+1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;;N;;;;;
+1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;;
+1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;;
+12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;;
+12311;CUNEIFORM SIGN U2;Lo;0;L;;;;;N;;;;;
+12312;CUNEIFORM SIGN UB;Lo;0;L;;;;;N;;;;;
+12313;CUNEIFORM SIGN UD;Lo;0;L;;;;;N;;;;;
+12314;CUNEIFORM SIGN UD KUSHU2;Lo;0;L;;;;;N;;;;;
+12315;CUNEIFORM SIGN UD TIMES BAD;Lo;0;L;;;;;N;;;;;
+12316;CUNEIFORM SIGN UD TIMES MI;Lo;0;L;;;;;N;;;;;
+12317;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U;Lo;0;L;;;;;N;;;;;
+12318;CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU;Lo;0;L;;;;;N;;;;;
+12319;CUNEIFORM SIGN UD GUNU;Lo;0;L;;;;;N;;;;;
+1231A;CUNEIFORM SIGN UD SHESHIG;Lo;0;L;;;;;N;;;;;
+1231B;CUNEIFORM SIGN UD SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;;
+1231C;CUNEIFORM SIGN UDUG;Lo;0;L;;;;;N;;;;;
+1231D;CUNEIFORM SIGN UM;Lo;0;L;;;;;N;;;;;
+1231E;CUNEIFORM SIGN UM TIMES LAGAB;Lo;0;L;;;;;N;;;;;
+1231F;CUNEIFORM SIGN UM TIMES ME PLUS DA;Lo;0;L;;;;;N;;;;;
+12320;CUNEIFORM SIGN UM TIMES SHA3;Lo;0;L;;;;;N;;;;;
+12321;CUNEIFORM SIGN UM TIMES U;Lo;0;L;;;;;N;;;;;
+12322;CUNEIFORM SIGN UMBIN;Lo;0;L;;;;;N;;;;;
+12323;CUNEIFORM SIGN UMUM;Lo;0;L;;;;;N;;;;;
+12324;CUNEIFORM SIGN UMUM TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+12325;CUNEIFORM SIGN UMUM TIMES PA;Lo;0;L;;;;;N;;;;;
+12326;CUNEIFORM SIGN UN;Lo;0;L;;;;;N;;;;;
+12327;CUNEIFORM SIGN UN GUNU;Lo;0;L;;;;;N;;;;;
+12328;CUNEIFORM SIGN UR;Lo;0;L;;;;;N;;;;;
+12329;CUNEIFORM SIGN UR CROSSING UR;Lo;0;L;;;;;N;;;;;
+1232A;CUNEIFORM SIGN UR SHESHIG;Lo;0;L;;;;;N;;;;;
+1232B;CUNEIFORM SIGN UR2;Lo;0;L;;;;;N;;;;;
+1232C;CUNEIFORM SIGN UR2 TIMES A PLUS HA;Lo;0;L;;;;;N;;;;;
+1232D;CUNEIFORM SIGN UR2 TIMES A PLUS NA;Lo;0;L;;;;;N;;;;;
+1232E;CUNEIFORM SIGN UR2 TIMES AL;Lo;0;L;;;;;N;;;;;
+1232F;CUNEIFORM SIGN UR2 TIMES HA;Lo;0;L;;;;;N;;;;;
+12330;CUNEIFORM SIGN UR2 TIMES NUN;Lo;0;L;;;;;N;;;;;
+12331;CUNEIFORM SIGN UR2 TIMES U2;Lo;0;L;;;;;N;;;;;
+12332;CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH;Lo;0;L;;;;;N;;;;;
+12333;CUNEIFORM SIGN UR2 TIMES U2 PLUS BI;Lo;0;L;;;;;N;;;;;
+12334;CUNEIFORM SIGN UR4;Lo;0;L;;;;;N;;;;;
+12335;CUNEIFORM SIGN URI;Lo;0;L;;;;;N;;;;;
+12336;CUNEIFORM SIGN URI3;Lo;0;L;;;;;N;;;;;
+12337;CUNEIFORM SIGN URU;Lo;0;L;;;;;N;;;;;
+12338;CUNEIFORM SIGN URU TIMES A;Lo;0;L;;;;;N;;;;;
+12339;CUNEIFORM SIGN URU TIMES ASHGAB;Lo;0;L;;;;;N;;;;;
+1233A;CUNEIFORM SIGN URU TIMES BAR;Lo;0;L;;;;;N;;;;;
+1233B;CUNEIFORM SIGN URU TIMES DUN;Lo;0;L;;;;;N;;;;;
+1233C;CUNEIFORM SIGN URU TIMES GA;Lo;0;L;;;;;N;;;;;
+1233D;CUNEIFORM SIGN URU TIMES GAL;Lo;0;L;;;;;N;;;;;
+1233E;CUNEIFORM SIGN URU TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1233F;CUNEIFORM SIGN URU TIMES GAR;Lo;0;L;;;;;N;;;;;
+12340;CUNEIFORM SIGN URU TIMES GU;Lo;0;L;;;;;N;;;;;
+12341;CUNEIFORM SIGN URU TIMES HA;Lo;0;L;;;;;N;;;;;
+12342;CUNEIFORM SIGN URU TIMES IGI;Lo;0;L;;;;;N;;;;;
+12343;CUNEIFORM SIGN URU TIMES IM;Lo;0;L;;;;;N;;;;;
+12344;CUNEIFORM SIGN URU TIMES ISH;Lo;0;L;;;;;N;;;;;
+12345;CUNEIFORM SIGN URU TIMES KI;Lo;0;L;;;;;N;;;;;
+12346;CUNEIFORM SIGN URU TIMES LUM;Lo;0;L;;;;;N;;;;;
+12347;CUNEIFORM SIGN URU TIMES MIN;Lo;0;L;;;;;N;;;;;
+12348;CUNEIFORM SIGN URU TIMES PA;Lo;0;L;;;;;N;;;;;
+12349;CUNEIFORM SIGN URU TIMES SHE;Lo;0;L;;;;;N;;;;;
+1234A;CUNEIFORM SIGN URU TIMES SIG4;Lo;0;L;;;;;N;;;;;
+1234B;CUNEIFORM SIGN URU TIMES TU;Lo;0;L;;;;;N;;;;;
+1234C;CUNEIFORM SIGN URU TIMES U PLUS GUD;Lo;0;L;;;;;N;;;;;
+1234D;CUNEIFORM SIGN URU TIMES UD;Lo;0;L;;;;;N;;;;;
+1234E;CUNEIFORM SIGN URU TIMES URUDA;Lo;0;L;;;;;N;;;;;
+1234F;CUNEIFORM SIGN URUDA;Lo;0;L;;;;;N;;;;;
+12350;CUNEIFORM SIGN URUDA TIMES U;Lo;0;L;;;;;N;;;;;
+12351;CUNEIFORM SIGN USH;Lo;0;L;;;;;N;;;;;
+12352;CUNEIFORM SIGN USH TIMES A;Lo;0;L;;;;;N;;;;;
+12353;CUNEIFORM SIGN USH TIMES KU;Lo;0;L;;;;;N;;;;;
+12354;CUNEIFORM SIGN USH TIMES KUR;Lo;0;L;;;;;N;;;;;
+12355;CUNEIFORM SIGN USH TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12356;CUNEIFORM SIGN USHX;Lo;0;L;;;;;N;;;;;
+12357;CUNEIFORM SIGN USH2;Lo;0;L;;;;;N;;;;;
+12358;CUNEIFORM SIGN USHUMX;Lo;0;L;;;;;N;;;;;
+12359;CUNEIFORM SIGN UTUKI;Lo;0;L;;;;;N;;;;;
+1235A;CUNEIFORM SIGN UZ3;Lo;0;L;;;;;N;;;;;
+1235B;CUNEIFORM SIGN UZ3 TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+1235C;CUNEIFORM SIGN UZU;Lo;0;L;;;;;N;;;;;
+1235D;CUNEIFORM SIGN ZA;Lo;0;L;;;;;N;;;;;
+1235E;CUNEIFORM SIGN ZA TENU;Lo;0;L;;;;;N;;;;;
+1235F;CUNEIFORM SIGN ZA SQUARED TIMES KUR;Lo;0;L;;;;;N;;;;;
+12360;CUNEIFORM SIGN ZAG;Lo;0;L;;;;;N;;;;;
+12361;CUNEIFORM SIGN ZAMX;Lo;0;L;;;;;N;;;;;
+12362;CUNEIFORM SIGN ZE2;Lo;0;L;;;;;N;;;;;
+12363;CUNEIFORM SIGN ZI;Lo;0;L;;;;;N;;;;;
+12364;CUNEIFORM SIGN ZI OVER ZI;Lo;0;L;;;;;N;;;;;
+12365;CUNEIFORM SIGN ZI3;Lo;0;L;;;;;N;;;;;
+12366;CUNEIFORM SIGN ZIB;Lo;0;L;;;;;N;;;;;
+12367;CUNEIFORM SIGN ZIB KABA TENU;Lo;0;L;;;;;N;;;;;
+12368;CUNEIFORM SIGN ZIG;Lo;0;L;;;;;N;;;;;
+12369;CUNEIFORM SIGN ZIZ2;Lo;0;L;;;;;N;;;;;
+1236A;CUNEIFORM SIGN ZU;Lo;0;L;;;;;N;;;;;
+1236B;CUNEIFORM SIGN ZU5;Lo;0;L;;;;;N;;;;;
+1236C;CUNEIFORM SIGN ZU5 TIMES A;Lo;0;L;;;;;N;;;;;
+1236D;CUNEIFORM SIGN ZUBUR;Lo;0;L;;;;;N;;;;;
+1236E;CUNEIFORM SIGN ZUM;Lo;0;L;;;;;N;;;;;
+1236F;CUNEIFORM SIGN KAP ELAMITE;Lo;0;L;;;;;N;;;;;
+12370;CUNEIFORM SIGN AB TIMES NUN;Lo;0;L;;;;;N;;;;;
+12371;CUNEIFORM SIGN AB2 TIMES A;Lo;0;L;;;;;N;;;;;
+12372;CUNEIFORM SIGN AMAR TIMES KUG;Lo;0;L;;;;;N;;;;;
+12373;CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH;Lo;0;L;;;;;N;;;;;
+12374;CUNEIFORM SIGN DAG3;Lo;0;L;;;;;N;;;;;
+12375;CUNEIFORM SIGN DISH PLUS SHU;Lo;0;L;;;;;N;;;;;
+12376;CUNEIFORM SIGN DUB TIMES SHE;Lo;0;L;;;;;N;;;;;
+12377;CUNEIFORM SIGN EZEN TIMES GUD;Lo;0;L;;;;;N;;;;;
+12378;CUNEIFORM SIGN EZEN TIMES SHE;Lo;0;L;;;;;N;;;;;
+12379;CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A;Lo;0;L;;;;;N;;;;;
+1237A;CUNEIFORM SIGN GA2 TIMES ASH2;Lo;0;L;;;;;N;;;;;
+1237B;CUNEIFORM SIGN GE22;Lo;0;L;;;;;N;;;;;
+1237C;CUNEIFORM SIGN GIG;Lo;0;L;;;;;N;;;;;
+1237D;CUNEIFORM SIGN HUSH;Lo;0;L;;;;;N;;;;;
+1237E;CUNEIFORM SIGN KA TIMES ANSHE;Lo;0;L;;;;;N;;;;;
+1237F;CUNEIFORM SIGN KA TIMES ASH3;Lo;0;L;;;;;N;;;;;
+12380;CUNEIFORM SIGN KA TIMES GISH;Lo;0;L;;;;;N;;;;;
+12381;CUNEIFORM SIGN KA TIMES GUD;Lo;0;L;;;;;N;;;;;
+12382;CUNEIFORM SIGN KA TIMES HI TIMES ASH2;Lo;0;L;;;;;N;;;;;
+12383;CUNEIFORM SIGN KA TIMES LUM;Lo;0;L;;;;;N;;;;;
+12384;CUNEIFORM SIGN KA TIMES PA;Lo;0;L;;;;;N;;;;;
+12385;CUNEIFORM SIGN KA TIMES SHUL;Lo;0;L;;;;;N;;;;;
+12386;CUNEIFORM SIGN KA TIMES TU;Lo;0;L;;;;;N;;;;;
+12387;CUNEIFORM SIGN KA TIMES UR2;Lo;0;L;;;;;N;;;;;
+12388;CUNEIFORM SIGN LAGAB TIMES GI;Lo;0;L;;;;;N;;;;;
+12389;CUNEIFORM SIGN LU2 SHESHIG TIMES BAD;Lo;0;L;;;;;N;;;;;
+1238A;CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL;Lo;0;L;;;;;N;;;;;
+1238B;CUNEIFORM SIGN LU2 TIMES SHU;Lo;0;L;;;;;N;;;;;
+1238C;CUNEIFORM SIGN MESH;Lo;0;L;;;;;N;;;;;
+1238D;CUNEIFORM SIGN MUSH3 TIMES ZA;Lo;0;L;;;;;N;;;;;
+1238E;CUNEIFORM SIGN NA4;Lo;0;L;;;;;N;;;;;
+1238F;CUNEIFORM SIGN NIN;Lo;0;L;;;;;N;;;;;
+12390;CUNEIFORM SIGN NIN9;Lo;0;L;;;;;N;;;;;
+12391;CUNEIFORM SIGN NINDA2 TIMES BAL;Lo;0;L;;;;;N;;;;;
+12392;CUNEIFORM SIGN NINDA2 TIMES GI;Lo;0;L;;;;;N;;;;;
+12393;CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;;
+12394;CUNEIFORM SIGN PESH2 ASTERISK;Lo;0;L;;;;;N;;;;;
+12395;CUNEIFORM SIGN PIR2;Lo;0;L;;;;;N;;;;;
+12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;;
+12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;;
+12399;CUNEIFORM SIGN U U;Lo;0;L;;;;;N;;;;;
+12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;;
+12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;;
+12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;;
+12403;CUNEIFORM NUMERIC SIGN FIVE ASH;Nl;0;L;;;;5;N;;;;;
+12404;CUNEIFORM NUMERIC SIGN SIX ASH;Nl;0;L;;;;6;N;;;;;
+12405;CUNEIFORM NUMERIC SIGN SEVEN ASH;Nl;0;L;;;;7;N;;;;;
+12406;CUNEIFORM NUMERIC SIGN EIGHT ASH;Nl;0;L;;;;8;N;;;;;
+12407;CUNEIFORM NUMERIC SIGN NINE ASH;Nl;0;L;;;;9;N;;;;;
+12408;CUNEIFORM NUMERIC SIGN THREE DISH;Nl;0;L;;;;3;N;;;;;
+12409;CUNEIFORM NUMERIC SIGN FOUR DISH;Nl;0;L;;;;4;N;;;;;
+1240A;CUNEIFORM NUMERIC SIGN FIVE DISH;Nl;0;L;;;;5;N;;;;;
+1240B;CUNEIFORM NUMERIC SIGN SIX DISH;Nl;0;L;;;;6;N;;;;;
+1240C;CUNEIFORM NUMERIC SIGN SEVEN DISH;Nl;0;L;;;;7;N;;;;;
+1240D;CUNEIFORM NUMERIC SIGN EIGHT DISH;Nl;0;L;;;;8;N;;;;;
+1240E;CUNEIFORM NUMERIC SIGN NINE DISH;Nl;0;L;;;;9;N;;;;;
+1240F;CUNEIFORM NUMERIC SIGN FOUR U;Nl;0;L;;;;4;N;;;;;
+12410;CUNEIFORM NUMERIC SIGN FIVE U;Nl;0;L;;;;5;N;;;;;
+12411;CUNEIFORM NUMERIC SIGN SIX U;Nl;0;L;;;;6;N;;;;;
+12412;CUNEIFORM NUMERIC SIGN SEVEN U;Nl;0;L;;;;7;N;;;;;
+12413;CUNEIFORM NUMERIC SIGN EIGHT U;Nl;0;L;;;;8;N;;;;;
+12414;CUNEIFORM NUMERIC SIGN NINE U;Nl;0;L;;;;9;N;;;;;
+12415;CUNEIFORM NUMERIC SIGN ONE GESH2;Nl;0;L;;;;1;N;;;;;
+12416;CUNEIFORM NUMERIC SIGN TWO GESH2;Nl;0;L;;;;2;N;;;;;
+12417;CUNEIFORM NUMERIC SIGN THREE GESH2;Nl;0;L;;;;3;N;;;;;
+12418;CUNEIFORM NUMERIC SIGN FOUR GESH2;Nl;0;L;;;;4;N;;;;;
+12419;CUNEIFORM NUMERIC SIGN FIVE GESH2;Nl;0;L;;;;5;N;;;;;
+1241A;CUNEIFORM NUMERIC SIGN SIX GESH2;Nl;0;L;;;;6;N;;;;;
+1241B;CUNEIFORM NUMERIC SIGN SEVEN GESH2;Nl;0;L;;;;7;N;;;;;
+1241C;CUNEIFORM NUMERIC SIGN EIGHT GESH2;Nl;0;L;;;;8;N;;;;;
+1241D;CUNEIFORM NUMERIC SIGN NINE GESH2;Nl;0;L;;;;9;N;;;;;
+1241E;CUNEIFORM NUMERIC SIGN ONE GESHU;Nl;0;L;;;;1;N;;;;;
+1241F;CUNEIFORM NUMERIC SIGN TWO GESHU;Nl;0;L;;;;2;N;;;;;
+12420;CUNEIFORM NUMERIC SIGN THREE GESHU;Nl;0;L;;;;3;N;;;;;
+12421;CUNEIFORM NUMERIC SIGN FOUR GESHU;Nl;0;L;;;;4;N;;;;;
+12422;CUNEIFORM NUMERIC SIGN FIVE GESHU;Nl;0;L;;;;5;N;;;;;
+12423;CUNEIFORM NUMERIC SIGN TWO SHAR2;Nl;0;L;;;;2;N;;;;;
+12424;CUNEIFORM NUMERIC SIGN THREE SHAR2;Nl;0;L;;;;3;N;;;;;
+12425;CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM;Nl;0;L;;;;3;N;;;;;
+12426;CUNEIFORM NUMERIC SIGN FOUR SHAR2;Nl;0;L;;;;4;N;;;;;
+12427;CUNEIFORM NUMERIC SIGN FIVE SHAR2;Nl;0;L;;;;5;N;;;;;
+12428;CUNEIFORM NUMERIC SIGN SIX SHAR2;Nl;0;L;;;;6;N;;;;;
+12429;CUNEIFORM NUMERIC SIGN SEVEN SHAR2;Nl;0;L;;;;7;N;;;;;
+1242A;CUNEIFORM NUMERIC SIGN EIGHT SHAR2;Nl;0;L;;;;8;N;;;;;
+1242B;CUNEIFORM NUMERIC SIGN NINE SHAR2;Nl;0;L;;;;9;N;;;;;
+1242C;CUNEIFORM NUMERIC SIGN ONE SHARU;Nl;0;L;;;;1;N;;;;;
+1242D;CUNEIFORM NUMERIC SIGN TWO SHARU;Nl;0;L;;;;2;N;;;;;
+1242E;CUNEIFORM NUMERIC SIGN THREE SHARU;Nl;0;L;;;;3;N;;;;;
+1242F;CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM;Nl;0;L;;;;3;N;;;;;
+12430;CUNEIFORM NUMERIC SIGN FOUR SHARU;Nl;0;L;;;;4;N;;;;;
+12431;CUNEIFORM NUMERIC SIGN FIVE SHARU;Nl;0;L;;;;5;N;;;;;
+12432;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH;Nl;0;L;;;;216000;N;;;;;
+12433;CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN;Nl;0;L;;;;432000;N;;;;;
+12434;CUNEIFORM NUMERIC SIGN ONE BURU;Nl;0;L;;;;1;N;;;;;
+12435;CUNEIFORM NUMERIC SIGN TWO BURU;Nl;0;L;;;;2;N;;;;;
+12436;CUNEIFORM NUMERIC SIGN THREE BURU;Nl;0;L;;;;3;N;;;;;
+12437;CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM;Nl;0;L;;;;3;N;;;;;
+12438;CUNEIFORM NUMERIC SIGN FOUR BURU;Nl;0;L;;;;4;N;;;;;
+12439;CUNEIFORM NUMERIC SIGN FIVE BURU;Nl;0;L;;;;5;N;;;;;
+1243A;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16;Nl;0;L;;;;3;N;;;;;
+1243B;CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21;Nl;0;L;;;;3;N;;;;;
+1243C;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU;Nl;0;L;;;;4;N;;;;;
+1243D;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4;Nl;0;L;;;;4;N;;;;;
+1243E;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A;Nl;0;L;;;;4;N;;;;;
+1243F;CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B;Nl;0;L;;;;4;N;;;;;
+12440;CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9;Nl;0;L;;;;6;N;;;;;
+12441;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3;Nl;0;L;;;;7;N;;;;;
+12442;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A;Nl;0;L;;;;7;N;;;;;
+12443;CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B;Nl;0;L;;;;7;N;;;;;
+12444;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU;Nl;0;L;;;;8;N;;;;;
+12445;CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3;Nl;0;L;;;;8;N;;;;;
+12446;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU;Nl;0;L;;;;9;N;;;;;
+12447;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3;Nl;0;L;;;;9;N;;;;;
+12448;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4;Nl;0;L;;;;9;N;;;;;
+12449;CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A;Nl;0;L;;;;9;N;;;;;
+1244A;CUNEIFORM NUMERIC SIGN TWO ASH TENU;Nl;0;L;;;;2;N;;;;;
+1244B;CUNEIFORM NUMERIC SIGN THREE ASH TENU;Nl;0;L;;;;3;N;;;;;
+1244C;CUNEIFORM NUMERIC SIGN FOUR ASH TENU;Nl;0;L;;;;4;N;;;;;
+1244D;CUNEIFORM NUMERIC SIGN FIVE ASH TENU;Nl;0;L;;;;5;N;;;;;
+1244E;CUNEIFORM NUMERIC SIGN SIX ASH TENU;Nl;0;L;;;;6;N;;;;;
+1244F;CUNEIFORM NUMERIC SIGN ONE BAN2;Nl;0;L;;;;1;N;;;;;
+12450;CUNEIFORM NUMERIC SIGN TWO BAN2;Nl;0;L;;;;2;N;;;;;
+12451;CUNEIFORM NUMERIC SIGN THREE BAN2;Nl;0;L;;;;3;N;;;;;
+12452;CUNEIFORM NUMERIC SIGN FOUR BAN2;Nl;0;L;;;;4;N;;;;;
+12453;CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM;Nl;0;L;;;;4;N;;;;;
+12454;CUNEIFORM NUMERIC SIGN FIVE BAN2;Nl;0;L;;;;5;N;;;;;
+12455;CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM;Nl;0;L;;;;5;N;;;;;
+12456;CUNEIFORM NUMERIC SIGN NIGIDAMIN;Nl;0;L;;;;2;N;;;;;
+12457;CUNEIFORM NUMERIC SIGN NIGIDAESH;Nl;0;L;;;;3;N;;;;;
+12458;CUNEIFORM NUMERIC SIGN ONE ESHE3;Nl;0;L;;;;1;N;;;;;
+12459;CUNEIFORM NUMERIC SIGN TWO ESHE3;Nl;0;L;;;;2;N;;;;;
+1245A;CUNEIFORM NUMERIC SIGN ONE THIRD DISH;Nl;0;L;;;;1/3;N;;;;;
+1245B;CUNEIFORM NUMERIC SIGN TWO THIRDS DISH;Nl;0;L;;;;2/3;N;;;;;
+1245C;CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH;Nl;0;L;;;;5/6;N;;;;;
+1245D;CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A;Nl;0;L;;;;1/3;N;;;;;
+1245E;CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A;Nl;0;L;;;;2/3;N;;;;;
+1245F;CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH;Nl;0;L;;;;1/8;N;;;;;
+12460;CUNEIFORM NUMERIC SIGN ONE QUARTER ASH;Nl;0;L;;;;1/4;N;;;;;
+12461;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH;Nl;0;L;;;;1/6;N;;;;;
+12462;CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER;Nl;0;L;;;;1/4;N;;;;;
+12463;CUNEIFORM NUMERIC SIGN ONE QUARTER GUR;Nl;0;L;;;;1/4;N;;;;;
+12464;CUNEIFORM NUMERIC SIGN ONE HALF GUR;Nl;0;L;;;;1/2;N;;;;;
+12465;CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD;Nl;0;L;;;;1/3;N;;;;;
+12466;CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS;Nl;0;L;;;;2/3;N;;;;;
+12467;CUNEIFORM NUMERIC SIGN ELAMITE FORTY;Nl;0;L;;;;40;N;;;;;
+12468;CUNEIFORM NUMERIC SIGN ELAMITE FIFTY;Nl;0;L;;;;50;N;;;;;
+12469;CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM;Nl;0;L;;;;4;N;;;;;
+1246A;CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM;Nl;0;L;;;;5;N;;;;;
+1246B;CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM;Nl;0;L;;;;6;N;;;;;
+1246C;CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM;Nl;0;L;;;;7;N;;;;;
+1246D;CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM;Nl;0;L;;;;8;N;;;;;
+1246E;CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM;Nl;0;L;;;;9;N;;;;;
+12470;CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER;Po;0;L;;;;;N;;;;;
+12471;CUNEIFORM PUNCTUATION SIGN VERTICAL COLON;Po;0;L;;;;;N;;;;;
+12472;CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON;Po;0;L;;;;;N;;;;;
+12473;CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON;Po;0;L;;;;;N;;;;;
+12474;CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON;Po;0;L;;;;;N;;;;;
+12480;CUNEIFORM SIGN AB TIMES NUN TENU;Lo;0;L;;;;;N;;;;;
+12481;CUNEIFORM SIGN AB TIMES SHU2;Lo;0;L;;;;;N;;;;;
+12482;CUNEIFORM SIGN AD TIMES ESH2;Lo;0;L;;;;;N;;;;;
+12483;CUNEIFORM SIGN BAD TIMES DISH TENU;Lo;0;L;;;;;N;;;;;
+12484;CUNEIFORM SIGN BAHAR2 TIMES AB2;Lo;0;L;;;;;N;;;;;
+12485;CUNEIFORM SIGN BAHAR2 TIMES NI;Lo;0;L;;;;;N;;;;;
+12486;CUNEIFORM SIGN BAHAR2 TIMES ZA;Lo;0;L;;;;;N;;;;;
+12487;CUNEIFORM SIGN BU OVER BU TIMES NA2;Lo;0;L;;;;;N;;;;;
+12488;CUNEIFORM SIGN DA TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12489;CUNEIFORM SIGN DAG TIMES KUR;Lo;0;L;;;;;N;;;;;
+1248A;CUNEIFORM SIGN DIM TIMES IGI;Lo;0;L;;;;;N;;;;;
+1248B;CUNEIFORM SIGN DIM TIMES U U U;Lo;0;L;;;;;N;;;;;
+1248C;CUNEIFORM SIGN DIM2 TIMES UD;Lo;0;L;;;;;N;;;;;
+1248D;CUNEIFORM SIGN DUG TIMES ANSHE;Lo;0;L;;;;;N;;;;;
+1248E;CUNEIFORM SIGN DUG TIMES ASH;Lo;0;L;;;;;N;;;;;
+1248F;CUNEIFORM SIGN DUG TIMES ASH AT LEFT;Lo;0;L;;;;;N;;;;;
+12490;CUNEIFORM SIGN DUG TIMES DIN;Lo;0;L;;;;;N;;;;;
+12491;CUNEIFORM SIGN DUG TIMES DUN;Lo;0;L;;;;;N;;;;;
+12492;CUNEIFORM SIGN DUG TIMES ERIN2;Lo;0;L;;;;;N;;;;;
+12493;CUNEIFORM SIGN DUG TIMES GA;Lo;0;L;;;;;N;;;;;
+12494;CUNEIFORM SIGN DUG TIMES GI;Lo;0;L;;;;;N;;;;;
+12495;CUNEIFORM SIGN DUG TIMES GIR2 GUNU;Lo;0;L;;;;;N;;;;;
+12496;CUNEIFORM SIGN DUG TIMES GISH;Lo;0;L;;;;;N;;;;;
+12497;CUNEIFORM SIGN DUG TIMES HA;Lo;0;L;;;;;N;;;;;
+12498;CUNEIFORM SIGN DUG TIMES HI;Lo;0;L;;;;;N;;;;;
+12499;CUNEIFORM SIGN DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+1249A;CUNEIFORM SIGN DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+1249B;CUNEIFORM SIGN DUG TIMES KUR;Lo;0;L;;;;;N;;;;;
+1249C;CUNEIFORM SIGN DUG TIMES KUSHU2;Lo;0;L;;;;;N;;;;;
+1249D;CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;;
+1249E;CUNEIFORM SIGN DUG TIMES LAK-020;Lo;0;L;;;;;N;;;;;
+1249F;CUNEIFORM SIGN DUG TIMES LAM;Lo;0;L;;;;;N;;;;;
+124A0;CUNEIFORM SIGN DUG TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;;
+124A1;CUNEIFORM SIGN DUG TIMES LUH PLUS GISH;Lo;0;L;;;;;N;;;;;
+124A2;CUNEIFORM SIGN DUG TIMES MASH;Lo;0;L;;;;;N;;;;;
+124A3;CUNEIFORM SIGN DUG TIMES MES;Lo;0;L;;;;;N;;;;;
+124A4;CUNEIFORM SIGN DUG TIMES MI;Lo;0;L;;;;;N;;;;;
+124A5;CUNEIFORM SIGN DUG TIMES NI;Lo;0;L;;;;;N;;;;;
+124A6;CUNEIFORM SIGN DUG TIMES PI;Lo;0;L;;;;;N;;;;;
+124A7;CUNEIFORM SIGN DUG TIMES SHE;Lo;0;L;;;;;N;;;;;
+124A8;CUNEIFORM SIGN DUG TIMES SI GUNU;Lo;0;L;;;;;N;;;;;
+124A9;CUNEIFORM SIGN E2 TIMES KUR;Lo;0;L;;;;;N;;;;;
+124AA;CUNEIFORM SIGN E2 TIMES PAP;Lo;0;L;;;;;N;;;;;
+124AB;CUNEIFORM SIGN ERIN2 X;Lo;0;L;;;;;N;;;;;
+124AC;CUNEIFORM SIGN ESH2 CROSSING ESH2;Lo;0;L;;;;;N;;;;;
+124AD;CUNEIFORM SIGN EZEN SHESHIG TIMES ASH;Lo;0;L;;;;;N;;;;;
+124AE;CUNEIFORM SIGN EZEN SHESHIG TIMES HI;Lo;0;L;;;;;N;;;;;
+124AF;CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+124B0;CUNEIFORM SIGN EZEN SHESHIG TIMES LA;Lo;0;L;;;;;N;;;;;
+124B1;CUNEIFORM SIGN EZEN SHESHIG TIMES LAL;Lo;0;L;;;;;N;;;;;
+124B2;CUNEIFORM SIGN EZEN SHESHIG TIMES ME;Lo;0;L;;;;;N;;;;;
+124B3;CUNEIFORM SIGN EZEN SHESHIG TIMES MES;Lo;0;L;;;;;N;;;;;
+124B4;CUNEIFORM SIGN EZEN SHESHIG TIMES SU;Lo;0;L;;;;;N;;;;;
+124B5;CUNEIFORM SIGN EZEN TIMES SU;Lo;0;L;;;;;N;;;;;
+124B6;CUNEIFORM SIGN GA2 TIMES BAHAR2;Lo;0;L;;;;;N;;;;;
+124B7;CUNEIFORM SIGN GA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;;
+124B8;CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+124B9;CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL;Lo;0;L;;;;;N;;;;;
+124BA;CUNEIFORM SIGN GA2 TIMES EREN;Lo;0;L;;;;;N;;;;;
+124BB;CUNEIFORM SIGN GA2 TIMES GA;Lo;0;L;;;;;N;;;;;
+124BC;CUNEIFORM SIGN GA2 TIMES GAR PLUS DI;Lo;0;L;;;;;N;;;;;
+124BD;CUNEIFORM SIGN GA2 TIMES GAR PLUS NE;Lo;0;L;;;;;N;;;;;
+124BE;CUNEIFORM SIGN GA2 TIMES HA PLUS A;Lo;0;L;;;;;N;;;;;
+124BF;CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL;Lo;0;L;;;;;N;;;;;
+124C0;CUNEIFORM SIGN GA2 TIMES LAM;Lo;0;L;;;;;N;;;;;
+124C1;CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR;Lo;0;L;;;;;N;;;;;
+124C2;CUNEIFORM SIGN GA2 TIMES LUH;Lo;0;L;;;;;N;;;;;
+124C3;CUNEIFORM SIGN GA2 TIMES MUSH;Lo;0;L;;;;;N;;;;;
+124C4;CUNEIFORM SIGN GA2 TIMES NE;Lo;0;L;;;;;N;;;;;
+124C5;CUNEIFORM SIGN GA2 TIMES NE PLUS E2;Lo;0;L;;;;;N;;;;;
+124C6;CUNEIFORM SIGN GA2 TIMES NE PLUS GI;Lo;0;L;;;;;N;;;;;
+124C7;CUNEIFORM SIGN GA2 TIMES SHIM;Lo;0;L;;;;;N;;;;;
+124C8;CUNEIFORM SIGN GA2 TIMES ZIZ2;Lo;0;L;;;;;N;;;;;
+124C9;CUNEIFORM SIGN GABA ROTATED NINETY DEGREES;Lo;0;L;;;;;N;;;;;
+124CA;CUNEIFORM SIGN GESHTIN TIMES U;Lo;0;L;;;;;N;;;;;
+124CB;CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH;Lo;0;L;;;;;N;;;;;
+124CC;CUNEIFORM SIGN GU2 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+124CD;CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4;Lo;0;L;;;;;N;;;;;
+124CE;CUNEIFORM SIGN HA TENU GUNU;Lo;0;L;;;;;N;;;;;
+124CF;CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH;Lo;0;L;;;;;N;;;;;
+124D0;CUNEIFORM SIGN KA TIMES BU;Lo;0;L;;;;;N;;;;;
+124D1;CUNEIFORM SIGN KA TIMES KA;Lo;0;L;;;;;N;;;;;
+124D2;CUNEIFORM SIGN KA TIMES U U U;Lo;0;L;;;;;N;;;;;
+124D3;CUNEIFORM SIGN KA TIMES UR;Lo;0;L;;;;;N;;;;;
+124D4;CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU;Lo;0;L;;;;;N;;;;;
+124D5;CUNEIFORM SIGN LAK-003;Lo;0;L;;;;;N;;;;;
+124D6;CUNEIFORM SIGN LAK-021;Lo;0;L;;;;;N;;;;;
+124D7;CUNEIFORM SIGN LAK-025;Lo;0;L;;;;;N;;;;;
+124D8;CUNEIFORM SIGN LAK-030;Lo;0;L;;;;;N;;;;;
+124D9;CUNEIFORM SIGN LAK-050;Lo;0;L;;;;;N;;;;;
+124DA;CUNEIFORM SIGN LAK-051;Lo;0;L;;;;;N;;;;;
+124DB;CUNEIFORM SIGN LAK-062;Lo;0;L;;;;;N;;;;;
+124DC;CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU;Lo;0;L;;;;;N;;;;;
+124DD;CUNEIFORM SIGN LAK-080;Lo;0;L;;;;;N;;;;;
+124DE;CUNEIFORM SIGN LAK-081 OVER LAK-081;Lo;0;L;;;;;N;;;;;
+124DF;CUNEIFORM SIGN LAK-092;Lo;0;L;;;;;N;;;;;
+124E0;CUNEIFORM SIGN LAK-130;Lo;0;L;;;;;N;;;;;
+124E1;CUNEIFORM SIGN LAK-142;Lo;0;L;;;;;N;;;;;
+124E2;CUNEIFORM SIGN LAK-210;Lo;0;L;;;;;N;;;;;
+124E3;CUNEIFORM SIGN LAK-219;Lo;0;L;;;;;N;;;;;
+124E4;CUNEIFORM SIGN LAK-220;Lo;0;L;;;;;N;;;;;
+124E5;CUNEIFORM SIGN LAK-225;Lo;0;L;;;;;N;;;;;
+124E6;CUNEIFORM SIGN LAK-228;Lo;0;L;;;;;N;;;;;
+124E7;CUNEIFORM SIGN LAK-238;Lo;0;L;;;;;N;;;;;
+124E8;CUNEIFORM SIGN LAK-265;Lo;0;L;;;;;N;;;;;
+124E9;CUNEIFORM SIGN LAK-266;Lo;0;L;;;;;N;;;;;
+124EA;CUNEIFORM SIGN LAK-343;Lo;0;L;;;;;N;;;;;
+124EB;CUNEIFORM SIGN LAK-347;Lo;0;L;;;;;N;;;;;
+124EC;CUNEIFORM SIGN LAK-348;Lo;0;L;;;;;N;;;;;
+124ED;CUNEIFORM SIGN LAK-383;Lo;0;L;;;;;N;;;;;
+124EE;CUNEIFORM SIGN LAK-384;Lo;0;L;;;;;N;;;;;
+124EF;CUNEIFORM SIGN LAK-390;Lo;0;L;;;;;N;;;;;
+124F0;CUNEIFORM SIGN LAK-441;Lo;0;L;;;;;N;;;;;
+124F1;CUNEIFORM SIGN LAK-449;Lo;0;L;;;;;N;;;;;
+124F2;CUNEIFORM SIGN LAK-449 TIMES GU;Lo;0;L;;;;;N;;;;;
+124F3;CUNEIFORM SIGN LAK-449 TIMES IGI;Lo;0;L;;;;;N;;;;;
+124F4;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3;Lo;0;L;;;;;N;;;;;
+124F5;CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;
+124F6;CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA;Lo;0;L;;;;;N;;;;;
+124F7;CUNEIFORM SIGN LAK-450;Lo;0;L;;;;;N;;;;;
+124F8;CUNEIFORM SIGN LAK-457;Lo;0;L;;;;;N;;;;;
+124F9;CUNEIFORM SIGN LAK-470;Lo;0;L;;;;;N;;;;;
+124FA;CUNEIFORM SIGN LAK-483;Lo;0;L;;;;;N;;;;;
+124FB;CUNEIFORM SIGN LAK-490;Lo;0;L;;;;;N;;;;;
+124FC;CUNEIFORM SIGN LAK-492;Lo;0;L;;;;;N;;;;;
+124FD;CUNEIFORM SIGN LAK-493;Lo;0;L;;;;;N;;;;;
+124FE;CUNEIFORM SIGN LAK-495;Lo;0;L;;;;;N;;;;;
+124FF;CUNEIFORM SIGN LAK-550;Lo;0;L;;;;;N;;;;;
+12500;CUNEIFORM SIGN LAK-608;Lo;0;L;;;;;N;;;;;
+12501;CUNEIFORM SIGN LAK-617;Lo;0;L;;;;;N;;;;;
+12502;CUNEIFORM SIGN LAK-617 TIMES ASH;Lo;0;L;;;;;N;;;;;
+12503;CUNEIFORM SIGN LAK-617 TIMES BAD;Lo;0;L;;;;;N;;;;;
+12504;CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU;Lo;0;L;;;;;N;;;;;
+12505;CUNEIFORM SIGN LAK-617 TIMES KU3;Lo;0;L;;;;;N;;;;;
+12506;CUNEIFORM SIGN LAK-617 TIMES LA;Lo;0;L;;;;;N;;;;;
+12507;CUNEIFORM SIGN LAK-617 TIMES TAR;Lo;0;L;;;;;N;;;;;
+12508;CUNEIFORM SIGN LAK-617 TIMES TE;Lo;0;L;;;;;N;;;;;
+12509;CUNEIFORM SIGN LAK-617 TIMES U2;Lo;0;L;;;;;N;;;;;
+1250A;CUNEIFORM SIGN LAK-617 TIMES UD;Lo;0;L;;;;;N;;;;;
+1250B;CUNEIFORM SIGN LAK-617 TIMES URUDA;Lo;0;L;;;;;N;;;;;
+1250C;CUNEIFORM SIGN LAK-636;Lo;0;L;;;;;N;;;;;
+1250D;CUNEIFORM SIGN LAK-648;Lo;0;L;;;;;N;;;;;
+1250E;CUNEIFORM SIGN LAK-648 TIMES DUB;Lo;0;L;;;;;N;;;;;
+1250F;CUNEIFORM SIGN LAK-648 TIMES GA;Lo;0;L;;;;;N;;;;;
+12510;CUNEIFORM SIGN LAK-648 TIMES IGI;Lo;0;L;;;;;N;;;;;
+12511;CUNEIFORM SIGN LAK-648 TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
+12512;CUNEIFORM SIGN LAK-648 TIMES NI;Lo;0;L;;;;;N;;;;;
+12513;CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;
+12514;CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI;Lo;0;L;;;;;N;;;;;
+12515;CUNEIFORM SIGN LAK-648 TIMES UD;Lo;0;L;;;;;N;;;;;
+12516;CUNEIFORM SIGN LAK-648 TIMES URUDA;Lo;0;L;;;;;N;;;;;
+12517;CUNEIFORM SIGN LAK-724;Lo;0;L;;;;;N;;;;;
+12518;CUNEIFORM SIGN LAK-749;Lo;0;L;;;;;N;;;;;
+12519;CUNEIFORM SIGN LU2 GUNU TIMES ASH;Lo;0;L;;;;;N;;;;;
+1251A;CUNEIFORM SIGN LU2 TIMES DISH;Lo;0;L;;;;;N;;;;;
+1251B;CUNEIFORM SIGN LU2 TIMES HAL;Lo;0;L;;;;;N;;;;;
+1251C;CUNEIFORM SIGN LU2 TIMES PAP;Lo;0;L;;;;;N;;;;;
+1251D;CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3;Lo;0;L;;;;;N;;;;;
+1251E;CUNEIFORM SIGN LU2 TIMES TAK4;Lo;0;L;;;;;N;;;;;
+1251F;CUNEIFORM SIGN MI PLUS ZA7;Lo;0;L;;;;;N;;;;;
+12520;CUNEIFORM SIGN MUSH OVER MUSH TIMES GA;Lo;0;L;;;;;N;;;;;
+12521;CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK;Lo;0;L;;;;;N;;;;;
+12522;CUNEIFORM SIGN NINDA2 TIMES DIM GUNU;Lo;0;L;;;;;N;;;;;
+12523;CUNEIFORM SIGN NINDA2 TIMES GISH;Lo;0;L;;;;;N;;;;;
+12524;CUNEIFORM SIGN NINDA2 TIMES GUL;Lo;0;L;;;;;N;;;;;
+12525;CUNEIFORM SIGN NINDA2 TIMES HI;Lo;0;L;;;;;N;;;;;
+12526;CUNEIFORM SIGN NINDA2 TIMES KESH2;Lo;0;L;;;;;N;;;;;
+12527;CUNEIFORM SIGN NINDA2 TIMES LAK-050;Lo;0;L;;;;;N;;;;;
+12528;CUNEIFORM SIGN NINDA2 TIMES MASH;Lo;0;L;;;;;N;;;;;
+12529;CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP;Lo;0;L;;;;;N;;;;;
+1252A;CUNEIFORM SIGN NINDA2 TIMES U;Lo;0;L;;;;;N;;;;;
+1252B;CUNEIFORM SIGN NINDA2 TIMES U PLUS U;Lo;0;L;;;;;N;;;;;
+1252C;CUNEIFORM SIGN NINDA2 TIMES URUDA;Lo;0;L;;;;;N;;;;;
+1252D;CUNEIFORM SIGN SAG GUNU TIMES HA;Lo;0;L;;;;;N;;;;;
+1252E;CUNEIFORM SIGN SAG TIMES EN;Lo;0;L;;;;;N;;;;;
+1252F;CUNEIFORM SIGN SAG TIMES SHE AT LEFT;Lo;0;L;;;;;N;;;;;
+12530;CUNEIFORM SIGN SAG TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12531;CUNEIFORM SIGN SHA6 TENU;Lo;0;L;;;;;N;;;;;
+12532;CUNEIFORM SIGN SHE OVER SHE;Lo;0;L;;;;;N;;;;;
+12533;CUNEIFORM SIGN SHE PLUS HUB2;Lo;0;L;;;;;N;;;;;
+12534;CUNEIFORM SIGN SHE PLUS NAM2;Lo;0;L;;;;;N;;;;;
+12535;CUNEIFORM SIGN SHE PLUS SAR;Lo;0;L;;;;;N;;;;;
+12536;CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI;Lo;0;L;;;;;N;;;;;
+12537;CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN;Lo;0;L;;;;;N;;;;;
+12538;CUNEIFORM SIGN SI TIMES TAK4;Lo;0;L;;;;;N;;;;;
+12539;CUNEIFORM SIGN TAK4 PLUS SAG;Lo;0;L;;;;;N;;;;;
+1253A;CUNEIFORM SIGN TUM TIMES GAN2 TENU;Lo;0;L;;;;;N;;;;;
+1253B;CUNEIFORM SIGN TUM TIMES THREE DISH;Lo;0;L;;;;;N;;;;;
+1253C;CUNEIFORM SIGN UR2 INVERTED;Lo;0;L;;;;;N;;;;;
+1253D;CUNEIFORM SIGN UR2 TIMES UD;Lo;0;L;;;;;N;;;;;
+1253E;CUNEIFORM SIGN URU TIMES DARA3;Lo;0;L;;;;;N;;;;;
+1253F;CUNEIFORM SIGN URU TIMES LAK-668;Lo;0;L;;;;;N;;;;;
+12540;CUNEIFORM SIGN URU TIMES LU3;Lo;0;L;;;;;N;;;;;
+12541;CUNEIFORM SIGN ZA7;Lo;0;L;;;;;N;;;;;
+12542;CUNEIFORM SIGN ZU OVER ZU PLUS SAR;Lo;0;L;;;;;N;;;;;
+12543;CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU;Lo;0;L;;;;;N;;;;;
+13000;EGYPTIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;;
+13001;EGYPTIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;;
+13002;EGYPTIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;;
+13003;EGYPTIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;;
+13004;EGYPTIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;;
+13005;EGYPTIAN HIEROGLYPH A005A;Lo;0;L;;;;;N;;;;;
+13006;EGYPTIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;;
+13007;EGYPTIAN HIEROGLYPH A006A;Lo;0;L;;;;;N;;;;;
+13008;EGYPTIAN HIEROGLYPH A006B;Lo;0;L;;;;;N;;;;;
+13009;EGYPTIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;;
+1300A;EGYPTIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;;
+1300B;EGYPTIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;;
+1300C;EGYPTIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;;
+1300D;EGYPTIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;;
+1300E;EGYPTIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;;
+1300F;EGYPTIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;;
+13010;EGYPTIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;;
+13011;EGYPTIAN HIEROGLYPH A014A;Lo;0;L;;;;;N;;;;;
+13012;EGYPTIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;;
+13013;EGYPTIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;;
+13014;EGYPTIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;;
+13015;EGYPTIAN HIEROGLYPH A017A;Lo;0;L;;;;;N;;;;;
+13016;EGYPTIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;;
+13017;EGYPTIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;;
+13018;EGYPTIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;;
+13019;EGYPTIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;;
+1301A;EGYPTIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;;
+1301B;EGYPTIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;;
+1301C;EGYPTIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;;
+1301D;EGYPTIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;;
+1301E;EGYPTIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;;
+1301F;EGYPTIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;;
+13020;EGYPTIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;;
+13021;EGYPTIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;;
+13022;EGYPTIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;;
+13023;EGYPTIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;;
+13024;EGYPTIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;;
+13025;EGYPTIAN HIEROGLYPH A032A;Lo;0;L;;;;;N;;;;;
+13026;EGYPTIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;;
+13027;EGYPTIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;;
+13028;EGYPTIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;;
+13029;EGYPTIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;;
+1302A;EGYPTIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;;
+1302B;EGYPTIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;;
+1302C;EGYPTIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;;
+1302D;EGYPTIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;;
+1302E;EGYPTIAN HIEROGLYPH A040A;Lo;0;L;;;;;N;;;;;
+1302F;EGYPTIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;;
+13030;EGYPTIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;;
+13031;EGYPTIAN HIEROGLYPH A042A;Lo;0;L;;;;;N;;;;;
+13032;EGYPTIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;;
+13033;EGYPTIAN HIEROGLYPH A043A;Lo;0;L;;;;;N;;;;;
+13034;EGYPTIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;;
+13035;EGYPTIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;;
+13036;EGYPTIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;;
+13037;EGYPTIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;;
+13038;EGYPTIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;;
+13039;EGYPTIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;;
+1303A;EGYPTIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;;
+1303B;EGYPTIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;;
+1303C;EGYPTIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;;
+1303D;EGYPTIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;;
+1303E;EGYPTIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;;
+1303F;EGYPTIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;;
+13040;EGYPTIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;;
+13041;EGYPTIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;;
+13042;EGYPTIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;;
+13043;EGYPTIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;;
+13044;EGYPTIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;;
+13045;EGYPTIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;;
+13046;EGYPTIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;;
+13047;EGYPTIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;;
+13048;EGYPTIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;;
+13049;EGYPTIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;;
+1304A;EGYPTIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;;
+1304B;EGYPTIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;;
+1304C;EGYPTIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;;
+1304D;EGYPTIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;;
+1304E;EGYPTIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;;
+1304F;EGYPTIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;;
+13050;EGYPTIAN HIEROGLYPH B001;Lo;0;L;;;;;N;;;;;
+13051;EGYPTIAN HIEROGLYPH B002;Lo;0;L;;;;;N;;;;;
+13052;EGYPTIAN HIEROGLYPH B003;Lo;0;L;;;;;N;;;;;
+13053;EGYPTIAN HIEROGLYPH B004;Lo;0;L;;;;;N;;;;;
+13054;EGYPTIAN HIEROGLYPH B005;Lo;0;L;;;;;N;;;;;
+13055;EGYPTIAN HIEROGLYPH B005A;Lo;0;L;;;;;N;;;;;
+13056;EGYPTIAN HIEROGLYPH B006;Lo;0;L;;;;;N;;;;;
+13057;EGYPTIAN HIEROGLYPH B007;Lo;0;L;;;;;N;;;;;
+13058;EGYPTIAN HIEROGLYPH B008;Lo;0;L;;;;;N;;;;;
+13059;EGYPTIAN HIEROGLYPH B009;Lo;0;L;;;;;N;;;;;
+1305A;EGYPTIAN HIEROGLYPH C001;Lo;0;L;;;;;N;;;;;
+1305B;EGYPTIAN HIEROGLYPH C002;Lo;0;L;;;;;N;;;;;
+1305C;EGYPTIAN HIEROGLYPH C002A;Lo;0;L;;;;;N;;;;;
+1305D;EGYPTIAN HIEROGLYPH C002B;Lo;0;L;;;;;N;;;;;
+1305E;EGYPTIAN HIEROGLYPH C002C;Lo;0;L;;;;;N;;;;;
+1305F;EGYPTIAN HIEROGLYPH C003;Lo;0;L;;;;;N;;;;;
+13060;EGYPTIAN HIEROGLYPH C004;Lo;0;L;;;;;N;;;;;
+13061;EGYPTIAN HIEROGLYPH C005;Lo;0;L;;;;;N;;;;;
+13062;EGYPTIAN HIEROGLYPH C006;Lo;0;L;;;;;N;;;;;
+13063;EGYPTIAN HIEROGLYPH C007;Lo;0;L;;;;;N;;;;;
+13064;EGYPTIAN HIEROGLYPH C008;Lo;0;L;;;;;N;;;;;
+13065;EGYPTIAN HIEROGLYPH C009;Lo;0;L;;;;;N;;;;;
+13066;EGYPTIAN HIEROGLYPH C010;Lo;0;L;;;;;N;;;;;
+13067;EGYPTIAN HIEROGLYPH C010A;Lo;0;L;;;;;N;;;;;
+13068;EGYPTIAN HIEROGLYPH C011;Lo;0;L;;;;;N;;;;;
+13069;EGYPTIAN HIEROGLYPH C012;Lo;0;L;;;;;N;;;;;
+1306A;EGYPTIAN HIEROGLYPH C013;Lo;0;L;;;;;N;;;;;
+1306B;EGYPTIAN HIEROGLYPH C014;Lo;0;L;;;;;N;;;;;
+1306C;EGYPTIAN HIEROGLYPH C015;Lo;0;L;;;;;N;;;;;
+1306D;EGYPTIAN HIEROGLYPH C016;Lo;0;L;;;;;N;;;;;
+1306E;EGYPTIAN HIEROGLYPH C017;Lo;0;L;;;;;N;;;;;
+1306F;EGYPTIAN HIEROGLYPH C018;Lo;0;L;;;;;N;;;;;
+13070;EGYPTIAN HIEROGLYPH C019;Lo;0;L;;;;;N;;;;;
+13071;EGYPTIAN HIEROGLYPH C020;Lo;0;L;;;;;N;;;;;
+13072;EGYPTIAN HIEROGLYPH C021;Lo;0;L;;;;;N;;;;;
+13073;EGYPTIAN HIEROGLYPH C022;Lo;0;L;;;;;N;;;;;
+13074;EGYPTIAN HIEROGLYPH C023;Lo;0;L;;;;;N;;;;;
+13075;EGYPTIAN HIEROGLYPH C024;Lo;0;L;;;;;N;;;;;
+13076;EGYPTIAN HIEROGLYPH D001;Lo;0;L;;;;;N;;;;;
+13077;EGYPTIAN HIEROGLYPH D002;Lo;0;L;;;;;N;;;;;
+13078;EGYPTIAN HIEROGLYPH D003;Lo;0;L;;;;;N;;;;;
+13079;EGYPTIAN HIEROGLYPH D004;Lo;0;L;;;;;N;;;;;
+1307A;EGYPTIAN HIEROGLYPH D005;Lo;0;L;;;;;N;;;;;
+1307B;EGYPTIAN HIEROGLYPH D006;Lo;0;L;;;;;N;;;;;
+1307C;EGYPTIAN HIEROGLYPH D007;Lo;0;L;;;;;N;;;;;
+1307D;EGYPTIAN HIEROGLYPH D008;Lo;0;L;;;;;N;;;;;
+1307E;EGYPTIAN HIEROGLYPH D008A;Lo;0;L;;;;;N;;;;;
+1307F;EGYPTIAN HIEROGLYPH D009;Lo;0;L;;;;;N;;;;;
+13080;EGYPTIAN HIEROGLYPH D010;Lo;0;L;;;;;N;;;;;
+13081;EGYPTIAN HIEROGLYPH D011;Lo;0;L;;;;;N;;;;;
+13082;EGYPTIAN HIEROGLYPH D012;Lo;0;L;;;;;N;;;;;
+13083;EGYPTIAN HIEROGLYPH D013;Lo;0;L;;;;;N;;;;;
+13084;EGYPTIAN HIEROGLYPH D014;Lo;0;L;;;;;N;;;;;
+13085;EGYPTIAN HIEROGLYPH D015;Lo;0;L;;;;;N;;;;;
+13086;EGYPTIAN HIEROGLYPH D016;Lo;0;L;;;;;N;;;;;
+13087;EGYPTIAN HIEROGLYPH D017;Lo;0;L;;;;;N;;;;;
+13088;EGYPTIAN HIEROGLYPH D018;Lo;0;L;;;;;N;;;;;
+13089;EGYPTIAN HIEROGLYPH D019;Lo;0;L;;;;;N;;;;;
+1308A;EGYPTIAN HIEROGLYPH D020;Lo;0;L;;;;;N;;;;;
+1308B;EGYPTIAN HIEROGLYPH D021;Lo;0;L;;;;;N;;;;;
+1308C;EGYPTIAN HIEROGLYPH D022;Lo;0;L;;;;;N;;;;;
+1308D;EGYPTIAN HIEROGLYPH D023;Lo;0;L;;;;;N;;;;;
+1308E;EGYPTIAN HIEROGLYPH D024;Lo;0;L;;;;;N;;;;;
+1308F;EGYPTIAN HIEROGLYPH D025;Lo;0;L;;;;;N;;;;;
+13090;EGYPTIAN HIEROGLYPH D026;Lo;0;L;;;;;N;;;;;
+13091;EGYPTIAN HIEROGLYPH D027;Lo;0;L;;;;;N;;;;;
+13092;EGYPTIAN HIEROGLYPH D027A;Lo;0;L;;;;;N;;;;;
+13093;EGYPTIAN HIEROGLYPH D028;Lo;0;L;;;;;N;;;;;
+13094;EGYPTIAN HIEROGLYPH D029;Lo;0;L;;;;;N;;;;;
+13095;EGYPTIAN HIEROGLYPH D030;Lo;0;L;;;;;N;;;;;
+13096;EGYPTIAN HIEROGLYPH D031;Lo;0;L;;;;;N;;;;;
+13097;EGYPTIAN HIEROGLYPH D031A;Lo;0;L;;;;;N;;;;;
+13098;EGYPTIAN HIEROGLYPH D032;Lo;0;L;;;;;N;;;;;
+13099;EGYPTIAN HIEROGLYPH D033;Lo;0;L;;;;;N;;;;;
+1309A;EGYPTIAN HIEROGLYPH D034;Lo;0;L;;;;;N;;;;;
+1309B;EGYPTIAN HIEROGLYPH D034A;Lo;0;L;;;;;N;;;;;
+1309C;EGYPTIAN HIEROGLYPH D035;Lo;0;L;;;;;N;;;;;
+1309D;EGYPTIAN HIEROGLYPH D036;Lo;0;L;;;;;N;;;;;
+1309E;EGYPTIAN HIEROGLYPH D037;Lo;0;L;;;;;N;;;;;
+1309F;EGYPTIAN HIEROGLYPH D038;Lo;0;L;;;;;N;;;;;
+130A0;EGYPTIAN HIEROGLYPH D039;Lo;0;L;;;;;N;;;;;
+130A1;EGYPTIAN HIEROGLYPH D040;Lo;0;L;;;;;N;;;;;
+130A2;EGYPTIAN HIEROGLYPH D041;Lo;0;L;;;;;N;;;;;
+130A3;EGYPTIAN HIEROGLYPH D042;Lo;0;L;;;;;N;;;;;
+130A4;EGYPTIAN HIEROGLYPH D043;Lo;0;L;;;;;N;;;;;
+130A5;EGYPTIAN HIEROGLYPH D044;Lo;0;L;;;;;N;;;;;
+130A6;EGYPTIAN HIEROGLYPH D045;Lo;0;L;;;;;N;;;;;
+130A7;EGYPTIAN HIEROGLYPH D046;Lo;0;L;;;;;N;;;;;
+130A8;EGYPTIAN HIEROGLYPH D046A;Lo;0;L;;;;;N;;;;;
+130A9;EGYPTIAN HIEROGLYPH D047;Lo;0;L;;;;;N;;;;;
+130AA;EGYPTIAN HIEROGLYPH D048;Lo;0;L;;;;;N;;;;;
+130AB;EGYPTIAN HIEROGLYPH D048A;Lo;0;L;;;;;N;;;;;
+130AC;EGYPTIAN HIEROGLYPH D049;Lo;0;L;;;;;N;;;;;
+130AD;EGYPTIAN HIEROGLYPH D050;Lo;0;L;;;;;N;;;;;
+130AE;EGYPTIAN HIEROGLYPH D050A;Lo;0;L;;;;;N;;;;;
+130AF;EGYPTIAN HIEROGLYPH D050B;Lo;0;L;;;;;N;;;;;
+130B0;EGYPTIAN HIEROGLYPH D050C;Lo;0;L;;;;;N;;;;;
+130B1;EGYPTIAN HIEROGLYPH D050D;Lo;0;L;;;;;N;;;;;
+130B2;EGYPTIAN HIEROGLYPH D050E;Lo;0;L;;;;;N;;;;;
+130B3;EGYPTIAN HIEROGLYPH D050F;Lo;0;L;;;;;N;;;;;
+130B4;EGYPTIAN HIEROGLYPH D050G;Lo;0;L;;;;;N;;;;;
+130B5;EGYPTIAN HIEROGLYPH D050H;Lo;0;L;;;;;N;;;;;
+130B6;EGYPTIAN HIEROGLYPH D050I;Lo;0;L;;;;;N;;;;;
+130B7;EGYPTIAN HIEROGLYPH D051;Lo;0;L;;;;;N;;;;;
+130B8;EGYPTIAN HIEROGLYPH D052;Lo;0;L;;;;;N;;;;;
+130B9;EGYPTIAN HIEROGLYPH D052A;Lo;0;L;;;;;N;;;;;
+130BA;EGYPTIAN HIEROGLYPH D053;Lo;0;L;;;;;N;;;;;
+130BB;EGYPTIAN HIEROGLYPH D054;Lo;0;L;;;;;N;;;;;
+130BC;EGYPTIAN HIEROGLYPH D054A;Lo;0;L;;;;;N;;;;;
+130BD;EGYPTIAN HIEROGLYPH D055;Lo;0;L;;;;;N;;;;;
+130BE;EGYPTIAN HIEROGLYPH D056;Lo;0;L;;;;;N;;;;;
+130BF;EGYPTIAN HIEROGLYPH D057;Lo;0;L;;;;;N;;;;;
+130C0;EGYPTIAN HIEROGLYPH D058;Lo;0;L;;;;;N;;;;;
+130C1;EGYPTIAN HIEROGLYPH D059;Lo;0;L;;;;;N;;;;;
+130C2;EGYPTIAN HIEROGLYPH D060;Lo;0;L;;;;;N;;;;;
+130C3;EGYPTIAN HIEROGLYPH D061;Lo;0;L;;;;;N;;;;;
+130C4;EGYPTIAN HIEROGLYPH D062;Lo;0;L;;;;;N;;;;;
+130C5;EGYPTIAN HIEROGLYPH D063;Lo;0;L;;;;;N;;;;;
+130C6;EGYPTIAN HIEROGLYPH D064;Lo;0;L;;;;;N;;;;;
+130C7;EGYPTIAN HIEROGLYPH D065;Lo;0;L;;;;;N;;;;;
+130C8;EGYPTIAN HIEROGLYPH D066;Lo;0;L;;;;;N;;;;;
+130C9;EGYPTIAN HIEROGLYPH D067;Lo;0;L;;;;;N;;;;;
+130CA;EGYPTIAN HIEROGLYPH D067A;Lo;0;L;;;;;N;;;;;
+130CB;EGYPTIAN HIEROGLYPH D067B;Lo;0;L;;;;;N;;;;;
+130CC;EGYPTIAN HIEROGLYPH D067C;Lo;0;L;;;;;N;;;;;
+130CD;EGYPTIAN HIEROGLYPH D067D;Lo;0;L;;;;;N;;;;;
+130CE;EGYPTIAN HIEROGLYPH D067E;Lo;0;L;;;;;N;;;;;
+130CF;EGYPTIAN HIEROGLYPH D067F;Lo;0;L;;;;;N;;;;;
+130D0;EGYPTIAN HIEROGLYPH D067G;Lo;0;L;;;;;N;;;;;
+130D1;EGYPTIAN HIEROGLYPH D067H;Lo;0;L;;;;;N;;;;;
+130D2;EGYPTIAN HIEROGLYPH E001;Lo;0;L;;;;;N;;;;;
+130D3;EGYPTIAN HIEROGLYPH E002;Lo;0;L;;;;;N;;;;;
+130D4;EGYPTIAN HIEROGLYPH E003;Lo;0;L;;;;;N;;;;;
+130D5;EGYPTIAN HIEROGLYPH E004;Lo;0;L;;;;;N;;;;;
+130D6;EGYPTIAN HIEROGLYPH E005;Lo;0;L;;;;;N;;;;;
+130D7;EGYPTIAN HIEROGLYPH E006;Lo;0;L;;;;;N;;;;;
+130D8;EGYPTIAN HIEROGLYPH E007;Lo;0;L;;;;;N;;;;;
+130D9;EGYPTIAN HIEROGLYPH E008;Lo;0;L;;;;;N;;;;;
+130DA;EGYPTIAN HIEROGLYPH E008A;Lo;0;L;;;;;N;;;;;
+130DB;EGYPTIAN HIEROGLYPH E009;Lo;0;L;;;;;N;;;;;
+130DC;EGYPTIAN HIEROGLYPH E009A;Lo;0;L;;;;;N;;;;;
+130DD;EGYPTIAN HIEROGLYPH E010;Lo;0;L;;;;;N;;;;;
+130DE;EGYPTIAN HIEROGLYPH E011;Lo;0;L;;;;;N;;;;;
+130DF;EGYPTIAN HIEROGLYPH E012;Lo;0;L;;;;;N;;;;;
+130E0;EGYPTIAN HIEROGLYPH E013;Lo;0;L;;;;;N;;;;;
+130E1;EGYPTIAN HIEROGLYPH E014;Lo;0;L;;;;;N;;;;;
+130E2;EGYPTIAN HIEROGLYPH E015;Lo;0;L;;;;;N;;;;;
+130E3;EGYPTIAN HIEROGLYPH E016;Lo;0;L;;;;;N;;;;;
+130E4;EGYPTIAN HIEROGLYPH E016A;Lo;0;L;;;;;N;;;;;
+130E5;EGYPTIAN HIEROGLYPH E017;Lo;0;L;;;;;N;;;;;
+130E6;EGYPTIAN HIEROGLYPH E017A;Lo;0;L;;;;;N;;;;;
+130E7;EGYPTIAN HIEROGLYPH E018;Lo;0;L;;;;;N;;;;;
+130E8;EGYPTIAN HIEROGLYPH E019;Lo;0;L;;;;;N;;;;;
+130E9;EGYPTIAN HIEROGLYPH E020;Lo;0;L;;;;;N;;;;;
+130EA;EGYPTIAN HIEROGLYPH E020A;Lo;0;L;;;;;N;;;;;
+130EB;EGYPTIAN HIEROGLYPH E021;Lo;0;L;;;;;N;;;;;
+130EC;EGYPTIAN HIEROGLYPH E022;Lo;0;L;;;;;N;;;;;
+130ED;EGYPTIAN HIEROGLYPH E023;Lo;0;L;;;;;N;;;;;
+130EE;EGYPTIAN HIEROGLYPH E024;Lo;0;L;;;;;N;;;;;
+130EF;EGYPTIAN HIEROGLYPH E025;Lo;0;L;;;;;N;;;;;
+130F0;EGYPTIAN HIEROGLYPH E026;Lo;0;L;;;;;N;;;;;
+130F1;EGYPTIAN HIEROGLYPH E027;Lo;0;L;;;;;N;;;;;
+130F2;EGYPTIAN HIEROGLYPH E028;Lo;0;L;;;;;N;;;;;
+130F3;EGYPTIAN HIEROGLYPH E028A;Lo;0;L;;;;;N;;;;;
+130F4;EGYPTIAN HIEROGLYPH E029;Lo;0;L;;;;;N;;;;;
+130F5;EGYPTIAN HIEROGLYPH E030;Lo;0;L;;;;;N;;;;;
+130F6;EGYPTIAN HIEROGLYPH E031;Lo;0;L;;;;;N;;;;;
+130F7;EGYPTIAN HIEROGLYPH E032;Lo;0;L;;;;;N;;;;;
+130F8;EGYPTIAN HIEROGLYPH E033;Lo;0;L;;;;;N;;;;;
+130F9;EGYPTIAN HIEROGLYPH E034;Lo;0;L;;;;;N;;;;;
+130FA;EGYPTIAN HIEROGLYPH E034A;Lo;0;L;;;;;N;;;;;
+130FB;EGYPTIAN HIEROGLYPH E036;Lo;0;L;;;;;N;;;;;
+130FC;EGYPTIAN HIEROGLYPH E037;Lo;0;L;;;;;N;;;;;
+130FD;EGYPTIAN HIEROGLYPH E038;Lo;0;L;;;;;N;;;;;
+130FE;EGYPTIAN HIEROGLYPH F001;Lo;0;L;;;;;N;;;;;
+130FF;EGYPTIAN HIEROGLYPH F001A;Lo;0;L;;;;;N;;;;;
+13100;EGYPTIAN HIEROGLYPH F002;Lo;0;L;;;;;N;;;;;
+13101;EGYPTIAN HIEROGLYPH F003;Lo;0;L;;;;;N;;;;;
+13102;EGYPTIAN HIEROGLYPH F004;Lo;0;L;;;;;N;;;;;
+13103;EGYPTIAN HIEROGLYPH F005;Lo;0;L;;;;;N;;;;;
+13104;EGYPTIAN HIEROGLYPH F006;Lo;0;L;;;;;N;;;;;
+13105;EGYPTIAN HIEROGLYPH F007;Lo;0;L;;;;;N;;;;;
+13106;EGYPTIAN HIEROGLYPH F008;Lo;0;L;;;;;N;;;;;
+13107;EGYPTIAN HIEROGLYPH F009;Lo;0;L;;;;;N;;;;;
+13108;EGYPTIAN HIEROGLYPH F010;Lo;0;L;;;;;N;;;;;
+13109;EGYPTIAN HIEROGLYPH F011;Lo;0;L;;;;;N;;;;;
+1310A;EGYPTIAN HIEROGLYPH F012;Lo;0;L;;;;;N;;;;;
+1310B;EGYPTIAN HIEROGLYPH F013;Lo;0;L;;;;;N;;;;;
+1310C;EGYPTIAN HIEROGLYPH F013A;Lo;0;L;;;;;N;;;;;
+1310D;EGYPTIAN HIEROGLYPH F014;Lo;0;L;;;;;N;;;;;
+1310E;EGYPTIAN HIEROGLYPH F015;Lo;0;L;;;;;N;;;;;
+1310F;EGYPTIAN HIEROGLYPH F016;Lo;0;L;;;;;N;;;;;
+13110;EGYPTIAN HIEROGLYPH F017;Lo;0;L;;;;;N;;;;;
+13111;EGYPTIAN HIEROGLYPH F018;Lo;0;L;;;;;N;;;;;
+13112;EGYPTIAN HIEROGLYPH F019;Lo;0;L;;;;;N;;;;;
+13113;EGYPTIAN HIEROGLYPH F020;Lo;0;L;;;;;N;;;;;
+13114;EGYPTIAN HIEROGLYPH F021;Lo;0;L;;;;;N;;;;;
+13115;EGYPTIAN HIEROGLYPH F021A;Lo;0;L;;;;;N;;;;;
+13116;EGYPTIAN HIEROGLYPH F022;Lo;0;L;;;;;N;;;;;
+13117;EGYPTIAN HIEROGLYPH F023;Lo;0;L;;;;;N;;;;;
+13118;EGYPTIAN HIEROGLYPH F024;Lo;0;L;;;;;N;;;;;
+13119;EGYPTIAN HIEROGLYPH F025;Lo;0;L;;;;;N;;;;;
+1311A;EGYPTIAN HIEROGLYPH F026;Lo;0;L;;;;;N;;;;;
+1311B;EGYPTIAN HIEROGLYPH F027;Lo;0;L;;;;;N;;;;;
+1311C;EGYPTIAN HIEROGLYPH F028;Lo;0;L;;;;;N;;;;;
+1311D;EGYPTIAN HIEROGLYPH F029;Lo;0;L;;;;;N;;;;;
+1311E;EGYPTIAN HIEROGLYPH F030;Lo;0;L;;;;;N;;;;;
+1311F;EGYPTIAN HIEROGLYPH F031;Lo;0;L;;;;;N;;;;;
+13120;EGYPTIAN HIEROGLYPH F031A;Lo;0;L;;;;;N;;;;;
+13121;EGYPTIAN HIEROGLYPH F032;Lo;0;L;;;;;N;;;;;
+13122;EGYPTIAN HIEROGLYPH F033;Lo;0;L;;;;;N;;;;;
+13123;EGYPTIAN HIEROGLYPH F034;Lo;0;L;;;;;N;;;;;
+13124;EGYPTIAN HIEROGLYPH F035;Lo;0;L;;;;;N;;;;;
+13125;EGYPTIAN HIEROGLYPH F036;Lo;0;L;;;;;N;;;;;
+13126;EGYPTIAN HIEROGLYPH F037;Lo;0;L;;;;;N;;;;;
+13127;EGYPTIAN HIEROGLYPH F037A;Lo;0;L;;;;;N;;;;;
+13128;EGYPTIAN HIEROGLYPH F038;Lo;0;L;;;;;N;;;;;
+13129;EGYPTIAN HIEROGLYPH F038A;Lo;0;L;;;;;N;;;;;
+1312A;EGYPTIAN HIEROGLYPH F039;Lo;0;L;;;;;N;;;;;
+1312B;EGYPTIAN HIEROGLYPH F040;Lo;0;L;;;;;N;;;;;
+1312C;EGYPTIAN HIEROGLYPH F041;Lo;0;L;;;;;N;;;;;
+1312D;EGYPTIAN HIEROGLYPH F042;Lo;0;L;;;;;N;;;;;
+1312E;EGYPTIAN HIEROGLYPH F043;Lo;0;L;;;;;N;;;;;
+1312F;EGYPTIAN HIEROGLYPH F044;Lo;0;L;;;;;N;;;;;
+13130;EGYPTIAN HIEROGLYPH F045;Lo;0;L;;;;;N;;;;;
+13131;EGYPTIAN HIEROGLYPH F045A;Lo;0;L;;;;;N;;;;;
+13132;EGYPTIAN HIEROGLYPH F046;Lo;0;L;;;;;N;;;;;
+13133;EGYPTIAN HIEROGLYPH F046A;Lo;0;L;;;;;N;;;;;
+13134;EGYPTIAN HIEROGLYPH F047;Lo;0;L;;;;;N;;;;;
+13135;EGYPTIAN HIEROGLYPH F047A;Lo;0;L;;;;;N;;;;;
+13136;EGYPTIAN HIEROGLYPH F048;Lo;0;L;;;;;N;;;;;
+13137;EGYPTIAN HIEROGLYPH F049;Lo;0;L;;;;;N;;;;;
+13138;EGYPTIAN HIEROGLYPH F050;Lo;0;L;;;;;N;;;;;
+13139;EGYPTIAN HIEROGLYPH F051;Lo;0;L;;;;;N;;;;;
+1313A;EGYPTIAN HIEROGLYPH F051A;Lo;0;L;;;;;N;;;;;
+1313B;EGYPTIAN HIEROGLYPH F051B;Lo;0;L;;;;;N;;;;;
+1313C;EGYPTIAN HIEROGLYPH F051C;Lo;0;L;;;;;N;;;;;
+1313D;EGYPTIAN HIEROGLYPH F052;Lo;0;L;;;;;N;;;;;
+1313E;EGYPTIAN HIEROGLYPH F053;Lo;0;L;;;;;N;;;;;
+1313F;EGYPTIAN HIEROGLYPH G001;Lo;0;L;;;;;N;;;;;
+13140;EGYPTIAN HIEROGLYPH G002;Lo;0;L;;;;;N;;;;;
+13141;EGYPTIAN HIEROGLYPH G003;Lo;0;L;;;;;N;;;;;
+13142;EGYPTIAN HIEROGLYPH G004;Lo;0;L;;;;;N;;;;;
+13143;EGYPTIAN HIEROGLYPH G005;Lo;0;L;;;;;N;;;;;
+13144;EGYPTIAN HIEROGLYPH G006;Lo;0;L;;;;;N;;;;;
+13145;EGYPTIAN HIEROGLYPH G006A;Lo;0;L;;;;;N;;;;;
+13146;EGYPTIAN HIEROGLYPH G007;Lo;0;L;;;;;N;;;;;
+13147;EGYPTIAN HIEROGLYPH G007A;Lo;0;L;;;;;N;;;;;
+13148;EGYPTIAN HIEROGLYPH G007B;Lo;0;L;;;;;N;;;;;
+13149;EGYPTIAN HIEROGLYPH G008;Lo;0;L;;;;;N;;;;;
+1314A;EGYPTIAN HIEROGLYPH G009;Lo;0;L;;;;;N;;;;;
+1314B;EGYPTIAN HIEROGLYPH G010;Lo;0;L;;;;;N;;;;;
+1314C;EGYPTIAN HIEROGLYPH G011;Lo;0;L;;;;;N;;;;;
+1314D;EGYPTIAN HIEROGLYPH G011A;Lo;0;L;;;;;N;;;;;
+1314E;EGYPTIAN HIEROGLYPH G012;Lo;0;L;;;;;N;;;;;
+1314F;EGYPTIAN HIEROGLYPH G013;Lo;0;L;;;;;N;;;;;
+13150;EGYPTIAN HIEROGLYPH G014;Lo;0;L;;;;;N;;;;;
+13151;EGYPTIAN HIEROGLYPH G015;Lo;0;L;;;;;N;;;;;
+13152;EGYPTIAN HIEROGLYPH G016;Lo;0;L;;;;;N;;;;;
+13153;EGYPTIAN HIEROGLYPH G017;Lo;0;L;;;;;N;;;;;
+13154;EGYPTIAN HIEROGLYPH G018;Lo;0;L;;;;;N;;;;;
+13155;EGYPTIAN HIEROGLYPH G019;Lo;0;L;;;;;N;;;;;
+13156;EGYPTIAN HIEROGLYPH G020;Lo;0;L;;;;;N;;;;;
+13157;EGYPTIAN HIEROGLYPH G020A;Lo;0;L;;;;;N;;;;;
+13158;EGYPTIAN HIEROGLYPH G021;Lo;0;L;;;;;N;;;;;
+13159;EGYPTIAN HIEROGLYPH G022;Lo;0;L;;;;;N;;;;;
+1315A;EGYPTIAN HIEROGLYPH G023;Lo;0;L;;;;;N;;;;;
+1315B;EGYPTIAN HIEROGLYPH G024;Lo;0;L;;;;;N;;;;;
+1315C;EGYPTIAN HIEROGLYPH G025;Lo;0;L;;;;;N;;;;;
+1315D;EGYPTIAN HIEROGLYPH G026;Lo;0;L;;;;;N;;;;;
+1315E;EGYPTIAN HIEROGLYPH G026A;Lo;0;L;;;;;N;;;;;
+1315F;EGYPTIAN HIEROGLYPH G027;Lo;0;L;;;;;N;;;;;
+13160;EGYPTIAN HIEROGLYPH G028;Lo;0;L;;;;;N;;;;;
+13161;EGYPTIAN HIEROGLYPH G029;Lo;0;L;;;;;N;;;;;
+13162;EGYPTIAN HIEROGLYPH G030;Lo;0;L;;;;;N;;;;;
+13163;EGYPTIAN HIEROGLYPH G031;Lo;0;L;;;;;N;;;;;
+13164;EGYPTIAN HIEROGLYPH G032;Lo;0;L;;;;;N;;;;;
+13165;EGYPTIAN HIEROGLYPH G033;Lo;0;L;;;;;N;;;;;
+13166;EGYPTIAN HIEROGLYPH G034;Lo;0;L;;;;;N;;;;;
+13167;EGYPTIAN HIEROGLYPH G035;Lo;0;L;;;;;N;;;;;
+13168;EGYPTIAN HIEROGLYPH G036;Lo;0;L;;;;;N;;;;;
+13169;EGYPTIAN HIEROGLYPH G036A;Lo;0;L;;;;;N;;;;;
+1316A;EGYPTIAN HIEROGLYPH G037;Lo;0;L;;;;;N;;;;;
+1316B;EGYPTIAN HIEROGLYPH G037A;Lo;0;L;;;;;N;;;;;
+1316C;EGYPTIAN HIEROGLYPH G038;Lo;0;L;;;;;N;;;;;
+1316D;EGYPTIAN HIEROGLYPH G039;Lo;0;L;;;;;N;;;;;
+1316E;EGYPTIAN HIEROGLYPH G040;Lo;0;L;;;;;N;;;;;
+1316F;EGYPTIAN HIEROGLYPH G041;Lo;0;L;;;;;N;;;;;
+13170;EGYPTIAN HIEROGLYPH G042;Lo;0;L;;;;;N;;;;;
+13171;EGYPTIAN HIEROGLYPH G043;Lo;0;L;;;;;N;;;;;
+13172;EGYPTIAN HIEROGLYPH G043A;Lo;0;L;;;;;N;;;;;
+13173;EGYPTIAN HIEROGLYPH G044;Lo;0;L;;;;;N;;;;;
+13174;EGYPTIAN HIEROGLYPH G045;Lo;0;L;;;;;N;;;;;
+13175;EGYPTIAN HIEROGLYPH G045A;Lo;0;L;;;;;N;;;;;
+13176;EGYPTIAN HIEROGLYPH G046;Lo;0;L;;;;;N;;;;;
+13177;EGYPTIAN HIEROGLYPH G047;Lo;0;L;;;;;N;;;;;
+13178;EGYPTIAN HIEROGLYPH G048;Lo;0;L;;;;;N;;;;;
+13179;EGYPTIAN HIEROGLYPH G049;Lo;0;L;;;;;N;;;;;
+1317A;EGYPTIAN HIEROGLYPH G050;Lo;0;L;;;;;N;;;;;
+1317B;EGYPTIAN HIEROGLYPH G051;Lo;0;L;;;;;N;;;;;
+1317C;EGYPTIAN HIEROGLYPH G052;Lo;0;L;;;;;N;;;;;
+1317D;EGYPTIAN HIEROGLYPH G053;Lo;0;L;;;;;N;;;;;
+1317E;EGYPTIAN HIEROGLYPH G054;Lo;0;L;;;;;N;;;;;
+1317F;EGYPTIAN HIEROGLYPH H001;Lo;0;L;;;;;N;;;;;
+13180;EGYPTIAN HIEROGLYPH H002;Lo;0;L;;;;;N;;;;;
+13181;EGYPTIAN HIEROGLYPH H003;Lo;0;L;;;;;N;;;;;
+13182;EGYPTIAN HIEROGLYPH H004;Lo;0;L;;;;;N;;;;;
+13183;EGYPTIAN HIEROGLYPH H005;Lo;0;L;;;;;N;;;;;
+13184;EGYPTIAN HIEROGLYPH H006;Lo;0;L;;;;;N;;;;;
+13185;EGYPTIAN HIEROGLYPH H006A;Lo;0;L;;;;;N;;;;;
+13186;EGYPTIAN HIEROGLYPH H007;Lo;0;L;;;;;N;;;;;
+13187;EGYPTIAN HIEROGLYPH H008;Lo;0;L;;;;;N;;;;;
+13188;EGYPTIAN HIEROGLYPH I001;Lo;0;L;;;;;N;;;;;
+13189;EGYPTIAN HIEROGLYPH I002;Lo;0;L;;;;;N;;;;;
+1318A;EGYPTIAN HIEROGLYPH I003;Lo;0;L;;;;;N;;;;;
+1318B;EGYPTIAN HIEROGLYPH I004;Lo;0;L;;;;;N;;;;;
+1318C;EGYPTIAN HIEROGLYPH I005;Lo;0;L;;;;;N;;;;;
+1318D;EGYPTIAN HIEROGLYPH I005A;Lo;0;L;;;;;N;;;;;
+1318E;EGYPTIAN HIEROGLYPH I006;Lo;0;L;;;;;N;;;;;
+1318F;EGYPTIAN HIEROGLYPH I007;Lo;0;L;;;;;N;;;;;
+13190;EGYPTIAN HIEROGLYPH I008;Lo;0;L;;;;;N;;;;;
+13191;EGYPTIAN HIEROGLYPH I009;Lo;0;L;;;;;N;;;;;
+13192;EGYPTIAN HIEROGLYPH I009A;Lo;0;L;;;;;N;;;;;
+13193;EGYPTIAN HIEROGLYPH I010;Lo;0;L;;;;;N;;;;;
+13194;EGYPTIAN HIEROGLYPH I010A;Lo;0;L;;;;;N;;;;;
+13195;EGYPTIAN HIEROGLYPH I011;Lo;0;L;;;;;N;;;;;
+13196;EGYPTIAN HIEROGLYPH I011A;Lo;0;L;;;;;N;;;;;
+13197;EGYPTIAN HIEROGLYPH I012;Lo;0;L;;;;;N;;;;;
+13198;EGYPTIAN HIEROGLYPH I013;Lo;0;L;;;;;N;;;;;
+13199;EGYPTIAN HIEROGLYPH I014;Lo;0;L;;;;;N;;;;;
+1319A;EGYPTIAN HIEROGLYPH I015;Lo;0;L;;;;;N;;;;;
+1319B;EGYPTIAN HIEROGLYPH K001;Lo;0;L;;;;;N;;;;;
+1319C;EGYPTIAN HIEROGLYPH K002;Lo;0;L;;;;;N;;;;;
+1319D;EGYPTIAN HIEROGLYPH K003;Lo;0;L;;;;;N;;;;;
+1319E;EGYPTIAN HIEROGLYPH K004;Lo;0;L;;;;;N;;;;;
+1319F;EGYPTIAN HIEROGLYPH K005;Lo;0;L;;;;;N;;;;;
+131A0;EGYPTIAN HIEROGLYPH K006;Lo;0;L;;;;;N;;;;;
+131A1;EGYPTIAN HIEROGLYPH K007;Lo;0;L;;;;;N;;;;;
+131A2;EGYPTIAN HIEROGLYPH K008;Lo;0;L;;;;;N;;;;;
+131A3;EGYPTIAN HIEROGLYPH L001;Lo;0;L;;;;;N;;;;;
+131A4;EGYPTIAN HIEROGLYPH L002;Lo;0;L;;;;;N;;;;;
+131A5;EGYPTIAN HIEROGLYPH L002A;Lo;0;L;;;;;N;;;;;
+131A6;EGYPTIAN HIEROGLYPH L003;Lo;0;L;;;;;N;;;;;
+131A7;EGYPTIAN HIEROGLYPH L004;Lo;0;L;;;;;N;;;;;
+131A8;EGYPTIAN HIEROGLYPH L005;Lo;0;L;;;;;N;;;;;
+131A9;EGYPTIAN HIEROGLYPH L006;Lo;0;L;;;;;N;;;;;
+131AA;EGYPTIAN HIEROGLYPH L006A;Lo;0;L;;;;;N;;;;;
+131AB;EGYPTIAN HIEROGLYPH L007;Lo;0;L;;;;;N;;;;;
+131AC;EGYPTIAN HIEROGLYPH L008;Lo;0;L;;;;;N;;;;;
+131AD;EGYPTIAN HIEROGLYPH M001;Lo;0;L;;;;;N;;;;;
+131AE;EGYPTIAN HIEROGLYPH M001A;Lo;0;L;;;;;N;;;;;
+131AF;EGYPTIAN HIEROGLYPH M001B;Lo;0;L;;;;;N;;;;;
+131B0;EGYPTIAN HIEROGLYPH M002;Lo;0;L;;;;;N;;;;;
+131B1;EGYPTIAN HIEROGLYPH M003;Lo;0;L;;;;;N;;;;;
+131B2;EGYPTIAN HIEROGLYPH M003A;Lo;0;L;;;;;N;;;;;
+131B3;EGYPTIAN HIEROGLYPH M004;Lo;0;L;;;;;N;;;;;
+131B4;EGYPTIAN HIEROGLYPH M005;Lo;0;L;;;;;N;;;;;
+131B5;EGYPTIAN HIEROGLYPH M006;Lo;0;L;;;;;N;;;;;
+131B6;EGYPTIAN HIEROGLYPH M007;Lo;0;L;;;;;N;;;;;
+131B7;EGYPTIAN HIEROGLYPH M008;Lo;0;L;;;;;N;;;;;
+131B8;EGYPTIAN HIEROGLYPH M009;Lo;0;L;;;;;N;;;;;
+131B9;EGYPTIAN HIEROGLYPH M010;Lo;0;L;;;;;N;;;;;
+131BA;EGYPTIAN HIEROGLYPH M010A;Lo;0;L;;;;;N;;;;;
+131BB;EGYPTIAN HIEROGLYPH M011;Lo;0;L;;;;;N;;;;;
+131BC;EGYPTIAN HIEROGLYPH M012;Lo;0;L;;;;;N;;;;;
+131BD;EGYPTIAN HIEROGLYPH M012A;Lo;0;L;;;;;N;;;;;
+131BE;EGYPTIAN HIEROGLYPH M012B;Lo;0;L;;;;;N;;;;;
+131BF;EGYPTIAN HIEROGLYPH M012C;Lo;0;L;;;;;N;;;;;
+131C0;EGYPTIAN HIEROGLYPH M012D;Lo;0;L;;;;;N;;;;;
+131C1;EGYPTIAN HIEROGLYPH M012E;Lo;0;L;;;;;N;;;;;
+131C2;EGYPTIAN HIEROGLYPH M012F;Lo;0;L;;;;;N;;;;;
+131C3;EGYPTIAN HIEROGLYPH M012G;Lo;0;L;;;;;N;;;;;
+131C4;EGYPTIAN HIEROGLYPH M012H;Lo;0;L;;;;;N;;;;;
+131C5;EGYPTIAN HIEROGLYPH M013;Lo;0;L;;;;;N;;;;;
+131C6;EGYPTIAN HIEROGLYPH M014;Lo;0;L;;;;;N;;;;;
+131C7;EGYPTIAN HIEROGLYPH M015;Lo;0;L;;;;;N;;;;;
+131C8;EGYPTIAN HIEROGLYPH M015A;Lo;0;L;;;;;N;;;;;
+131C9;EGYPTIAN HIEROGLYPH M016;Lo;0;L;;;;;N;;;;;
+131CA;EGYPTIAN HIEROGLYPH M016A;Lo;0;L;;;;;N;;;;;
+131CB;EGYPTIAN HIEROGLYPH M017;Lo;0;L;;;;;N;;;;;
+131CC;EGYPTIAN HIEROGLYPH M017A;Lo;0;L;;;;;N;;;;;
+131CD;EGYPTIAN HIEROGLYPH M018;Lo;0;L;;;;;N;;;;;
+131CE;EGYPTIAN HIEROGLYPH M019;Lo;0;L;;;;;N;;;;;
+131CF;EGYPTIAN HIEROGLYPH M020;Lo;0;L;;;;;N;;;;;
+131D0;EGYPTIAN HIEROGLYPH M021;Lo;0;L;;;;;N;;;;;
+131D1;EGYPTIAN HIEROGLYPH M022;Lo;0;L;;;;;N;;;;;
+131D2;EGYPTIAN HIEROGLYPH M022A;Lo;0;L;;;;;N;;;;;
+131D3;EGYPTIAN HIEROGLYPH M023;Lo;0;L;;;;;N;;;;;
+131D4;EGYPTIAN HIEROGLYPH M024;Lo;0;L;;;;;N;;;;;
+131D5;EGYPTIAN HIEROGLYPH M024A;Lo;0;L;;;;;N;;;;;
+131D6;EGYPTIAN HIEROGLYPH M025;Lo;0;L;;;;;N;;;;;
+131D7;EGYPTIAN HIEROGLYPH M026;Lo;0;L;;;;;N;;;;;
+131D8;EGYPTIAN HIEROGLYPH M027;Lo;0;L;;;;;N;;;;;
+131D9;EGYPTIAN HIEROGLYPH M028;Lo;0;L;;;;;N;;;;;
+131DA;EGYPTIAN HIEROGLYPH M028A;Lo;0;L;;;;;N;;;;;
+131DB;EGYPTIAN HIEROGLYPH M029;Lo;0;L;;;;;N;;;;;
+131DC;EGYPTIAN HIEROGLYPH M030;Lo;0;L;;;;;N;;;;;
+131DD;EGYPTIAN HIEROGLYPH M031;Lo;0;L;;;;;N;;;;;
+131DE;EGYPTIAN HIEROGLYPH M031A;Lo;0;L;;;;;N;;;;;
+131DF;EGYPTIAN HIEROGLYPH M032;Lo;0;L;;;;;N;;;;;
+131E0;EGYPTIAN HIEROGLYPH M033;Lo;0;L;;;;;N;;;;;
+131E1;EGYPTIAN HIEROGLYPH M033A;Lo;0;L;;;;;N;;;;;
+131E2;EGYPTIAN HIEROGLYPH M033B;Lo;0;L;;;;;N;;;;;
+131E3;EGYPTIAN HIEROGLYPH M034;Lo;0;L;;;;;N;;;;;
+131E4;EGYPTIAN HIEROGLYPH M035;Lo;0;L;;;;;N;;;;;
+131E5;EGYPTIAN HIEROGLYPH M036;Lo;0;L;;;;;N;;;;;
+131E6;EGYPTIAN HIEROGLYPH M037;Lo;0;L;;;;;N;;;;;
+131E7;EGYPTIAN HIEROGLYPH M038;Lo;0;L;;;;;N;;;;;
+131E8;EGYPTIAN HIEROGLYPH M039;Lo;0;L;;;;;N;;;;;
+131E9;EGYPTIAN HIEROGLYPH M040;Lo;0;L;;;;;N;;;;;
+131EA;EGYPTIAN HIEROGLYPH M040A;Lo;0;L;;;;;N;;;;;
+131EB;EGYPTIAN HIEROGLYPH M041;Lo;0;L;;;;;N;;;;;
+131EC;EGYPTIAN HIEROGLYPH M042;Lo;0;L;;;;;N;;;;;
+131ED;EGYPTIAN HIEROGLYPH M043;Lo;0;L;;;;;N;;;;;
+131EE;EGYPTIAN HIEROGLYPH M044;Lo;0;L;;;;;N;;;;;
+131EF;EGYPTIAN HIEROGLYPH N001;Lo;0;L;;;;;N;;;;;
+131F0;EGYPTIAN HIEROGLYPH N002;Lo;0;L;;;;;N;;;;;
+131F1;EGYPTIAN HIEROGLYPH N003;Lo;0;L;;;;;N;;;;;
+131F2;EGYPTIAN HIEROGLYPH N004;Lo;0;L;;;;;N;;;;;
+131F3;EGYPTIAN HIEROGLYPH N005;Lo;0;L;;;;;N;;;;;
+131F4;EGYPTIAN HIEROGLYPH N006;Lo;0;L;;;;;N;;;;;
+131F5;EGYPTIAN HIEROGLYPH N007;Lo;0;L;;;;;N;;;;;
+131F6;EGYPTIAN HIEROGLYPH N008;Lo;0;L;;;;;N;;;;;
+131F7;EGYPTIAN HIEROGLYPH N009;Lo;0;L;;;;;N;;;;;
+131F8;EGYPTIAN HIEROGLYPH N010;Lo;0;L;;;;;N;;;;;
+131F9;EGYPTIAN HIEROGLYPH N011;Lo;0;L;;;;;N;;;;;
+131FA;EGYPTIAN HIEROGLYPH N012;Lo;0;L;;;;;N;;;;;
+131FB;EGYPTIAN HIEROGLYPH N013;Lo;0;L;;;;;N;;;;;
+131FC;EGYPTIAN HIEROGLYPH N014;Lo;0;L;;;;;N;;;;;
+131FD;EGYPTIAN HIEROGLYPH N015;Lo;0;L;;;;;N;;;;;
+131FE;EGYPTIAN HIEROGLYPH N016;Lo;0;L;;;;;N;;;;;
+131FF;EGYPTIAN HIEROGLYPH N017;Lo;0;L;;;;;N;;;;;
+13200;EGYPTIAN HIEROGLYPH N018;Lo;0;L;;;;;N;;;;;
+13201;EGYPTIAN HIEROGLYPH N018A;Lo;0;L;;;;;N;;;;;
+13202;EGYPTIAN HIEROGLYPH N018B;Lo;0;L;;;;;N;;;;;
+13203;EGYPTIAN HIEROGLYPH N019;Lo;0;L;;;;;N;;;;;
+13204;EGYPTIAN HIEROGLYPH N020;Lo;0;L;;;;;N;;;;;
+13205;EGYPTIAN HIEROGLYPH N021;Lo;0;L;;;;;N;;;;;
+13206;EGYPTIAN HIEROGLYPH N022;Lo;0;L;;;;;N;;;;;
+13207;EGYPTIAN HIEROGLYPH N023;Lo;0;L;;;;;N;;;;;
+13208;EGYPTIAN HIEROGLYPH N024;Lo;0;L;;;;;N;;;;;
+13209;EGYPTIAN HIEROGLYPH N025;Lo;0;L;;;;;N;;;;;
+1320A;EGYPTIAN HIEROGLYPH N025A;Lo;0;L;;;;;N;;;;;
+1320B;EGYPTIAN HIEROGLYPH N026;Lo;0;L;;;;;N;;;;;
+1320C;EGYPTIAN HIEROGLYPH N027;Lo;0;L;;;;;N;;;;;
+1320D;EGYPTIAN HIEROGLYPH N028;Lo;0;L;;;;;N;;;;;
+1320E;EGYPTIAN HIEROGLYPH N029;Lo;0;L;;;;;N;;;;;
+1320F;EGYPTIAN HIEROGLYPH N030;Lo;0;L;;;;;N;;;;;
+13210;EGYPTIAN HIEROGLYPH N031;Lo;0;L;;;;;N;;;;;
+13211;EGYPTIAN HIEROGLYPH N032;Lo;0;L;;;;;N;;;;;
+13212;EGYPTIAN HIEROGLYPH N033;Lo;0;L;;;;;N;;;;;
+13213;EGYPTIAN HIEROGLYPH N033A;Lo;0;L;;;;;N;;;;;
+13214;EGYPTIAN HIEROGLYPH N034;Lo;0;L;;;;;N;;;;;
+13215;EGYPTIAN HIEROGLYPH N034A;Lo;0;L;;;;;N;;;;;
+13216;EGYPTIAN HIEROGLYPH N035;Lo;0;L;;;;;N;;;;;
+13217;EGYPTIAN HIEROGLYPH N035A;Lo;0;L;;;;;N;;;;;
+13218;EGYPTIAN HIEROGLYPH N036;Lo;0;L;;;;;N;;;;;
+13219;EGYPTIAN HIEROGLYPH N037;Lo;0;L;;;;;N;;;;;
+1321A;EGYPTIAN HIEROGLYPH N037A;Lo;0;L;;;;;N;;;;;
+1321B;EGYPTIAN HIEROGLYPH N038;Lo;0;L;;;;;N;;;;;
+1321C;EGYPTIAN HIEROGLYPH N039;Lo;0;L;;;;;N;;;;;
+1321D;EGYPTIAN HIEROGLYPH N040;Lo;0;L;;;;;N;;;;;
+1321E;EGYPTIAN HIEROGLYPH N041;Lo;0;L;;;;;N;;;;;
+1321F;EGYPTIAN HIEROGLYPH N042;Lo;0;L;;;;;N;;;;;
+13220;EGYPTIAN HIEROGLYPH NL001;Lo;0;L;;;;;N;;;;;
+13221;EGYPTIAN HIEROGLYPH NL002;Lo;0;L;;;;;N;;;;;
+13222;EGYPTIAN HIEROGLYPH NL003;Lo;0;L;;;;;N;;;;;
+13223;EGYPTIAN HIEROGLYPH NL004;Lo;0;L;;;;;N;;;;;
+13224;EGYPTIAN HIEROGLYPH NL005;Lo;0;L;;;;;N;;;;;
+13225;EGYPTIAN HIEROGLYPH NL005A;Lo;0;L;;;;;N;;;;;
+13226;EGYPTIAN HIEROGLYPH NL006;Lo;0;L;;;;;N;;;;;
+13227;EGYPTIAN HIEROGLYPH NL007;Lo;0;L;;;;;N;;;;;
+13228;EGYPTIAN HIEROGLYPH NL008;Lo;0;L;;;;;N;;;;;
+13229;EGYPTIAN HIEROGLYPH NL009;Lo;0;L;;;;;N;;;;;
+1322A;EGYPTIAN HIEROGLYPH NL010;Lo;0;L;;;;;N;;;;;
+1322B;EGYPTIAN HIEROGLYPH NL011;Lo;0;L;;;;;N;;;;;
+1322C;EGYPTIAN HIEROGLYPH NL012;Lo;0;L;;;;;N;;;;;
+1322D;EGYPTIAN HIEROGLYPH NL013;Lo;0;L;;;;;N;;;;;
+1322E;EGYPTIAN HIEROGLYPH NL014;Lo;0;L;;;;;N;;;;;
+1322F;EGYPTIAN HIEROGLYPH NL015;Lo;0;L;;;;;N;;;;;
+13230;EGYPTIAN HIEROGLYPH NL016;Lo;0;L;;;;;N;;;;;
+13231;EGYPTIAN HIEROGLYPH NL017;Lo;0;L;;;;;N;;;;;
+13232;EGYPTIAN HIEROGLYPH NL017A;Lo;0;L;;;;;N;;;;;
+13233;EGYPTIAN HIEROGLYPH NL018;Lo;0;L;;;;;N;;;;;
+13234;EGYPTIAN HIEROGLYPH NL019;Lo;0;L;;;;;N;;;;;
+13235;EGYPTIAN HIEROGLYPH NL020;Lo;0;L;;;;;N;;;;;
+13236;EGYPTIAN HIEROGLYPH NU001;Lo;0;L;;;;;N;;;;;
+13237;EGYPTIAN HIEROGLYPH NU002;Lo;0;L;;;;;N;;;;;
+13238;EGYPTIAN HIEROGLYPH NU003;Lo;0;L;;;;;N;;;;;
+13239;EGYPTIAN HIEROGLYPH NU004;Lo;0;L;;;;;N;;;;;
+1323A;EGYPTIAN HIEROGLYPH NU005;Lo;0;L;;;;;N;;;;;
+1323B;EGYPTIAN HIEROGLYPH NU006;Lo;0;L;;;;;N;;;;;
+1323C;EGYPTIAN HIEROGLYPH NU007;Lo;0;L;;;;;N;;;;;
+1323D;EGYPTIAN HIEROGLYPH NU008;Lo;0;L;;;;;N;;;;;
+1323E;EGYPTIAN HIEROGLYPH NU009;Lo;0;L;;;;;N;;;;;
+1323F;EGYPTIAN HIEROGLYPH NU010;Lo;0;L;;;;;N;;;;;
+13240;EGYPTIAN HIEROGLYPH NU010A;Lo;0;L;;;;;N;;;;;
+13241;EGYPTIAN HIEROGLYPH NU011;Lo;0;L;;;;;N;;;;;
+13242;EGYPTIAN HIEROGLYPH NU011A;Lo;0;L;;;;;N;;;;;
+13243;EGYPTIAN HIEROGLYPH NU012;Lo;0;L;;;;;N;;;;;
+13244;EGYPTIAN HIEROGLYPH NU013;Lo;0;L;;;;;N;;;;;
+13245;EGYPTIAN HIEROGLYPH NU014;Lo;0;L;;;;;N;;;;;
+13246;EGYPTIAN HIEROGLYPH NU015;Lo;0;L;;;;;N;;;;;
+13247;EGYPTIAN HIEROGLYPH NU016;Lo;0;L;;;;;N;;;;;
+13248;EGYPTIAN HIEROGLYPH NU017;Lo;0;L;;;;;N;;;;;
+13249;EGYPTIAN HIEROGLYPH NU018;Lo;0;L;;;;;N;;;;;
+1324A;EGYPTIAN HIEROGLYPH NU018A;Lo;0;L;;;;;N;;;;;
+1324B;EGYPTIAN HIEROGLYPH NU019;Lo;0;L;;;;;N;;;;;
+1324C;EGYPTIAN HIEROGLYPH NU020;Lo;0;L;;;;;N;;;;;
+1324D;EGYPTIAN HIEROGLYPH NU021;Lo;0;L;;;;;N;;;;;
+1324E;EGYPTIAN HIEROGLYPH NU022;Lo;0;L;;;;;N;;;;;
+1324F;EGYPTIAN HIEROGLYPH NU022A;Lo;0;L;;;;;N;;;;;
+13250;EGYPTIAN HIEROGLYPH O001;Lo;0;L;;;;;N;;;;;
+13251;EGYPTIAN HIEROGLYPH O001A;Lo;0;L;;;;;N;;;;;
+13252;EGYPTIAN HIEROGLYPH O002;Lo;0;L;;;;;N;;;;;
+13253;EGYPTIAN HIEROGLYPH O003;Lo;0;L;;;;;N;;;;;
+13254;EGYPTIAN HIEROGLYPH O004;Lo;0;L;;;;;N;;;;;
+13255;EGYPTIAN HIEROGLYPH O005;Lo;0;L;;;;;N;;;;;
+13256;EGYPTIAN HIEROGLYPH O005A;Lo;0;L;;;;;N;;;;;
+13257;EGYPTIAN HIEROGLYPH O006;Lo;0;L;;;;;N;;;;;
+13258;EGYPTIAN HIEROGLYPH O006A;Lo;0;L;;;;;N;;;;;
+13259;EGYPTIAN HIEROGLYPH O006B;Lo;0;L;;;;;N;;;;;
+1325A;EGYPTIAN HIEROGLYPH O006C;Lo;0;L;;;;;N;;;;;
+1325B;EGYPTIAN HIEROGLYPH O006D;Lo;0;L;;;;;N;;;;;
+1325C;EGYPTIAN HIEROGLYPH O006E;Lo;0;L;;;;;N;;;;;
+1325D;EGYPTIAN HIEROGLYPH O006F;Lo;0;L;;;;;N;;;;;
+1325E;EGYPTIAN HIEROGLYPH O007;Lo;0;L;;;;;N;;;;;
+1325F;EGYPTIAN HIEROGLYPH O008;Lo;0;L;;;;;N;;;;;
+13260;EGYPTIAN HIEROGLYPH O009;Lo;0;L;;;;;N;;;;;
+13261;EGYPTIAN HIEROGLYPH O010;Lo;0;L;;;;;N;;;;;
+13262;EGYPTIAN HIEROGLYPH O010A;Lo;0;L;;;;;N;;;;;
+13263;EGYPTIAN HIEROGLYPH O010B;Lo;0;L;;;;;N;;;;;
+13264;EGYPTIAN HIEROGLYPH O010C;Lo;0;L;;;;;N;;;;;
+13265;EGYPTIAN HIEROGLYPH O011;Lo;0;L;;;;;N;;;;;
+13266;EGYPTIAN HIEROGLYPH O012;Lo;0;L;;;;;N;;;;;
+13267;EGYPTIAN HIEROGLYPH O013;Lo;0;L;;;;;N;;;;;
+13268;EGYPTIAN HIEROGLYPH O014;Lo;0;L;;;;;N;;;;;
+13269;EGYPTIAN HIEROGLYPH O015;Lo;0;L;;;;;N;;;;;
+1326A;EGYPTIAN HIEROGLYPH O016;Lo;0;L;;;;;N;;;;;
+1326B;EGYPTIAN HIEROGLYPH O017;Lo;0;L;;;;;N;;;;;
+1326C;EGYPTIAN HIEROGLYPH O018;Lo;0;L;;;;;N;;;;;
+1326D;EGYPTIAN HIEROGLYPH O019;Lo;0;L;;;;;N;;;;;
+1326E;EGYPTIAN HIEROGLYPH O019A;Lo;0;L;;;;;N;;;;;
+1326F;EGYPTIAN HIEROGLYPH O020;Lo;0;L;;;;;N;;;;;
+13270;EGYPTIAN HIEROGLYPH O020A;Lo;0;L;;;;;N;;;;;
+13271;EGYPTIAN HIEROGLYPH O021;Lo;0;L;;;;;N;;;;;
+13272;EGYPTIAN HIEROGLYPH O022;Lo;0;L;;;;;N;;;;;
+13273;EGYPTIAN HIEROGLYPH O023;Lo;0;L;;;;;N;;;;;
+13274;EGYPTIAN HIEROGLYPH O024;Lo;0;L;;;;;N;;;;;
+13275;EGYPTIAN HIEROGLYPH O024A;Lo;0;L;;;;;N;;;;;
+13276;EGYPTIAN HIEROGLYPH O025;Lo;0;L;;;;;N;;;;;
+13277;EGYPTIAN HIEROGLYPH O025A;Lo;0;L;;;;;N;;;;;
+13278;EGYPTIAN HIEROGLYPH O026;Lo;0;L;;;;;N;;;;;
+13279;EGYPTIAN HIEROGLYPH O027;Lo;0;L;;;;;N;;;;;
+1327A;EGYPTIAN HIEROGLYPH O028;Lo;0;L;;;;;N;;;;;
+1327B;EGYPTIAN HIEROGLYPH O029;Lo;0;L;;;;;N;;;;;
+1327C;EGYPTIAN HIEROGLYPH O029A;Lo;0;L;;;;;N;;;;;
+1327D;EGYPTIAN HIEROGLYPH O030;Lo;0;L;;;;;N;;;;;
+1327E;EGYPTIAN HIEROGLYPH O030A;Lo;0;L;;;;;N;;;;;
+1327F;EGYPTIAN HIEROGLYPH O031;Lo;0;L;;;;;N;;;;;
+13280;EGYPTIAN HIEROGLYPH O032;Lo;0;L;;;;;N;;;;;
+13281;EGYPTIAN HIEROGLYPH O033;Lo;0;L;;;;;N;;;;;
+13282;EGYPTIAN HIEROGLYPH O033A;Lo;0;L;;;;;N;;;;;
+13283;EGYPTIAN HIEROGLYPH O034;Lo;0;L;;;;;N;;;;;
+13284;EGYPTIAN HIEROGLYPH O035;Lo;0;L;;;;;N;;;;;
+13285;EGYPTIAN HIEROGLYPH O036;Lo;0;L;;;;;N;;;;;
+13286;EGYPTIAN HIEROGLYPH O036A;Lo;0;L;;;;;N;;;;;
+13287;EGYPTIAN HIEROGLYPH O036B;Lo;0;L;;;;;N;;;;;
+13288;EGYPTIAN HIEROGLYPH O036C;Lo;0;L;;;;;N;;;;;
+13289;EGYPTIAN HIEROGLYPH O036D;Lo;0;L;;;;;N;;;;;
+1328A;EGYPTIAN HIEROGLYPH O037;Lo;0;L;;;;;N;;;;;
+1328B;EGYPTIAN HIEROGLYPH O038;Lo;0;L;;;;;N;;;;;
+1328C;EGYPTIAN HIEROGLYPH O039;Lo;0;L;;;;;N;;;;;
+1328D;EGYPTIAN HIEROGLYPH O040;Lo;0;L;;;;;N;;;;;
+1328E;EGYPTIAN HIEROGLYPH O041;Lo;0;L;;;;;N;;;;;
+1328F;EGYPTIAN HIEROGLYPH O042;Lo;0;L;;;;;N;;;;;
+13290;EGYPTIAN HIEROGLYPH O043;Lo;0;L;;;;;N;;;;;
+13291;EGYPTIAN HIEROGLYPH O044;Lo;0;L;;;;;N;;;;;
+13292;EGYPTIAN HIEROGLYPH O045;Lo;0;L;;;;;N;;;;;
+13293;EGYPTIAN HIEROGLYPH O046;Lo;0;L;;;;;N;;;;;
+13294;EGYPTIAN HIEROGLYPH O047;Lo;0;L;;;;;N;;;;;
+13295;EGYPTIAN HIEROGLYPH O048;Lo;0;L;;;;;N;;;;;
+13296;EGYPTIAN HIEROGLYPH O049;Lo;0;L;;;;;N;;;;;
+13297;EGYPTIAN HIEROGLYPH O050;Lo;0;L;;;;;N;;;;;
+13298;EGYPTIAN HIEROGLYPH O050A;Lo;0;L;;;;;N;;;;;
+13299;EGYPTIAN HIEROGLYPH O050B;Lo;0;L;;;;;N;;;;;
+1329A;EGYPTIAN HIEROGLYPH O051;Lo;0;L;;;;;N;;;;;
+1329B;EGYPTIAN HIEROGLYPH P001;Lo;0;L;;;;;N;;;;;
+1329C;EGYPTIAN HIEROGLYPH P001A;Lo;0;L;;;;;N;;;;;
+1329D;EGYPTIAN HIEROGLYPH P002;Lo;0;L;;;;;N;;;;;
+1329E;EGYPTIAN HIEROGLYPH P003;Lo;0;L;;;;;N;;;;;
+1329F;EGYPTIAN HIEROGLYPH P003A;Lo;0;L;;;;;N;;;;;
+132A0;EGYPTIAN HIEROGLYPH P004;Lo;0;L;;;;;N;;;;;
+132A1;EGYPTIAN HIEROGLYPH P005;Lo;0;L;;;;;N;;;;;
+132A2;EGYPTIAN HIEROGLYPH P006;Lo;0;L;;;;;N;;;;;
+132A3;EGYPTIAN HIEROGLYPH P007;Lo;0;L;;;;;N;;;;;
+132A4;EGYPTIAN HIEROGLYPH P008;Lo;0;L;;;;;N;;;;;
+132A5;EGYPTIAN HIEROGLYPH P009;Lo;0;L;;;;;N;;;;;
+132A6;EGYPTIAN HIEROGLYPH P010;Lo;0;L;;;;;N;;;;;
+132A7;EGYPTIAN HIEROGLYPH P011;Lo;0;L;;;;;N;;;;;
+132A8;EGYPTIAN HIEROGLYPH Q001;Lo;0;L;;;;;N;;;;;
+132A9;EGYPTIAN HIEROGLYPH Q002;Lo;0;L;;;;;N;;;;;
+132AA;EGYPTIAN HIEROGLYPH Q003;Lo;0;L;;;;;N;;;;;
+132AB;EGYPTIAN HIEROGLYPH Q004;Lo;0;L;;;;;N;;;;;
+132AC;EGYPTIAN HIEROGLYPH Q005;Lo;0;L;;;;;N;;;;;
+132AD;EGYPTIAN HIEROGLYPH Q006;Lo;0;L;;;;;N;;;;;
+132AE;EGYPTIAN HIEROGLYPH Q007;Lo;0;L;;;;;N;;;;;
+132AF;EGYPTIAN HIEROGLYPH R001;Lo;0;L;;;;;N;;;;;
+132B0;EGYPTIAN HIEROGLYPH R002;Lo;0;L;;;;;N;;;;;
+132B1;EGYPTIAN HIEROGLYPH R002A;Lo;0;L;;;;;N;;;;;
+132B2;EGYPTIAN HIEROGLYPH R003;Lo;0;L;;;;;N;;;;;
+132B3;EGYPTIAN HIEROGLYPH R003A;Lo;0;L;;;;;N;;;;;
+132B4;EGYPTIAN HIEROGLYPH R003B;Lo;0;L;;;;;N;;;;;
+132B5;EGYPTIAN HIEROGLYPH R004;Lo;0;L;;;;;N;;;;;
+132B6;EGYPTIAN HIEROGLYPH R005;Lo;0;L;;;;;N;;;;;
+132B7;EGYPTIAN HIEROGLYPH R006;Lo;0;L;;;;;N;;;;;
+132B8;EGYPTIAN HIEROGLYPH R007;Lo;0;L;;;;;N;;;;;
+132B9;EGYPTIAN HIEROGLYPH R008;Lo;0;L;;;;;N;;;;;
+132BA;EGYPTIAN HIEROGLYPH R009;Lo;0;L;;;;;N;;;;;
+132BB;EGYPTIAN HIEROGLYPH R010;Lo;0;L;;;;;N;;;;;
+132BC;EGYPTIAN HIEROGLYPH R010A;Lo;0;L;;;;;N;;;;;
+132BD;EGYPTIAN HIEROGLYPH R011;Lo;0;L;;;;;N;;;;;
+132BE;EGYPTIAN HIEROGLYPH R012;Lo;0;L;;;;;N;;;;;
+132BF;EGYPTIAN HIEROGLYPH R013;Lo;0;L;;;;;N;;;;;
+132C0;EGYPTIAN HIEROGLYPH R014;Lo;0;L;;;;;N;;;;;
+132C1;EGYPTIAN HIEROGLYPH R015;Lo;0;L;;;;;N;;;;;
+132C2;EGYPTIAN HIEROGLYPH R016;Lo;0;L;;;;;N;;;;;
+132C3;EGYPTIAN HIEROGLYPH R016A;Lo;0;L;;;;;N;;;;;
+132C4;EGYPTIAN HIEROGLYPH R017;Lo;0;L;;;;;N;;;;;
+132C5;EGYPTIAN HIEROGLYPH R018;Lo;0;L;;;;;N;;;;;
+132C6;EGYPTIAN HIEROGLYPH R019;Lo;0;L;;;;;N;;;;;
+132C7;EGYPTIAN HIEROGLYPH R020;Lo;0;L;;;;;N;;;;;
+132C8;EGYPTIAN HIEROGLYPH R021;Lo;0;L;;;;;N;;;;;
+132C9;EGYPTIAN HIEROGLYPH R022;Lo;0;L;;;;;N;;;;;
+132CA;EGYPTIAN HIEROGLYPH R023;Lo;0;L;;;;;N;;;;;
+132CB;EGYPTIAN HIEROGLYPH R024;Lo;0;L;;;;;N;;;;;
+132CC;EGYPTIAN HIEROGLYPH R025;Lo;0;L;;;;;N;;;;;
+132CD;EGYPTIAN HIEROGLYPH R026;Lo;0;L;;;;;N;;;;;
+132CE;EGYPTIAN HIEROGLYPH R027;Lo;0;L;;;;;N;;;;;
+132CF;EGYPTIAN HIEROGLYPH R028;Lo;0;L;;;;;N;;;;;
+132D0;EGYPTIAN HIEROGLYPH R029;Lo;0;L;;;;;N;;;;;
+132D1;EGYPTIAN HIEROGLYPH S001;Lo;0;L;;;;;N;;;;;
+132D2;EGYPTIAN HIEROGLYPH S002;Lo;0;L;;;;;N;;;;;
+132D3;EGYPTIAN HIEROGLYPH S002A;Lo;0;L;;;;;N;;;;;
+132D4;EGYPTIAN HIEROGLYPH S003;Lo;0;L;;;;;N;;;;;
+132D5;EGYPTIAN HIEROGLYPH S004;Lo;0;L;;;;;N;;;;;
+132D6;EGYPTIAN HIEROGLYPH S005;Lo;0;L;;;;;N;;;;;
+132D7;EGYPTIAN HIEROGLYPH S006;Lo;0;L;;;;;N;;;;;
+132D8;EGYPTIAN HIEROGLYPH S006A;Lo;0;L;;;;;N;;;;;
+132D9;EGYPTIAN HIEROGLYPH S007;Lo;0;L;;;;;N;;;;;
+132DA;EGYPTIAN HIEROGLYPH S008;Lo;0;L;;;;;N;;;;;
+132DB;EGYPTIAN HIEROGLYPH S009;Lo;0;L;;;;;N;;;;;
+132DC;EGYPTIAN HIEROGLYPH S010;Lo;0;L;;;;;N;;;;;
+132DD;EGYPTIAN HIEROGLYPH S011;Lo;0;L;;;;;N;;;;;
+132DE;EGYPTIAN HIEROGLYPH S012;Lo;0;L;;;;;N;;;;;
+132DF;EGYPTIAN HIEROGLYPH S013;Lo;0;L;;;;;N;;;;;
+132E0;EGYPTIAN HIEROGLYPH S014;Lo;0;L;;;;;N;;;;;
+132E1;EGYPTIAN HIEROGLYPH S014A;Lo;0;L;;;;;N;;;;;
+132E2;EGYPTIAN HIEROGLYPH S014B;Lo;0;L;;;;;N;;;;;
+132E3;EGYPTIAN HIEROGLYPH S015;Lo;0;L;;;;;N;;;;;
+132E4;EGYPTIAN HIEROGLYPH S016;Lo;0;L;;;;;N;;;;;
+132E5;EGYPTIAN HIEROGLYPH S017;Lo;0;L;;;;;N;;;;;
+132E6;EGYPTIAN HIEROGLYPH S017A;Lo;0;L;;;;;N;;;;;
+132E7;EGYPTIAN HIEROGLYPH S018;Lo;0;L;;;;;N;;;;;
+132E8;EGYPTIAN HIEROGLYPH S019;Lo;0;L;;;;;N;;;;;
+132E9;EGYPTIAN HIEROGLYPH S020;Lo;0;L;;;;;N;;;;;
+132EA;EGYPTIAN HIEROGLYPH S021;Lo;0;L;;;;;N;;;;;
+132EB;EGYPTIAN HIEROGLYPH S022;Lo;0;L;;;;;N;;;;;
+132EC;EGYPTIAN HIEROGLYPH S023;Lo;0;L;;;;;N;;;;;
+132ED;EGYPTIAN HIEROGLYPH S024;Lo;0;L;;;;;N;;;;;
+132EE;EGYPTIAN HIEROGLYPH S025;Lo;0;L;;;;;N;;;;;
+132EF;EGYPTIAN HIEROGLYPH S026;Lo;0;L;;;;;N;;;;;
+132F0;EGYPTIAN HIEROGLYPH S026A;Lo;0;L;;;;;N;;;;;
+132F1;EGYPTIAN HIEROGLYPH S026B;Lo;0;L;;;;;N;;;;;
+132F2;EGYPTIAN HIEROGLYPH S027;Lo;0;L;;;;;N;;;;;
+132F3;EGYPTIAN HIEROGLYPH S028;Lo;0;L;;;;;N;;;;;
+132F4;EGYPTIAN HIEROGLYPH S029;Lo;0;L;;;;;N;;;;;
+132F5;EGYPTIAN HIEROGLYPH S030;Lo;0;L;;;;;N;;;;;
+132F6;EGYPTIAN HIEROGLYPH S031;Lo;0;L;;;;;N;;;;;
+132F7;EGYPTIAN HIEROGLYPH S032;Lo;0;L;;;;;N;;;;;
+132F8;EGYPTIAN HIEROGLYPH S033;Lo;0;L;;;;;N;;;;;
+132F9;EGYPTIAN HIEROGLYPH S034;Lo;0;L;;;;;N;;;;;
+132FA;EGYPTIAN HIEROGLYPH S035;Lo;0;L;;;;;N;;;;;
+132FB;EGYPTIAN HIEROGLYPH S035A;Lo;0;L;;;;;N;;;;;
+132FC;EGYPTIAN HIEROGLYPH S036;Lo;0;L;;;;;N;;;;;
+132FD;EGYPTIAN HIEROGLYPH S037;Lo;0;L;;;;;N;;;;;
+132FE;EGYPTIAN HIEROGLYPH S038;Lo;0;L;;;;;N;;;;;
+132FF;EGYPTIAN HIEROGLYPH S039;Lo;0;L;;;;;N;;;;;
+13300;EGYPTIAN HIEROGLYPH S040;Lo;0;L;;;;;N;;;;;
+13301;EGYPTIAN HIEROGLYPH S041;Lo;0;L;;;;;N;;;;;
+13302;EGYPTIAN HIEROGLYPH S042;Lo;0;L;;;;;N;;;;;
+13303;EGYPTIAN HIEROGLYPH S043;Lo;0;L;;;;;N;;;;;
+13304;EGYPTIAN HIEROGLYPH S044;Lo;0;L;;;;;N;;;;;
+13305;EGYPTIAN HIEROGLYPH S045;Lo;0;L;;;;;N;;;;;
+13306;EGYPTIAN HIEROGLYPH S046;Lo;0;L;;;;;N;;;;;
+13307;EGYPTIAN HIEROGLYPH T001;Lo;0;L;;;;;N;;;;;
+13308;EGYPTIAN HIEROGLYPH T002;Lo;0;L;;;;;N;;;;;
+13309;EGYPTIAN HIEROGLYPH T003;Lo;0;L;;;;;N;;;;;
+1330A;EGYPTIAN HIEROGLYPH T003A;Lo;0;L;;;;;N;;;;;
+1330B;EGYPTIAN HIEROGLYPH T004;Lo;0;L;;;;;N;;;;;
+1330C;EGYPTIAN HIEROGLYPH T005;Lo;0;L;;;;;N;;;;;
+1330D;EGYPTIAN HIEROGLYPH T006;Lo;0;L;;;;;N;;;;;
+1330E;EGYPTIAN HIEROGLYPH T007;Lo;0;L;;;;;N;;;;;
+1330F;EGYPTIAN HIEROGLYPH T007A;Lo;0;L;;;;;N;;;;;
+13310;EGYPTIAN HIEROGLYPH T008;Lo;0;L;;;;;N;;;;;
+13311;EGYPTIAN HIEROGLYPH T008A;Lo;0;L;;;;;N;;;;;
+13312;EGYPTIAN HIEROGLYPH T009;Lo;0;L;;;;;N;;;;;
+13313;EGYPTIAN HIEROGLYPH T009A;Lo;0;L;;;;;N;;;;;
+13314;EGYPTIAN HIEROGLYPH T010;Lo;0;L;;;;;N;;;;;
+13315;EGYPTIAN HIEROGLYPH T011;Lo;0;L;;;;;N;;;;;
+13316;EGYPTIAN HIEROGLYPH T011A;Lo;0;L;;;;;N;;;;;
+13317;EGYPTIAN HIEROGLYPH T012;Lo;0;L;;;;;N;;;;;
+13318;EGYPTIAN HIEROGLYPH T013;Lo;0;L;;;;;N;;;;;
+13319;EGYPTIAN HIEROGLYPH T014;Lo;0;L;;;;;N;;;;;
+1331A;EGYPTIAN HIEROGLYPH T015;Lo;0;L;;;;;N;;;;;
+1331B;EGYPTIAN HIEROGLYPH T016;Lo;0;L;;;;;N;;;;;
+1331C;EGYPTIAN HIEROGLYPH T016A;Lo;0;L;;;;;N;;;;;
+1331D;EGYPTIAN HIEROGLYPH T017;Lo;0;L;;;;;N;;;;;
+1331E;EGYPTIAN HIEROGLYPH T018;Lo;0;L;;;;;N;;;;;
+1331F;EGYPTIAN HIEROGLYPH T019;Lo;0;L;;;;;N;;;;;
+13320;EGYPTIAN HIEROGLYPH T020;Lo;0;L;;;;;N;;;;;
+13321;EGYPTIAN HIEROGLYPH T021;Lo;0;L;;;;;N;;;;;
+13322;EGYPTIAN HIEROGLYPH T022;Lo;0;L;;;;;N;;;;;
+13323;EGYPTIAN HIEROGLYPH T023;Lo;0;L;;;;;N;;;;;
+13324;EGYPTIAN HIEROGLYPH T024;Lo;0;L;;;;;N;;;;;
+13325;EGYPTIAN HIEROGLYPH T025;Lo;0;L;;;;;N;;;;;
+13326;EGYPTIAN HIEROGLYPH T026;Lo;0;L;;;;;N;;;;;
+13327;EGYPTIAN HIEROGLYPH T027;Lo;0;L;;;;;N;;;;;
+13328;EGYPTIAN HIEROGLYPH T028;Lo;0;L;;;;;N;;;;;
+13329;EGYPTIAN HIEROGLYPH T029;Lo;0;L;;;;;N;;;;;
+1332A;EGYPTIAN HIEROGLYPH T030;Lo;0;L;;;;;N;;;;;
+1332B;EGYPTIAN HIEROGLYPH T031;Lo;0;L;;;;;N;;;;;
+1332C;EGYPTIAN HIEROGLYPH T032;Lo;0;L;;;;;N;;;;;
+1332D;EGYPTIAN HIEROGLYPH T032A;Lo;0;L;;;;;N;;;;;
+1332E;EGYPTIAN HIEROGLYPH T033;Lo;0;L;;;;;N;;;;;
+1332F;EGYPTIAN HIEROGLYPH T033A;Lo;0;L;;;;;N;;;;;
+13330;EGYPTIAN HIEROGLYPH T034;Lo;0;L;;;;;N;;;;;
+13331;EGYPTIAN HIEROGLYPH T035;Lo;0;L;;;;;N;;;;;
+13332;EGYPTIAN HIEROGLYPH T036;Lo;0;L;;;;;N;;;;;
+13333;EGYPTIAN HIEROGLYPH U001;Lo;0;L;;;;;N;;;;;
+13334;EGYPTIAN HIEROGLYPH U002;Lo;0;L;;;;;N;;;;;
+13335;EGYPTIAN HIEROGLYPH U003;Lo;0;L;;;;;N;;;;;
+13336;EGYPTIAN HIEROGLYPH U004;Lo;0;L;;;;;N;;;;;
+13337;EGYPTIAN HIEROGLYPH U005;Lo;0;L;;;;;N;;;;;
+13338;EGYPTIAN HIEROGLYPH U006;Lo;0;L;;;;;N;;;;;
+13339;EGYPTIAN HIEROGLYPH U006A;Lo;0;L;;;;;N;;;;;
+1333A;EGYPTIAN HIEROGLYPH U006B;Lo;0;L;;;;;N;;;;;
+1333B;EGYPTIAN HIEROGLYPH U007;Lo;0;L;;;;;N;;;;;
+1333C;EGYPTIAN HIEROGLYPH U008;Lo;0;L;;;;;N;;;;;
+1333D;EGYPTIAN HIEROGLYPH U009;Lo;0;L;;;;;N;;;;;
+1333E;EGYPTIAN HIEROGLYPH U010;Lo;0;L;;;;;N;;;;;
+1333F;EGYPTIAN HIEROGLYPH U011;Lo;0;L;;;;;N;;;;;
+13340;EGYPTIAN HIEROGLYPH U012;Lo;0;L;;;;;N;;;;;
+13341;EGYPTIAN HIEROGLYPH U013;Lo;0;L;;;;;N;;;;;
+13342;EGYPTIAN HIEROGLYPH U014;Lo;0;L;;;;;N;;;;;
+13343;EGYPTIAN HIEROGLYPH U015;Lo;0;L;;;;;N;;;;;
+13344;EGYPTIAN HIEROGLYPH U016;Lo;0;L;;;;;N;;;;;
+13345;EGYPTIAN HIEROGLYPH U017;Lo;0;L;;;;;N;;;;;
+13346;EGYPTIAN HIEROGLYPH U018;Lo;0;L;;;;;N;;;;;
+13347;EGYPTIAN HIEROGLYPH U019;Lo;0;L;;;;;N;;;;;
+13348;EGYPTIAN HIEROGLYPH U020;Lo;0;L;;;;;N;;;;;
+13349;EGYPTIAN HIEROGLYPH U021;Lo;0;L;;;;;N;;;;;
+1334A;EGYPTIAN HIEROGLYPH U022;Lo;0;L;;;;;N;;;;;
+1334B;EGYPTIAN HIEROGLYPH U023;Lo;0;L;;;;;N;;;;;
+1334C;EGYPTIAN HIEROGLYPH U023A;Lo;0;L;;;;;N;;;;;
+1334D;EGYPTIAN HIEROGLYPH U024;Lo;0;L;;;;;N;;;;;
+1334E;EGYPTIAN HIEROGLYPH U025;Lo;0;L;;;;;N;;;;;
+1334F;EGYPTIAN HIEROGLYPH U026;Lo;0;L;;;;;N;;;;;
+13350;EGYPTIAN HIEROGLYPH U027;Lo;0;L;;;;;N;;;;;
+13351;EGYPTIAN HIEROGLYPH U028;Lo;0;L;;;;;N;;;;;
+13352;EGYPTIAN HIEROGLYPH U029;Lo;0;L;;;;;N;;;;;
+13353;EGYPTIAN HIEROGLYPH U029A;Lo;0;L;;;;;N;;;;;
+13354;EGYPTIAN HIEROGLYPH U030;Lo;0;L;;;;;N;;;;;
+13355;EGYPTIAN HIEROGLYPH U031;Lo;0;L;;;;;N;;;;;
+13356;EGYPTIAN HIEROGLYPH U032;Lo;0;L;;;;;N;;;;;
+13357;EGYPTIAN HIEROGLYPH U032A;Lo;0;L;;;;;N;;;;;
+13358;EGYPTIAN HIEROGLYPH U033;Lo;0;L;;;;;N;;;;;
+13359;EGYPTIAN HIEROGLYPH U034;Lo;0;L;;;;;N;;;;;
+1335A;EGYPTIAN HIEROGLYPH U035;Lo;0;L;;;;;N;;;;;
+1335B;EGYPTIAN HIEROGLYPH U036;Lo;0;L;;;;;N;;;;;
+1335C;EGYPTIAN HIEROGLYPH U037;Lo;0;L;;;;;N;;;;;
+1335D;EGYPTIAN HIEROGLYPH U038;Lo;0;L;;;;;N;;;;;
+1335E;EGYPTIAN HIEROGLYPH U039;Lo;0;L;;;;;N;;;;;
+1335F;EGYPTIAN HIEROGLYPH U040;Lo;0;L;;;;;N;;;;;
+13360;EGYPTIAN HIEROGLYPH U041;Lo;0;L;;;;;N;;;;;
+13361;EGYPTIAN HIEROGLYPH U042;Lo;0;L;;;;;N;;;;;
+13362;EGYPTIAN HIEROGLYPH V001;Lo;0;L;;;;;N;;;;;
+13363;EGYPTIAN HIEROGLYPH V001A;Lo;0;L;;;;;N;;;;;
+13364;EGYPTIAN HIEROGLYPH V001B;Lo;0;L;;;;;N;;;;;
+13365;EGYPTIAN HIEROGLYPH V001C;Lo;0;L;;;;;N;;;;;
+13366;EGYPTIAN HIEROGLYPH V001D;Lo;0;L;;;;;N;;;;;
+13367;EGYPTIAN HIEROGLYPH V001E;Lo;0;L;;;;;N;;;;;
+13368;EGYPTIAN HIEROGLYPH V001F;Lo;0;L;;;;;N;;;;;
+13369;EGYPTIAN HIEROGLYPH V001G;Lo;0;L;;;;;N;;;;;
+1336A;EGYPTIAN HIEROGLYPH V001H;Lo;0;L;;;;;N;;;;;
+1336B;EGYPTIAN HIEROGLYPH V001I;Lo;0;L;;;;;N;;;;;
+1336C;EGYPTIAN HIEROGLYPH V002;Lo;0;L;;;;;N;;;;;
+1336D;EGYPTIAN HIEROGLYPH V002A;Lo;0;L;;;;;N;;;;;
+1336E;EGYPTIAN HIEROGLYPH V003;Lo;0;L;;;;;N;;;;;
+1336F;EGYPTIAN HIEROGLYPH V004;Lo;0;L;;;;;N;;;;;
+13370;EGYPTIAN HIEROGLYPH V005;Lo;0;L;;;;;N;;;;;
+13371;EGYPTIAN HIEROGLYPH V006;Lo;0;L;;;;;N;;;;;
+13372;EGYPTIAN HIEROGLYPH V007;Lo;0;L;;;;;N;;;;;
+13373;EGYPTIAN HIEROGLYPH V007A;Lo;0;L;;;;;N;;;;;
+13374;EGYPTIAN HIEROGLYPH V007B;Lo;0;L;;;;;N;;;;;
+13375;EGYPTIAN HIEROGLYPH V008;Lo;0;L;;;;;N;;;;;
+13376;EGYPTIAN HIEROGLYPH V009;Lo;0;L;;;;;N;;;;;
+13377;EGYPTIAN HIEROGLYPH V010;Lo;0;L;;;;;N;;;;;
+13378;EGYPTIAN HIEROGLYPH V011;Lo;0;L;;;;;N;;;;;
+13379;EGYPTIAN HIEROGLYPH V011A;Lo;0;L;;;;;N;;;;;
+1337A;EGYPTIAN HIEROGLYPH V011B;Lo;0;L;;;;;N;;;;;
+1337B;EGYPTIAN HIEROGLYPH V011C;Lo;0;L;;;;;N;;;;;
+1337C;EGYPTIAN HIEROGLYPH V012;Lo;0;L;;;;;N;;;;;
+1337D;EGYPTIAN HIEROGLYPH V012A;Lo;0;L;;;;;N;;;;;
+1337E;EGYPTIAN HIEROGLYPH V012B;Lo;0;L;;;;;N;;;;;
+1337F;EGYPTIAN HIEROGLYPH V013;Lo;0;L;;;;;N;;;;;
+13380;EGYPTIAN HIEROGLYPH V014;Lo;0;L;;;;;N;;;;;
+13381;EGYPTIAN HIEROGLYPH V015;Lo;0;L;;;;;N;;;;;
+13382;EGYPTIAN HIEROGLYPH V016;Lo;0;L;;;;;N;;;;;
+13383;EGYPTIAN HIEROGLYPH V017;Lo;0;L;;;;;N;;;;;
+13384;EGYPTIAN HIEROGLYPH V018;Lo;0;L;;;;;N;;;;;
+13385;EGYPTIAN HIEROGLYPH V019;Lo;0;L;;;;;N;;;;;
+13386;EGYPTIAN HIEROGLYPH V020;Lo;0;L;;;;;N;;;;;
+13387;EGYPTIAN HIEROGLYPH V020A;Lo;0;L;;;;;N;;;;;
+13388;EGYPTIAN HIEROGLYPH V020B;Lo;0;L;;;;;N;;;;;
+13389;EGYPTIAN HIEROGLYPH V020C;Lo;0;L;;;;;N;;;;;
+1338A;EGYPTIAN HIEROGLYPH V020D;Lo;0;L;;;;;N;;;;;
+1338B;EGYPTIAN HIEROGLYPH V020E;Lo;0;L;;;;;N;;;;;
+1338C;EGYPTIAN HIEROGLYPH V020F;Lo;0;L;;;;;N;;;;;
+1338D;EGYPTIAN HIEROGLYPH V020G;Lo;0;L;;;;;N;;;;;
+1338E;EGYPTIAN HIEROGLYPH V020H;Lo;0;L;;;;;N;;;;;
+1338F;EGYPTIAN HIEROGLYPH V020I;Lo;0;L;;;;;N;;;;;
+13390;EGYPTIAN HIEROGLYPH V020J;Lo;0;L;;;;;N;;;;;
+13391;EGYPTIAN HIEROGLYPH V020K;Lo;0;L;;;;;N;;;;;
+13392;EGYPTIAN HIEROGLYPH V020L;Lo;0;L;;;;;N;;;;;
+13393;EGYPTIAN HIEROGLYPH V021;Lo;0;L;;;;;N;;;;;
+13394;EGYPTIAN HIEROGLYPH V022;Lo;0;L;;;;;N;;;;;
+13395;EGYPTIAN HIEROGLYPH V023;Lo;0;L;;;;;N;;;;;
+13396;EGYPTIAN HIEROGLYPH V023A;Lo;0;L;;;;;N;;;;;
+13397;EGYPTIAN HIEROGLYPH V024;Lo;0;L;;;;;N;;;;;
+13398;EGYPTIAN HIEROGLYPH V025;Lo;0;L;;;;;N;;;;;
+13399;EGYPTIAN HIEROGLYPH V026;Lo;0;L;;;;;N;;;;;
+1339A;EGYPTIAN HIEROGLYPH V027;Lo;0;L;;;;;N;;;;;
+1339B;EGYPTIAN HIEROGLYPH V028;Lo;0;L;;;;;N;;;;;
+1339C;EGYPTIAN HIEROGLYPH V028A;Lo;0;L;;;;;N;;;;;
+1339D;EGYPTIAN HIEROGLYPH V029;Lo;0;L;;;;;N;;;;;
+1339E;EGYPTIAN HIEROGLYPH V029A;Lo;0;L;;;;;N;;;;;
+1339F;EGYPTIAN HIEROGLYPH V030;Lo;0;L;;;;;N;;;;;
+133A0;EGYPTIAN HIEROGLYPH V030A;Lo;0;L;;;;;N;;;;;
+133A1;EGYPTIAN HIEROGLYPH V031;Lo;0;L;;;;;N;;;;;
+133A2;EGYPTIAN HIEROGLYPH V031A;Lo;0;L;;;;;N;;;;;
+133A3;EGYPTIAN HIEROGLYPH V032;Lo;0;L;;;;;N;;;;;
+133A4;EGYPTIAN HIEROGLYPH V033;Lo;0;L;;;;;N;;;;;
+133A5;EGYPTIAN HIEROGLYPH V033A;Lo;0;L;;;;;N;;;;;
+133A6;EGYPTIAN HIEROGLYPH V034;Lo;0;L;;;;;N;;;;;
+133A7;EGYPTIAN HIEROGLYPH V035;Lo;0;L;;;;;N;;;;;
+133A8;EGYPTIAN HIEROGLYPH V036;Lo;0;L;;;;;N;;;;;
+133A9;EGYPTIAN HIEROGLYPH V037;Lo;0;L;;;;;N;;;;;
+133AA;EGYPTIAN HIEROGLYPH V037A;Lo;0;L;;;;;N;;;;;
+133AB;EGYPTIAN HIEROGLYPH V038;Lo;0;L;;;;;N;;;;;
+133AC;EGYPTIAN HIEROGLYPH V039;Lo;0;L;;;;;N;;;;;
+133AD;EGYPTIAN HIEROGLYPH V040;Lo;0;L;;;;;N;;;;;
+133AE;EGYPTIAN HIEROGLYPH V040A;Lo;0;L;;;;;N;;;;;
+133AF;EGYPTIAN HIEROGLYPH W001;Lo;0;L;;;;;N;;;;;
+133B0;EGYPTIAN HIEROGLYPH W002;Lo;0;L;;;;;N;;;;;
+133B1;EGYPTIAN HIEROGLYPH W003;Lo;0;L;;;;;N;;;;;
+133B2;EGYPTIAN HIEROGLYPH W003A;Lo;0;L;;;;;N;;;;;
+133B3;EGYPTIAN HIEROGLYPH W004;Lo;0;L;;;;;N;;;;;
+133B4;EGYPTIAN HIEROGLYPH W005;Lo;0;L;;;;;N;;;;;
+133B5;EGYPTIAN HIEROGLYPH W006;Lo;0;L;;;;;N;;;;;
+133B6;EGYPTIAN HIEROGLYPH W007;Lo;0;L;;;;;N;;;;;
+133B7;EGYPTIAN HIEROGLYPH W008;Lo;0;L;;;;;N;;;;;
+133B8;EGYPTIAN HIEROGLYPH W009;Lo;0;L;;;;;N;;;;;
+133B9;EGYPTIAN HIEROGLYPH W009A;Lo;0;L;;;;;N;;;;;
+133BA;EGYPTIAN HIEROGLYPH W010;Lo;0;L;;;;;N;;;;;
+133BB;EGYPTIAN HIEROGLYPH W010A;Lo;0;L;;;;;N;;;;;
+133BC;EGYPTIAN HIEROGLYPH W011;Lo;0;L;;;;;N;;;;;
+133BD;EGYPTIAN HIEROGLYPH W012;Lo;0;L;;;;;N;;;;;
+133BE;EGYPTIAN HIEROGLYPH W013;Lo;0;L;;;;;N;;;;;
+133BF;EGYPTIAN HIEROGLYPH W014;Lo;0;L;;;;;N;;;;;
+133C0;EGYPTIAN HIEROGLYPH W014A;Lo;0;L;;;;;N;;;;;
+133C1;EGYPTIAN HIEROGLYPH W015;Lo;0;L;;;;;N;;;;;
+133C2;EGYPTIAN HIEROGLYPH W016;Lo;0;L;;;;;N;;;;;
+133C3;EGYPTIAN HIEROGLYPH W017;Lo;0;L;;;;;N;;;;;
+133C4;EGYPTIAN HIEROGLYPH W017A;Lo;0;L;;;;;N;;;;;
+133C5;EGYPTIAN HIEROGLYPH W018;Lo;0;L;;;;;N;;;;;
+133C6;EGYPTIAN HIEROGLYPH W018A;Lo;0;L;;;;;N;;;;;
+133C7;EGYPTIAN HIEROGLYPH W019;Lo;0;L;;;;;N;;;;;
+133C8;EGYPTIAN HIEROGLYPH W020;Lo;0;L;;;;;N;;;;;
+133C9;EGYPTIAN HIEROGLYPH W021;Lo;0;L;;;;;N;;;;;
+133CA;EGYPTIAN HIEROGLYPH W022;Lo;0;L;;;;;N;;;;;
+133CB;EGYPTIAN HIEROGLYPH W023;Lo;0;L;;;;;N;;;;;
+133CC;EGYPTIAN HIEROGLYPH W024;Lo;0;L;;;;;N;;;;;
+133CD;EGYPTIAN HIEROGLYPH W024A;Lo;0;L;;;;;N;;;;;
+133CE;EGYPTIAN HIEROGLYPH W025;Lo;0;L;;;;;N;;;;;
+133CF;EGYPTIAN HIEROGLYPH X001;Lo;0;L;;;;;N;;;;;
+133D0;EGYPTIAN HIEROGLYPH X002;Lo;0;L;;;;;N;;;;;
+133D1;EGYPTIAN HIEROGLYPH X003;Lo;0;L;;;;;N;;;;;
+133D2;EGYPTIAN HIEROGLYPH X004;Lo;0;L;;;;;N;;;;;
+133D3;EGYPTIAN HIEROGLYPH X004A;Lo;0;L;;;;;N;;;;;
+133D4;EGYPTIAN HIEROGLYPH X004B;Lo;0;L;;;;;N;;;;;
+133D5;EGYPTIAN HIEROGLYPH X005;Lo;0;L;;;;;N;;;;;
+133D6;EGYPTIAN HIEROGLYPH X006;Lo;0;L;;;;;N;;;;;
+133D7;EGYPTIAN HIEROGLYPH X006A;Lo;0;L;;;;;N;;;;;
+133D8;EGYPTIAN HIEROGLYPH X007;Lo;0;L;;;;;N;;;;;
+133D9;EGYPTIAN HIEROGLYPH X008;Lo;0;L;;;;;N;;;;;
+133DA;EGYPTIAN HIEROGLYPH X008A;Lo;0;L;;;;;N;;;;;
+133DB;EGYPTIAN HIEROGLYPH Y001;Lo;0;L;;;;;N;;;;;
+133DC;EGYPTIAN HIEROGLYPH Y001A;Lo;0;L;;;;;N;;;;;
+133DD;EGYPTIAN HIEROGLYPH Y002;Lo;0;L;;;;;N;;;;;
+133DE;EGYPTIAN HIEROGLYPH Y003;Lo;0;L;;;;;N;;;;;
+133DF;EGYPTIAN HIEROGLYPH Y004;Lo;0;L;;;;;N;;;;;
+133E0;EGYPTIAN HIEROGLYPH Y005;Lo;0;L;;;;;N;;;;;
+133E1;EGYPTIAN HIEROGLYPH Y006;Lo;0;L;;;;;N;;;;;
+133E2;EGYPTIAN HIEROGLYPH Y007;Lo;0;L;;;;;N;;;;;
+133E3;EGYPTIAN HIEROGLYPH Y008;Lo;0;L;;;;;N;;;;;
+133E4;EGYPTIAN HIEROGLYPH Z001;Lo;0;L;;;;;N;;;;;
+133E5;EGYPTIAN HIEROGLYPH Z002;Lo;0;L;;;;;N;;;;;
+133E6;EGYPTIAN HIEROGLYPH Z002A;Lo;0;L;;;;;N;;;;;
+133E7;EGYPTIAN HIEROGLYPH Z002B;Lo;0;L;;;;;N;;;;;
+133E8;EGYPTIAN HIEROGLYPH Z002C;Lo;0;L;;;;;N;;;;;
+133E9;EGYPTIAN HIEROGLYPH Z002D;Lo;0;L;;;;;N;;;;;
+133EA;EGYPTIAN HIEROGLYPH Z003;Lo;0;L;;;;;N;;;;;
+133EB;EGYPTIAN HIEROGLYPH Z003A;Lo;0;L;;;;;N;;;;;
+133EC;EGYPTIAN HIEROGLYPH Z003B;Lo;0;L;;;;;N;;;;;
+133ED;EGYPTIAN HIEROGLYPH Z004;Lo;0;L;;;;;N;;;;;
+133EE;EGYPTIAN HIEROGLYPH Z004A;Lo;0;L;;;;;N;;;;;
+133EF;EGYPTIAN HIEROGLYPH Z005;Lo;0;L;;;;;N;;;;;
+133F0;EGYPTIAN HIEROGLYPH Z005A;Lo;0;L;;;;;N;;;;;
+133F1;EGYPTIAN HIEROGLYPH Z006;Lo;0;L;;;;;N;;;;;
+133F2;EGYPTIAN HIEROGLYPH Z007;Lo;0;L;;;;;N;;;;;
+133F3;EGYPTIAN HIEROGLYPH Z008;Lo;0;L;;;;;N;;;;;
+133F4;EGYPTIAN HIEROGLYPH Z009;Lo;0;L;;;;;N;;;;;
+133F5;EGYPTIAN HIEROGLYPH Z010;Lo;0;L;;;;;N;;;;;
+133F6;EGYPTIAN HIEROGLYPH Z011;Lo;0;L;;;;;N;;;;;
+133F7;EGYPTIAN HIEROGLYPH Z012;Lo;0;L;;;;;N;;;;;
+133F8;EGYPTIAN HIEROGLYPH Z013;Lo;0;L;;;;;N;;;;;
+133F9;EGYPTIAN HIEROGLYPH Z014;Lo;0;L;;;;;N;;;;;
+133FA;EGYPTIAN HIEROGLYPH Z015;Lo;0;L;;;;;N;;;;;
+133FB;EGYPTIAN HIEROGLYPH Z015A;Lo;0;L;;;;;N;;;;;
+133FC;EGYPTIAN HIEROGLYPH Z015B;Lo;0;L;;;;;N;;;;;
+133FD;EGYPTIAN HIEROGLYPH Z015C;Lo;0;L;;;;;N;;;;;
+133FE;EGYPTIAN HIEROGLYPH Z015D;Lo;0;L;;;;;N;;;;;
+133FF;EGYPTIAN HIEROGLYPH Z015E;Lo;0;L;;;;;N;;;;;
+13400;EGYPTIAN HIEROGLYPH Z015F;Lo;0;L;;;;;N;;;;;
+13401;EGYPTIAN HIEROGLYPH Z015G;Lo;0;L;;;;;N;;;;;
+13402;EGYPTIAN HIEROGLYPH Z015H;Lo;0;L;;;;;N;;;;;
+13403;EGYPTIAN HIEROGLYPH Z015I;Lo;0;L;;;;;N;;;;;
+13404;EGYPTIAN HIEROGLYPH Z016;Lo;0;L;;;;;N;;;;;
+13405;EGYPTIAN HIEROGLYPH Z016A;Lo;0;L;;;;;N;;;;;
+13406;EGYPTIAN HIEROGLYPH Z016B;Lo;0;L;;;;;N;;;;;
+13407;EGYPTIAN HIEROGLYPH Z016C;Lo;0;L;;;;;N;;;;;
+13408;EGYPTIAN HIEROGLYPH Z016D;Lo;0;L;;;;;N;;;;;
+13409;EGYPTIAN HIEROGLYPH Z016E;Lo;0;L;;;;;N;;;;;
+1340A;EGYPTIAN HIEROGLYPH Z016F;Lo;0;L;;;;;N;;;;;
+1340B;EGYPTIAN HIEROGLYPH Z016G;Lo;0;L;;;;;N;;;;;
+1340C;EGYPTIAN HIEROGLYPH Z016H;Lo;0;L;;;;;N;;;;;
+1340D;EGYPTIAN HIEROGLYPH AA001;Lo;0;L;;;;;N;;;;;
+1340E;EGYPTIAN HIEROGLYPH AA002;Lo;0;L;;;;;N;;;;;
+1340F;EGYPTIAN HIEROGLYPH AA003;Lo;0;L;;;;;N;;;;;
+13410;EGYPTIAN HIEROGLYPH AA004;Lo;0;L;;;;;N;;;;;
+13411;EGYPTIAN HIEROGLYPH AA005;Lo;0;L;;;;;N;;;;;
+13412;EGYPTIAN HIEROGLYPH AA006;Lo;0;L;;;;;N;;;;;
+13413;EGYPTIAN HIEROGLYPH AA007;Lo;0;L;;;;;N;;;;;
+13414;EGYPTIAN HIEROGLYPH AA007A;Lo;0;L;;;;;N;;;;;
+13415;EGYPTIAN HIEROGLYPH AA007B;Lo;0;L;;;;;N;;;;;
+13416;EGYPTIAN HIEROGLYPH AA008;Lo;0;L;;;;;N;;;;;
+13417;EGYPTIAN HIEROGLYPH AA009;Lo;0;L;;;;;N;;;;;
+13418;EGYPTIAN HIEROGLYPH AA010;Lo;0;L;;;;;N;;;;;
+13419;EGYPTIAN HIEROGLYPH AA011;Lo;0;L;;;;;N;;;;;
+1341A;EGYPTIAN HIEROGLYPH AA012;Lo;0;L;;;;;N;;;;;
+1341B;EGYPTIAN HIEROGLYPH AA013;Lo;0;L;;;;;N;;;;;
+1341C;EGYPTIAN HIEROGLYPH AA014;Lo;0;L;;;;;N;;;;;
+1341D;EGYPTIAN HIEROGLYPH AA015;Lo;0;L;;;;;N;;;;;
+1341E;EGYPTIAN HIEROGLYPH AA016;Lo;0;L;;;;;N;;;;;
+1341F;EGYPTIAN HIEROGLYPH AA017;Lo;0;L;;;;;N;;;;;
+13420;EGYPTIAN HIEROGLYPH AA018;Lo;0;L;;;;;N;;;;;
+13421;EGYPTIAN HIEROGLYPH AA019;Lo;0;L;;;;;N;;;;;
+13422;EGYPTIAN HIEROGLYPH AA020;Lo;0;L;;;;;N;;;;;
+13423;EGYPTIAN HIEROGLYPH AA021;Lo;0;L;;;;;N;;;;;
+13424;EGYPTIAN HIEROGLYPH AA022;Lo;0;L;;;;;N;;;;;
+13425;EGYPTIAN HIEROGLYPH AA023;Lo;0;L;;;;;N;;;;;
+13426;EGYPTIAN HIEROGLYPH AA024;Lo;0;L;;;;;N;;;;;
+13427;EGYPTIAN HIEROGLYPH AA025;Lo;0;L;;;;;N;;;;;
+13428;EGYPTIAN HIEROGLYPH AA026;Lo;0;L;;;;;N;;;;;
+13429;EGYPTIAN HIEROGLYPH AA027;Lo;0;L;;;;;N;;;;;
+1342A;EGYPTIAN HIEROGLYPH AA028;Lo;0;L;;;;;N;;;;;
+1342B;EGYPTIAN HIEROGLYPH AA029;Lo;0;L;;;;;N;;;;;
+1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;;
+1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;;
+1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;;
+14400;ANATOLIAN HIEROGLYPH A001;Lo;0;L;;;;;N;;;;;
+14401;ANATOLIAN HIEROGLYPH A002;Lo;0;L;;;;;N;;;;;
+14402;ANATOLIAN HIEROGLYPH A003;Lo;0;L;;;;;N;;;;;
+14403;ANATOLIAN HIEROGLYPH A004;Lo;0;L;;;;;N;;;;;
+14404;ANATOLIAN HIEROGLYPH A005;Lo;0;L;;;;;N;;;;;
+14405;ANATOLIAN HIEROGLYPH A006;Lo;0;L;;;;;N;;;;;
+14406;ANATOLIAN HIEROGLYPH A007;Lo;0;L;;;;;N;;;;;
+14407;ANATOLIAN HIEROGLYPH A008;Lo;0;L;;;;;N;;;;;
+14408;ANATOLIAN HIEROGLYPH A009;Lo;0;L;;;;;N;;;;;
+14409;ANATOLIAN HIEROGLYPH A010;Lo;0;L;;;;;N;;;;;
+1440A;ANATOLIAN HIEROGLYPH A010A;Lo;0;L;;;;;N;;;;;
+1440B;ANATOLIAN HIEROGLYPH A011;Lo;0;L;;;;;N;;;;;
+1440C;ANATOLIAN HIEROGLYPH A012;Lo;0;L;;;;;N;;;;;
+1440D;ANATOLIAN HIEROGLYPH A013;Lo;0;L;;;;;N;;;;;
+1440E;ANATOLIAN HIEROGLYPH A014;Lo;0;L;;;;;N;;;;;
+1440F;ANATOLIAN HIEROGLYPH A015;Lo;0;L;;;;;N;;;;;
+14410;ANATOLIAN HIEROGLYPH A016;Lo;0;L;;;;;N;;;;;
+14411;ANATOLIAN HIEROGLYPH A017;Lo;0;L;;;;;N;;;;;
+14412;ANATOLIAN HIEROGLYPH A018;Lo;0;L;;;;;N;;;;;
+14413;ANATOLIAN HIEROGLYPH A019;Lo;0;L;;;;;N;;;;;
+14414;ANATOLIAN HIEROGLYPH A020;Lo;0;L;;;;;N;;;;;
+14415;ANATOLIAN HIEROGLYPH A021;Lo;0;L;;;;;N;;;;;
+14416;ANATOLIAN HIEROGLYPH A022;Lo;0;L;;;;;N;;;;;
+14417;ANATOLIAN HIEROGLYPH A023;Lo;0;L;;;;;N;;;;;
+14418;ANATOLIAN HIEROGLYPH A024;Lo;0;L;;;;;N;;;;;
+14419;ANATOLIAN HIEROGLYPH A025;Lo;0;L;;;;;N;;;;;
+1441A;ANATOLIAN HIEROGLYPH A026;Lo;0;L;;;;;N;;;;;
+1441B;ANATOLIAN HIEROGLYPH A026A;Lo;0;L;;;;;N;;;;;
+1441C;ANATOLIAN HIEROGLYPH A027;Lo;0;L;;;;;N;;;;;
+1441D;ANATOLIAN HIEROGLYPH A028;Lo;0;L;;;;;N;;;;;
+1441E;ANATOLIAN HIEROGLYPH A029;Lo;0;L;;;;;N;;;;;
+1441F;ANATOLIAN HIEROGLYPH A030;Lo;0;L;;;;;N;;;;;
+14420;ANATOLIAN HIEROGLYPH A031;Lo;0;L;;;;;N;;;;;
+14421;ANATOLIAN HIEROGLYPH A032;Lo;0;L;;;;;N;;;;;
+14422;ANATOLIAN HIEROGLYPH A033;Lo;0;L;;;;;N;;;;;
+14423;ANATOLIAN HIEROGLYPH A034;Lo;0;L;;;;;N;;;;;
+14424;ANATOLIAN HIEROGLYPH A035;Lo;0;L;;;;;N;;;;;
+14425;ANATOLIAN HIEROGLYPH A036;Lo;0;L;;;;;N;;;;;
+14426;ANATOLIAN HIEROGLYPH A037;Lo;0;L;;;;;N;;;;;
+14427;ANATOLIAN HIEROGLYPH A038;Lo;0;L;;;;;N;;;;;
+14428;ANATOLIAN HIEROGLYPH A039;Lo;0;L;;;;;N;;;;;
+14429;ANATOLIAN HIEROGLYPH A039A;Lo;0;L;;;;;N;;;;;
+1442A;ANATOLIAN HIEROGLYPH A040;Lo;0;L;;;;;N;;;;;
+1442B;ANATOLIAN HIEROGLYPH A041;Lo;0;L;;;;;N;;;;;
+1442C;ANATOLIAN HIEROGLYPH A041A;Lo;0;L;;;;;N;;;;;
+1442D;ANATOLIAN HIEROGLYPH A042;Lo;0;L;;;;;N;;;;;
+1442E;ANATOLIAN HIEROGLYPH A043;Lo;0;L;;;;;N;;;;;
+1442F;ANATOLIAN HIEROGLYPH A044;Lo;0;L;;;;;N;;;;;
+14430;ANATOLIAN HIEROGLYPH A045;Lo;0;L;;;;;N;;;;;
+14431;ANATOLIAN HIEROGLYPH A045A;Lo;0;L;;;;;N;;;;;
+14432;ANATOLIAN HIEROGLYPH A046;Lo;0;L;;;;;N;;;;;
+14433;ANATOLIAN HIEROGLYPH A046A;Lo;0;L;;;;;N;;;;;
+14434;ANATOLIAN HIEROGLYPH A046B;Lo;0;L;;;;;N;;;;;
+14435;ANATOLIAN HIEROGLYPH A047;Lo;0;L;;;;;N;;;;;
+14436;ANATOLIAN HIEROGLYPH A048;Lo;0;L;;;;;N;;;;;
+14437;ANATOLIAN HIEROGLYPH A049;Lo;0;L;;;;;N;;;;;
+14438;ANATOLIAN HIEROGLYPH A050;Lo;0;L;;;;;N;;;;;
+14439;ANATOLIAN HIEROGLYPH A051;Lo;0;L;;;;;N;;;;;
+1443A;ANATOLIAN HIEROGLYPH A052;Lo;0;L;;;;;N;;;;;
+1443B;ANATOLIAN HIEROGLYPH A053;Lo;0;L;;;;;N;;;;;
+1443C;ANATOLIAN HIEROGLYPH A054;Lo;0;L;;;;;N;;;;;
+1443D;ANATOLIAN HIEROGLYPH A055;Lo;0;L;;;;;N;;;;;
+1443E;ANATOLIAN HIEROGLYPH A056;Lo;0;L;;;;;N;;;;;
+1443F;ANATOLIAN HIEROGLYPH A057;Lo;0;L;;;;;N;;;;;
+14440;ANATOLIAN HIEROGLYPH A058;Lo;0;L;;;;;N;;;;;
+14441;ANATOLIAN HIEROGLYPH A059;Lo;0;L;;;;;N;;;;;
+14442;ANATOLIAN HIEROGLYPH A060;Lo;0;L;;;;;N;;;;;
+14443;ANATOLIAN HIEROGLYPH A061;Lo;0;L;;;;;N;;;;;
+14444;ANATOLIAN HIEROGLYPH A062;Lo;0;L;;;;;N;;;;;
+14445;ANATOLIAN HIEROGLYPH A063;Lo;0;L;;;;;N;;;;;
+14446;ANATOLIAN HIEROGLYPH A064;Lo;0;L;;;;;N;;;;;
+14447;ANATOLIAN HIEROGLYPH A065;Lo;0;L;;;;;N;;;;;
+14448;ANATOLIAN HIEROGLYPH A066;Lo;0;L;;;;;N;;;;;
+14449;ANATOLIAN HIEROGLYPH A066A;Lo;0;L;;;;;N;;;;;
+1444A;ANATOLIAN HIEROGLYPH A066B;Lo;0;L;;;;;N;;;;;
+1444B;ANATOLIAN HIEROGLYPH A066C;Lo;0;L;;;;;N;;;;;
+1444C;ANATOLIAN HIEROGLYPH A067;Lo;0;L;;;;;N;;;;;
+1444D;ANATOLIAN HIEROGLYPH A068;Lo;0;L;;;;;N;;;;;
+1444E;ANATOLIAN HIEROGLYPH A069;Lo;0;L;;;;;N;;;;;
+1444F;ANATOLIAN HIEROGLYPH A070;Lo;0;L;;;;;N;;;;;
+14450;ANATOLIAN HIEROGLYPH A071;Lo;0;L;;;;;N;;;;;
+14451;ANATOLIAN HIEROGLYPH A072;Lo;0;L;;;;;N;;;;;
+14452;ANATOLIAN HIEROGLYPH A073;Lo;0;L;;;;;N;;;;;
+14453;ANATOLIAN HIEROGLYPH A074;Lo;0;L;;;;;N;;;;;
+14454;ANATOLIAN HIEROGLYPH A075;Lo;0;L;;;;;N;;;;;
+14455;ANATOLIAN HIEROGLYPH A076;Lo;0;L;;;;;N;;;;;
+14456;ANATOLIAN HIEROGLYPH A077;Lo;0;L;;;;;N;;;;;
+14457;ANATOLIAN HIEROGLYPH A078;Lo;0;L;;;;;N;;;;;
+14458;ANATOLIAN HIEROGLYPH A079;Lo;0;L;;;;;N;;;;;
+14459;ANATOLIAN HIEROGLYPH A080;Lo;0;L;;;;;N;;;;;
+1445A;ANATOLIAN HIEROGLYPH A081;Lo;0;L;;;;;N;;;;;
+1445B;ANATOLIAN HIEROGLYPH A082;Lo;0;L;;;;;N;;;;;
+1445C;ANATOLIAN HIEROGLYPH A083;Lo;0;L;;;;;N;;;;;
+1445D;ANATOLIAN HIEROGLYPH A084;Lo;0;L;;;;;N;;;;;
+1445E;ANATOLIAN HIEROGLYPH A085;Lo;0;L;;;;;N;;;;;
+1445F;ANATOLIAN HIEROGLYPH A086;Lo;0;L;;;;;N;;;;;
+14460;ANATOLIAN HIEROGLYPH A087;Lo;0;L;;;;;N;;;;;
+14461;ANATOLIAN HIEROGLYPH A088;Lo;0;L;;;;;N;;;;;
+14462;ANATOLIAN HIEROGLYPH A089;Lo;0;L;;;;;N;;;;;
+14463;ANATOLIAN HIEROGLYPH A090;Lo;0;L;;;;;N;;;;;
+14464;ANATOLIAN HIEROGLYPH A091;Lo;0;L;;;;;N;;;;;
+14465;ANATOLIAN HIEROGLYPH A092;Lo;0;L;;;;;N;;;;;
+14466;ANATOLIAN HIEROGLYPH A093;Lo;0;L;;;;;N;;;;;
+14467;ANATOLIAN HIEROGLYPH A094;Lo;0;L;;;;;N;;;;;
+14468;ANATOLIAN HIEROGLYPH A095;Lo;0;L;;;;;N;;;;;
+14469;ANATOLIAN HIEROGLYPH A096;Lo;0;L;;;;;N;;;;;
+1446A;ANATOLIAN HIEROGLYPH A097;Lo;0;L;;;;;N;;;;;
+1446B;ANATOLIAN HIEROGLYPH A097A;Lo;0;L;;;;;N;;;;;
+1446C;ANATOLIAN HIEROGLYPH A098;Lo;0;L;;;;;N;;;;;
+1446D;ANATOLIAN HIEROGLYPH A098A;Lo;0;L;;;;;N;;;;;
+1446E;ANATOLIAN HIEROGLYPH A099;Lo;0;L;;;;;N;;;;;
+1446F;ANATOLIAN HIEROGLYPH A100;Lo;0;L;;;;;N;;;;;
+14470;ANATOLIAN HIEROGLYPH A100A;Lo;0;L;;;;;N;;;;;
+14471;ANATOLIAN HIEROGLYPH A101;Lo;0;L;;;;;N;;;;;
+14472;ANATOLIAN HIEROGLYPH A101A;Lo;0;L;;;;;N;;;;;
+14473;ANATOLIAN HIEROGLYPH A102;Lo;0;L;;;;;N;;;;;
+14474;ANATOLIAN HIEROGLYPH A102A;Lo;0;L;;;;;N;;;;;
+14475;ANATOLIAN HIEROGLYPH A103;Lo;0;L;;;;;N;;;;;
+14476;ANATOLIAN HIEROGLYPH A104;Lo;0;L;;;;;N;;;;;
+14477;ANATOLIAN HIEROGLYPH A104A;Lo;0;L;;;;;N;;;;;
+14478;ANATOLIAN HIEROGLYPH A104B;Lo;0;L;;;;;N;;;;;
+14479;ANATOLIAN HIEROGLYPH A104C;Lo;0;L;;;;;N;;;;;
+1447A;ANATOLIAN HIEROGLYPH A105;Lo;0;L;;;;;N;;;;;
+1447B;ANATOLIAN HIEROGLYPH A105A;Lo;0;L;;;;;N;;;;;
+1447C;ANATOLIAN HIEROGLYPH A105B;Lo;0;L;;;;;N;;;;;
+1447D;ANATOLIAN HIEROGLYPH A106;Lo;0;L;;;;;N;;;;;
+1447E;ANATOLIAN HIEROGLYPH A107;Lo;0;L;;;;;N;;;;;
+1447F;ANATOLIAN HIEROGLYPH A107A;Lo;0;L;;;;;N;;;;;
+14480;ANATOLIAN HIEROGLYPH A107B;Lo;0;L;;;;;N;;;;;
+14481;ANATOLIAN HIEROGLYPH A107C;Lo;0;L;;;;;N;;;;;
+14482;ANATOLIAN HIEROGLYPH A108;Lo;0;L;;;;;N;;;;;
+14483;ANATOLIAN HIEROGLYPH A109;Lo;0;L;;;;;N;;;;;
+14484;ANATOLIAN HIEROGLYPH A110;Lo;0;L;;;;;N;;;;;
+14485;ANATOLIAN HIEROGLYPH A110A;Lo;0;L;;;;;N;;;;;
+14486;ANATOLIAN HIEROGLYPH A110B;Lo;0;L;;;;;N;;;;;
+14487;ANATOLIAN HIEROGLYPH A111;Lo;0;L;;;;;N;;;;;
+14488;ANATOLIAN HIEROGLYPH A112;Lo;0;L;;;;;N;;;;;
+14489;ANATOLIAN HIEROGLYPH A113;Lo;0;L;;;;;N;;;;;
+1448A;ANATOLIAN HIEROGLYPH A114;Lo;0;L;;;;;N;;;;;
+1448B;ANATOLIAN HIEROGLYPH A115;Lo;0;L;;;;;N;;;;;
+1448C;ANATOLIAN HIEROGLYPH A115A;Lo;0;L;;;;;N;;;;;
+1448D;ANATOLIAN HIEROGLYPH A116;Lo;0;L;;;;;N;;;;;
+1448E;ANATOLIAN HIEROGLYPH A117;Lo;0;L;;;;;N;;;;;
+1448F;ANATOLIAN HIEROGLYPH A118;Lo;0;L;;;;;N;;;;;
+14490;ANATOLIAN HIEROGLYPH A119;Lo;0;L;;;;;N;;;;;
+14491;ANATOLIAN HIEROGLYPH A120;Lo;0;L;;;;;N;;;;;
+14492;ANATOLIAN HIEROGLYPH A121;Lo;0;L;;;;;N;;;;;
+14493;ANATOLIAN HIEROGLYPH A122;Lo;0;L;;;;;N;;;;;
+14494;ANATOLIAN HIEROGLYPH A123;Lo;0;L;;;;;N;;;;;
+14495;ANATOLIAN HIEROGLYPH A124;Lo;0;L;;;;;N;;;;;
+14496;ANATOLIAN HIEROGLYPH A125;Lo;0;L;;;;;N;;;;;
+14497;ANATOLIAN HIEROGLYPH A125A;Lo;0;L;;;;;N;;;;;
+14498;ANATOLIAN HIEROGLYPH A126;Lo;0;L;;;;;N;;;;;
+14499;ANATOLIAN HIEROGLYPH A127;Lo;0;L;;;;;N;;;;;
+1449A;ANATOLIAN HIEROGLYPH A128;Lo;0;L;;;;;N;;;;;
+1449B;ANATOLIAN HIEROGLYPH A129;Lo;0;L;;;;;N;;;;;
+1449C;ANATOLIAN HIEROGLYPH A130;Lo;0;L;;;;;N;;;;;
+1449D;ANATOLIAN HIEROGLYPH A131;Lo;0;L;;;;;N;;;;;
+1449E;ANATOLIAN HIEROGLYPH A132;Lo;0;L;;;;;N;;;;;
+1449F;ANATOLIAN HIEROGLYPH A133;Lo;0;L;;;;;N;;;;;
+144A0;ANATOLIAN HIEROGLYPH A134;Lo;0;L;;;;;N;;;;;
+144A1;ANATOLIAN HIEROGLYPH A135;Lo;0;L;;;;;N;;;;;
+144A2;ANATOLIAN HIEROGLYPH A135A;Lo;0;L;;;;;N;;;;;
+144A3;ANATOLIAN HIEROGLYPH A136;Lo;0;L;;;;;N;;;;;
+144A4;ANATOLIAN HIEROGLYPH A137;Lo;0;L;;;;;N;;;;;
+144A5;ANATOLIAN HIEROGLYPH A138;Lo;0;L;;;;;N;;;;;
+144A6;ANATOLIAN HIEROGLYPH A139;Lo;0;L;;;;;N;;;;;
+144A7;ANATOLIAN HIEROGLYPH A140;Lo;0;L;;;;;N;;;;;
+144A8;ANATOLIAN HIEROGLYPH A141;Lo;0;L;;;;;N;;;;;
+144A9;ANATOLIAN HIEROGLYPH A142;Lo;0;L;;;;;N;;;;;
+144AA;ANATOLIAN HIEROGLYPH A143;Lo;0;L;;;;;N;;;;;
+144AB;ANATOLIAN HIEROGLYPH A144;Lo;0;L;;;;;N;;;;;
+144AC;ANATOLIAN HIEROGLYPH A145;Lo;0;L;;;;;N;;;;;
+144AD;ANATOLIAN HIEROGLYPH A146;Lo;0;L;;;;;N;;;;;
+144AE;ANATOLIAN HIEROGLYPH A147;Lo;0;L;;;;;N;;;;;
+144AF;ANATOLIAN HIEROGLYPH A148;Lo;0;L;;;;;N;;;;;
+144B0;ANATOLIAN HIEROGLYPH A149;Lo;0;L;;;;;N;;;;;
+144B1;ANATOLIAN HIEROGLYPH A150;Lo;0;L;;;;;N;;;;;
+144B2;ANATOLIAN HIEROGLYPH A151;Lo;0;L;;;;;N;;;;;
+144B3;ANATOLIAN HIEROGLYPH A152;Lo;0;L;;;;;N;;;;;
+144B4;ANATOLIAN HIEROGLYPH A153;Lo;0;L;;;;;N;;;;;
+144B5;ANATOLIAN HIEROGLYPH A154;Lo;0;L;;;;;N;;;;;
+144B6;ANATOLIAN HIEROGLYPH A155;Lo;0;L;;;;;N;;;;;
+144B7;ANATOLIAN HIEROGLYPH A156;Lo;0;L;;;;;N;;;;;
+144B8;ANATOLIAN HIEROGLYPH A157;Lo;0;L;;;;;N;;;;;
+144B9;ANATOLIAN HIEROGLYPH A158;Lo;0;L;;;;;N;;;;;
+144BA;ANATOLIAN HIEROGLYPH A159;Lo;0;L;;;;;N;;;;;
+144BB;ANATOLIAN HIEROGLYPH A160;Lo;0;L;;;;;N;;;;;
+144BC;ANATOLIAN HIEROGLYPH A161;Lo;0;L;;;;;N;;;;;
+144BD;ANATOLIAN HIEROGLYPH A162;Lo;0;L;;;;;N;;;;;
+144BE;ANATOLIAN HIEROGLYPH A163;Lo;0;L;;;;;N;;;;;
+144BF;ANATOLIAN HIEROGLYPH A164;Lo;0;L;;;;;N;;;;;
+144C0;ANATOLIAN HIEROGLYPH A165;Lo;0;L;;;;;N;;;;;
+144C1;ANATOLIAN HIEROGLYPH A166;Lo;0;L;;;;;N;;;;;
+144C2;ANATOLIAN HIEROGLYPH A167;Lo;0;L;;;;;N;;;;;
+144C3;ANATOLIAN HIEROGLYPH A168;Lo;0;L;;;;;N;;;;;
+144C4;ANATOLIAN HIEROGLYPH A169;Lo;0;L;;;;;N;;;;;
+144C5;ANATOLIAN HIEROGLYPH A170;Lo;0;L;;;;;N;;;;;
+144C6;ANATOLIAN HIEROGLYPH A171;Lo;0;L;;;;;N;;;;;
+144C7;ANATOLIAN HIEROGLYPH A172;Lo;0;L;;;;;N;;;;;
+144C8;ANATOLIAN HIEROGLYPH A173;Lo;0;L;;;;;N;;;;;
+144C9;ANATOLIAN HIEROGLYPH A174;Lo;0;L;;;;;N;;;;;
+144CA;ANATOLIAN HIEROGLYPH A175;Lo;0;L;;;;;N;;;;;
+144CB;ANATOLIAN HIEROGLYPH A176;Lo;0;L;;;;;N;;;;;
+144CC;ANATOLIAN HIEROGLYPH A177;Lo;0;L;;;;;N;;;;;
+144CD;ANATOLIAN HIEROGLYPH A178;Lo;0;L;;;;;N;;;;;
+144CE;ANATOLIAN HIEROGLYPH A179;Lo;0;L;;;;;N;;;;;
+144CF;ANATOLIAN HIEROGLYPH A180;Lo;0;L;;;;;N;;;;;
+144D0;ANATOLIAN HIEROGLYPH A181;Lo;0;L;;;;;N;;;;;
+144D1;ANATOLIAN HIEROGLYPH A182;Lo;0;L;;;;;N;;;;;
+144D2;ANATOLIAN HIEROGLYPH A183;Lo;0;L;;;;;N;;;;;
+144D3;ANATOLIAN HIEROGLYPH A184;Lo;0;L;;;;;N;;;;;
+144D4;ANATOLIAN HIEROGLYPH A185;Lo;0;L;;;;;N;;;;;
+144D5;ANATOLIAN HIEROGLYPH A186;Lo;0;L;;;;;N;;;;;
+144D6;ANATOLIAN HIEROGLYPH A187;Lo;0;L;;;;;N;;;;;
+144D7;ANATOLIAN HIEROGLYPH A188;Lo;0;L;;;;;N;;;;;
+144D8;ANATOLIAN HIEROGLYPH A189;Lo;0;L;;;;;N;;;;;
+144D9;ANATOLIAN HIEROGLYPH A190;Lo;0;L;;;;;N;;;;;
+144DA;ANATOLIAN HIEROGLYPH A191;Lo;0;L;;;;;N;;;;;
+144DB;ANATOLIAN HIEROGLYPH A192;Lo;0;L;;;;;N;;;;;
+144DC;ANATOLIAN HIEROGLYPH A193;Lo;0;L;;;;;N;;;;;
+144DD;ANATOLIAN HIEROGLYPH A194;Lo;0;L;;;;;N;;;;;
+144DE;ANATOLIAN HIEROGLYPH A195;Lo;0;L;;;;;N;;;;;
+144DF;ANATOLIAN HIEROGLYPH A196;Lo;0;L;;;;;N;;;;;
+144E0;ANATOLIAN HIEROGLYPH A197;Lo;0;L;;;;;N;;;;;
+144E1;ANATOLIAN HIEROGLYPH A198;Lo;0;L;;;;;N;;;;;
+144E2;ANATOLIAN HIEROGLYPH A199;Lo;0;L;;;;;N;;;;;
+144E3;ANATOLIAN HIEROGLYPH A200;Lo;0;L;;;;;N;;;;;
+144E4;ANATOLIAN HIEROGLYPH A201;Lo;0;L;;;;;N;;;;;
+144E5;ANATOLIAN HIEROGLYPH A202;Lo;0;L;;;;;N;;;;;
+144E6;ANATOLIAN HIEROGLYPH A202A;Lo;0;L;;;;;N;;;;;
+144E7;ANATOLIAN HIEROGLYPH A202B;Lo;0;L;;;;;N;;;;;
+144E8;ANATOLIAN HIEROGLYPH A203;Lo;0;L;;;;;N;;;;;
+144E9;ANATOLIAN HIEROGLYPH A204;Lo;0;L;;;;;N;;;;;
+144EA;ANATOLIAN HIEROGLYPH A205;Lo;0;L;;;;;N;;;;;
+144EB;ANATOLIAN HIEROGLYPH A206;Lo;0;L;;;;;N;;;;;
+144EC;ANATOLIAN HIEROGLYPH A207;Lo;0;L;;;;;N;;;;;
+144ED;ANATOLIAN HIEROGLYPH A207A;Lo;0;L;;;;;N;;;;;
+144EE;ANATOLIAN HIEROGLYPH A208;Lo;0;L;;;;;N;;;;;
+144EF;ANATOLIAN HIEROGLYPH A209;Lo;0;L;;;;;N;;;;;
+144F0;ANATOLIAN HIEROGLYPH A209A;Lo;0;L;;;;;N;;;;;
+144F1;ANATOLIAN HIEROGLYPH A210;Lo;0;L;;;;;N;;;;;
+144F2;ANATOLIAN HIEROGLYPH A211;Lo;0;L;;;;;N;;;;;
+144F3;ANATOLIAN HIEROGLYPH A212;Lo;0;L;;;;;N;;;;;
+144F4;ANATOLIAN HIEROGLYPH A213;Lo;0;L;;;;;N;;;;;
+144F5;ANATOLIAN HIEROGLYPH A214;Lo;0;L;;;;;N;;;;;
+144F6;ANATOLIAN HIEROGLYPH A215;Lo;0;L;;;;;N;;;;;
+144F7;ANATOLIAN HIEROGLYPH A215A;Lo;0;L;;;;;N;;;;;
+144F8;ANATOLIAN HIEROGLYPH A216;Lo;0;L;;;;;N;;;;;
+144F9;ANATOLIAN HIEROGLYPH A216A;Lo;0;L;;;;;N;;;;;
+144FA;ANATOLIAN HIEROGLYPH A217;Lo;0;L;;;;;N;;;;;
+144FB;ANATOLIAN HIEROGLYPH A218;Lo;0;L;;;;;N;;;;;
+144FC;ANATOLIAN HIEROGLYPH A219;Lo;0;L;;;;;N;;;;;
+144FD;ANATOLIAN HIEROGLYPH A220;Lo;0;L;;;;;N;;;;;
+144FE;ANATOLIAN HIEROGLYPH A221;Lo;0;L;;;;;N;;;;;
+144FF;ANATOLIAN HIEROGLYPH A222;Lo;0;L;;;;;N;;;;;
+14500;ANATOLIAN HIEROGLYPH A223;Lo;0;L;;;;;N;;;;;
+14501;ANATOLIAN HIEROGLYPH A224;Lo;0;L;;;;;N;;;;;
+14502;ANATOLIAN HIEROGLYPH A225;Lo;0;L;;;;;N;;;;;
+14503;ANATOLIAN HIEROGLYPH A226;Lo;0;L;;;;;N;;;;;
+14504;ANATOLIAN HIEROGLYPH A227;Lo;0;L;;;;;N;;;;;
+14505;ANATOLIAN HIEROGLYPH A227A;Lo;0;L;;;;;N;;;;;
+14506;ANATOLIAN HIEROGLYPH A228;Lo;0;L;;;;;N;;;;;
+14507;ANATOLIAN HIEROGLYPH A229;Lo;0;L;;;;;N;;;;;
+14508;ANATOLIAN HIEROGLYPH A230;Lo;0;L;;;;;N;;;;;
+14509;ANATOLIAN HIEROGLYPH A231;Lo;0;L;;;;;N;;;;;
+1450A;ANATOLIAN HIEROGLYPH A232;Lo;0;L;;;;;N;;;;;
+1450B;ANATOLIAN HIEROGLYPH A233;Lo;0;L;;;;;N;;;;;
+1450C;ANATOLIAN HIEROGLYPH A234;Lo;0;L;;;;;N;;;;;
+1450D;ANATOLIAN HIEROGLYPH A235;Lo;0;L;;;;;N;;;;;
+1450E;ANATOLIAN HIEROGLYPH A236;Lo;0;L;;;;;N;;;;;
+1450F;ANATOLIAN HIEROGLYPH A237;Lo;0;L;;;;;N;;;;;
+14510;ANATOLIAN HIEROGLYPH A238;Lo;0;L;;;;;N;;;;;
+14511;ANATOLIAN HIEROGLYPH A239;Lo;0;L;;;;;N;;;;;
+14512;ANATOLIAN HIEROGLYPH A240;Lo;0;L;;;;;N;;;;;
+14513;ANATOLIAN HIEROGLYPH A241;Lo;0;L;;;;;N;;;;;
+14514;ANATOLIAN HIEROGLYPH A242;Lo;0;L;;;;;N;;;;;
+14515;ANATOLIAN HIEROGLYPH A243;Lo;0;L;;;;;N;;;;;
+14516;ANATOLIAN HIEROGLYPH A244;Lo;0;L;;;;;N;;;;;
+14517;ANATOLIAN HIEROGLYPH A245;Lo;0;L;;;;;N;;;;;
+14518;ANATOLIAN HIEROGLYPH A246;Lo;0;L;;;;;N;;;;;
+14519;ANATOLIAN HIEROGLYPH A247;Lo;0;L;;;;;N;;;;;
+1451A;ANATOLIAN HIEROGLYPH A248;Lo;0;L;;;;;N;;;;;
+1451B;ANATOLIAN HIEROGLYPH A249;Lo;0;L;;;;;N;;;;;
+1451C;ANATOLIAN HIEROGLYPH A250;Lo;0;L;;;;;N;;;;;
+1451D;ANATOLIAN HIEROGLYPH A251;Lo;0;L;;;;;N;;;;;
+1451E;ANATOLIAN HIEROGLYPH A252;Lo;0;L;;;;;N;;;;;
+1451F;ANATOLIAN HIEROGLYPH A253;Lo;0;L;;;;;N;;;;;
+14520;ANATOLIAN HIEROGLYPH A254;Lo;0;L;;;;;N;;;;;
+14521;ANATOLIAN HIEROGLYPH A255;Lo;0;L;;;;;N;;;;;
+14522;ANATOLIAN HIEROGLYPH A256;Lo;0;L;;;;;N;;;;;
+14523;ANATOLIAN HIEROGLYPH A257;Lo;0;L;;;;;N;;;;;
+14524;ANATOLIAN HIEROGLYPH A258;Lo;0;L;;;;;N;;;;;
+14525;ANATOLIAN HIEROGLYPH A259;Lo;0;L;;;;;N;;;;;
+14526;ANATOLIAN HIEROGLYPH A260;Lo;0;L;;;;;N;;;;;
+14527;ANATOLIAN HIEROGLYPH A261;Lo;0;L;;;;;N;;;;;
+14528;ANATOLIAN HIEROGLYPH A262;Lo;0;L;;;;;N;;;;;
+14529;ANATOLIAN HIEROGLYPH A263;Lo;0;L;;;;;N;;;;;
+1452A;ANATOLIAN HIEROGLYPH A264;Lo;0;L;;;;;N;;;;;
+1452B;ANATOLIAN HIEROGLYPH A265;Lo;0;L;;;;;N;;;;;
+1452C;ANATOLIAN HIEROGLYPH A266;Lo;0;L;;;;;N;;;;;
+1452D;ANATOLIAN HIEROGLYPH A267;Lo;0;L;;;;;N;;;;;
+1452E;ANATOLIAN HIEROGLYPH A267A;Lo;0;L;;;;;N;;;;;
+1452F;ANATOLIAN HIEROGLYPH A268;Lo;0;L;;;;;N;;;;;
+14530;ANATOLIAN HIEROGLYPH A269;Lo;0;L;;;;;N;;;;;
+14531;ANATOLIAN HIEROGLYPH A270;Lo;0;L;;;;;N;;;;;
+14532;ANATOLIAN HIEROGLYPH A271;Lo;0;L;;;;;N;;;;;
+14533;ANATOLIAN HIEROGLYPH A272;Lo;0;L;;;;;N;;;;;
+14534;ANATOLIAN HIEROGLYPH A273;Lo;0;L;;;;;N;;;;;
+14535;ANATOLIAN HIEROGLYPH A274;Lo;0;L;;;;;N;;;;;
+14536;ANATOLIAN HIEROGLYPH A275;Lo;0;L;;;;;N;;;;;
+14537;ANATOLIAN HIEROGLYPH A276;Lo;0;L;;;;;N;;;;;
+14538;ANATOLIAN HIEROGLYPH A277;Lo;0;L;;;;;N;;;;;
+14539;ANATOLIAN HIEROGLYPH A278;Lo;0;L;;;;;N;;;;;
+1453A;ANATOLIAN HIEROGLYPH A279;Lo;0;L;;;;;N;;;;;
+1453B;ANATOLIAN HIEROGLYPH A280;Lo;0;L;;;;;N;;;;;
+1453C;ANATOLIAN HIEROGLYPH A281;Lo;0;L;;;;;N;;;;;
+1453D;ANATOLIAN HIEROGLYPH A282;Lo;0;L;;;;;N;;;;;
+1453E;ANATOLIAN HIEROGLYPH A283;Lo;0;L;;;;;N;;;;;
+1453F;ANATOLIAN HIEROGLYPH A284;Lo;0;L;;;;;N;;;;;
+14540;ANATOLIAN HIEROGLYPH A285;Lo;0;L;;;;;N;;;;;
+14541;ANATOLIAN HIEROGLYPH A286;Lo;0;L;;;;;N;;;;;
+14542;ANATOLIAN HIEROGLYPH A287;Lo;0;L;;;;;N;;;;;
+14543;ANATOLIAN HIEROGLYPH A288;Lo;0;L;;;;;N;;;;;
+14544;ANATOLIAN HIEROGLYPH A289;Lo;0;L;;;;;N;;;;;
+14545;ANATOLIAN HIEROGLYPH A289A;Lo;0;L;;;;;N;;;;;
+14546;ANATOLIAN HIEROGLYPH A290;Lo;0;L;;;;;N;;;;;
+14547;ANATOLIAN HIEROGLYPH A291;Lo;0;L;;;;;N;;;;;
+14548;ANATOLIAN HIEROGLYPH A292;Lo;0;L;;;;;N;;;;;
+14549;ANATOLIAN HIEROGLYPH A293;Lo;0;L;;;;;N;;;;;
+1454A;ANATOLIAN HIEROGLYPH A294;Lo;0;L;;;;;N;;;;;
+1454B;ANATOLIAN HIEROGLYPH A294A;Lo;0;L;;;;;N;;;;;
+1454C;ANATOLIAN HIEROGLYPH A295;Lo;0;L;;;;;N;;;;;
+1454D;ANATOLIAN HIEROGLYPH A296;Lo;0;L;;;;;N;;;;;
+1454E;ANATOLIAN HIEROGLYPH A297;Lo;0;L;;;;;N;;;;;
+1454F;ANATOLIAN HIEROGLYPH A298;Lo;0;L;;;;;N;;;;;
+14550;ANATOLIAN HIEROGLYPH A299;Lo;0;L;;;;;N;;;;;
+14551;ANATOLIAN HIEROGLYPH A299A;Lo;0;L;;;;;N;;;;;
+14552;ANATOLIAN HIEROGLYPH A300;Lo;0;L;;;;;N;;;;;
+14553;ANATOLIAN HIEROGLYPH A301;Lo;0;L;;;;;N;;;;;
+14554;ANATOLIAN HIEROGLYPH A302;Lo;0;L;;;;;N;;;;;
+14555;ANATOLIAN HIEROGLYPH A303;Lo;0;L;;;;;N;;;;;
+14556;ANATOLIAN HIEROGLYPH A304;Lo;0;L;;;;;N;;;;;
+14557;ANATOLIAN HIEROGLYPH A305;Lo;0;L;;;;;N;;;;;
+14558;ANATOLIAN HIEROGLYPH A306;Lo;0;L;;;;;N;;;;;
+14559;ANATOLIAN HIEROGLYPH A307;Lo;0;L;;;;;N;;;;;
+1455A;ANATOLIAN HIEROGLYPH A308;Lo;0;L;;;;;N;;;;;
+1455B;ANATOLIAN HIEROGLYPH A309;Lo;0;L;;;;;N;;;;;
+1455C;ANATOLIAN HIEROGLYPH A309A;Lo;0;L;;;;;N;;;;;
+1455D;ANATOLIAN HIEROGLYPH A310;Lo;0;L;;;;;N;;;;;
+1455E;ANATOLIAN HIEROGLYPH A311;Lo;0;L;;;;;N;;;;;
+1455F;ANATOLIAN HIEROGLYPH A312;Lo;0;L;;;;;N;;;;;
+14560;ANATOLIAN HIEROGLYPH A313;Lo;0;L;;;;;N;;;;;
+14561;ANATOLIAN HIEROGLYPH A314;Lo;0;L;;;;;N;;;;;
+14562;ANATOLIAN HIEROGLYPH A315;Lo;0;L;;;;;N;;;;;
+14563;ANATOLIAN HIEROGLYPH A316;Lo;0;L;;;;;N;;;;;
+14564;ANATOLIAN HIEROGLYPH A317;Lo;0;L;;;;;N;;;;;
+14565;ANATOLIAN HIEROGLYPH A318;Lo;0;L;;;;;N;;;;;
+14566;ANATOLIAN HIEROGLYPH A319;Lo;0;L;;;;;N;;;;;
+14567;ANATOLIAN HIEROGLYPH A320;Lo;0;L;;;;;N;;;;;
+14568;ANATOLIAN HIEROGLYPH A321;Lo;0;L;;;;;N;;;;;
+14569;ANATOLIAN HIEROGLYPH A322;Lo;0;L;;;;;N;;;;;
+1456A;ANATOLIAN HIEROGLYPH A323;Lo;0;L;;;;;N;;;;;
+1456B;ANATOLIAN HIEROGLYPH A324;Lo;0;L;;;;;N;;;;;
+1456C;ANATOLIAN HIEROGLYPH A325;Lo;0;L;;;;;N;;;;;
+1456D;ANATOLIAN HIEROGLYPH A326;Lo;0;L;;;;;N;;;;;
+1456E;ANATOLIAN HIEROGLYPH A327;Lo;0;L;;;;;N;;;;;
+1456F;ANATOLIAN HIEROGLYPH A328;Lo;0;L;;;;;N;;;;;
+14570;ANATOLIAN HIEROGLYPH A329;Lo;0;L;;;;;N;;;;;
+14571;ANATOLIAN HIEROGLYPH A329A;Lo;0;L;;;;;N;;;;;
+14572;ANATOLIAN HIEROGLYPH A330;Lo;0;L;;;;;N;;;;;
+14573;ANATOLIAN HIEROGLYPH A331;Lo;0;L;;;;;N;;;;;
+14574;ANATOLIAN HIEROGLYPH A332A;Lo;0;L;;;;;N;;;;;
+14575;ANATOLIAN HIEROGLYPH A332B;Lo;0;L;;;;;N;;;;;
+14576;ANATOLIAN HIEROGLYPH A332C;Lo;0;L;;;;;N;;;;;
+14577;ANATOLIAN HIEROGLYPH A333;Lo;0;L;;;;;N;;;;;
+14578;ANATOLIAN HIEROGLYPH A334;Lo;0;L;;;;;N;;;;;
+14579;ANATOLIAN HIEROGLYPH A335;Lo;0;L;;;;;N;;;;;
+1457A;ANATOLIAN HIEROGLYPH A336;Lo;0;L;;;;;N;;;;;
+1457B;ANATOLIAN HIEROGLYPH A336A;Lo;0;L;;;;;N;;;;;
+1457C;ANATOLIAN HIEROGLYPH A336B;Lo;0;L;;;;;N;;;;;
+1457D;ANATOLIAN HIEROGLYPH A336C;Lo;0;L;;;;;N;;;;;
+1457E;ANATOLIAN HIEROGLYPH A337;Lo;0;L;;;;;N;;;;;
+1457F;ANATOLIAN HIEROGLYPH A338;Lo;0;L;;;;;N;;;;;
+14580;ANATOLIAN HIEROGLYPH A339;Lo;0;L;;;;;N;;;;;
+14581;ANATOLIAN HIEROGLYPH A340;Lo;0;L;;;;;N;;;;;
+14582;ANATOLIAN HIEROGLYPH A341;Lo;0;L;;;;;N;;;;;
+14583;ANATOLIAN HIEROGLYPH A342;Lo;0;L;;;;;N;;;;;
+14584;ANATOLIAN HIEROGLYPH A343;Lo;0;L;;;;;N;;;;;
+14585;ANATOLIAN HIEROGLYPH A344;Lo;0;L;;;;;N;;;;;
+14586;ANATOLIAN HIEROGLYPH A345;Lo;0;L;;;;;N;;;;;
+14587;ANATOLIAN HIEROGLYPH A346;Lo;0;L;;;;;N;;;;;
+14588;ANATOLIAN HIEROGLYPH A347;Lo;0;L;;;;;N;;;;;
+14589;ANATOLIAN HIEROGLYPH A348;Lo;0;L;;;;;N;;;;;
+1458A;ANATOLIAN HIEROGLYPH A349;Lo;0;L;;;;;N;;;;;
+1458B;ANATOLIAN HIEROGLYPH A350;Lo;0;L;;;;;N;;;;;
+1458C;ANATOLIAN HIEROGLYPH A351;Lo;0;L;;;;;N;;;;;
+1458D;ANATOLIAN HIEROGLYPH A352;Lo;0;L;;;;;N;;;;;
+1458E;ANATOLIAN HIEROGLYPH A353;Lo;0;L;;;;;N;;;;;
+1458F;ANATOLIAN HIEROGLYPH A354;Lo;0;L;;;;;N;;;;;
+14590;ANATOLIAN HIEROGLYPH A355;Lo;0;L;;;;;N;;;;;
+14591;ANATOLIAN HIEROGLYPH A356;Lo;0;L;;;;;N;;;;;
+14592;ANATOLIAN HIEROGLYPH A357;Lo;0;L;;;;;N;;;;;
+14593;ANATOLIAN HIEROGLYPH A358;Lo;0;L;;;;;N;;;;;
+14594;ANATOLIAN HIEROGLYPH A359;Lo;0;L;;;;;N;;;;;
+14595;ANATOLIAN HIEROGLYPH A359A;Lo;0;L;;;;;N;;;;;
+14596;ANATOLIAN HIEROGLYPH A360;Lo;0;L;;;;;N;;;;;
+14597;ANATOLIAN HIEROGLYPH A361;Lo;0;L;;;;;N;;;;;
+14598;ANATOLIAN HIEROGLYPH A362;Lo;0;L;;;;;N;;;;;
+14599;ANATOLIAN HIEROGLYPH A363;Lo;0;L;;;;;N;;;;;
+1459A;ANATOLIAN HIEROGLYPH A364;Lo;0;L;;;;;N;;;;;
+1459B;ANATOLIAN HIEROGLYPH A364A;Lo;0;L;;;;;N;;;;;
+1459C;ANATOLIAN HIEROGLYPH A365;Lo;0;L;;;;;N;;;;;
+1459D;ANATOLIAN HIEROGLYPH A366;Lo;0;L;;;;;N;;;;;
+1459E;ANATOLIAN HIEROGLYPH A367;Lo;0;L;;;;;N;;;;;
+1459F;ANATOLIAN HIEROGLYPH A368;Lo;0;L;;;;;N;;;;;
+145A0;ANATOLIAN HIEROGLYPH A368A;Lo;0;L;;;;;N;;;;;
+145A1;ANATOLIAN HIEROGLYPH A369;Lo;0;L;;;;;N;;;;;
+145A2;ANATOLIAN HIEROGLYPH A370;Lo;0;L;;;;;N;;;;;
+145A3;ANATOLIAN HIEROGLYPH A371;Lo;0;L;;;;;N;;;;;
+145A4;ANATOLIAN HIEROGLYPH A371A;Lo;0;L;;;;;N;;;;;
+145A5;ANATOLIAN HIEROGLYPH A372;Lo;0;L;;;;;N;;;;;
+145A6;ANATOLIAN HIEROGLYPH A373;Lo;0;L;;;;;N;;;;;
+145A7;ANATOLIAN HIEROGLYPH A374;Lo;0;L;;;;;N;;;;;
+145A8;ANATOLIAN HIEROGLYPH A375;Lo;0;L;;;;;N;;;;;
+145A9;ANATOLIAN HIEROGLYPH A376;Lo;0;L;;;;;N;;;;;
+145AA;ANATOLIAN HIEROGLYPH A377;Lo;0;L;;;;;N;;;;;
+145AB;ANATOLIAN HIEROGLYPH A378;Lo;0;L;;;;;N;;;;;
+145AC;ANATOLIAN HIEROGLYPH A379;Lo;0;L;;;;;N;;;;;
+145AD;ANATOLIAN HIEROGLYPH A380;Lo;0;L;;;;;N;;;;;
+145AE;ANATOLIAN HIEROGLYPH A381;Lo;0;L;;;;;N;;;;;
+145AF;ANATOLIAN HIEROGLYPH A381A;Lo;0;L;;;;;N;;;;;
+145B0;ANATOLIAN HIEROGLYPH A382;Lo;0;L;;;;;N;;;;;
+145B1;ANATOLIAN HIEROGLYPH A383 RA OR RI;Lo;0;L;;;;;N;;;;;
+145B2;ANATOLIAN HIEROGLYPH A383A;Lo;0;L;;;;;N;;;;;
+145B3;ANATOLIAN HIEROGLYPH A384;Lo;0;L;;;;;N;;;;;
+145B4;ANATOLIAN HIEROGLYPH A385;Lo;0;L;;;;;N;;;;;
+145B5;ANATOLIAN HIEROGLYPH A386;Lo;0;L;;;;;N;;;;;
+145B6;ANATOLIAN HIEROGLYPH A386A;Lo;0;L;;;;;N;;;;;
+145B7;ANATOLIAN HIEROGLYPH A387;Lo;0;L;;;;;N;;;;;
+145B8;ANATOLIAN HIEROGLYPH A388;Lo;0;L;;;;;N;;;;;
+145B9;ANATOLIAN HIEROGLYPH A389;Lo;0;L;;;;;N;;;;;
+145BA;ANATOLIAN HIEROGLYPH A390;Lo;0;L;;;;;N;;;;;
+145BB;ANATOLIAN HIEROGLYPH A391;Lo;0;L;;;;;N;;;;;
+145BC;ANATOLIAN HIEROGLYPH A392;Lo;0;L;;;;;N;;;;;
+145BD;ANATOLIAN HIEROGLYPH A393 EIGHT;Lo;0;L;;;;;N;;;;;
+145BE;ANATOLIAN HIEROGLYPH A394;Lo;0;L;;;;;N;;;;;
+145BF;ANATOLIAN HIEROGLYPH A395;Lo;0;L;;;;;N;;;;;
+145C0;ANATOLIAN HIEROGLYPH A396;Lo;0;L;;;;;N;;;;;
+145C1;ANATOLIAN HIEROGLYPH A397;Lo;0;L;;;;;N;;;;;
+145C2;ANATOLIAN HIEROGLYPH A398;Lo;0;L;;;;;N;;;;;
+145C3;ANATOLIAN HIEROGLYPH A399;Lo;0;L;;;;;N;;;;;
+145C4;ANATOLIAN HIEROGLYPH A400;Lo;0;L;;;;;N;;;;;
+145C5;ANATOLIAN HIEROGLYPH A401;Lo;0;L;;;;;N;;;;;
+145C6;ANATOLIAN HIEROGLYPH A402;Lo;0;L;;;;;N;;;;;
+145C7;ANATOLIAN HIEROGLYPH A403;Lo;0;L;;;;;N;;;;;
+145C8;ANATOLIAN HIEROGLYPH A404;Lo;0;L;;;;;N;;;;;
+145C9;ANATOLIAN HIEROGLYPH A405;Lo;0;L;;;;;N;;;;;
+145CA;ANATOLIAN HIEROGLYPH A406;Lo;0;L;;;;;N;;;;;
+145CB;ANATOLIAN HIEROGLYPH A407;Lo;0;L;;;;;N;;;;;
+145CC;ANATOLIAN HIEROGLYPH A408;Lo;0;L;;;;;N;;;;;
+145CD;ANATOLIAN HIEROGLYPH A409;Lo;0;L;;;;;N;;;;;
+145CE;ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK;Lo;0;L;;;;;N;;;;;
+145CF;ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK;Lo;0;L;;;;;N;;;;;
+145D0;ANATOLIAN HIEROGLYPH A411;Lo;0;L;;;;;N;;;;;
+145D1;ANATOLIAN HIEROGLYPH A412;Lo;0;L;;;;;N;;;;;
+145D2;ANATOLIAN HIEROGLYPH A413;Lo;0;L;;;;;N;;;;;
+145D3;ANATOLIAN HIEROGLYPH A414;Lo;0;L;;;;;N;;;;;
+145D4;ANATOLIAN HIEROGLYPH A415;Lo;0;L;;;;;N;;;;;
+145D5;ANATOLIAN HIEROGLYPH A416;Lo;0;L;;;;;N;;;;;
+145D6;ANATOLIAN HIEROGLYPH A417;Lo;0;L;;;;;N;;;;;
+145D7;ANATOLIAN HIEROGLYPH A418;Lo;0;L;;;;;N;;;;;
+145D8;ANATOLIAN HIEROGLYPH A419;Lo;0;L;;;;;N;;;;;
+145D9;ANATOLIAN HIEROGLYPH A420;Lo;0;L;;;;;N;;;;;
+145DA;ANATOLIAN HIEROGLYPH A421;Lo;0;L;;;;;N;;;;;
+145DB;ANATOLIAN HIEROGLYPH A422;Lo;0;L;;;;;N;;;;;
+145DC;ANATOLIAN HIEROGLYPH A423;Lo;0;L;;;;;N;;;;;
+145DD;ANATOLIAN HIEROGLYPH A424;Lo;0;L;;;;;N;;;;;
+145DE;ANATOLIAN HIEROGLYPH A425;Lo;0;L;;;;;N;;;;;
+145DF;ANATOLIAN HIEROGLYPH A426;Lo;0;L;;;;;N;;;;;
+145E0;ANATOLIAN HIEROGLYPH A427;Lo;0;L;;;;;N;;;;;
+145E1;ANATOLIAN HIEROGLYPH A428;Lo;0;L;;;;;N;;;;;
+145E2;ANATOLIAN HIEROGLYPH A429;Lo;0;L;;;;;N;;;;;
+145E3;ANATOLIAN HIEROGLYPH A430;Lo;0;L;;;;;N;;;;;
+145E4;ANATOLIAN HIEROGLYPH A431;Lo;0;L;;;;;N;;;;;
+145E5;ANATOLIAN HIEROGLYPH A432;Lo;0;L;;;;;N;;;;;
+145E6;ANATOLIAN HIEROGLYPH A433;Lo;0;L;;;;;N;;;;;
+145E7;ANATOLIAN HIEROGLYPH A434;Lo;0;L;;;;;N;;;;;
+145E8;ANATOLIAN HIEROGLYPH A435;Lo;0;L;;;;;N;;;;;
+145E9;ANATOLIAN HIEROGLYPH A436;Lo;0;L;;;;;N;;;;;
+145EA;ANATOLIAN HIEROGLYPH A437;Lo;0;L;;;;;N;;;;;
+145EB;ANATOLIAN HIEROGLYPH A438;Lo;0;L;;;;;N;;;;;
+145EC;ANATOLIAN HIEROGLYPH A439;Lo;0;L;;;;;N;;;;;
+145ED;ANATOLIAN HIEROGLYPH A440;Lo;0;L;;;;;N;;;;;
+145EE;ANATOLIAN HIEROGLYPH A441;Lo;0;L;;;;;N;;;;;
+145EF;ANATOLIAN HIEROGLYPH A442;Lo;0;L;;;;;N;;;;;
+145F0;ANATOLIAN HIEROGLYPH A443;Lo;0;L;;;;;N;;;;;
+145F1;ANATOLIAN HIEROGLYPH A444;Lo;0;L;;;;;N;;;;;
+145F2;ANATOLIAN HIEROGLYPH A445;Lo;0;L;;;;;N;;;;;
+145F3;ANATOLIAN HIEROGLYPH A446;Lo;0;L;;;;;N;;;;;
+145F4;ANATOLIAN HIEROGLYPH A447;Lo;0;L;;;;;N;;;;;
+145F5;ANATOLIAN HIEROGLYPH A448;Lo;0;L;;;;;N;;;;;
+145F6;ANATOLIAN HIEROGLYPH A449;Lo;0;L;;;;;N;;;;;
+145F7;ANATOLIAN HIEROGLYPH A450;Lo;0;L;;;;;N;;;;;
+145F8;ANATOLIAN HIEROGLYPH A450A;Lo;0;L;;;;;N;;;;;
+145F9;ANATOLIAN HIEROGLYPH A451;Lo;0;L;;;;;N;;;;;
+145FA;ANATOLIAN HIEROGLYPH A452;Lo;0;L;;;;;N;;;;;
+145FB;ANATOLIAN HIEROGLYPH A453;Lo;0;L;;;;;N;;;;;
+145FC;ANATOLIAN HIEROGLYPH A454;Lo;0;L;;;;;N;;;;;
+145FD;ANATOLIAN HIEROGLYPH A455;Lo;0;L;;;;;N;;;;;
+145FE;ANATOLIAN HIEROGLYPH A456;Lo;0;L;;;;;N;;;;;
+145FF;ANATOLIAN HIEROGLYPH A457;Lo;0;L;;;;;N;;;;;
+14600;ANATOLIAN HIEROGLYPH A457A;Lo;0;L;;;;;N;;;;;
+14601;ANATOLIAN HIEROGLYPH A458;Lo;0;L;;;;;N;;;;;
+14602;ANATOLIAN HIEROGLYPH A459;Lo;0;L;;;;;N;;;;;
+14603;ANATOLIAN HIEROGLYPH A460;Lo;0;L;;;;;N;;;;;
+14604;ANATOLIAN HIEROGLYPH A461;Lo;0;L;;;;;N;;;;;
+14605;ANATOLIAN HIEROGLYPH A462;Lo;0;L;;;;;N;;;;;
+14606;ANATOLIAN HIEROGLYPH A463;Lo;0;L;;;;;N;;;;;
+14607;ANATOLIAN HIEROGLYPH A464;Lo;0;L;;;;;N;;;;;
+14608;ANATOLIAN HIEROGLYPH A465;Lo;0;L;;;;;N;;;;;
+14609;ANATOLIAN HIEROGLYPH A466;Lo;0;L;;;;;N;;;;;
+1460A;ANATOLIAN HIEROGLYPH A467;Lo;0;L;;;;;N;;;;;
+1460B;ANATOLIAN HIEROGLYPH A468;Lo;0;L;;;;;N;;;;;
+1460C;ANATOLIAN HIEROGLYPH A469;Lo;0;L;;;;;N;;;;;
+1460D;ANATOLIAN HIEROGLYPH A470;Lo;0;L;;;;;N;;;;;
+1460E;ANATOLIAN HIEROGLYPH A471;Lo;0;L;;;;;N;;;;;
+1460F;ANATOLIAN HIEROGLYPH A472;Lo;0;L;;;;;N;;;;;
+14610;ANATOLIAN HIEROGLYPH A473;Lo;0;L;;;;;N;;;;;
+14611;ANATOLIAN HIEROGLYPH A474;Lo;0;L;;;;;N;;;;;
+14612;ANATOLIAN HIEROGLYPH A475;Lo;0;L;;;;;N;;;;;
+14613;ANATOLIAN HIEROGLYPH A476;Lo;0;L;;;;;N;;;;;
+14614;ANATOLIAN HIEROGLYPH A477;Lo;0;L;;;;;N;;;;;
+14615;ANATOLIAN HIEROGLYPH A478;Lo;0;L;;;;;N;;;;;
+14616;ANATOLIAN HIEROGLYPH A479;Lo;0;L;;;;;N;;;;;
+14617;ANATOLIAN HIEROGLYPH A480;Lo;0;L;;;;;N;;;;;
+14618;ANATOLIAN HIEROGLYPH A481;Lo;0;L;;;;;N;;;;;
+14619;ANATOLIAN HIEROGLYPH A482;Lo;0;L;;;;;N;;;;;
+1461A;ANATOLIAN HIEROGLYPH A483;Lo;0;L;;;;;N;;;;;
+1461B;ANATOLIAN HIEROGLYPH A484;Lo;0;L;;;;;N;;;;;
+1461C;ANATOLIAN HIEROGLYPH A485;Lo;0;L;;;;;N;;;;;
+1461D;ANATOLIAN HIEROGLYPH A486;Lo;0;L;;;;;N;;;;;
+1461E;ANATOLIAN HIEROGLYPH A487;Lo;0;L;;;;;N;;;;;
+1461F;ANATOLIAN HIEROGLYPH A488;Lo;0;L;;;;;N;;;;;
+14620;ANATOLIAN HIEROGLYPH A489;Lo;0;L;;;;;N;;;;;
+14621;ANATOLIAN HIEROGLYPH A490;Lo;0;L;;;;;N;;;;;
+14622;ANATOLIAN HIEROGLYPH A491;Lo;0;L;;;;;N;;;;;
+14623;ANATOLIAN HIEROGLYPH A492;Lo;0;L;;;;;N;;;;;
+14624;ANATOLIAN HIEROGLYPH A493;Lo;0;L;;;;;N;;;;;
+14625;ANATOLIAN HIEROGLYPH A494;Lo;0;L;;;;;N;;;;;
+14626;ANATOLIAN HIEROGLYPH A495;Lo;0;L;;;;;N;;;;;
+14627;ANATOLIAN HIEROGLYPH A496;Lo;0;L;;;;;N;;;;;
+14628;ANATOLIAN HIEROGLYPH A497;Lo;0;L;;;;;N;;;;;
+14629;ANATOLIAN HIEROGLYPH A501;Lo;0;L;;;;;N;;;;;
+1462A;ANATOLIAN HIEROGLYPH A502;Lo;0;L;;;;;N;;;;;
+1462B;ANATOLIAN HIEROGLYPH A503;Lo;0;L;;;;;N;;;;;
+1462C;ANATOLIAN HIEROGLYPH A504;Lo;0;L;;;;;N;;;;;
+1462D;ANATOLIAN HIEROGLYPH A505;Lo;0;L;;;;;N;;;;;
+1462E;ANATOLIAN HIEROGLYPH A506;Lo;0;L;;;;;N;;;;;
+1462F;ANATOLIAN HIEROGLYPH A507;Lo;0;L;;;;;N;;;;;
+14630;ANATOLIAN HIEROGLYPH A508;Lo;0;L;;;;;N;;;;;
+14631;ANATOLIAN HIEROGLYPH A509;Lo;0;L;;;;;N;;;;;
+14632;ANATOLIAN HIEROGLYPH A510;Lo;0;L;;;;;N;;;;;
+14633;ANATOLIAN HIEROGLYPH A511;Lo;0;L;;;;;N;;;;;
+14634;ANATOLIAN HIEROGLYPH A512;Lo;0;L;;;;;N;;;;;
+14635;ANATOLIAN HIEROGLYPH A513;Lo;0;L;;;;;N;;;;;
+14636;ANATOLIAN HIEROGLYPH A514;Lo;0;L;;;;;N;;;;;
+14637;ANATOLIAN HIEROGLYPH A515;Lo;0;L;;;;;N;;;;;
+14638;ANATOLIAN HIEROGLYPH A516;Lo;0;L;;;;;N;;;;;
+14639;ANATOLIAN HIEROGLYPH A517;Lo;0;L;;;;;N;;;;;
+1463A;ANATOLIAN HIEROGLYPH A518;Lo;0;L;;;;;N;;;;;
+1463B;ANATOLIAN HIEROGLYPH A519;Lo;0;L;;;;;N;;;;;
+1463C;ANATOLIAN HIEROGLYPH A520;Lo;0;L;;;;;N;;;;;
+1463D;ANATOLIAN HIEROGLYPH A521;Lo;0;L;;;;;N;;;;;
+1463E;ANATOLIAN HIEROGLYPH A522;Lo;0;L;;;;;N;;;;;
+1463F;ANATOLIAN HIEROGLYPH A523;Lo;0;L;;;;;N;;;;;
+14640;ANATOLIAN HIEROGLYPH A524;Lo;0;L;;;;;N;;;;;
+14641;ANATOLIAN HIEROGLYPH A525;Lo;0;L;;;;;N;;;;;
+14642;ANATOLIAN HIEROGLYPH A526;Lo;0;L;;;;;N;;;;;
+14643;ANATOLIAN HIEROGLYPH A527;Lo;0;L;;;;;N;;;;;
+14644;ANATOLIAN HIEROGLYPH A528;Lo;0;L;;;;;N;;;;;
+14645;ANATOLIAN HIEROGLYPH A529;Lo;0;L;;;;;N;;;;;
+14646;ANATOLIAN HIEROGLYPH A530;Lo;0;L;;;;;N;;;;;
+16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;;
+16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;;
+16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;;
+16803;BAMUM LETTER PHASE-A PON MFON PIPAEMBA;Lo;0;L;;;;;N;;;;;
+16804;BAMUM LETTER PHASE-A NAA MFON;Lo;0;L;;;;;N;;;;;
+16805;BAMUM LETTER PHASE-A SHUENSHUET;Lo;0;L;;;;;N;;;;;
+16806;BAMUM LETTER PHASE-A TITA MFON;Lo;0;L;;;;;N;;;;;
+16807;BAMUM LETTER PHASE-A NZA MFON;Lo;0;L;;;;;N;;;;;
+16808;BAMUM LETTER PHASE-A SHINDA PA NJI;Lo;0;L;;;;;N;;;;;
+16809;BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE;Lo;0;L;;;;;N;;;;;
+1680A;BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA;Lo;0;L;;;;;N;;;;;
+1680B;BAMUM LETTER PHASE-A MAEMBGBIEE;Lo;0;L;;;;;N;;;;;
+1680C;BAMUM LETTER PHASE-A TU MAEMBA;Lo;0;L;;;;;N;;;;;
+1680D;BAMUM LETTER PHASE-A NGANGU;Lo;0;L;;;;;N;;;;;
+1680E;BAMUM LETTER PHASE-A MAEMVEUX;Lo;0;L;;;;;N;;;;;
+1680F;BAMUM LETTER PHASE-A MANSUAE;Lo;0;L;;;;;N;;;;;
+16810;BAMUM LETTER PHASE-A MVEUAENGAM;Lo;0;L;;;;;N;;;;;
+16811;BAMUM LETTER PHASE-A SEUNYAM;Lo;0;L;;;;;N;;;;;
+16812;BAMUM LETTER PHASE-A NTOQPEN;Lo;0;L;;;;;N;;;;;
+16813;BAMUM LETTER PHASE-A KEUKEUTNDA;Lo;0;L;;;;;N;;;;;
+16814;BAMUM LETTER PHASE-A NKINDI;Lo;0;L;;;;;N;;;;;
+16815;BAMUM LETTER PHASE-A SUU;Lo;0;L;;;;;N;;;;;
+16816;BAMUM LETTER PHASE-A NGKUENZEUM;Lo;0;L;;;;;N;;;;;
+16817;BAMUM LETTER PHASE-A LAPAQ;Lo;0;L;;;;;N;;;;;
+16818;BAMUM LETTER PHASE-A LET KUT;Lo;0;L;;;;;N;;;;;
+16819;BAMUM LETTER PHASE-A NTAP MFAA;Lo;0;L;;;;;N;;;;;
+1681A;BAMUM LETTER PHASE-A MAEKEUP;Lo;0;L;;;;;N;;;;;
+1681B;BAMUM LETTER PHASE-A PASHAE;Lo;0;L;;;;;N;;;;;
+1681C;BAMUM LETTER PHASE-A GHEUAERAE;Lo;0;L;;;;;N;;;;;
+1681D;BAMUM LETTER PHASE-A PAMSHAE;Lo;0;L;;;;;N;;;;;
+1681E;BAMUM LETTER PHASE-A MON NGGEUAET;Lo;0;L;;;;;N;;;;;
+1681F;BAMUM LETTER PHASE-A NZUN MEUT;Lo;0;L;;;;;N;;;;;
+16820;BAMUM LETTER PHASE-A U YUQ NAE;Lo;0;L;;;;;N;;;;;
+16821;BAMUM LETTER PHASE-A GHEUAEGHEUAE;Lo;0;L;;;;;N;;;;;
+16822;BAMUM LETTER PHASE-A NTAP NTAA;Lo;0;L;;;;;N;;;;;
+16823;BAMUM LETTER PHASE-A SISA;Lo;0;L;;;;;N;;;;;
+16824;BAMUM LETTER PHASE-A MGBASA;Lo;0;L;;;;;N;;;;;
+16825;BAMUM LETTER PHASE-A MEUNJOMNDEUQ;Lo;0;L;;;;;N;;;;;
+16826;BAMUM LETTER PHASE-A MOOMPUQ;Lo;0;L;;;;;N;;;;;
+16827;BAMUM LETTER PHASE-A KAFA;Lo;0;L;;;;;N;;;;;
+16828;BAMUM LETTER PHASE-A PA LEERAEWA;Lo;0;L;;;;;N;;;;;
+16829;BAMUM LETTER PHASE-A NDA LEERAEWA;Lo;0;L;;;;;N;;;;;
+1682A;BAMUM LETTER PHASE-A PET;Lo;0;L;;;;;N;;;;;
+1682B;BAMUM LETTER PHASE-A MAEMKPEN;Lo;0;L;;;;;N;;;;;
+1682C;BAMUM LETTER PHASE-A NIKA;Lo;0;L;;;;;N;;;;;
+1682D;BAMUM LETTER PHASE-A PUP;Lo;0;L;;;;;N;;;;;
+1682E;BAMUM LETTER PHASE-A TUAEP;Lo;0;L;;;;;N;;;;;
+1682F;BAMUM LETTER PHASE-A LUAEP;Lo;0;L;;;;;N;;;;;
+16830;BAMUM LETTER PHASE-A SONJAM;Lo;0;L;;;;;N;;;;;
+16831;BAMUM LETTER PHASE-A TEUTEUWEN;Lo;0;L;;;;;N;;;;;
+16832;BAMUM LETTER PHASE-A MAENYI;Lo;0;L;;;;;N;;;;;
+16833;BAMUM LETTER PHASE-A KET;Lo;0;L;;;;;N;;;;;
+16834;BAMUM LETTER PHASE-A NDAANGGEUAET;Lo;0;L;;;;;N;;;;;
+16835;BAMUM LETTER PHASE-A KUOQ;Lo;0;L;;;;;N;;;;;
+16836;BAMUM LETTER PHASE-A MOOMEUT;Lo;0;L;;;;;N;;;;;
+16837;BAMUM LETTER PHASE-A SHUM;Lo;0;L;;;;;N;;;;;
+16838;BAMUM LETTER PHASE-A LOMMAE;Lo;0;L;;;;;N;;;;;
+16839;BAMUM LETTER PHASE-A FIRI;Lo;0;L;;;;;N;;;;;
+1683A;BAMUM LETTER PHASE-A ROM;Lo;0;L;;;;;N;;;;;
+1683B;BAMUM LETTER PHASE-A KPOQ;Lo;0;L;;;;;N;;;;;
+1683C;BAMUM LETTER PHASE-A SOQ;Lo;0;L;;;;;N;;;;;
+1683D;BAMUM LETTER PHASE-A MAP PIEET;Lo;0;L;;;;;N;;;;;
+1683E;BAMUM LETTER PHASE-A SHIRAE;Lo;0;L;;;;;N;;;;;
+1683F;BAMUM LETTER PHASE-A NTAP;Lo;0;L;;;;;N;;;;;
+16840;BAMUM LETTER PHASE-A SHOQ NSHUT YUM;Lo;0;L;;;;;N;;;;;
+16841;BAMUM LETTER PHASE-A NYIT MONGKEUAEQ;Lo;0;L;;;;;N;;;;;
+16842;BAMUM LETTER PHASE-A PAARAE;Lo;0;L;;;;;N;;;;;
+16843;BAMUM LETTER PHASE-A NKAARAE;Lo;0;L;;;;;N;;;;;
+16844;BAMUM LETTER PHASE-A UNKNOWN;Lo;0;L;;;;;N;;;;;
+16845;BAMUM LETTER PHASE-A NGGEN;Lo;0;L;;;;;N;;;;;
+16846;BAMUM LETTER PHASE-A MAESI;Lo;0;L;;;;;N;;;;;
+16847;BAMUM LETTER PHASE-A NJAM;Lo;0;L;;;;;N;;;;;
+16848;BAMUM LETTER PHASE-A MBANYI;Lo;0;L;;;;;N;;;;;
+16849;BAMUM LETTER PHASE-A NYET;Lo;0;L;;;;;N;;;;;
+1684A;BAMUM LETTER PHASE-A TEUAEN;Lo;0;L;;;;;N;;;;;
+1684B;BAMUM LETTER PHASE-A SOT;Lo;0;L;;;;;N;;;;;
+1684C;BAMUM LETTER PHASE-A PAAM;Lo;0;L;;;;;N;;;;;
+1684D;BAMUM LETTER PHASE-A NSHIEE;Lo;0;L;;;;;N;;;;;
+1684E;BAMUM LETTER PHASE-A MAEM;Lo;0;L;;;;;N;;;;;
+1684F;BAMUM LETTER PHASE-A NYI;Lo;0;L;;;;;N;;;;;
+16850;BAMUM LETTER PHASE-A KAQ;Lo;0;L;;;;;N;;;;;
+16851;BAMUM LETTER PHASE-A NSHA;Lo;0;L;;;;;N;;;;;
+16852;BAMUM LETTER PHASE-A VEE;Lo;0;L;;;;;N;;;;;
+16853;BAMUM LETTER PHASE-A LU;Lo;0;L;;;;;N;;;;;
+16854;BAMUM LETTER PHASE-A NEN;Lo;0;L;;;;;N;;;;;
+16855;BAMUM LETTER PHASE-A NAQ;Lo;0;L;;;;;N;;;;;
+16856;BAMUM LETTER PHASE-A MBAQ;Lo;0;L;;;;;N;;;;;
+16857;BAMUM LETTER PHASE-B NSHUET;Lo;0;L;;;;;N;;;;;
+16858;BAMUM LETTER PHASE-B TU MAEMGBIEE;Lo;0;L;;;;;N;;;;;
+16859;BAMUM LETTER PHASE-B SIEE;Lo;0;L;;;;;N;;;;;
+1685A;BAMUM LETTER PHASE-B SET TU;Lo;0;L;;;;;N;;;;;
+1685B;BAMUM LETTER PHASE-B LOM NTEUM;Lo;0;L;;;;;N;;;;;
+1685C;BAMUM LETTER PHASE-B MBA MAELEE;Lo;0;L;;;;;N;;;;;
+1685D;BAMUM LETTER PHASE-B KIEEM;Lo;0;L;;;;;N;;;;;
+1685E;BAMUM LETTER PHASE-B YEURAE;Lo;0;L;;;;;N;;;;;
+1685F;BAMUM LETTER PHASE-B MBAARAE;Lo;0;L;;;;;N;;;;;
+16860;BAMUM LETTER PHASE-B KAM;Lo;0;L;;;;;N;;;;;
+16861;BAMUM LETTER PHASE-B PEESHI;Lo;0;L;;;;;N;;;;;
+16862;BAMUM LETTER PHASE-B YAFU LEERAEWA;Lo;0;L;;;;;N;;;;;
+16863;BAMUM LETTER PHASE-B LAM NSHUT NYAM;Lo;0;L;;;;;N;;;;;
+16864;BAMUM LETTER PHASE-B NTIEE SHEUOQ;Lo;0;L;;;;;N;;;;;
+16865;BAMUM LETTER PHASE-B NDU NJAA;Lo;0;L;;;;;N;;;;;
+16866;BAMUM LETTER PHASE-B GHEUGHEUAEM;Lo;0;L;;;;;N;;;;;
+16867;BAMUM LETTER PHASE-B PIT;Lo;0;L;;;;;N;;;;;
+16868;BAMUM LETTER PHASE-B TU NSIEE;Lo;0;L;;;;;N;;;;;
+16869;BAMUM LETTER PHASE-B SHET NJAQ;Lo;0;L;;;;;N;;;;;
+1686A;BAMUM LETTER PHASE-B SHEUAEQTU;Lo;0;L;;;;;N;;;;;
+1686B;BAMUM LETTER PHASE-B MFON TEUAEQ;Lo;0;L;;;;;N;;;;;
+1686C;BAMUM LETTER PHASE-B MBIT MBAAKET;Lo;0;L;;;;;N;;;;;
+1686D;BAMUM LETTER PHASE-B NYI NTEUM;Lo;0;L;;;;;N;;;;;
+1686E;BAMUM LETTER PHASE-B KEUPUQ;Lo;0;L;;;;;N;;;;;
+1686F;BAMUM LETTER PHASE-B GHEUGHEN;Lo;0;L;;;;;N;;;;;
+16870;BAMUM LETTER PHASE-B KEUYEUX;Lo;0;L;;;;;N;;;;;
+16871;BAMUM LETTER PHASE-B LAANAE;Lo;0;L;;;;;N;;;;;
+16872;BAMUM LETTER PHASE-B PARUM;Lo;0;L;;;;;N;;;;;
+16873;BAMUM LETTER PHASE-B VEUM;Lo;0;L;;;;;N;;;;;
+16874;BAMUM LETTER PHASE-B NGKINDI MVOP;Lo;0;L;;;;;N;;;;;
+16875;BAMUM LETTER PHASE-B NGGEU MBU;Lo;0;L;;;;;N;;;;;
+16876;BAMUM LETTER PHASE-B WUAET;Lo;0;L;;;;;N;;;;;
+16877;BAMUM LETTER PHASE-B SAKEUAE;Lo;0;L;;;;;N;;;;;
+16878;BAMUM LETTER PHASE-B TAAM;Lo;0;L;;;;;N;;;;;
+16879;BAMUM LETTER PHASE-B MEUQ;Lo;0;L;;;;;N;;;;;
+1687A;BAMUM LETTER PHASE-B NGGUOQ;Lo;0;L;;;;;N;;;;;
+1687B;BAMUM LETTER PHASE-B NGGUOQ LARGE;Lo;0;L;;;;;N;;;;;
+1687C;BAMUM LETTER PHASE-B MFIYAQ;Lo;0;L;;;;;N;;;;;
+1687D;BAMUM LETTER PHASE-B SUE;Lo;0;L;;;;;N;;;;;
+1687E;BAMUM LETTER PHASE-B MBEURI;Lo;0;L;;;;;N;;;;;
+1687F;BAMUM LETTER PHASE-B MONTIEEN;Lo;0;L;;;;;N;;;;;
+16880;BAMUM LETTER PHASE-B NYAEMAE;Lo;0;L;;;;;N;;;;;
+16881;BAMUM LETTER PHASE-B PUNGAAM;Lo;0;L;;;;;N;;;;;
+16882;BAMUM LETTER PHASE-B MEUT NGGEET;Lo;0;L;;;;;N;;;;;
+16883;BAMUM LETTER PHASE-B FEUX;Lo;0;L;;;;;N;;;;;
+16884;BAMUM LETTER PHASE-B MBUOQ;Lo;0;L;;;;;N;;;;;
+16885;BAMUM LETTER PHASE-B FEE;Lo;0;L;;;;;N;;;;;
+16886;BAMUM LETTER PHASE-B KEUAEM;Lo;0;L;;;;;N;;;;;
+16887;BAMUM LETTER PHASE-B MA NJEUAENA;Lo;0;L;;;;;N;;;;;
+16888;BAMUM LETTER PHASE-B MA NJUQA;Lo;0;L;;;;;N;;;;;
+16889;BAMUM LETTER PHASE-B LET;Lo;0;L;;;;;N;;;;;
+1688A;BAMUM LETTER PHASE-B NGGAAM;Lo;0;L;;;;;N;;;;;
+1688B;BAMUM LETTER PHASE-B NSEN;Lo;0;L;;;;;N;;;;;
+1688C;BAMUM LETTER PHASE-B MA;Lo;0;L;;;;;N;;;;;
+1688D;BAMUM LETTER PHASE-B KIQ;Lo;0;L;;;;;N;;;;;
+1688E;BAMUM LETTER PHASE-B NGOM;Lo;0;L;;;;;N;;;;;
+1688F;BAMUM LETTER PHASE-C NGKUE MAEMBA;Lo;0;L;;;;;N;;;;;
+16890;BAMUM LETTER PHASE-C NZA;Lo;0;L;;;;;N;;;;;
+16891;BAMUM LETTER PHASE-C YUM;Lo;0;L;;;;;N;;;;;
+16892;BAMUM LETTER PHASE-C WANGKUOQ;Lo;0;L;;;;;N;;;;;
+16893;BAMUM LETTER PHASE-C NGGEN;Lo;0;L;;;;;N;;;;;
+16894;BAMUM LETTER PHASE-C NDEUAEREE;Lo;0;L;;;;;N;;;;;
+16895;BAMUM LETTER PHASE-C NGKAQ;Lo;0;L;;;;;N;;;;;
+16896;BAMUM LETTER PHASE-C GHARAE;Lo;0;L;;;;;N;;;;;
+16897;BAMUM LETTER PHASE-C MBEEKEET;Lo;0;L;;;;;N;;;;;
+16898;BAMUM LETTER PHASE-C GBAYI;Lo;0;L;;;;;N;;;;;
+16899;BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN;Lo;0;L;;;;;N;;;;;
+1689A;BAMUM LETTER PHASE-C NTU MBIT;Lo;0;L;;;;;N;;;;;
+1689B;BAMUM LETTER PHASE-C MBEUM;Lo;0;L;;;;;N;;;;;
+1689C;BAMUM LETTER PHASE-C PIRIEEN;Lo;0;L;;;;;N;;;;;
+1689D;BAMUM LETTER PHASE-C NDOMBU;Lo;0;L;;;;;N;;;;;
+1689E;BAMUM LETTER PHASE-C MBAA CABBAGE-TREE;Lo;0;L;;;;;N;;;;;
+1689F;BAMUM LETTER PHASE-C KEUSHEUAEP;Lo;0;L;;;;;N;;;;;
+168A0;BAMUM LETTER PHASE-C GHAP;Lo;0;L;;;;;N;;;;;
+168A1;BAMUM LETTER PHASE-C KEUKAQ;Lo;0;L;;;;;N;;;;;
+168A2;BAMUM LETTER PHASE-C YU MUOMAE;Lo;0;L;;;;;N;;;;;
+168A3;BAMUM LETTER PHASE-C NZEUM;Lo;0;L;;;;;N;;;;;
+168A4;BAMUM LETTER PHASE-C MBUE;Lo;0;L;;;;;N;;;;;
+168A5;BAMUM LETTER PHASE-C NSEUAEN;Lo;0;L;;;;;N;;;;;
+168A6;BAMUM LETTER PHASE-C MBIT;Lo;0;L;;;;;N;;;;;
+168A7;BAMUM LETTER PHASE-C YEUQ;Lo;0;L;;;;;N;;;;;
+168A8;BAMUM LETTER PHASE-C KPARAQ;Lo;0;L;;;;;N;;;;;
+168A9;BAMUM LETTER PHASE-C KAA;Lo;0;L;;;;;N;;;;;
+168AA;BAMUM LETTER PHASE-C SEUX;Lo;0;L;;;;;N;;;;;
+168AB;BAMUM LETTER PHASE-C NDIDA;Lo;0;L;;;;;N;;;;;
+168AC;BAMUM LETTER PHASE-C TAASHAE;Lo;0;L;;;;;N;;;;;
+168AD;BAMUM LETTER PHASE-C NJUEQ;Lo;0;L;;;;;N;;;;;
+168AE;BAMUM LETTER PHASE-C TITA YUE;Lo;0;L;;;;;N;;;;;
+168AF;BAMUM LETTER PHASE-C SUAET;Lo;0;L;;;;;N;;;;;
+168B0;BAMUM LETTER PHASE-C NGGUAEN NYAM;Lo;0;L;;;;;N;;;;;
+168B1;BAMUM LETTER PHASE-C VEUX;Lo;0;L;;;;;N;;;;;
+168B2;BAMUM LETTER PHASE-C NANSANAQ;Lo;0;L;;;;;N;;;;;
+168B3;BAMUM LETTER PHASE-C MA KEUAERI;Lo;0;L;;;;;N;;;;;
+168B4;BAMUM LETTER PHASE-C NTAA;Lo;0;L;;;;;N;;;;;
+168B5;BAMUM LETTER PHASE-C NGGUON;Lo;0;L;;;;;N;;;;;
+168B6;BAMUM LETTER PHASE-C LAP;Lo;0;L;;;;;N;;;;;
+168B7;BAMUM LETTER PHASE-C MBIRIEEN;Lo;0;L;;;;;N;;;;;
+168B8;BAMUM LETTER PHASE-C MGBASAQ;Lo;0;L;;;;;N;;;;;
+168B9;BAMUM LETTER PHASE-C NTEUNGBA;Lo;0;L;;;;;N;;;;;
+168BA;BAMUM LETTER PHASE-C TEUTEUX;Lo;0;L;;;;;N;;;;;
+168BB;BAMUM LETTER PHASE-C NGGUM;Lo;0;L;;;;;N;;;;;
+168BC;BAMUM LETTER PHASE-C FUE;Lo;0;L;;;;;N;;;;;
+168BD;BAMUM LETTER PHASE-C NDEUT;Lo;0;L;;;;;N;;;;;
+168BE;BAMUM LETTER PHASE-C NSA;Lo;0;L;;;;;N;;;;;
+168BF;BAMUM LETTER PHASE-C NSHAQ;Lo;0;L;;;;;N;;;;;
+168C0;BAMUM LETTER PHASE-C BUNG;Lo;0;L;;;;;N;;;;;
+168C1;BAMUM LETTER PHASE-C VEUAEPEN;Lo;0;L;;;;;N;;;;;
+168C2;BAMUM LETTER PHASE-C MBERAE;Lo;0;L;;;;;N;;;;;
+168C3;BAMUM LETTER PHASE-C RU;Lo;0;L;;;;;N;;;;;
+168C4;BAMUM LETTER PHASE-C NJAEM;Lo;0;L;;;;;N;;;;;
+168C5;BAMUM LETTER PHASE-C LAM;Lo;0;L;;;;;N;;;;;
+168C6;BAMUM LETTER PHASE-C TITUAEP;Lo;0;L;;;;;N;;;;;
+168C7;BAMUM LETTER PHASE-C NSUOT NGOM;Lo;0;L;;;;;N;;;;;
+168C8;BAMUM LETTER PHASE-C NJEEEE;Lo;0;L;;;;;N;;;;;
+168C9;BAMUM LETTER PHASE-C KET;Lo;0;L;;;;;N;;;;;
+168CA;BAMUM LETTER PHASE-C NGGU;Lo;0;L;;;;;N;;;;;
+168CB;BAMUM LETTER PHASE-C MAESI;Lo;0;L;;;;;N;;;;;
+168CC;BAMUM LETTER PHASE-C MBUAEM;Lo;0;L;;;;;N;;;;;
+168CD;BAMUM LETTER PHASE-C LU;Lo;0;L;;;;;N;;;;;
+168CE;BAMUM LETTER PHASE-C KUT;Lo;0;L;;;;;N;;;;;
+168CF;BAMUM LETTER PHASE-C NJAM;Lo;0;L;;;;;N;;;;;
+168D0;BAMUM LETTER PHASE-C NGOM;Lo;0;L;;;;;N;;;;;
+168D1;BAMUM LETTER PHASE-C WUP;Lo;0;L;;;;;N;;;;;
+168D2;BAMUM LETTER PHASE-C NGGUEET;Lo;0;L;;;;;N;;;;;
+168D3;BAMUM LETTER PHASE-C NSOM;Lo;0;L;;;;;N;;;;;
+168D4;BAMUM LETTER PHASE-C NTEN;Lo;0;L;;;;;N;;;;;
+168D5;BAMUM LETTER PHASE-C KUOP NKAARAE;Lo;0;L;;;;;N;;;;;
+168D6;BAMUM LETTER PHASE-C NSUN;Lo;0;L;;;;;N;;;;;
+168D7;BAMUM LETTER PHASE-C NDAM;Lo;0;L;;;;;N;;;;;
+168D8;BAMUM LETTER PHASE-C MA NSIEE;Lo;0;L;;;;;N;;;;;
+168D9;BAMUM LETTER PHASE-C YAA;Lo;0;L;;;;;N;;;;;
+168DA;BAMUM LETTER PHASE-C NDAP;Lo;0;L;;;;;N;;;;;
+168DB;BAMUM LETTER PHASE-C SHUEQ;Lo;0;L;;;;;N;;;;;
+168DC;BAMUM LETTER PHASE-C SETFON;Lo;0;L;;;;;N;;;;;
+168DD;BAMUM LETTER PHASE-C MBI;Lo;0;L;;;;;N;;;;;
+168DE;BAMUM LETTER PHASE-C MAEMBA;Lo;0;L;;;;;N;;;;;
+168DF;BAMUM LETTER PHASE-C MBANYI;Lo;0;L;;;;;N;;;;;
+168E0;BAMUM LETTER PHASE-C KEUSEUX;Lo;0;L;;;;;N;;;;;
+168E1;BAMUM LETTER PHASE-C MBEUX;Lo;0;L;;;;;N;;;;;
+168E2;BAMUM LETTER PHASE-C KEUM;Lo;0;L;;;;;N;;;;;
+168E3;BAMUM LETTER PHASE-C MBAA PICKET;Lo;0;L;;;;;N;;;;;
+168E4;BAMUM LETTER PHASE-C YUWOQ;Lo;0;L;;;;;N;;;;;
+168E5;BAMUM LETTER PHASE-C NJEUX;Lo;0;L;;;;;N;;;;;
+168E6;BAMUM LETTER PHASE-C MIEE;Lo;0;L;;;;;N;;;;;
+168E7;BAMUM LETTER PHASE-C MUAE;Lo;0;L;;;;;N;;;;;
+168E8;BAMUM LETTER PHASE-C SHIQ;Lo;0;L;;;;;N;;;;;
+168E9;BAMUM LETTER PHASE-C KEN LAW;Lo;0;L;;;;;N;;;;;
+168EA;BAMUM LETTER PHASE-C KEN FATIGUE;Lo;0;L;;;;;N;;;;;
+168EB;BAMUM LETTER PHASE-C NGAQ;Lo;0;L;;;;;N;;;;;
+168EC;BAMUM LETTER PHASE-C NAQ;Lo;0;L;;;;;N;;;;;
+168ED;BAMUM LETTER PHASE-C LIQ;Lo;0;L;;;;;N;;;;;
+168EE;BAMUM LETTER PHASE-C PIN;Lo;0;L;;;;;N;;;;;
+168EF;BAMUM LETTER PHASE-C PEN;Lo;0;L;;;;;N;;;;;
+168F0;BAMUM LETTER PHASE-C TET;Lo;0;L;;;;;N;;;;;
+168F1;BAMUM LETTER PHASE-D MBUO;Lo;0;L;;;;;N;;;;;
+168F2;BAMUM LETTER PHASE-D WAP;Lo;0;L;;;;;N;;;;;
+168F3;BAMUM LETTER PHASE-D NJI;Lo;0;L;;;;;N;;;;;
+168F4;BAMUM LETTER PHASE-D MFON;Lo;0;L;;;;;N;;;;;
+168F5;BAMUM LETTER PHASE-D NJIEE;Lo;0;L;;;;;N;;;;;
+168F6;BAMUM LETTER PHASE-D LIEE;Lo;0;L;;;;;N;;;;;
+168F7;BAMUM LETTER PHASE-D NJEUT;Lo;0;L;;;;;N;;;;;
+168F8;BAMUM LETTER PHASE-D NSHEE;Lo;0;L;;;;;N;;;;;
+168F9;BAMUM LETTER PHASE-D NGGAAMAE;Lo;0;L;;;;;N;;;;;
+168FA;BAMUM LETTER PHASE-D NYAM;Lo;0;L;;;;;N;;;;;
+168FB;BAMUM LETTER PHASE-D WUAEN;Lo;0;L;;;;;N;;;;;
+168FC;BAMUM LETTER PHASE-D NGKUN;Lo;0;L;;;;;N;;;;;
+168FD;BAMUM LETTER PHASE-D SHEE;Lo;0;L;;;;;N;;;;;
+168FE;BAMUM LETTER PHASE-D NGKAP;Lo;0;L;;;;;N;;;;;
+168FF;BAMUM LETTER PHASE-D KEUAETMEUN;Lo;0;L;;;;;N;;;;;
+16900;BAMUM LETTER PHASE-D TEUT;Lo;0;L;;;;;N;;;;;
+16901;BAMUM LETTER PHASE-D SHEUAE;Lo;0;L;;;;;N;;;;;
+16902;BAMUM LETTER PHASE-D NJAP;Lo;0;L;;;;;N;;;;;
+16903;BAMUM LETTER PHASE-D SUE;Lo;0;L;;;;;N;;;;;
+16904;BAMUM LETTER PHASE-D KET;Lo;0;L;;;;;N;;;;;
+16905;BAMUM LETTER PHASE-D YAEMMAE;Lo;0;L;;;;;N;;;;;
+16906;BAMUM LETTER PHASE-D KUOM;Lo;0;L;;;;;N;;;;;
+16907;BAMUM LETTER PHASE-D SAP;Lo;0;L;;;;;N;;;;;
+16908;BAMUM LETTER PHASE-D MFEUT;Lo;0;L;;;;;N;;;;;
+16909;BAMUM LETTER PHASE-D NDEUX;Lo;0;L;;;;;N;;;;;
+1690A;BAMUM LETTER PHASE-D MALEERI;Lo;0;L;;;;;N;;;;;
+1690B;BAMUM LETTER PHASE-D MEUT;Lo;0;L;;;;;N;;;;;
+1690C;BAMUM LETTER PHASE-D SEUAEQ;Lo;0;L;;;;;N;;;;;
+1690D;BAMUM LETTER PHASE-D YEN;Lo;0;L;;;;;N;;;;;
+1690E;BAMUM LETTER PHASE-D NJEUAEM;Lo;0;L;;;;;N;;;;;
+1690F;BAMUM LETTER PHASE-D KEUOT MBUAE;Lo;0;L;;;;;N;;;;;
+16910;BAMUM LETTER PHASE-D NGKEURI;Lo;0;L;;;;;N;;;;;
+16911;BAMUM LETTER PHASE-D TU;Lo;0;L;;;;;N;;;;;
+16912;BAMUM LETTER PHASE-D GHAA;Lo;0;L;;;;;N;;;;;
+16913;BAMUM LETTER PHASE-D NGKYEE;Lo;0;L;;;;;N;;;;;
+16914;BAMUM LETTER PHASE-D FEUFEUAET;Lo;0;L;;;;;N;;;;;
+16915;BAMUM LETTER PHASE-D NDEE;Lo;0;L;;;;;N;;;;;
+16916;BAMUM LETTER PHASE-D MGBOFUM;Lo;0;L;;;;;N;;;;;
+16917;BAMUM LETTER PHASE-D LEUAEP;Lo;0;L;;;;;N;;;;;
+16918;BAMUM LETTER PHASE-D NDON;Lo;0;L;;;;;N;;;;;
+16919;BAMUM LETTER PHASE-D MONI;Lo;0;L;;;;;N;;;;;
+1691A;BAMUM LETTER PHASE-D MGBEUN;Lo;0;L;;;;;N;;;;;
+1691B;BAMUM LETTER PHASE-D PUUT;Lo;0;L;;;;;N;;;;;
+1691C;BAMUM LETTER PHASE-D MGBIEE;Lo;0;L;;;;;N;;;;;
+1691D;BAMUM LETTER PHASE-D MFO;Lo;0;L;;;;;N;;;;;
+1691E;BAMUM LETTER PHASE-D LUM;Lo;0;L;;;;;N;;;;;
+1691F;BAMUM LETTER PHASE-D NSIEEP;Lo;0;L;;;;;N;;;;;
+16920;BAMUM LETTER PHASE-D MBAA;Lo;0;L;;;;;N;;;;;
+16921;BAMUM LETTER PHASE-D KWAET;Lo;0;L;;;;;N;;;;;
+16922;BAMUM LETTER PHASE-D NYET;Lo;0;L;;;;;N;;;;;
+16923;BAMUM LETTER PHASE-D TEUAEN;Lo;0;L;;;;;N;;;;;
+16924;BAMUM LETTER PHASE-D SOT;Lo;0;L;;;;;N;;;;;
+16925;BAMUM LETTER PHASE-D YUWOQ;Lo;0;L;;;;;N;;;;;
+16926;BAMUM LETTER PHASE-D KEUM;Lo;0;L;;;;;N;;;;;
+16927;BAMUM LETTER PHASE-D RAEM;Lo;0;L;;;;;N;;;;;
+16928;BAMUM LETTER PHASE-D TEEEE;Lo;0;L;;;;;N;;;;;
+16929;BAMUM LETTER PHASE-D NGKEUAEQ;Lo;0;L;;;;;N;;;;;
+1692A;BAMUM LETTER PHASE-D MFEUAE;Lo;0;L;;;;;N;;;;;
+1692B;BAMUM LETTER PHASE-D NSIEET;Lo;0;L;;;;;N;;;;;
+1692C;BAMUM LETTER PHASE-D KEUP;Lo;0;L;;;;;N;;;;;
+1692D;BAMUM LETTER PHASE-D PIP;Lo;0;L;;;;;N;;;;;
+1692E;BAMUM LETTER PHASE-D PEUTAE;Lo;0;L;;;;;N;;;;;
+1692F;BAMUM LETTER PHASE-D NYUE;Lo;0;L;;;;;N;;;;;
+16930;BAMUM LETTER PHASE-D LET;Lo;0;L;;;;;N;;;;;
+16931;BAMUM LETTER PHASE-D NGGAAM;Lo;0;L;;;;;N;;;;;
+16932;BAMUM LETTER PHASE-D MFIEE;Lo;0;L;;;;;N;;;;;
+16933;BAMUM LETTER PHASE-D NGGWAEN;Lo;0;L;;;;;N;;;;;
+16934;BAMUM LETTER PHASE-D YUOM;Lo;0;L;;;;;N;;;;;
+16935;BAMUM LETTER PHASE-D PAP;Lo;0;L;;;;;N;;;;;
+16936;BAMUM LETTER PHASE-D YUOP;Lo;0;L;;;;;N;;;;;
+16937;BAMUM LETTER PHASE-D NDAM;Lo;0;L;;;;;N;;;;;
+16938;BAMUM LETTER PHASE-D NTEUM;Lo;0;L;;;;;N;;;;;
+16939;BAMUM LETTER PHASE-D SUAE;Lo;0;L;;;;;N;;;;;
+1693A;BAMUM LETTER PHASE-D KUN;Lo;0;L;;;;;N;;;;;
+1693B;BAMUM LETTER PHASE-D NGGEUX;Lo;0;L;;;;;N;;;;;
+1693C;BAMUM LETTER PHASE-D NGKIEE;Lo;0;L;;;;;N;;;;;
+1693D;BAMUM LETTER PHASE-D TUOT;Lo;0;L;;;;;N;;;;;
+1693E;BAMUM LETTER PHASE-D MEUN;Lo;0;L;;;;;N;;;;;
+1693F;BAMUM LETTER PHASE-D KUQ;Lo;0;L;;;;;N;;;;;
+16940;BAMUM LETTER PHASE-D NSUM;Lo;0;L;;;;;N;;;;;
+16941;BAMUM LETTER PHASE-D TEUN;Lo;0;L;;;;;N;;;;;
+16942;BAMUM LETTER PHASE-D MAENJET;Lo;0;L;;;;;N;;;;;
+16943;BAMUM LETTER PHASE-D NGGAP;Lo;0;L;;;;;N;;;;;
+16944;BAMUM LETTER PHASE-D LEUM;Lo;0;L;;;;;N;;;;;
+16945;BAMUM LETTER PHASE-D NGGUOM;Lo;0;L;;;;;N;;;;;
+16946;BAMUM LETTER PHASE-D NSHUT;Lo;0;L;;;;;N;;;;;
+16947;BAMUM LETTER PHASE-D NJUEQ;Lo;0;L;;;;;N;;;;;
+16948;BAMUM LETTER PHASE-D GHEUAE;Lo;0;L;;;;;N;;;;;
+16949;BAMUM LETTER PHASE-D KU;Lo;0;L;;;;;N;;;;;
+1694A;BAMUM LETTER PHASE-D REN OLD;Lo;0;L;;;;;N;;;;;
+1694B;BAMUM LETTER PHASE-D TAE;Lo;0;L;;;;;N;;;;;
+1694C;BAMUM LETTER PHASE-D TOQ;Lo;0;L;;;;;N;;;;;
+1694D;BAMUM LETTER PHASE-D NYI;Lo;0;L;;;;;N;;;;;
+1694E;BAMUM LETTER PHASE-D RII;Lo;0;L;;;;;N;;;;;
+1694F;BAMUM LETTER PHASE-D LEEEE;Lo;0;L;;;;;N;;;;;
+16950;BAMUM LETTER PHASE-D MEEEE;Lo;0;L;;;;;N;;;;;
+16951;BAMUM LETTER PHASE-D M;Lo;0;L;;;;;N;;;;;
+16952;BAMUM LETTER PHASE-D SUU;Lo;0;L;;;;;N;;;;;
+16953;BAMUM LETTER PHASE-D MU;Lo;0;L;;;;;N;;;;;
+16954;BAMUM LETTER PHASE-D SHII;Lo;0;L;;;;;N;;;;;
+16955;BAMUM LETTER PHASE-D SHEUX;Lo;0;L;;;;;N;;;;;
+16956;BAMUM LETTER PHASE-D KYEE;Lo;0;L;;;;;N;;;;;
+16957;BAMUM LETTER PHASE-D NU;Lo;0;L;;;;;N;;;;;
+16958;BAMUM LETTER PHASE-D SHU;Lo;0;L;;;;;N;;;;;
+16959;BAMUM LETTER PHASE-D NTEE;Lo;0;L;;;;;N;;;;;
+1695A;BAMUM LETTER PHASE-D PEE;Lo;0;L;;;;;N;;;;;
+1695B;BAMUM LETTER PHASE-D NI;Lo;0;L;;;;;N;;;;;
+1695C;BAMUM LETTER PHASE-D SHOQ;Lo;0;L;;;;;N;;;;;
+1695D;BAMUM LETTER PHASE-D PUQ;Lo;0;L;;;;;N;;;;;
+1695E;BAMUM LETTER PHASE-D MVOP;Lo;0;L;;;;;N;;;;;
+1695F;BAMUM LETTER PHASE-D LOQ;Lo;0;L;;;;;N;;;;;
+16960;BAMUM LETTER PHASE-D REN MUCH;Lo;0;L;;;;;N;;;;;
+16961;BAMUM LETTER PHASE-D TI;Lo;0;L;;;;;N;;;;;
+16962;BAMUM LETTER PHASE-D NTUU;Lo;0;L;;;;;N;;;;;
+16963;BAMUM LETTER PHASE-D MBAA SEVEN;Lo;0;L;;;;;N;;;;;
+16964;BAMUM LETTER PHASE-D SAQ;Lo;0;L;;;;;N;;;;;
+16965;BAMUM LETTER PHASE-D FAA;Lo;0;L;;;;;N;;;;;
+16966;BAMUM LETTER PHASE-E NDAP;Lo;0;L;;;;;N;;;;;
+16967;BAMUM LETTER PHASE-E TOON;Lo;0;L;;;;;N;;;;;
+16968;BAMUM LETTER PHASE-E MBEUM;Lo;0;L;;;;;N;;;;;
+16969;BAMUM LETTER PHASE-E LAP;Lo;0;L;;;;;N;;;;;
+1696A;BAMUM LETTER PHASE-E VOM;Lo;0;L;;;;;N;;;;;
+1696B;BAMUM LETTER PHASE-E LOON;Lo;0;L;;;;;N;;;;;
+1696C;BAMUM LETTER PHASE-E PAA;Lo;0;L;;;;;N;;;;;
+1696D;BAMUM LETTER PHASE-E SOM;Lo;0;L;;;;;N;;;;;
+1696E;BAMUM LETTER PHASE-E RAQ;Lo;0;L;;;;;N;;;;;
+1696F;BAMUM LETTER PHASE-E NSHUOP;Lo;0;L;;;;;N;;;;;
+16970;BAMUM LETTER PHASE-E NDUN;Lo;0;L;;;;;N;;;;;
+16971;BAMUM LETTER PHASE-E PUAE;Lo;0;L;;;;;N;;;;;
+16972;BAMUM LETTER PHASE-E TAM;Lo;0;L;;;;;N;;;;;
+16973;BAMUM LETTER PHASE-E NGKA;Lo;0;L;;;;;N;;;;;
+16974;BAMUM LETTER PHASE-E KPEUX;Lo;0;L;;;;;N;;;;;
+16975;BAMUM LETTER PHASE-E WUO;Lo;0;L;;;;;N;;;;;
+16976;BAMUM LETTER PHASE-E SEE;Lo;0;L;;;;;N;;;;;
+16977;BAMUM LETTER PHASE-E NGGEUAET;Lo;0;L;;;;;N;;;;;
+16978;BAMUM LETTER PHASE-E PAAM;Lo;0;L;;;;;N;;;;;
+16979;BAMUM LETTER PHASE-E TOO;Lo;0;L;;;;;N;;;;;
+1697A;BAMUM LETTER PHASE-E KUOP;Lo;0;L;;;;;N;;;;;
+1697B;BAMUM LETTER PHASE-E LOM;Lo;0;L;;;;;N;;;;;
+1697C;BAMUM LETTER PHASE-E NSHIEE;Lo;0;L;;;;;N;;;;;
+1697D;BAMUM LETTER PHASE-E NGOP;Lo;0;L;;;;;N;;;;;
+1697E;BAMUM LETTER PHASE-E MAEM;Lo;0;L;;;;;N;;;;;
+1697F;BAMUM LETTER PHASE-E NGKEUX;Lo;0;L;;;;;N;;;;;
+16980;BAMUM LETTER PHASE-E NGOQ;Lo;0;L;;;;;N;;;;;
+16981;BAMUM LETTER PHASE-E NSHUE;Lo;0;L;;;;;N;;;;;
+16982;BAMUM LETTER PHASE-E RIMGBA;Lo;0;L;;;;;N;;;;;
+16983;BAMUM LETTER PHASE-E NJEUX;Lo;0;L;;;;;N;;;;;
+16984;BAMUM LETTER PHASE-E PEEM;Lo;0;L;;;;;N;;;;;
+16985;BAMUM LETTER PHASE-E SAA;Lo;0;L;;;;;N;;;;;
+16986;BAMUM LETTER PHASE-E NGGURAE;Lo;0;L;;;;;N;;;;;
+16987;BAMUM LETTER PHASE-E MGBA;Lo;0;L;;;;;N;;;;;
+16988;BAMUM LETTER PHASE-E GHEUX;Lo;0;L;;;;;N;;;;;
+16989;BAMUM LETTER PHASE-E NGKEUAEM;Lo;0;L;;;;;N;;;;;
+1698A;BAMUM LETTER PHASE-E NJAEMLI;Lo;0;L;;;;;N;;;;;
+1698B;BAMUM LETTER PHASE-E MAP;Lo;0;L;;;;;N;;;;;
+1698C;BAMUM LETTER PHASE-E LOOT;Lo;0;L;;;;;N;;;;;
+1698D;BAMUM LETTER PHASE-E NGGEEEE;Lo;0;L;;;;;N;;;;;
+1698E;BAMUM LETTER PHASE-E NDIQ;Lo;0;L;;;;;N;;;;;
+1698F;BAMUM LETTER PHASE-E TAEN NTEUM;Lo;0;L;;;;;N;;;;;
+16990;BAMUM LETTER PHASE-E SET;Lo;0;L;;;;;N;;;;;
+16991;BAMUM LETTER PHASE-E PUM;Lo;0;L;;;;;N;;;;;
+16992;BAMUM LETTER PHASE-E NDAA SOFTNESS;Lo;0;L;;;;;N;;;;;
+16993;BAMUM LETTER PHASE-E NGGUAESHAE NYAM;Lo;0;L;;;;;N;;;;;
+16994;BAMUM LETTER PHASE-E YIEE;Lo;0;L;;;;;N;;;;;
+16995;BAMUM LETTER PHASE-E GHEUN;Lo;0;L;;;;;N;;;;;
+16996;BAMUM LETTER PHASE-E TUAE;Lo;0;L;;;;;N;;;;;
+16997;BAMUM LETTER PHASE-E YEUAE;Lo;0;L;;;;;N;;;;;
+16998;BAMUM LETTER PHASE-E PO;Lo;0;L;;;;;N;;;;;
+16999;BAMUM LETTER PHASE-E TUMAE;Lo;0;L;;;;;N;;;;;
+1699A;BAMUM LETTER PHASE-E KEUAE;Lo;0;L;;;;;N;;;;;
+1699B;BAMUM LETTER PHASE-E SUAEN;Lo;0;L;;;;;N;;;;;
+1699C;BAMUM LETTER PHASE-E TEUAEQ;Lo;0;L;;;;;N;;;;;
+1699D;BAMUM LETTER PHASE-E VEUAE;Lo;0;L;;;;;N;;;;;
+1699E;BAMUM LETTER PHASE-E WEUX;Lo;0;L;;;;;N;;;;;
+1699F;BAMUM LETTER PHASE-E LAAM;Lo;0;L;;;;;N;;;;;
+169A0;BAMUM LETTER PHASE-E PU;Lo;0;L;;;;;N;;;;;
+169A1;BAMUM LETTER PHASE-E TAAQ;Lo;0;L;;;;;N;;;;;
+169A2;BAMUM LETTER PHASE-E GHAAMAE;Lo;0;L;;;;;N;;;;;
+169A3;BAMUM LETTER PHASE-E NGEUREUT;Lo;0;L;;;;;N;;;;;
+169A4;BAMUM LETTER PHASE-E SHEUAEQ;Lo;0;L;;;;;N;;;;;
+169A5;BAMUM LETTER PHASE-E MGBEN;Lo;0;L;;;;;N;;;;;
+169A6;BAMUM LETTER PHASE-E MBEE;Lo;0;L;;;;;N;;;;;
+169A7;BAMUM LETTER PHASE-E NZAQ;Lo;0;L;;;;;N;;;;;
+169A8;BAMUM LETTER PHASE-E NKOM;Lo;0;L;;;;;N;;;;;
+169A9;BAMUM LETTER PHASE-E GBET;Lo;0;L;;;;;N;;;;;
+169AA;BAMUM LETTER PHASE-E TUM;Lo;0;L;;;;;N;;;;;
+169AB;BAMUM LETTER PHASE-E KUET;Lo;0;L;;;;;N;;;;;
+169AC;BAMUM LETTER PHASE-E YAP;Lo;0;L;;;;;N;;;;;
+169AD;BAMUM LETTER PHASE-E NYI CLEAVER;Lo;0;L;;;;;N;;;;;
+169AE;BAMUM LETTER PHASE-E YIT;Lo;0;L;;;;;N;;;;;
+169AF;BAMUM LETTER PHASE-E MFEUQ;Lo;0;L;;;;;N;;;;;
+169B0;BAMUM LETTER PHASE-E NDIAQ;Lo;0;L;;;;;N;;;;;
+169B1;BAMUM LETTER PHASE-E PIEEQ;Lo;0;L;;;;;N;;;;;
+169B2;BAMUM LETTER PHASE-E YUEQ;Lo;0;L;;;;;N;;;;;
+169B3;BAMUM LETTER PHASE-E LEUAEM;Lo;0;L;;;;;N;;;;;
+169B4;BAMUM LETTER PHASE-E FUE;Lo;0;L;;;;;N;;;;;
+169B5;BAMUM LETTER PHASE-E GBEUX;Lo;0;L;;;;;N;;;;;
+169B6;BAMUM LETTER PHASE-E NGKUP;Lo;0;L;;;;;N;;;;;
+169B7;BAMUM LETTER PHASE-E KET;Lo;0;L;;;;;N;;;;;
+169B8;BAMUM LETTER PHASE-E MAE;Lo;0;L;;;;;N;;;;;
+169B9;BAMUM LETTER PHASE-E NGKAAMI;Lo;0;L;;;;;N;;;;;
+169BA;BAMUM LETTER PHASE-E GHET;Lo;0;L;;;;;N;;;;;
+169BB;BAMUM LETTER PHASE-E FA;Lo;0;L;;;;;N;;;;;
+169BC;BAMUM LETTER PHASE-E NTUM;Lo;0;L;;;;;N;;;;;
+169BD;BAMUM LETTER PHASE-E PEUT;Lo;0;L;;;;;N;;;;;
+169BE;BAMUM LETTER PHASE-E YEUM;Lo;0;L;;;;;N;;;;;
+169BF;BAMUM LETTER PHASE-E NGGEUAE;Lo;0;L;;;;;N;;;;;
+169C0;BAMUM LETTER PHASE-E NYI BETWEEN;Lo;0;L;;;;;N;;;;;
+169C1;BAMUM LETTER PHASE-E NZUQ;Lo;0;L;;;;;N;;;;;
+169C2;BAMUM LETTER PHASE-E POON;Lo;0;L;;;;;N;;;;;
+169C3;BAMUM LETTER PHASE-E MIEE;Lo;0;L;;;;;N;;;;;
+169C4;BAMUM LETTER PHASE-E FUET;Lo;0;L;;;;;N;;;;;
+169C5;BAMUM LETTER PHASE-E NAE;Lo;0;L;;;;;N;;;;;
+169C6;BAMUM LETTER PHASE-E MUAE;Lo;0;L;;;;;N;;;;;
+169C7;BAMUM LETTER PHASE-E GHEUAE;Lo;0;L;;;;;N;;;;;
+169C8;BAMUM LETTER PHASE-E FU I;Lo;0;L;;;;;N;;;;;
+169C9;BAMUM LETTER PHASE-E MVI;Lo;0;L;;;;;N;;;;;
+169CA;BAMUM LETTER PHASE-E PUAQ;Lo;0;L;;;;;N;;;;;
+169CB;BAMUM LETTER PHASE-E NGKUM;Lo;0;L;;;;;N;;;;;
+169CC;BAMUM LETTER PHASE-E KUT;Lo;0;L;;;;;N;;;;;
+169CD;BAMUM LETTER PHASE-E PIET;Lo;0;L;;;;;N;;;;;
+169CE;BAMUM LETTER PHASE-E NTAP;Lo;0;L;;;;;N;;;;;
+169CF;BAMUM LETTER PHASE-E YEUAET;Lo;0;L;;;;;N;;;;;
+169D0;BAMUM LETTER PHASE-E NGGUP;Lo;0;L;;;;;N;;;;;
+169D1;BAMUM LETTER PHASE-E PA PEOPLE;Lo;0;L;;;;;N;;;;;
+169D2;BAMUM LETTER PHASE-E FU CALL;Lo;0;L;;;;;N;;;;;
+169D3;BAMUM LETTER PHASE-E FOM;Lo;0;L;;;;;N;;;;;
+169D4;BAMUM LETTER PHASE-E NJEE;Lo;0;L;;;;;N;;;;;
+169D5;BAMUM LETTER PHASE-E A;Lo;0;L;;;;;N;;;;;
+169D6;BAMUM LETTER PHASE-E TOQ;Lo;0;L;;;;;N;;;;;
+169D7;BAMUM LETTER PHASE-E O;Lo;0;L;;;;;N;;;;;
+169D8;BAMUM LETTER PHASE-E I;Lo;0;L;;;;;N;;;;;
+169D9;BAMUM LETTER PHASE-E LAQ;Lo;0;L;;;;;N;;;;;
+169DA;BAMUM LETTER PHASE-E PA PLURAL;Lo;0;L;;;;;N;;;;;
+169DB;BAMUM LETTER PHASE-E TAA;Lo;0;L;;;;;N;;;;;
+169DC;BAMUM LETTER PHASE-E TAQ;Lo;0;L;;;;;N;;;;;
+169DD;BAMUM LETTER PHASE-E NDAA MY HOUSE;Lo;0;L;;;;;N;;;;;
+169DE;BAMUM LETTER PHASE-E SHIQ;Lo;0;L;;;;;N;;;;;
+169DF;BAMUM LETTER PHASE-E YEUX;Lo;0;L;;;;;N;;;;;
+169E0;BAMUM LETTER PHASE-E NGUAE;Lo;0;L;;;;;N;;;;;
+169E1;BAMUM LETTER PHASE-E YUAEN;Lo;0;L;;;;;N;;;;;
+169E2;BAMUM LETTER PHASE-E YOQ SWIMMING;Lo;0;L;;;;;N;;;;;
+169E3;BAMUM LETTER PHASE-E YOQ COVER;Lo;0;L;;;;;N;;;;;
+169E4;BAMUM LETTER PHASE-E YUQ;Lo;0;L;;;;;N;;;;;
+169E5;BAMUM LETTER PHASE-E YUN;Lo;0;L;;;;;N;;;;;
+169E6;BAMUM LETTER PHASE-E KEUX;Lo;0;L;;;;;N;;;;;
+169E7;BAMUM LETTER PHASE-E PEUX;Lo;0;L;;;;;N;;;;;
+169E8;BAMUM LETTER PHASE-E NJEE EPOCH;Lo;0;L;;;;;N;;;;;
+169E9;BAMUM LETTER PHASE-E PUE;Lo;0;L;;;;;N;;;;;
+169EA;BAMUM LETTER PHASE-E WUE;Lo;0;L;;;;;N;;;;;
+169EB;BAMUM LETTER PHASE-E FEE;Lo;0;L;;;;;N;;;;;
+169EC;BAMUM LETTER PHASE-E VEE;Lo;0;L;;;;;N;;;;;
+169ED;BAMUM LETTER PHASE-E LU;Lo;0;L;;;;;N;;;;;
+169EE;BAMUM LETTER PHASE-E MI;Lo;0;L;;;;;N;;;;;
+169EF;BAMUM LETTER PHASE-E REUX;Lo;0;L;;;;;N;;;;;
+169F0;BAMUM LETTER PHASE-E RAE;Lo;0;L;;;;;N;;;;;
+169F1;BAMUM LETTER PHASE-E NGUAET;Lo;0;L;;;;;N;;;;;
+169F2;BAMUM LETTER PHASE-E NGA;Lo;0;L;;;;;N;;;;;
+169F3;BAMUM LETTER PHASE-E SHO;Lo;0;L;;;;;N;;;;;
+169F4;BAMUM LETTER PHASE-E SHOQ;Lo;0;L;;;;;N;;;;;
+169F5;BAMUM LETTER PHASE-E FU REMEDY;Lo;0;L;;;;;N;;;;;
+169F6;BAMUM LETTER PHASE-E NA;Lo;0;L;;;;;N;;;;;
+169F7;BAMUM LETTER PHASE-E PI;Lo;0;L;;;;;N;;;;;
+169F8;BAMUM LETTER PHASE-E LOQ;Lo;0;L;;;;;N;;;;;
+169F9;BAMUM LETTER PHASE-E KO;Lo;0;L;;;;;N;;;;;
+169FA;BAMUM LETTER PHASE-E MEN;Lo;0;L;;;;;N;;;;;
+169FB;BAMUM LETTER PHASE-E MA;Lo;0;L;;;;;N;;;;;
+169FC;BAMUM LETTER PHASE-E MAQ;Lo;0;L;;;;;N;;;;;
+169FD;BAMUM LETTER PHASE-E TEU;Lo;0;L;;;;;N;;;;;
+169FE;BAMUM LETTER PHASE-E KI;Lo;0;L;;;;;N;;;;;
+169FF;BAMUM LETTER PHASE-E MON;Lo;0;L;;;;;N;;;;;
+16A00;BAMUM LETTER PHASE-E TEN;Lo;0;L;;;;;N;;;;;
+16A01;BAMUM LETTER PHASE-E FAQ;Lo;0;L;;;;;N;;;;;
+16A02;BAMUM LETTER PHASE-E GHOM;Lo;0;L;;;;;N;;;;;
+16A03;BAMUM LETTER PHASE-F KA;Lo;0;L;;;;;N;;;;;
+16A04;BAMUM LETTER PHASE-F U;Lo;0;L;;;;;N;;;;;
+16A05;BAMUM LETTER PHASE-F KU;Lo;0;L;;;;;N;;;;;
+16A06;BAMUM LETTER PHASE-F EE;Lo;0;L;;;;;N;;;;;
+16A07;BAMUM LETTER PHASE-F REE;Lo;0;L;;;;;N;;;;;
+16A08;BAMUM LETTER PHASE-F TAE;Lo;0;L;;;;;N;;;;;
+16A09;BAMUM LETTER PHASE-F NYI;Lo;0;L;;;;;N;;;;;
+16A0A;BAMUM LETTER PHASE-F LA;Lo;0;L;;;;;N;;;;;
+16A0B;BAMUM LETTER PHASE-F RII;Lo;0;L;;;;;N;;;;;
+16A0C;BAMUM LETTER PHASE-F RIEE;Lo;0;L;;;;;N;;;;;
+16A0D;BAMUM LETTER PHASE-F MEEEE;Lo;0;L;;;;;N;;;;;
+16A0E;BAMUM LETTER PHASE-F TAA;Lo;0;L;;;;;N;;;;;
+16A0F;BAMUM LETTER PHASE-F NDAA;Lo;0;L;;;;;N;;;;;
+16A10;BAMUM LETTER PHASE-F NJAEM;Lo;0;L;;;;;N;;;;;
+16A11;BAMUM LETTER PHASE-F M;Lo;0;L;;;;;N;;;;;
+16A12;BAMUM LETTER PHASE-F SUU;Lo;0;L;;;;;N;;;;;
+16A13;BAMUM LETTER PHASE-F SHII;Lo;0;L;;;;;N;;;;;
+16A14;BAMUM LETTER PHASE-F SI;Lo;0;L;;;;;N;;;;;
+16A15;BAMUM LETTER PHASE-F SEUX;Lo;0;L;;;;;N;;;;;
+16A16;BAMUM LETTER PHASE-F KYEE;Lo;0;L;;;;;N;;;;;
+16A17;BAMUM LETTER PHASE-F KET;Lo;0;L;;;;;N;;;;;
+16A18;BAMUM LETTER PHASE-F NUAE;Lo;0;L;;;;;N;;;;;
+16A19;BAMUM LETTER PHASE-F NU;Lo;0;L;;;;;N;;;;;
+16A1A;BAMUM LETTER PHASE-F NJUAE;Lo;0;L;;;;;N;;;;;
+16A1B;BAMUM LETTER PHASE-F YOQ;Lo;0;L;;;;;N;;;;;
+16A1C;BAMUM LETTER PHASE-F SHU;Lo;0;L;;;;;N;;;;;
+16A1D;BAMUM LETTER PHASE-F YA;Lo;0;L;;;;;N;;;;;
+16A1E;BAMUM LETTER PHASE-F NSHA;Lo;0;L;;;;;N;;;;;
+16A1F;BAMUM LETTER PHASE-F PEUX;Lo;0;L;;;;;N;;;;;
+16A20;BAMUM LETTER PHASE-F NTEE;Lo;0;L;;;;;N;;;;;
+16A21;BAMUM LETTER PHASE-F WUE;Lo;0;L;;;;;N;;;;;
+16A22;BAMUM LETTER PHASE-F PEE;Lo;0;L;;;;;N;;;;;
+16A23;BAMUM LETTER PHASE-F RU;Lo;0;L;;;;;N;;;;;
+16A24;BAMUM LETTER PHASE-F NI;Lo;0;L;;;;;N;;;;;
+16A25;BAMUM LETTER PHASE-F REUX;Lo;0;L;;;;;N;;;;;
+16A26;BAMUM LETTER PHASE-F KEN;Lo;0;L;;;;;N;;;;;
+16A27;BAMUM LETTER PHASE-F NGKWAEN;Lo;0;L;;;;;N;;;;;
+16A28;BAMUM LETTER PHASE-F NGGA;Lo;0;L;;;;;N;;;;;
+16A29;BAMUM LETTER PHASE-F SHO;Lo;0;L;;;;;N;;;;;
+16A2A;BAMUM LETTER PHASE-F PUAE;Lo;0;L;;;;;N;;;;;
+16A2B;BAMUM LETTER PHASE-F FOM;Lo;0;L;;;;;N;;;;;
+16A2C;BAMUM LETTER PHASE-F WA;Lo;0;L;;;;;N;;;;;
+16A2D;BAMUM LETTER PHASE-F LI;Lo;0;L;;;;;N;;;;;
+16A2E;BAMUM LETTER PHASE-F LOQ;Lo;0;L;;;;;N;;;;;
+16A2F;BAMUM LETTER PHASE-F KO;Lo;0;L;;;;;N;;;;;
+16A30;BAMUM LETTER PHASE-F MBEN;Lo;0;L;;;;;N;;;;;
+16A31;BAMUM LETTER PHASE-F REN;Lo;0;L;;;;;N;;;;;
+16A32;BAMUM LETTER PHASE-F MA;Lo;0;L;;;;;N;;;;;
+16A33;BAMUM LETTER PHASE-F MO;Lo;0;L;;;;;N;;;;;
+16A34;BAMUM LETTER PHASE-F MBAA;Lo;0;L;;;;;N;;;;;
+16A35;BAMUM LETTER PHASE-F TET;Lo;0;L;;;;;N;;;;;
+16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;;
+16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;;
+16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;;
+16A40;MRO LETTER TA;Lo;0;L;;;;;N;;;;;
+16A41;MRO LETTER NGI;Lo;0;L;;;;;N;;;;;
+16A42;MRO LETTER YO;Lo;0;L;;;;;N;;;;;
+16A43;MRO LETTER MIM;Lo;0;L;;;;;N;;;;;
+16A44;MRO LETTER BA;Lo;0;L;;;;;N;;;;;
+16A45;MRO LETTER DA;Lo;0;L;;;;;N;;;;;
+16A46;MRO LETTER A;Lo;0;L;;;;;N;;;;;
+16A47;MRO LETTER PHI;Lo;0;L;;;;;N;;;;;
+16A48;MRO LETTER KHAI;Lo;0;L;;;;;N;;;;;
+16A49;MRO LETTER HAO;Lo;0;L;;;;;N;;;;;
+16A4A;MRO LETTER DAI;Lo;0;L;;;;;N;;;;;
+16A4B;MRO LETTER CHU;Lo;0;L;;;;;N;;;;;
+16A4C;MRO LETTER KEAAE;Lo;0;L;;;;;N;;;;;
+16A4D;MRO LETTER OL;Lo;0;L;;;;;N;;;;;
+16A4E;MRO LETTER MAEM;Lo;0;L;;;;;N;;;;;
+16A4F;MRO LETTER NIN;Lo;0;L;;;;;N;;;;;
+16A50;MRO LETTER PA;Lo;0;L;;;;;N;;;;;
+16A51;MRO LETTER OO;Lo;0;L;;;;;N;;;;;
+16A52;MRO LETTER O;Lo;0;L;;;;;N;;;;;
+16A53;MRO LETTER RO;Lo;0;L;;;;;N;;;;;
+16A54;MRO LETTER SHI;Lo;0;L;;;;;N;;;;;
+16A55;MRO LETTER THEA;Lo;0;L;;;;;N;;;;;
+16A56;MRO LETTER EA;Lo;0;L;;;;;N;;;;;
+16A57;MRO LETTER WA;Lo;0;L;;;;;N;;;;;
+16A58;MRO LETTER E;Lo;0;L;;;;;N;;;;;
+16A59;MRO LETTER KO;Lo;0;L;;;;;N;;;;;
+16A5A;MRO LETTER LAN;Lo;0;L;;;;;N;;;;;
+16A5B;MRO LETTER LA;Lo;0;L;;;;;N;;;;;
+16A5C;MRO LETTER HAI;Lo;0;L;;;;;N;;;;;
+16A5D;MRO LETTER RI;Lo;0;L;;;;;N;;;;;
+16A5E;MRO LETTER TEK;Lo;0;L;;;;;N;;;;;
+16A60;MRO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+16A61;MRO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+16A62;MRO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+16A63;MRO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+16A64;MRO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+16A65;MRO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+16A66;MRO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+16A67;MRO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+16A68;MRO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+16A69;MRO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+16A6E;MRO DANDA;Po;0;L;;;;;N;;;;;
+16A6F;MRO DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+16AD0;BASSA VAH LETTER ENNI;Lo;0;L;;;;;N;;;;;
+16AD1;BASSA VAH LETTER KA;Lo;0;L;;;;;N;;;;;
+16AD2;BASSA VAH LETTER SE;Lo;0;L;;;;;N;;;;;
+16AD3;BASSA VAH LETTER FA;Lo;0;L;;;;;N;;;;;
+16AD4;BASSA VAH LETTER MBE;Lo;0;L;;;;;N;;;;;
+16AD5;BASSA VAH LETTER YIE;Lo;0;L;;;;;N;;;;;
+16AD6;BASSA VAH LETTER GAH;Lo;0;L;;;;;N;;;;;
+16AD7;BASSA VAH LETTER DHII;Lo;0;L;;;;;N;;;;;
+16AD8;BASSA VAH LETTER KPAH;Lo;0;L;;;;;N;;;;;
+16AD9;BASSA VAH LETTER JO;Lo;0;L;;;;;N;;;;;
+16ADA;BASSA VAH LETTER HWAH;Lo;0;L;;;;;N;;;;;
+16ADB;BASSA VAH LETTER WA;Lo;0;L;;;;;N;;;;;
+16ADC;BASSA VAH LETTER ZO;Lo;0;L;;;;;N;;;;;
+16ADD;BASSA VAH LETTER GBU;Lo;0;L;;;;;N;;;;;
+16ADE;BASSA VAH LETTER DO;Lo;0;L;;;;;N;;;;;
+16ADF;BASSA VAH LETTER CE;Lo;0;L;;;;;N;;;;;
+16AE0;BASSA VAH LETTER UWU;Lo;0;L;;;;;N;;;;;
+16AE1;BASSA VAH LETTER TO;Lo;0;L;;;;;N;;;;;
+16AE2;BASSA VAH LETTER BA;Lo;0;L;;;;;N;;;;;
+16AE3;BASSA VAH LETTER VU;Lo;0;L;;;;;N;;;;;
+16AE4;BASSA VAH LETTER YEIN;Lo;0;L;;;;;N;;;;;
+16AE5;BASSA VAH LETTER PA;Lo;0;L;;;;;N;;;;;
+16AE6;BASSA VAH LETTER WADDA;Lo;0;L;;;;;N;;;;;
+16AE7;BASSA VAH LETTER A;Lo;0;L;;;;;N;;;;;
+16AE8;BASSA VAH LETTER O;Lo;0;L;;;;;N;;;;;
+16AE9;BASSA VAH LETTER OO;Lo;0;L;;;;;N;;;;;
+16AEA;BASSA VAH LETTER U;Lo;0;L;;;;;N;;;;;
+16AEB;BASSA VAH LETTER EE;Lo;0;L;;;;;N;;;;;
+16AEC;BASSA VAH LETTER E;Lo;0;L;;;;;N;;;;;
+16AED;BASSA VAH LETTER I;Lo;0;L;;;;;N;;;;;
+16AF0;BASSA VAH COMBINING HIGH TONE;Mn;1;NSM;;;;;N;;;;;
+16AF1;BASSA VAH COMBINING LOW TONE;Mn;1;NSM;;;;;N;;;;;
+16AF2;BASSA VAH COMBINING MID TONE;Mn;1;NSM;;;;;N;;;;;
+16AF3;BASSA VAH COMBINING LOW-MID TONE;Mn;1;NSM;;;;;N;;;;;
+16AF4;BASSA VAH COMBINING HIGH-LOW TONE;Mn;1;NSM;;;;;N;;;;;
+16AF5;BASSA VAH FULL STOP;Po;0;L;;;;;N;;;;;
+16B00;PAHAWH HMONG VOWEL KEEB;Lo;0;L;;;;;N;;;;;
+16B01;PAHAWH HMONG VOWEL KEEV;Lo;0;L;;;;;N;;;;;
+16B02;PAHAWH HMONG VOWEL KIB;Lo;0;L;;;;;N;;;;;
+16B03;PAHAWH HMONG VOWEL KIV;Lo;0;L;;;;;N;;;;;
+16B04;PAHAWH HMONG VOWEL KAUB;Lo;0;L;;;;;N;;;;;
+16B05;PAHAWH HMONG VOWEL KAUV;Lo;0;L;;;;;N;;;;;
+16B06;PAHAWH HMONG VOWEL KUB;Lo;0;L;;;;;N;;;;;
+16B07;PAHAWH HMONG VOWEL KUV;Lo;0;L;;;;;N;;;;;
+16B08;PAHAWH HMONG VOWEL KEB;Lo;0;L;;;;;N;;;;;
+16B09;PAHAWH HMONG VOWEL KEV;Lo;0;L;;;;;N;;;;;
+16B0A;PAHAWH HMONG VOWEL KAIB;Lo;0;L;;;;;N;;;;;
+16B0B;PAHAWH HMONG VOWEL KAIV;Lo;0;L;;;;;N;;;;;
+16B0C;PAHAWH HMONG VOWEL KOOB;Lo;0;L;;;;;N;;;;;
+16B0D;PAHAWH HMONG VOWEL KOOV;Lo;0;L;;;;;N;;;;;
+16B0E;PAHAWH HMONG VOWEL KAWB;Lo;0;L;;;;;N;;;;;
+16B0F;PAHAWH HMONG VOWEL KAWV;Lo;0;L;;;;;N;;;;;
+16B10;PAHAWH HMONG VOWEL KUAB;Lo;0;L;;;;;N;;;;;
+16B11;PAHAWH HMONG VOWEL KUAV;Lo;0;L;;;;;N;;;;;
+16B12;PAHAWH HMONG VOWEL KOB;Lo;0;L;;;;;N;;;;;
+16B13;PAHAWH HMONG VOWEL KOV;Lo;0;L;;;;;N;;;;;
+16B14;PAHAWH HMONG VOWEL KIAB;Lo;0;L;;;;;N;;;;;
+16B15;PAHAWH HMONG VOWEL KIAV;Lo;0;L;;;;;N;;;;;
+16B16;PAHAWH HMONG VOWEL KAB;Lo;0;L;;;;;N;;;;;
+16B17;PAHAWH HMONG VOWEL KAV;Lo;0;L;;;;;N;;;;;
+16B18;PAHAWH HMONG VOWEL KWB;Lo;0;L;;;;;N;;;;;
+16B19;PAHAWH HMONG VOWEL KWV;Lo;0;L;;;;;N;;;;;
+16B1A;PAHAWH HMONG VOWEL KAAB;Lo;0;L;;;;;N;;;;;
+16B1B;PAHAWH HMONG VOWEL KAAV;Lo;0;L;;;;;N;;;;;
+16B1C;PAHAWH HMONG CONSONANT VAU;Lo;0;L;;;;;N;;;;;
+16B1D;PAHAWH HMONG CONSONANT NTSAU;Lo;0;L;;;;;N;;;;;
+16B1E;PAHAWH HMONG CONSONANT LAU;Lo;0;L;;;;;N;;;;;
+16B1F;PAHAWH HMONG CONSONANT HAU;Lo;0;L;;;;;N;;;;;
+16B20;PAHAWH HMONG CONSONANT NLAU;Lo;0;L;;;;;N;;;;;
+16B21;PAHAWH HMONG CONSONANT RAU;Lo;0;L;;;;;N;;;;;
+16B22;PAHAWH HMONG CONSONANT NKAU;Lo;0;L;;;;;N;;;;;
+16B23;PAHAWH HMONG CONSONANT QHAU;Lo;0;L;;;;;N;;;;;
+16B24;PAHAWH HMONG CONSONANT YAU;Lo;0;L;;;;;N;;;;;
+16B25;PAHAWH HMONG CONSONANT HLAU;Lo;0;L;;;;;N;;;;;
+16B26;PAHAWH HMONG CONSONANT MAU;Lo;0;L;;;;;N;;;;;
+16B27;PAHAWH HMONG CONSONANT CHAU;Lo;0;L;;;;;N;;;;;
+16B28;PAHAWH HMONG CONSONANT NCHAU;Lo;0;L;;;;;N;;;;;
+16B29;PAHAWH HMONG CONSONANT HNAU;Lo;0;L;;;;;N;;;;;
+16B2A;PAHAWH HMONG CONSONANT PLHAU;Lo;0;L;;;;;N;;;;;
+16B2B;PAHAWH HMONG CONSONANT NTHAU;Lo;0;L;;;;;N;;;;;
+16B2C;PAHAWH HMONG CONSONANT NAU;Lo;0;L;;;;;N;;;;;
+16B2D;PAHAWH HMONG CONSONANT AU;Lo;0;L;;;;;N;;;;;
+16B2E;PAHAWH HMONG CONSONANT XAU;Lo;0;L;;;;;N;;;;;
+16B2F;PAHAWH HMONG CONSONANT CAU;Lo;0;L;;;;;N;;;;;
+16B30;PAHAWH HMONG MARK CIM TUB;Mn;230;NSM;;;;;N;;;;;
+16B31;PAHAWH HMONG MARK CIM SO;Mn;230;NSM;;;;;N;;;;;
+16B32;PAHAWH HMONG MARK CIM KES;Mn;230;NSM;;;;;N;;;;;
+16B33;PAHAWH HMONG MARK CIM KHAV;Mn;230;NSM;;;;;N;;;;;
+16B34;PAHAWH HMONG MARK CIM SUAM;Mn;230;NSM;;;;;N;;;;;
+16B35;PAHAWH HMONG MARK CIM HOM;Mn;230;NSM;;;;;N;;;;;
+16B36;PAHAWH HMONG MARK CIM TAUM;Mn;230;NSM;;;;;N;;;;;
+16B37;PAHAWH HMONG SIGN VOS THOM;Po;0;L;;;;;N;;;;;
+16B38;PAHAWH HMONG SIGN VOS TSHAB CEEB;Po;0;L;;;;;N;;;;;
+16B39;PAHAWH HMONG SIGN CIM CHEEM;Po;0;L;;;;;N;;;;;
+16B3A;PAHAWH HMONG SIGN VOS THIAB;Po;0;L;;;;;N;;;;;
+16B3B;PAHAWH HMONG SIGN VOS FEEM;Po;0;L;;;;;N;;;;;
+16B3C;PAHAWH HMONG SIGN XYEEM NTXIV;So;0;L;;;;;N;;;;;
+16B3D;PAHAWH HMONG SIGN XYEEM RHO;So;0;L;;;;;N;;;;;
+16B3E;PAHAWH HMONG SIGN XYEEM TOV;So;0;L;;;;;N;;;;;
+16B3F;PAHAWH HMONG SIGN XYEEM FAIB;So;0;L;;;;;N;;;;;
+16B40;PAHAWH HMONG SIGN VOS SEEV;Lm;0;L;;;;;N;;;;;
+16B41;PAHAWH HMONG SIGN MEEJ SUAB;Lm;0;L;;;;;N;;;;;
+16B42;PAHAWH HMONG SIGN VOS NRUA;Lm;0;L;;;;;N;;;;;
+16B43;PAHAWH HMONG SIGN IB YAM;Lm;0;L;;;;;N;;;;;
+16B44;PAHAWH HMONG SIGN XAUS;Po;0;L;;;;;N;;;;;
+16B45;PAHAWH HMONG SIGN CIM TSOV ROG;So;0;L;;;;;N;;;;;
+16B50;PAHAWH HMONG DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+16B51;PAHAWH HMONG DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+16B52;PAHAWH HMONG DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+16B53;PAHAWH HMONG DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+16B54;PAHAWH HMONG DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+16B55;PAHAWH HMONG DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+16B56;PAHAWH HMONG DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+16B57;PAHAWH HMONG DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+16B58;PAHAWH HMONG DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+16B59;PAHAWH HMONG DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+16B5B;PAHAWH HMONG NUMBER TENS;No;0;L;;;;10;N;;;;;
+16B5C;PAHAWH HMONG NUMBER HUNDREDS;No;0;L;;;;100;N;;;;;
+16B5D;PAHAWH HMONG NUMBER TEN THOUSANDS;No;0;L;;;;10000;N;;;;;
+16B5E;PAHAWH HMONG NUMBER MILLIONS;No;0;L;;;;1000000;N;;;;;
+16B5F;PAHAWH HMONG NUMBER HUNDRED MILLIONS;No;0;L;;;;100000000;N;;;;;
+16B60;PAHAWH HMONG NUMBER TEN BILLIONS;No;0;L;;;;10000000000;N;;;;;
+16B61;PAHAWH HMONG NUMBER TRILLIONS;No;0;L;;;;1000000000000;N;;;;;
+16B63;PAHAWH HMONG SIGN VOS LUB;Lo;0;L;;;;;N;;;;;
+16B64;PAHAWH HMONG SIGN XYOO;Lo;0;L;;;;;N;;;;;
+16B65;PAHAWH HMONG SIGN HLI;Lo;0;L;;;;;N;;;;;
+16B66;PAHAWH HMONG SIGN THIRD-STAGE HLI;Lo;0;L;;;;;N;;;;;
+16B67;PAHAWH HMONG SIGN ZWJ THAJ;Lo;0;L;;;;;N;;;;;
+16B68;PAHAWH HMONG SIGN HNUB;Lo;0;L;;;;;N;;;;;
+16B69;PAHAWH HMONG SIGN NQIG;Lo;0;L;;;;;N;;;;;
+16B6A;PAHAWH HMONG SIGN XIAB;Lo;0;L;;;;;N;;;;;
+16B6B;PAHAWH HMONG SIGN NTUJ;Lo;0;L;;;;;N;;;;;
+16B6C;PAHAWH HMONG SIGN AV;Lo;0;L;;;;;N;;;;;
+16B6D;PAHAWH HMONG SIGN TXHEEJ CEEV;Lo;0;L;;;;;N;;;;;
+16B6E;PAHAWH HMONG SIGN MEEJ TSEEB;Lo;0;L;;;;;N;;;;;
+16B6F;PAHAWH HMONG SIGN TAU;Lo;0;L;;;;;N;;;;;
+16B70;PAHAWH HMONG SIGN LOS;Lo;0;L;;;;;N;;;;;
+16B71;PAHAWH HMONG SIGN MUS;Lo;0;L;;;;;N;;;;;
+16B72;PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG;Lo;0;L;;;;;N;;;;;
+16B73;PAHAWH HMONG SIGN CIM CUAM TSHOOJ;Lo;0;L;;;;;N;;;;;
+16B74;PAHAWH HMONG SIGN CIM TXWV;Lo;0;L;;;;;N;;;;;
+16B75;PAHAWH HMONG SIGN CIM TXWV CHWV;Lo;0;L;;;;;N;;;;;
+16B76;PAHAWH HMONG SIGN CIM PUB DAWB;Lo;0;L;;;;;N;;;;;
+16B77;PAHAWH HMONG SIGN CIM NRES TOS;Lo;0;L;;;;;N;;;;;
+16B7D;PAHAWH HMONG CLAN SIGN TSHEEJ;Lo;0;L;;;;;N;;;;;
+16B7E;PAHAWH HMONG CLAN SIGN YEEG;Lo;0;L;;;;;N;;;;;
+16B7F;PAHAWH HMONG CLAN SIGN LIS;Lo;0;L;;;;;N;;;;;
+16B80;PAHAWH HMONG CLAN SIGN LAUJ;Lo;0;L;;;;;N;;;;;
+16B81;PAHAWH HMONG CLAN SIGN XYOOJ;Lo;0;L;;;;;N;;;;;
+16B82;PAHAWH HMONG CLAN SIGN KOO;Lo;0;L;;;;;N;;;;;
+16B83;PAHAWH HMONG CLAN SIGN HAWJ;Lo;0;L;;;;;N;;;;;
+16B84;PAHAWH HMONG CLAN SIGN MUAS;Lo;0;L;;;;;N;;;;;
+16B85;PAHAWH HMONG CLAN SIGN THOJ;Lo;0;L;;;;;N;;;;;
+16B86;PAHAWH HMONG CLAN SIGN TSAB;Lo;0;L;;;;;N;;;;;
+16B87;PAHAWH HMONG CLAN SIGN PHAB;Lo;0;L;;;;;N;;;;;
+16B88;PAHAWH HMONG CLAN SIGN KHAB;Lo;0;L;;;;;N;;;;;
+16B89;PAHAWH HMONG CLAN SIGN HAM;Lo;0;L;;;;;N;;;;;
+16B8A;PAHAWH HMONG CLAN SIGN VAJ;Lo;0;L;;;;;N;;;;;
+16B8B;PAHAWH HMONG CLAN SIGN FAJ;Lo;0;L;;;;;N;;;;;
+16B8C;PAHAWH HMONG CLAN SIGN YAJ;Lo;0;L;;;;;N;;;;;
+16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;;
+16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;;
+16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;;
+16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;;
+16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;;
+16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;;
+16F03;MIAO LETTER PLA;Lo;0;L;;;;;N;;;;;
+16F04;MIAO LETTER MA;Lo;0;L;;;;;N;;;;;
+16F05;MIAO LETTER MHA;Lo;0;L;;;;;N;;;;;
+16F06;MIAO LETTER ARCHAIC MA;Lo;0;L;;;;;N;;;;;
+16F07;MIAO LETTER FA;Lo;0;L;;;;;N;;;;;
+16F08;MIAO LETTER VA;Lo;0;L;;;;;N;;;;;
+16F09;MIAO LETTER VFA;Lo;0;L;;;;;N;;;;;
+16F0A;MIAO LETTER TA;Lo;0;L;;;;;N;;;;;
+16F0B;MIAO LETTER DA;Lo;0;L;;;;;N;;;;;
+16F0C;MIAO LETTER YI TTA;Lo;0;L;;;;;N;;;;;
+16F0D;MIAO LETTER YI TA;Lo;0;L;;;;;N;;;;;
+16F0E;MIAO LETTER TTA;Lo;0;L;;;;;N;;;;;
+16F0F;MIAO LETTER DDA;Lo;0;L;;;;;N;;;;;
+16F10;MIAO LETTER NA;Lo;0;L;;;;;N;;;;;
+16F11;MIAO LETTER NHA;Lo;0;L;;;;;N;;;;;
+16F12;MIAO LETTER YI NNA;Lo;0;L;;;;;N;;;;;
+16F13;MIAO LETTER ARCHAIC NA;Lo;0;L;;;;;N;;;;;
+16F14;MIAO LETTER NNA;Lo;0;L;;;;;N;;;;;
+16F15;MIAO LETTER NNHA;Lo;0;L;;;;;N;;;;;
+16F16;MIAO LETTER LA;Lo;0;L;;;;;N;;;;;
+16F17;MIAO LETTER LYA;Lo;0;L;;;;;N;;;;;
+16F18;MIAO LETTER LHA;Lo;0;L;;;;;N;;;;;
+16F19;MIAO LETTER LHYA;Lo;0;L;;;;;N;;;;;
+16F1A;MIAO LETTER TLHA;Lo;0;L;;;;;N;;;;;
+16F1B;MIAO LETTER DLHA;Lo;0;L;;;;;N;;;;;
+16F1C;MIAO LETTER TLHYA;Lo;0;L;;;;;N;;;;;
+16F1D;MIAO LETTER DLHYA;Lo;0;L;;;;;N;;;;;
+16F1E;MIAO LETTER KA;Lo;0;L;;;;;N;;;;;
+16F1F;MIAO LETTER GA;Lo;0;L;;;;;N;;;;;
+16F20;MIAO LETTER YI KA;Lo;0;L;;;;;N;;;;;
+16F21;MIAO LETTER QA;Lo;0;L;;;;;N;;;;;
+16F22;MIAO LETTER QGA;Lo;0;L;;;;;N;;;;;
+16F23;MIAO LETTER NGA;Lo;0;L;;;;;N;;;;;
+16F24;MIAO LETTER NGHA;Lo;0;L;;;;;N;;;;;
+16F25;MIAO LETTER ARCHAIC NGA;Lo;0;L;;;;;N;;;;;
+16F26;MIAO LETTER HA;Lo;0;L;;;;;N;;;;;
+16F27;MIAO LETTER XA;Lo;0;L;;;;;N;;;;;
+16F28;MIAO LETTER GHA;Lo;0;L;;;;;N;;;;;
+16F29;MIAO LETTER GHHA;Lo;0;L;;;;;N;;;;;
+16F2A;MIAO LETTER TSSA;Lo;0;L;;;;;N;;;;;
+16F2B;MIAO LETTER DZZA;Lo;0;L;;;;;N;;;;;
+16F2C;MIAO LETTER NYA;Lo;0;L;;;;;N;;;;;
+16F2D;MIAO LETTER NYHA;Lo;0;L;;;;;N;;;;;
+16F2E;MIAO LETTER TSHA;Lo;0;L;;;;;N;;;;;
+16F2F;MIAO LETTER DZHA;Lo;0;L;;;;;N;;;;;
+16F30;MIAO LETTER YI TSHA;Lo;0;L;;;;;N;;;;;
+16F31;MIAO LETTER YI DZHA;Lo;0;L;;;;;N;;;;;
+16F32;MIAO LETTER REFORMED TSHA;Lo;0;L;;;;;N;;;;;
+16F33;MIAO LETTER SHA;Lo;0;L;;;;;N;;;;;
+16F34;MIAO LETTER SSA;Lo;0;L;;;;;N;;;;;
+16F35;MIAO LETTER ZHA;Lo;0;L;;;;;N;;;;;
+16F36;MIAO LETTER ZSHA;Lo;0;L;;;;;N;;;;;
+16F37;MIAO LETTER TSA;Lo;0;L;;;;;N;;;;;
+16F38;MIAO LETTER DZA;Lo;0;L;;;;;N;;;;;
+16F39;MIAO LETTER YI TSA;Lo;0;L;;;;;N;;;;;
+16F3A;MIAO LETTER SA;Lo;0;L;;;;;N;;;;;
+16F3B;MIAO LETTER ZA;Lo;0;L;;;;;N;;;;;
+16F3C;MIAO LETTER ZSA;Lo;0;L;;;;;N;;;;;
+16F3D;MIAO LETTER ZZA;Lo;0;L;;;;;N;;;;;
+16F3E;MIAO LETTER ZZSA;Lo;0;L;;;;;N;;;;;
+16F3F;MIAO LETTER ARCHAIC ZZA;Lo;0;L;;;;;N;;;;;
+16F40;MIAO LETTER ZZYA;Lo;0;L;;;;;N;;;;;
+16F41;MIAO LETTER ZZSYA;Lo;0;L;;;;;N;;;;;
+16F42;MIAO LETTER WA;Lo;0;L;;;;;N;;;;;
+16F43;MIAO LETTER AH;Lo;0;L;;;;;N;;;;;
+16F44;MIAO LETTER HHA;Lo;0;L;;;;;N;;;;;
+16F50;MIAO LETTER NASALIZATION;Lo;0;L;;;;;N;;;;;
+16F51;MIAO SIGN ASPIRATION;Mc;0;L;;;;;N;;;;;
+16F52;MIAO SIGN REFORMED VOICING;Mc;0;L;;;;;N;;;;;
+16F53;MIAO SIGN REFORMED ASPIRATION;Mc;0;L;;;;;N;;;;;
+16F54;MIAO VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+16F55;MIAO VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+16F56;MIAO VOWEL SIGN AHH;Mc;0;L;;;;;N;;;;;
+16F57;MIAO VOWEL SIGN AN;Mc;0;L;;;;;N;;;;;
+16F58;MIAO VOWEL SIGN ANG;Mc;0;L;;;;;N;;;;;
+16F59;MIAO VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+16F5A;MIAO VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+16F5B;MIAO VOWEL SIGN WO;Mc;0;L;;;;;N;;;;;
+16F5C;MIAO VOWEL SIGN W;Mc;0;L;;;;;N;;;;;
+16F5D;MIAO VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+16F5E;MIAO VOWEL SIGN EN;Mc;0;L;;;;;N;;;;;
+16F5F;MIAO VOWEL SIGN ENG;Mc;0;L;;;;;N;;;;;
+16F60;MIAO VOWEL SIGN OEY;Mc;0;L;;;;;N;;;;;
+16F61;MIAO VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+16F62;MIAO VOWEL SIGN IA;Mc;0;L;;;;;N;;;;;
+16F63;MIAO VOWEL SIGN IAN;Mc;0;L;;;;;N;;;;;
+16F64;MIAO VOWEL SIGN IANG;Mc;0;L;;;;;N;;;;;
+16F65;MIAO VOWEL SIGN IO;Mc;0;L;;;;;N;;;;;
+16F66;MIAO VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;
+16F67;MIAO VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+16F68;MIAO VOWEL SIGN IU;Mc;0;L;;;;;N;;;;;
+16F69;MIAO VOWEL SIGN ING;Mc;0;L;;;;;N;;;;;
+16F6A;MIAO VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+16F6B;MIAO VOWEL SIGN UA;Mc;0;L;;;;;N;;;;;
+16F6C;MIAO VOWEL SIGN UAN;Mc;0;L;;;;;N;;;;;
+16F6D;MIAO VOWEL SIGN UANG;Mc;0;L;;;;;N;;;;;
+16F6E;MIAO VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+16F6F;MIAO VOWEL SIGN UEI;Mc;0;L;;;;;N;;;;;
+16F70;MIAO VOWEL SIGN UNG;Mc;0;L;;;;;N;;;;;
+16F71;MIAO VOWEL SIGN Y;Mc;0;L;;;;;N;;;;;
+16F72;MIAO VOWEL SIGN YI;Mc;0;L;;;;;N;;;;;
+16F73;MIAO VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+16F74;MIAO VOWEL SIGN AEE;Mc;0;L;;;;;N;;;;;
+16F75;MIAO VOWEL SIGN ERR;Mc;0;L;;;;;N;;;;;
+16F76;MIAO VOWEL SIGN ROUNDED ERR;Mc;0;L;;;;;N;;;;;
+16F77;MIAO VOWEL SIGN ER;Mc;0;L;;;;;N;;;;;
+16F78;MIAO VOWEL SIGN ROUNDED ER;Mc;0;L;;;;;N;;;;;
+16F79;MIAO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+16F7A;MIAO VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;
+16F7B;MIAO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+16F7C;MIAO VOWEL SIGN OU;Mc;0;L;;;;;N;;;;;
+16F7D;MIAO VOWEL SIGN N;Mc;0;L;;;;;N;;;;;
+16F7E;MIAO VOWEL SIGN NG;Mc;0;L;;;;;N;;;;;
+16F8F;MIAO TONE RIGHT;Mn;0;NSM;;;;;N;;;;;
+16F90;MIAO TONE TOP RIGHT;Mn;0;NSM;;;;;N;;;;;
+16F91;MIAO TONE ABOVE;Mn;0;NSM;;;;;N;;;;;
+16F92;MIAO TONE BELOW;Mn;0;NSM;;;;;N;;;;;
+16F93;MIAO LETTER TONE-2;Lm;0;L;;;;;N;;;;;
+16F94;MIAO LETTER TONE-3;Lm;0;L;;;;;N;;;;;
+16F95;MIAO LETTER TONE-4;Lm;0;L;;;;;N;;;;;
+16F96;MIAO LETTER TONE-5;Lm;0;L;;;;;N;;;;;
+16F97;MIAO LETTER TONE-6;Lm;0;L;;;;;N;;;;;
+16F98;MIAO LETTER TONE-7;Lm;0;L;;;;;N;;;;;
+16F99;MIAO LETTER TONE-8;Lm;0;L;;;;;N;;;;;
+16F9A;MIAO LETTER REFORMED TONE-1;Lm;0;L;;;;;N;;;;;
+16F9B;MIAO LETTER REFORMED TONE-2;Lm;0;L;;;;;N;;;;;
+16F9C;MIAO LETTER REFORMED TONE-4;Lm;0;L;;;;;N;;;;;
+16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;;
+16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;;
+16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;;
+16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;;
+17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;;
+187EC;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;
+18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;;
+18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;;
+18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;;
+18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;;
+18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;;
+18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;;
+18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;;
+18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;;
+18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;;
+1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;;
+1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;;
+1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;;
+1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;;
+1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;;
+1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;;
+18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;;
+18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;;
+18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;;
+18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;;
+18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;;
+18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;;
+18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;;
+18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;;
+18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;;
+18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;;
+1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;;
+1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;;
+1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;;
+1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;;
+1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;;
+1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;;
+18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;;
+18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;;
+18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;;
+18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;;
+18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;;
+18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;;
+18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;;
+18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;;
+18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;;
+18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;;
+1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;;
+1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;;
+1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;;
+1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;;
+1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;;
+1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;;
+18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;;
+18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;;
+18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;;
+18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;;
+18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;;
+18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;;
+18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;;
+18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;;
+18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;;
+18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;;
+1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;;
+1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;;
+1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;;
+1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;;
+1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;;
+1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;;
+18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;;
+18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;;
+18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;;
+18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;;
+18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;;
+18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;;
+18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;;
+18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;;
+18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;;
+18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;;
+1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;;
+1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;;
+1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;;
+1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;;
+1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;;
+1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;;
+18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;;
+18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;;
+18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;;
+18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;;
+18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;;
+18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;;
+18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;;
+18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;;
+18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;;
+18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;;
+1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;;
+1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;;
+1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;;
+1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;;
+1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;;
+1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;;
+18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;;
+18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;;
+18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;;
+18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;;
+18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;;
+18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;;
+18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;;
+18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;;
+18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;;
+18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;;
+1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;;
+1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;;
+1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;;
+1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;;
+1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;;
+1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;;
+18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;;
+18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;;
+18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;;
+18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;;
+18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;;
+18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;;
+18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;;
+18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;;
+18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;;
+18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;;
+1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;;
+1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;;
+1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;;
+1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;;
+1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;;
+1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;;
+18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;;
+18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;;
+18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;;
+18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;;
+18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;;
+18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;;
+18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;;
+18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;;
+18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;;
+18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;;
+1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;;
+1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;;
+1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;;
+1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;;
+1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;;
+1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;;
+18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;;
+18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;;
+18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;;
+18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;;
+18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;;
+18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;;
+18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;;
+18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;;
+18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;;
+18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;;
+1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;;
+1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;;
+1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;;
+1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;;
+1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;;
+1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;;
+188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;;
+188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;;
+188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;;
+188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;;
+188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;;
+188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;;
+188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;;
+188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;;
+188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;;
+188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;;
+188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;;
+188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;;
+188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;;
+188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;;
+188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;;
+188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;;
+188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;;
+188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;;
+188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;;
+188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;;
+188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;;
+188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;;
+188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;;
+188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;;
+188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;;
+188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;;
+188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;;
+188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;;
+188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;;
+188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;;
+188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;;
+188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;;
+188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;;
+188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;;
+188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;;
+188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;;
+188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;;
+188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;;
+188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;;
+188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;;
+188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;;
+188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;;
+188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;;
+188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;;
+188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;;
+188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;;
+188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;;
+188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;;
+188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;;
+188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;;
+188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;;
+188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;;
+188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;;
+188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;;
+188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;;
+188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;;
+188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;;
+188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;;
+188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;;
+188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;;
+188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;;
+188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;;
+188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;;
+188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;;
+188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;;
+188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;;
+188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;;
+188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;;
+188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;;
+188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;;
+188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;;
+188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;;
+188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;;
+188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;;
+188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;;
+188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;;
+188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;;
+188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;;
+188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;;
+188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;;
+188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;;
+188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;;
+188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;;
+188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;;
+188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;;
+188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;;
+188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;;
+188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;;
+188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;;
+188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;;
+188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;;
+188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;;
+188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;;
+188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;;
+188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;;
+188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;;
+18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;;
+18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;;
+18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;;
+18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;;
+18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;;
+18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;;
+18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;;
+18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;;
+18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;;
+18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;;
+1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;;
+1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;;
+1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;;
+1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;;
+1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;;
+1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;;
+18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;;
+18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;;
+18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;;
+18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;;
+18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;;
+18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;;
+18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;;
+18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;;
+18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;;
+18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;;
+1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;;
+1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;;
+1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;;
+1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;;
+1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;;
+1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;;
+18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;;
+18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;;
+18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;;
+18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;;
+18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;;
+18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;;
+18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;;
+18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;;
+18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;;
+18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;;
+1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;;
+1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;;
+1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;;
+1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;;
+1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;;
+1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;;
+18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;;
+18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;;
+18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;;
+18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;;
+18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;;
+18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;;
+18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;;
+18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;;
+18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;;
+18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;;
+1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;;
+1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;;
+1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;;
+1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;;
+1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;;
+1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;;
+18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;;
+18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;;
+18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;;
+18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;;
+18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;;
+18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;;
+18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;;
+18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;;
+18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;;
+18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;;
+1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;;
+1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;;
+1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;;
+1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;;
+1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;;
+1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;;
+18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;;
+18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;;
+18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;;
+18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;;
+18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;;
+18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;;
+18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;;
+18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;;
+18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;;
+18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;;
+1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;;
+1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;;
+1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;;
+1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;;
+1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;;
+1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;;
+18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;;
+18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;;
+18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;;
+18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;;
+18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;;
+18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;;
+18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;;
+18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;;
+18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;;
+18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;;
+1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;;
+1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;;
+1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;;
+1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;;
+1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;;
+1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;;
+18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;;
+18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;;
+18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;;
+18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;;
+18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;;
+18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;;
+18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;;
+18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;;
+18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;;
+18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;;
+1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;;
+1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;;
+1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;;
+1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;;
+1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;;
+1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;;
+18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;;
+18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;;
+18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;;
+18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;;
+18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;;
+18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;;
+18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;;
+18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;;
+18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;;
+18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;;
+1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;;
+1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;;
+1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;;
+1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;;
+1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;;
+1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;;
+18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;;
+18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;;
+18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;;
+18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;;
+18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;;
+18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;;
+18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;;
+18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;;
+18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;;
+18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;;
+1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;;
+1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;;
+1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;;
+1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;;
+1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;;
+1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;;
+189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;;
+189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;;
+189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;;
+189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;;
+189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;;
+189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;;
+189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;;
+189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;;
+189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;;
+189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;;
+189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;;
+189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;;
+189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;;
+189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;;
+189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;;
+189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;;
+189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;;
+189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;;
+189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;;
+189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;;
+189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;;
+189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;;
+189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;;
+189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;;
+189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;;
+189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;;
+189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;;
+189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;;
+189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;;
+189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;;
+189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;;
+189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;;
+189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;;
+189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;;
+189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;;
+189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;;
+189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;;
+189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;;
+189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;;
+189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;;
+189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;;
+189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;;
+189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;;
+189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;;
+189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;;
+189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;;
+189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;;
+189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;;
+189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;;
+189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;;
+189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;;
+189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;;
+189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;;
+189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;;
+189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;;
+189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;;
+189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;;
+189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;;
+189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;;
+189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;;
+189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;;
+189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;;
+189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;;
+189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;;
+189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;;
+189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;;
+189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;;
+189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;;
+189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;;
+189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;;
+189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;;
+189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;;
+189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;;
+189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;;
+189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;;
+189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;;
+189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;;
+189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;;
+189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;;
+189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;;
+189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;;
+189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;;
+189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;;
+189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;;
+189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;;
+189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;;
+189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;;
+189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;;
+189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;;
+189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;;
+189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;;
+189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;;
+189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;;
+189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;;
+189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;;
+189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;;
+18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;;
+18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;;
+18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;;
+18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;;
+18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;;
+18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;;
+18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;;
+18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;;
+18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;;
+18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;;
+18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;;
+18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;;
+18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;;
+18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;;
+18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;;
+18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;;
+18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;;
+18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;;
+18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;;
+18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;;
+18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;;
+18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;;
+18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;;
+18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;;
+18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;;
+18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;;
+18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;;
+18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;;
+18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;;
+18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;;
+18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;;
+18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;;
+18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;;
+18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;;
+18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;;
+18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;;
+18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;;
+18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;;
+18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;;
+18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;;
+18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;;
+18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;;
+18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;;
+18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;;
+18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;;
+18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;;
+18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;;
+18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;;
+18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;;
+18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;;
+18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;;
+18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;;
+18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;;
+18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;;
+18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;;
+18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;;
+18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;;
+18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;;
+18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;;
+18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;;
+18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;;
+18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;;
+18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;;
+18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;;
+18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;;
+18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;;
+18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;;
+18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;;
+18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;;
+18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;;
+18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;;
+18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;;
+18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;;
+18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;;
+18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;;
+18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;;
+18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;;
+18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;;
+18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;;
+18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;;
+18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;;
+18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;;
+18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;;
+18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;;
+18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;;
+18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;;
+18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;;
+18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;;
+18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;;
+18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;;
+18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;;
+18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;;
+18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;;
+18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;;
+18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;;
+18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;;
+18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;;
+18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;;
+18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;;
+18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;;
+18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;;
+18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;;
+18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;;
+18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;;
+18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;;
+18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;;
+18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;;
+18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;;
+18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;;
+18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;;
+18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;;
+18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;;
+18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;;
+18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;;
+18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;;
+18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;;
+18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;;
+18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;;
+18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;;
+18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;;
+18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;;
+18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;;
+18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;;
+18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;;
+18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;;
+18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;;
+18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;;
+18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;;
+18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;;
+18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;;
+18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;;
+18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;;
+18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;;
+18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;;
+18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;;
+18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;;
+18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;;
+18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;;
+18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;;
+18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;;
+18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;;
+18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;;
+18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;;
+18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;;
+18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;;
+18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;;
+18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;;
+18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;;
+18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;;
+18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;;
+18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;;
+18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;;
+18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;;
+18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;;
+18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;;
+18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;;
+18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;;
+18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;;
+18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;;
+18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;;
+18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;;
+18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;;
+18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;;
+18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;;
+18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;;
+18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;;
+18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;;
+18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;;
+18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;;
+18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;;
+18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;;
+18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;;
+18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;;
+18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;;
+18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;;
+18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;;
+18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;;
+18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;;
+18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;;
+18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;;
+18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;;
+18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;;
+18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;;
+18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;;
+18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;;
+18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;;
+18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;;
+18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;;
+18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;;
+18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;;
+18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;;
+18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;;
+18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;;
+18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;;
+18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;;
+18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;;
+18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;;
+18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;;
+18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;;
+18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;;
+18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;;
+18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;;
+18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;;
+18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;;
+18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;;
+18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;;
+18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;;
+18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;;
+18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;;
+18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;;
+18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;;
+18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;;
+18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;;
+18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;;
+18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;;
+18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;;
+18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;;
+18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;;
+18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;;
+18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;;
+18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;;
+18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;;
+18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;;
+18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;;
+18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;;
+18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;;
+18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;;
+18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;;
+18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;;
+18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;;
+18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;;
+18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;;
+18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;;
+18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;;
+18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;;
+18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;;
+18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;;
+18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;;
+18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;;
+18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;;
+18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;;
+18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;;
+18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;;
+1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;;
+1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;;
+1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;;
+1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;;
+1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;;
+1BC03;DUPLOYAN LETTER T;Lo;0;L;;;;;N;;;;;
+1BC04;DUPLOYAN LETTER F;Lo;0;L;;;;;N;;;;;
+1BC05;DUPLOYAN LETTER K;Lo;0;L;;;;;N;;;;;
+1BC06;DUPLOYAN LETTER L;Lo;0;L;;;;;N;;;;;
+1BC07;DUPLOYAN LETTER B;Lo;0;L;;;;;N;;;;;
+1BC08;DUPLOYAN LETTER D;Lo;0;L;;;;;N;;;;;
+1BC09;DUPLOYAN LETTER V;Lo;0;L;;;;;N;;;;;
+1BC0A;DUPLOYAN LETTER G;Lo;0;L;;;;;N;;;;;
+1BC0B;DUPLOYAN LETTER R;Lo;0;L;;;;;N;;;;;
+1BC0C;DUPLOYAN LETTER P N;Lo;0;L;;;;;N;;;;;
+1BC0D;DUPLOYAN LETTER D S;Lo;0;L;;;;;N;;;;;
+1BC0E;DUPLOYAN LETTER F N;Lo;0;L;;;;;N;;;;;
+1BC0F;DUPLOYAN LETTER K M;Lo;0;L;;;;;N;;;;;
+1BC10;DUPLOYAN LETTER R S;Lo;0;L;;;;;N;;;;;
+1BC11;DUPLOYAN LETTER TH;Lo;0;L;;;;;N;;;;;
+1BC12;DUPLOYAN LETTER SLOAN DH;Lo;0;L;;;;;N;;;;;
+1BC13;DUPLOYAN LETTER DH;Lo;0;L;;;;;N;;;;;
+1BC14;DUPLOYAN LETTER KK;Lo;0;L;;;;;N;;;;;
+1BC15;DUPLOYAN LETTER SLOAN J;Lo;0;L;;;;;N;;;;;
+1BC16;DUPLOYAN LETTER HL;Lo;0;L;;;;;N;;;;;
+1BC17;DUPLOYAN LETTER LH;Lo;0;L;;;;;N;;;;;
+1BC18;DUPLOYAN LETTER RH;Lo;0;L;;;;;N;;;;;
+1BC19;DUPLOYAN LETTER M;Lo;0;L;;;;;N;;;;;
+1BC1A;DUPLOYAN LETTER N;Lo;0;L;;;;;N;;;;;
+1BC1B;DUPLOYAN LETTER J;Lo;0;L;;;;;N;;;;;
+1BC1C;DUPLOYAN LETTER S;Lo;0;L;;;;;N;;;;;
+1BC1D;DUPLOYAN LETTER M N;Lo;0;L;;;;;N;;;;;
+1BC1E;DUPLOYAN LETTER N M;Lo;0;L;;;;;N;;;;;
+1BC1F;DUPLOYAN LETTER J M;Lo;0;L;;;;;N;;;;;
+1BC20;DUPLOYAN LETTER S J;Lo;0;L;;;;;N;;;;;
+1BC21;DUPLOYAN LETTER M WITH DOT;Lo;0;L;;;;;N;;;;;
+1BC22;DUPLOYAN LETTER N WITH DOT;Lo;0;L;;;;;N;;;;;
+1BC23;DUPLOYAN LETTER J WITH DOT;Lo;0;L;;;;;N;;;;;
+1BC24;DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE;Lo;0;L;;;;;N;;;;;
+1BC25;DUPLOYAN LETTER S WITH DOT;Lo;0;L;;;;;N;;;;;
+1BC26;DUPLOYAN LETTER S WITH DOT BELOW;Lo;0;L;;;;;N;;;;;
+1BC27;DUPLOYAN LETTER M S;Lo;0;L;;;;;N;;;;;
+1BC28;DUPLOYAN LETTER N S;Lo;0;L;;;;;N;;;;;
+1BC29;DUPLOYAN LETTER J S;Lo;0;L;;;;;N;;;;;
+1BC2A;DUPLOYAN LETTER S S;Lo;0;L;;;;;N;;;;;
+1BC2B;DUPLOYAN LETTER M N S;Lo;0;L;;;;;N;;;;;
+1BC2C;DUPLOYAN LETTER N M S;Lo;0;L;;;;;N;;;;;
+1BC2D;DUPLOYAN LETTER J M S;Lo;0;L;;;;;N;;;;;
+1BC2E;DUPLOYAN LETTER S J S;Lo;0;L;;;;;N;;;;;
+1BC2F;DUPLOYAN LETTER J S WITH DOT;Lo;0;L;;;;;N;;;;;
+1BC30;DUPLOYAN LETTER J N;Lo;0;L;;;;;N;;;;;
+1BC31;DUPLOYAN LETTER J N S;Lo;0;L;;;;;N;;;;;
+1BC32;DUPLOYAN LETTER S T;Lo;0;L;;;;;N;;;;;
+1BC33;DUPLOYAN LETTER S T R;Lo;0;L;;;;;N;;;;;
+1BC34;DUPLOYAN LETTER S P;Lo;0;L;;;;;N;;;;;
+1BC35;DUPLOYAN LETTER S P R;Lo;0;L;;;;;N;;;;;
+1BC36;DUPLOYAN LETTER T S;Lo;0;L;;;;;N;;;;;
+1BC37;DUPLOYAN LETTER T R S;Lo;0;L;;;;;N;;;;;
+1BC38;DUPLOYAN LETTER W;Lo;0;L;;;;;N;;;;;
+1BC39;DUPLOYAN LETTER WH;Lo;0;L;;;;;N;;;;;
+1BC3A;DUPLOYAN LETTER W R;Lo;0;L;;;;;N;;;;;
+1BC3B;DUPLOYAN LETTER S N;Lo;0;L;;;;;N;;;;;
+1BC3C;DUPLOYAN LETTER S M;Lo;0;L;;;;;N;;;;;
+1BC3D;DUPLOYAN LETTER K R S;Lo;0;L;;;;;N;;;;;
+1BC3E;DUPLOYAN LETTER G R S;Lo;0;L;;;;;N;;;;;
+1BC3F;DUPLOYAN LETTER S K;Lo;0;L;;;;;N;;;;;
+1BC40;DUPLOYAN LETTER S K R;Lo;0;L;;;;;N;;;;;
+1BC41;DUPLOYAN LETTER A;Lo;0;L;;;;;N;;;;;
+1BC42;DUPLOYAN LETTER SLOAN OW;Lo;0;L;;;;;N;;;;;
+1BC43;DUPLOYAN LETTER OA;Lo;0;L;;;;;N;;;;;
+1BC44;DUPLOYAN LETTER O;Lo;0;L;;;;;N;;;;;
+1BC45;DUPLOYAN LETTER AOU;Lo;0;L;;;;;N;;;;;
+1BC46;DUPLOYAN LETTER I;Lo;0;L;;;;;N;;;;;
+1BC47;DUPLOYAN LETTER E;Lo;0;L;;;;;N;;;;;
+1BC48;DUPLOYAN LETTER IE;Lo;0;L;;;;;N;;;;;
+1BC49;DUPLOYAN LETTER SHORT I;Lo;0;L;;;;;N;;;;;
+1BC4A;DUPLOYAN LETTER UI;Lo;0;L;;;;;N;;;;;
+1BC4B;DUPLOYAN LETTER EE;Lo;0;L;;;;;N;;;;;
+1BC4C;DUPLOYAN LETTER SLOAN EH;Lo;0;L;;;;;N;;;;;
+1BC4D;DUPLOYAN LETTER ROMANIAN I;Lo;0;L;;;;;N;;;;;
+1BC4E;DUPLOYAN LETTER SLOAN EE;Lo;0;L;;;;;N;;;;;
+1BC4F;DUPLOYAN LETTER LONG I;Lo;0;L;;;;;N;;;;;
+1BC50;DUPLOYAN LETTER YE;Lo;0;L;;;;;N;;;;;
+1BC51;DUPLOYAN LETTER U;Lo;0;L;;;;;N;;;;;
+1BC52;DUPLOYAN LETTER EU;Lo;0;L;;;;;N;;;;;
+1BC53;DUPLOYAN LETTER XW;Lo;0;L;;;;;N;;;;;
+1BC54;DUPLOYAN LETTER U N;Lo;0;L;;;;;N;;;;;
+1BC55;DUPLOYAN LETTER LONG U;Lo;0;L;;;;;N;;;;;
+1BC56;DUPLOYAN LETTER ROMANIAN U;Lo;0;L;;;;;N;;;;;
+1BC57;DUPLOYAN LETTER UH;Lo;0;L;;;;;N;;;;;
+1BC58;DUPLOYAN LETTER SLOAN U;Lo;0;L;;;;;N;;;;;
+1BC59;DUPLOYAN LETTER OOH;Lo;0;L;;;;;N;;;;;
+1BC5A;DUPLOYAN LETTER OW;Lo;0;L;;;;;N;;;;;
+1BC5B;DUPLOYAN LETTER OU;Lo;0;L;;;;;N;;;;;
+1BC5C;DUPLOYAN LETTER WA;Lo;0;L;;;;;N;;;;;
+1BC5D;DUPLOYAN LETTER WO;Lo;0;L;;;;;N;;;;;
+1BC5E;DUPLOYAN LETTER WI;Lo;0;L;;;;;N;;;;;
+1BC5F;DUPLOYAN LETTER WEI;Lo;0;L;;;;;N;;;;;
+1BC60;DUPLOYAN LETTER WOW;Lo;0;L;;;;;N;;;;;
+1BC61;DUPLOYAN LETTER NASAL U;Lo;0;L;;;;;N;;;;;
+1BC62;DUPLOYAN LETTER NASAL O;Lo;0;L;;;;;N;;;;;
+1BC63;DUPLOYAN LETTER NASAL I;Lo;0;L;;;;;N;;;;;
+1BC64;DUPLOYAN LETTER NASAL A;Lo;0;L;;;;;N;;;;;
+1BC65;DUPLOYAN LETTER PERNIN AN;Lo;0;L;;;;;N;;;;;
+1BC66;DUPLOYAN LETTER PERNIN AM;Lo;0;L;;;;;N;;;;;
+1BC67;DUPLOYAN LETTER SLOAN EN;Lo;0;L;;;;;N;;;;;
+1BC68;DUPLOYAN LETTER SLOAN AN;Lo;0;L;;;;;N;;;;;
+1BC69;DUPLOYAN LETTER SLOAN ON;Lo;0;L;;;;;N;;;;;
+1BC6A;DUPLOYAN LETTER VOCALIC M;Lo;0;L;;;;;N;;;;;
+1BC70;DUPLOYAN AFFIX LEFT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC71;DUPLOYAN AFFIX MID HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC72;DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC73;DUPLOYAN AFFIX LOW VERTICAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC74;DUPLOYAN AFFIX MID VERTICAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC75;DUPLOYAN AFFIX HIGH VERTICAL SECANT;Lo;0;L;;;;;N;;;;;
+1BC76;DUPLOYAN AFFIX ATTACHED SECANT;Lo;0;L;;;;;N;;;;;
+1BC77;DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT;Lo;0;L;;;;;N;;;;;
+1BC78;DUPLOYAN AFFIX ATTACHED TANGENT;Lo;0;L;;;;;N;;;;;
+1BC79;DUPLOYAN AFFIX ATTACHED TAIL;Lo;0;L;;;;;N;;;;;
+1BC7A;DUPLOYAN AFFIX ATTACHED E HOOK;Lo;0;L;;;;;N;;;;;
+1BC7B;DUPLOYAN AFFIX ATTACHED I HOOK;Lo;0;L;;;;;N;;;;;
+1BC7C;DUPLOYAN AFFIX ATTACHED TANGENT HOOK;Lo;0;L;;;;;N;;;;;
+1BC80;DUPLOYAN AFFIX HIGH ACUTE;Lo;0;L;;;;;N;;;;;
+1BC81;DUPLOYAN AFFIX HIGH TIGHT ACUTE;Lo;0;L;;;;;N;;;;;
+1BC82;DUPLOYAN AFFIX HIGH GRAVE;Lo;0;L;;;;;N;;;;;
+1BC83;DUPLOYAN AFFIX HIGH LONG GRAVE;Lo;0;L;;;;;N;;;;;
+1BC84;DUPLOYAN AFFIX HIGH DOT;Lo;0;L;;;;;N;;;;;
+1BC85;DUPLOYAN AFFIX HIGH CIRCLE;Lo;0;L;;;;;N;;;;;
+1BC86;DUPLOYAN AFFIX HIGH LINE;Lo;0;L;;;;;N;;;;;
+1BC87;DUPLOYAN AFFIX HIGH WAVE;Lo;0;L;;;;;N;;;;;
+1BC88;DUPLOYAN AFFIX HIGH VERTICAL;Lo;0;L;;;;;N;;;;;
+1BC90;DUPLOYAN AFFIX LOW ACUTE;Lo;0;L;;;;;N;;;;;
+1BC91;DUPLOYAN AFFIX LOW TIGHT ACUTE;Lo;0;L;;;;;N;;;;;
+1BC92;DUPLOYAN AFFIX LOW GRAVE;Lo;0;L;;;;;N;;;;;
+1BC93;DUPLOYAN AFFIX LOW LONG GRAVE;Lo;0;L;;;;;N;;;;;
+1BC94;DUPLOYAN AFFIX LOW DOT;Lo;0;L;;;;;N;;;;;
+1BC95;DUPLOYAN AFFIX LOW CIRCLE;Lo;0;L;;;;;N;;;;;
+1BC96;DUPLOYAN AFFIX LOW LINE;Lo;0;L;;;;;N;;;;;
+1BC97;DUPLOYAN AFFIX LOW WAVE;Lo;0;L;;;;;N;;;;;
+1BC98;DUPLOYAN AFFIX LOW VERTICAL;Lo;0;L;;;;;N;;;;;
+1BC99;DUPLOYAN AFFIX LOW ARROW;Lo;0;L;;;;;N;;;;;
+1BC9C;DUPLOYAN SIGN O WITH CROSS;So;0;L;;;;;N;;;;;
+1BC9D;DUPLOYAN THICK LETTER SELECTOR;Mn;0;NSM;;;;;N;;;;;
+1BC9E;DUPLOYAN DOUBLE MARK;Mn;1;NSM;;;;;N;;;;;
+1BC9F;DUPLOYAN PUNCTUATION CHINOOK FULL STOP;Po;0;L;;;;;N;;;;;
+1BCA0;SHORTHAND FORMAT LETTER OVERLAP;Cf;0;BN;;;;;N;;;;;
+1BCA1;SHORTHAND FORMAT CONTINUING OVERLAP;Cf;0;BN;;;;;N;;;;;
+1BCA2;SHORTHAND FORMAT DOWN STEP;Cf;0;BN;;;;;N;;;;;
+1BCA3;SHORTHAND FORMAT UP STEP;Cf;0;BN;;;;;N;;;;;
+1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;;
+1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;;
+1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;;
+1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;;
+1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;;
+1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;;
+1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;;
+1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;;
+1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;;
+1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;;
+1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;;
+1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;;
+1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;;
+1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;;
+1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;;
+1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;;
+1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;;
+1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;;
+1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;;
+1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;;
+1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;;
+1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;;
+1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;;
+1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;;
+1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;;
+1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;;
+1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;;
+1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;;
+1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;;
+1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;;
+1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;;
+1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;;
+1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;;
+1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;;
+1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;;
+1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;;
+1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;;
+1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;;
+1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;;
+1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;;
+1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;;
+1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;;
+1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;;
+1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;;
+1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;;
+1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;;
+1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;;
+1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;;
+1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;;
+1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;;
+1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;;
+1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;;
+1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;;
+1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;;
+1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;;
+1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;;
+1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;;
+1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;;
+1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;;
+1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;;
+1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;;
+1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;;
+1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;;
+1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;;
+1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;;
+1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;;
+1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;;
+1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;;
+1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;;
+1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;;
+1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;;
+1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;;
+1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;;
+1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;;
+1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;;
+1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;;
+1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;;
+1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;;
+1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;;
+1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;;
+1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;;
+1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;;
+1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;;
+1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;;
+1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;;
+1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;;
+1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;;
+1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;;
+1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;;
+1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;;
+1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;;
+1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;;
+1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;;
+1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;;
+1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;;
+1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;;
+1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;;
+1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;;
+1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;;
+1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;;
+1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;;
+1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;;
+1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;;
+1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;;
+1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;;
+1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;;
+1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;;
+1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;;
+1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;;
+1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;;
+1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;;
+1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;;
+1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;;
+1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;;
+1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;;
+1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;;
+1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;;
+1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;;
+1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;;
+1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;;
+1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;;
+1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;;
+1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;;
+1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;;
+1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;;
+1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;;
+1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;;
+1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;;
+1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;;
+1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;;
+1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;;
+1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;;
+1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;;
+1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;;
+1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;;
+1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;;
+1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;;
+1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;;
+1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;;
+1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;;
+1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;;
+1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;;
+1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;;
+1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;;
+1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;;
+1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;;
+1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;;
+1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;;
+1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;;
+1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;;
+1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;;
+1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;;
+1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;;
+1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;;
+1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;;
+1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;;
+1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;;
+1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;;
+1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;;
+1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;;
+1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;;
+1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;;
+1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;;
+1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;;
+1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;;
+1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;;
+1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;;
+1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;;
+1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;;
+1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;;
+1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;;
+1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;;
+1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;;
+1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;;
+1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;;
+1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;;
+1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;;
+1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;;
+1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;;
+1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;;
+1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;;
+1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;;
+1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;;
+1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;;
+1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;;
+1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;;
+1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;;
+1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;;
+1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;;
+1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;;
+1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;;
+1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;;
+1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;;
+1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;;
+1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;;
+1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;;
+1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;;
+1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;;
+1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;;
+1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;;
+1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;;
+1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;;
+1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;;
+1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;;
+1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;;
+1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;;
+1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;;
+1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;;
+1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;;
+1D129;MUSICAL SYMBOL MULTIPLE MEASURE REST;So;0;L;;;;;N;;;;;
+1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;;
+1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;;
+1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;;
+1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;;
+1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;;
+1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;;
+1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;;
+1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;;
+1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;;
+1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;;
+1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;;
+1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;;
+1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;;
+1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;;
+1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;;
+1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;;
+1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;;
+1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;;
+1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;;
+1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;;
+1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;;
+1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;;
+1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;;
+1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;;
+1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;;
+1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;;
+1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;;
+1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;;
+1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;;
+1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;;
+1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;;
+1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;;
+1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;;
+1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;;
+1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;;
+1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;;
+1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;;
+1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;;
+1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;;
+1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;;
+1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;;
+1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;;
+1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;;
+1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;;
+1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;;
+1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;;
+1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;;
+1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;;
+1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;;
+1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;;
+1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;;
+1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;;
+1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;;
+1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;;
+1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;;
+1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;;
+1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;;
+1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;;
+1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;;
+1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;;
+1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;;
+1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;;
+1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;;
+1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;;
+1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;;
+1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;;
+1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;;
+1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;;
+1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;;
+1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;;
+1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;;
+1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;;
+1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;;
+1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;;
+1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;;
+1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;;
+1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;;
+1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;;
+1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;;
+1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;;
+1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;;
+1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;;
+1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;;
+1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;;
+1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;;
+1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;;
+1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;;
+1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;;
+1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;;
+1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;;
+1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;;
+1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;;
+1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;;
+1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;;
+1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;;
+1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;;
+1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;;
+1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;;
+1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;;
+1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;;
+1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;;
+1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;;
+1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;;
+1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;;
+1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;;
+1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;;
+1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;;
+1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;;
+1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;;
+1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;;
+1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;;
+1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;;
+1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;;
+1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;;
+1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;;
+1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;;
+1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;;
+1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;;
+1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;;
+1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;;
+1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;;
+1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;;
+1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;;
+1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;;
+1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;;
+1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;;
+1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;;
+1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;;
+1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;;
+1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;;
+1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;;
+1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;;
+1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;;
+1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;;
+1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;;
+1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;;
+1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;;
+1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;;
+1D1DE;MUSICAL SYMBOL KIEVAN C CLEF;So;0;L;;;;;N;;;;;
+1D1DF;MUSICAL SYMBOL KIEVAN END OF PIECE;So;0;L;;;;;N;;;;;
+1D1E0;MUSICAL SYMBOL KIEVAN FINAL NOTE;So;0;L;;;;;N;;;;;
+1D1E1;MUSICAL SYMBOL KIEVAN RECITATIVE MARK;So;0;L;;;;;N;;;;;
+1D1E2;MUSICAL SYMBOL KIEVAN WHOLE NOTE;So;0;L;;;;;N;;;;;
+1D1E3;MUSICAL SYMBOL KIEVAN HALF NOTE;So;0;L;;;;;N;;;;;
+1D1E4;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN;So;0;L;;;;;N;;;;;
+1D1E5;MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP;So;0;L;;;;;N;;;;;
+1D1E6;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN;So;0;L;;;;;N;;;;;
+1D1E7;MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP;So;0;L;;;;;N;;;;;
+1D1E8;MUSICAL SYMBOL KIEVAN FLAT SIGN;So;0;L;;;;;N;;;;;
+1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;;
+1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;;
+1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;;
+1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;;
+1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;;
+1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;;
+1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;;
+1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;;
+1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;;
+1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;;
+1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;;
+1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;;
+1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;;
+1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;;
+1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;;
+1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;;
+1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;;
+1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;;
+1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;;
+1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;;
+1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;;
+1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;;
+1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;;
+1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;;
+1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;;
+1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;;
+1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;;
+1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;
+1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;
+1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;
+1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;
+1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;
+1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;;
+1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;;
+1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;;
+1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;;
+1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;;
+1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;;
+1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;;
+1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;;
+1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;;
+1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;;
+1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;;
+1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;;
+1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;;
+1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;;
+1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;;
+1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;;
+1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;;
+1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;;
+1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;;
+1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;;
+1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;;
+1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;;
+1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;;
+1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;;
+1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;;
+1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;;
+1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;;
+1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;;
+1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;;
+1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;;
+1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;;
+1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;;
+1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;;
+1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;;
+1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;;
+1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;;
+1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;;
+1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;;
+1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;;
+1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;;
+1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;;
+1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;;
+1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;;
+1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;;
+1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;;
+1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;;
+1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;;
+1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;;
+1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;;
+1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;;
+1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;;
+1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;;
+1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;;
+1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;;
+1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;;
+1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;;
+1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;;
+1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;;
+1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;;
+1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;;
+1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;;
+1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;;
+1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;;
+1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;;
+1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;;
+1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;;
+1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;;
+1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;;
+1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;;
+1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;;
+1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;;
+1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;;
+1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;;
+1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;;
+1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;;
+1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;;
+1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;;
+1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;;
+1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;;
+1D360;COUNTING ROD UNIT DIGIT ONE;No;0;L;;;;1;N;;;;;
+1D361;COUNTING ROD UNIT DIGIT TWO;No;0;L;;;;2;N;;;;;
+1D362;COUNTING ROD UNIT DIGIT THREE;No;0;L;;;;3;N;;;;;
+1D363;COUNTING ROD UNIT DIGIT FOUR;No;0;L;;;;4;N;;;;;
+1D364;COUNTING ROD UNIT DIGIT FIVE;No;0;L;;;;5;N;;;;;
+1D365;COUNTING ROD UNIT DIGIT SIX;No;0;L;;;;6;N;;;;;
+1D366;COUNTING ROD UNIT DIGIT SEVEN;No;0;L;;;;7;N;;;;;
+1D367;COUNTING ROD UNIT DIGIT EIGHT;No;0;L;;;;8;N;;;;;
+1D368;COUNTING ROD UNIT DIGIT NINE;No;0;L;;;;9;N;;;;;
+1D369;COUNTING ROD TENS DIGIT ONE;No;0;L;;;;10;N;;;;;
+1D36A;COUNTING ROD TENS DIGIT TWO;No;0;L;;;;20;N;;;;;
+1D36B;COUNTING ROD TENS DIGIT THREE;No;0;L;;;;30;N;;;;;
+1D36C;COUNTING ROD TENS DIGIT FOUR;No;0;L;;;;40;N;;;;;
+1D36D;COUNTING ROD TENS DIGIT FIVE;No;0;L;;;;50;N;;;;;
+1D36E;COUNTING ROD TENS DIGIT SIX;No;0;L;;;;60;N;;;;;
+1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;;
+1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;;
+1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;;
+1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;;
+1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;;
+1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;
+1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;
+1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;
+1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;
+1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;ON;<font> 2202;;;;Y;;;;;
+1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D7CA;MATHEMATICAL BOLD CAPITAL DIGAMMA;Lu;0;L;<font> 03DC;;;;N;;;;;
+1D7CB;MATHEMATICAL BOLD SMALL DIGAMMA;Ll;0;L;<font> 03DD;;;;N;;;;;
+1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D800;SIGNWRITING HAND-FIST INDEX;So;0;L;;;;;N;;;;;
+1D801;SIGNWRITING HAND-CIRCLE INDEX;So;0;L;;;;;N;;;;;
+1D802;SIGNWRITING HAND-CUP INDEX;So;0;L;;;;;N;;;;;
+1D803;SIGNWRITING HAND-OVAL INDEX;So;0;L;;;;;N;;;;;
+1D804;SIGNWRITING HAND-HINGE INDEX;So;0;L;;;;;N;;;;;
+1D805;SIGNWRITING HAND-ANGLE INDEX;So;0;L;;;;;N;;;;;
+1D806;SIGNWRITING HAND-FIST INDEX BENT;So;0;L;;;;;N;;;;;
+1D807;SIGNWRITING HAND-CIRCLE INDEX BENT;So;0;L;;;;;N;;;;;
+1D808;SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT;So;0;L;;;;;N;;;;;
+1D809;SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE;So;0;L;;;;;N;;;;;
+1D80A;SIGNWRITING HAND-FIST INDEX CUPPED;So;0;L;;;;;N;;;;;
+1D80B;SIGNWRITING HAND-FIST INDEX HINGED;So;0;L;;;;;N;;;;;
+1D80C;SIGNWRITING HAND-FIST INDEX HINGED LOW;So;0;L;;;;;N;;;;;
+1D80D;SIGNWRITING HAND-CIRCLE INDEX HINGE;So;0;L;;;;;N;;;;;
+1D80E;SIGNWRITING HAND-FIST INDEX MIDDLE;So;0;L;;;;;N;;;;;
+1D80F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE;So;0;L;;;;;N;;;;;
+1D810;SIGNWRITING HAND-FIST INDEX MIDDLE BENT;So;0;L;;;;;N;;;;;
+1D811;SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;;
+1D812;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED;So;0;L;;;;;N;;;;;
+1D813;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED;So;0;L;;;;;N;;;;;
+1D814;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP;So;0;L;;;;;N;;;;;
+1D815;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED;So;0;L;;;;;N;;;;;
+1D816;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT;So;0;L;;;;;N;;;;;
+1D817;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT;So;0;L;;;;;N;;;;;
+1D818;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED;So;0;L;;;;;N;;;;;
+1D819;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED;So;0;L;;;;;N;;;;;
+1D81A;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;;
+1D81B;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED;So;0;L;;;;;N;;;;;
+1D81C;SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX;So;0;L;;;;;N;;;;;
+1D81D;SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE;So;0;L;;;;;N;;;;;
+1D81E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;;
+1D81F;SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB;So;0;L;;;;;N;;;;;
+1D820;SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT;So;0;L;;;;;N;;;;;
+1D821;SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT;So;0;L;;;;;N;;;;;
+1D822;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT;So;0;L;;;;;N;;;;;
+1D823;SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE;So;0;L;;;;;N;;;;;
+1D824;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE;So;0;L;;;;;N;;;;;
+1D825;SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED;So;0;L;;;;;N;;;;;
+1D826;SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;;
+1D827;SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D828;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED;So;0;L;;;;;N;;;;;
+1D829;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED;So;0;L;;;;;N;;;;;
+1D82A;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED;So;0;L;;;;;N;;;;;
+1D82B;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED;So;0;L;;;;;N;;;;;
+1D82C;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT;So;0;L;;;;;N;;;;;
+1D82D;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE;So;0;L;;;;;N;;;;;
+1D82E;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;;
+1D82F;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT;So;0;L;;;;;N;;;;;
+1D830;SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP;So;0;L;;;;;N;;;;;
+1D831;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP;So;0;L;;;;;N;;;;;
+1D832;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE;So;0;L;;;;;N;;;;;
+1D833;SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE;So;0;L;;;;;N;;;;;
+1D834;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D835;SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D836;SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP;So;0;L;;;;;N;;;;;
+1D837;SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP;So;0;L;;;;;N;;;;;
+1D838;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP;So;0;L;;;;;N;;;;;
+1D839;SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED;So;0;L;;;;;N;;;;;
+1D83A;SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP;So;0;L;;;;;N;;;;;
+1D83B;SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP;So;0;L;;;;;N;;;;;
+1D83C;SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP;So;0;L;;;;;N;;;;;
+1D83D;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED;So;0;L;;;;;N;;;;;
+1D83E;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT;So;0;L;;;;;N;;;;;
+1D83F;SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED;So;0;L;;;;;N;;;;;
+1D840;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP;So;0;L;;;;;N;;;;;
+1D841;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED;So;0;L;;;;;N;;;;;
+1D842;SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP;So;0;L;;;;;N;;;;;
+1D843;SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED;So;0;L;;;;;N;;;;;
+1D844;SIGNWRITING HAND-FLAT FOUR FINGERS;So;0;L;;;;;N;;;;;
+1D845;SIGNWRITING HAND-FLAT FOUR FINGERS BENT;So;0;L;;;;;N;;;;;
+1D846;SIGNWRITING HAND-FLAT FOUR FINGERS HINGED;So;0;L;;;;;N;;;;;
+1D847;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;
+1D848;SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT;So;0;L;;;;;N;;;;;
+1D849;SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;
+1D84A;SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT;So;0;L;;;;;N;;;;;
+1D84B;SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED;So;0;L;;;;;N;;;;;
+1D84C;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;
+1D84D;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;
+1D84E;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;;
+1D84F;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT;So;0;L;;;;;N;;;;;
+1D850;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;;
+1D851;SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT;So;0;L;;;;;N;;;;;
+1D852;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D853;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;
+1D854;SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;;
+1D855;SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN;So;0;L;;;;;N;;;;;
+1D856;SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD;So;0;L;;;;;N;;;;;
+1D857;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED;So;0;L;;;;;N;;;;;
+1D858;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE;So;0;L;;;;;N;;;;;
+1D859;SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB;So;0;L;;;;;N;;;;;
+1D85A;SIGNWRITING HAND-FLAT;So;0;L;;;;;N;;;;;
+1D85B;SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS;So;0;L;;;;;N;;;;;
+1D85C;SIGNWRITING HAND-FLAT HEEL;So;0;L;;;;;N;;;;;
+1D85D;SIGNWRITING HAND-FLAT THUMB SIDE;So;0;L;;;;;N;;;;;
+1D85E;SIGNWRITING HAND-FLAT HEEL THUMB SIDE;So;0;L;;;;;N;;;;;
+1D85F;SIGNWRITING HAND-FLAT THUMB BENT;So;0;L;;;;;N;;;;;
+1D860;SIGNWRITING HAND-FLAT THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D861;SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE;So;0;L;;;;;N;;;;;
+1D862;SIGNWRITING HAND-FLAT SPLIT CENTRE;So;0;L;;;;;N;;;;;
+1D863;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE;So;0;L;;;;;N;;;;;
+1D864;SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT;So;0;L;;;;;N;;;;;
+1D865;SIGNWRITING HAND-FLAT SPLIT LITTLE;So;0;L;;;;;N;;;;;
+1D866;SIGNWRITING HAND-CLAW;So;0;L;;;;;N;;;;;
+1D867;SIGNWRITING HAND-CLAW THUMB SIDE;So;0;L;;;;;N;;;;;
+1D868;SIGNWRITING HAND-CLAW NO THUMB;So;0;L;;;;;N;;;;;
+1D869;SIGNWRITING HAND-CLAW THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D86A;SIGNWRITING HAND-HOOK CURLICUE;So;0;L;;;;;N;;;;;
+1D86B;SIGNWRITING HAND-HOOK;So;0;L;;;;;N;;;;;
+1D86C;SIGNWRITING HAND-CUP OPEN;So;0;L;;;;;N;;;;;
+1D86D;SIGNWRITING HAND-CUP;So;0;L;;;;;N;;;;;
+1D86E;SIGNWRITING HAND-CUP OPEN THUMB SIDE;So;0;L;;;;;N;;;;;
+1D86F;SIGNWRITING HAND-CUP THUMB SIDE;So;0;L;;;;;N;;;;;
+1D870;SIGNWRITING HAND-CUP OPEN NO THUMB;So;0;L;;;;;N;;;;;
+1D871;SIGNWRITING HAND-CUP NO THUMB;So;0;L;;;;;N;;;;;
+1D872;SIGNWRITING HAND-CUP OPEN THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D873;SIGNWRITING HAND-CUP THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D874;SIGNWRITING HAND-CURLICUE OPEN;So;0;L;;;;;N;;;;;
+1D875;SIGNWRITING HAND-CURLICUE;So;0;L;;;;;N;;;;;
+1D876;SIGNWRITING HAND-CIRCLE;So;0;L;;;;;N;;;;;
+1D877;SIGNWRITING HAND-OVAL;So;0;L;;;;;N;;;;;
+1D878;SIGNWRITING HAND-OVAL THUMB SIDE;So;0;L;;;;;N;;;;;
+1D879;SIGNWRITING HAND-OVAL NO THUMB;So;0;L;;;;;N;;;;;
+1D87A;SIGNWRITING HAND-OVAL THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D87B;SIGNWRITING HAND-HINGE OPEN;So;0;L;;;;;N;;;;;
+1D87C;SIGNWRITING HAND-HINGE OPEN THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D87D;SIGNWRITING HAND-HINGE;So;0;L;;;;;N;;;;;
+1D87E;SIGNWRITING HAND-HINGE SMALL;So;0;L;;;;;N;;;;;
+1D87F;SIGNWRITING HAND-HINGE OPEN THUMB SIDE;So;0;L;;;;;N;;;;;
+1D880;SIGNWRITING HAND-HINGE THUMB SIDE;So;0;L;;;;;N;;;;;
+1D881;SIGNWRITING HAND-HINGE OPEN NO THUMB;So;0;L;;;;;N;;;;;
+1D882;SIGNWRITING HAND-HINGE NO THUMB;So;0;L;;;;;N;;;;;
+1D883;SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX;So;0;L;;;;;N;;;;;
+1D884;SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;;
+1D885;SIGNWRITING HAND-ANGLE;So;0;L;;;;;N;;;;;
+1D886;SIGNWRITING HAND-FIST INDEX MIDDLE RING;So;0;L;;;;;N;;;;;
+1D887;SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;
+1D888;SIGNWRITING HAND-HINGE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;
+1D889;SIGNWRITING HAND-ANGLE INDEX MIDDLE RING;So;0;L;;;;;N;;;;;
+1D88A;SIGNWRITING HAND-HINGE LITTLE;So;0;L;;;;;N;;;;;
+1D88B;SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT;So;0;L;;;;;N;;;;;
+1D88C;SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;;
+1D88D;SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED;So;0;L;;;;;N;;;;;
+1D88E;SIGNWRITING HAND-FIST LITTLE DOWN;So;0;L;;;;;N;;;;;
+1D88F;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT;So;0;L;;;;;N;;;;;
+1D890;SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED;So;0;L;;;;;N;;;;;
+1D891;SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED;So;0;L;;;;;N;;;;;
+1D892;SIGNWRITING HAND-FIST LITTLE UP;So;0;L;;;;;N;;;;;
+1D893;SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP;So;0;L;;;;;N;;;;;
+1D894;SIGNWRITING HAND-CIRCLE LITTLE UP;So;0;L;;;;;N;;;;;
+1D895;SIGNWRITING HAND-OVAL LITTLE UP;So;0;L;;;;;N;;;;;
+1D896;SIGNWRITING HAND-ANGLE LITTLE UP;So;0;L;;;;;N;;;;;
+1D897;SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE;So;0;L;;;;;N;;;;;
+1D898;SIGNWRITING HAND-FIST LITTLE BENT;So;0;L;;;;;N;;;;;
+1D899;SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB;So;0;L;;;;;N;;;;;
+1D89A;SIGNWRITING HAND-FIST LITTLE THUMB;So;0;L;;;;;N;;;;;
+1D89B;SIGNWRITING HAND-HINGE LITTLE THUMB;So;0;L;;;;;N;;;;;
+1D89C;SIGNWRITING HAND-FIST LITTLE INDEX THUMB;So;0;L;;;;;N;;;;;
+1D89D;SIGNWRITING HAND-HINGE LITTLE INDEX THUMB;So;0;L;;;;;N;;;;;
+1D89E;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT;So;0;L;;;;;N;;;;;
+1D89F;SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB;So;0;L;;;;;N;;;;;
+1D8A0;SIGNWRITING HAND-FIST LITTLE INDEX;So;0;L;;;;;N;;;;;
+1D8A1;SIGNWRITING HAND-CIRCLE LITTLE INDEX;So;0;L;;;;;N;;;;;
+1D8A2;SIGNWRITING HAND-HINGE LITTLE INDEX;So;0;L;;;;;N;;;;;
+1D8A3;SIGNWRITING HAND-ANGLE LITTLE INDEX;So;0;L;;;;;N;;;;;
+1D8A4;SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;
+1D8A5;SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;
+1D8A6;SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;
+1D8A7;SIGNWRITING HAND-HINGE RING;So;0;L;;;;;N;;;;;
+1D8A8;SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE;So;0;L;;;;;N;;;;;
+1D8A9;SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;;
+1D8AA;SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE;So;0;L;;;;;N;;;;;
+1D8AB;SIGNWRITING HAND-FIST RING DOWN;So;0;L;;;;;N;;;;;
+1D8AC;SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE;So;0;L;;;;;N;;;;;
+1D8AD;SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS;So;0;L;;;;;N;;;;;
+1D8AE;SIGNWRITING HAND-FIST RING UP;So;0;L;;;;;N;;;;;
+1D8AF;SIGNWRITING HAND-FIST RING RAISED KNUCKLE;So;0;L;;;;;N;;;;;
+1D8B0;SIGNWRITING HAND-FIST RING LITTLE;So;0;L;;;;;N;;;;;
+1D8B1;SIGNWRITING HAND-CIRCLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8B2;SIGNWRITING HAND-OVAL RING LITTLE;So;0;L;;;;;N;;;;;
+1D8B3;SIGNWRITING HAND-ANGLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8B4;SIGNWRITING HAND-FIST RING MIDDLE;So;0;L;;;;;N;;;;;
+1D8B5;SIGNWRITING HAND-FIST RING MIDDLE CONJOINED;So;0;L;;;;;N;;;;;
+1D8B6;SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES;So;0;L;;;;;N;;;;;
+1D8B7;SIGNWRITING HAND-FIST RING INDEX;So;0;L;;;;;N;;;;;
+1D8B8;SIGNWRITING HAND-FIST RING THUMB;So;0;L;;;;;N;;;;;
+1D8B9;SIGNWRITING HAND-HOOK RING THUMB;So;0;L;;;;;N;;;;;
+1D8BA;SIGNWRITING HAND-FIST INDEX RING LITTLE;So;0;L;;;;;N;;;;;
+1D8BB;SIGNWRITING HAND-CIRCLE INDEX RING LITTLE;So;0;L;;;;;N;;;;;
+1D8BC;SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON;So;0;L;;;;;N;;;;;
+1D8BD;SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;;
+1D8BE;SIGNWRITING HAND-HOOK INDEX RING LITTLE IN;So;0;L;;;;;N;;;;;
+1D8BF;SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER;So;0;L;;;;;N;;;;;
+1D8C0;SIGNWRITING HAND-CUP INDEX RING LITTLE;So;0;L;;;;;N;;;;;
+1D8C1;SIGNWRITING HAND-HINGE INDEX RING LITTLE;So;0;L;;;;;N;;;;;
+1D8C2;SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT;So;0;L;;;;;N;;;;;
+1D8C3;SIGNWRITING HAND-ANGLE INDEX RING LITTLE;So;0;L;;;;;N;;;;;
+1D8C4;SIGNWRITING HAND-FIST MIDDLE DOWN;So;0;L;;;;;N;;;;;
+1D8C5;SIGNWRITING HAND-HINGE MIDDLE;So;0;L;;;;;N;;;;;
+1D8C6;SIGNWRITING HAND-FIST MIDDLE UP;So;0;L;;;;;N;;;;;
+1D8C7;SIGNWRITING HAND-CIRCLE MIDDLE UP;So;0;L;;;;;N;;;;;
+1D8C8;SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE;So;0;L;;;;;N;;;;;
+1D8C9;SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE;So;0;L;;;;;N;;;;;
+1D8CA;SIGNWRITING HAND-HOOK MIDDLE THUMB;So;0;L;;;;;N;;;;;
+1D8CB;SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE;So;0;L;;;;;N;;;;;
+1D8CC;SIGNWRITING HAND-FIST MIDDLE LITTLE;So;0;L;;;;;N;;;;;
+1D8CD;SIGNWRITING HAND-FIST MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8CE;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8CF;SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON;So;0;L;;;;;N;;;;;
+1D8D0;SIGNWRITING HAND-CUP MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8D1;SIGNWRITING HAND-HINGE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8D2;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT;So;0;L;;;;;N;;;;;
+1D8D3;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN;So;0;L;;;;;N;;;;;
+1D8D4;SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE;So;0;L;;;;;N;;;;;
+1D8D5;SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT;So;0;L;;;;;N;;;;;
+1D8D6;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;;
+1D8D7;SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE;So;0;L;;;;;N;;;;;
+1D8D8;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT;So;0;L;;;;;N;;;;;
+1D8D9;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN;So;0;L;;;;;N;;;;;
+1D8DA;SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED;So;0;L;;;;;N;;;;;
+1D8DB;SIGNWRITING HAND-HINGE INDEX HINGED;So;0;L;;;;;N;;;;;
+1D8DC;SIGNWRITING HAND-FIST INDEX THUMB SIDE;So;0;L;;;;;N;;;;;
+1D8DD;SIGNWRITING HAND-HINGE INDEX THUMB SIDE;So;0;L;;;;;N;;;;;
+1D8DE;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL;So;0;L;;;;;N;;;;;
+1D8DF;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED;So;0;L;;;;;N;;;;;
+1D8E0;SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT;So;0;L;;;;;N;;;;;
+1D8E1;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT;So;0;L;;;;;N;;;;;
+1D8E2;SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT;So;0;L;;;;;N;;;;;
+1D8E3;SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE;So;0;L;;;;;N;;;;;
+1D8E4;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT;So;0;L;;;;;N;;;;;
+1D8E5;SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT;So;0;L;;;;;N;;;;;
+1D8E6;SIGNWRITING HAND-FIST INDEX THUMB HOOK;So;0;L;;;;;N;;;;;
+1D8E7;SIGNWRITING HAND-FIST INDEX THUMB CURLICUE;So;0;L;;;;;N;;;;;
+1D8E8;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;;
+1D8E9;SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE;So;0;L;;;;;N;;;;;
+1D8EA;SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER;So;0;L;;;;;N;;;;;
+1D8EB;SIGNWRITING HAND-FIST INDEX THUMB CIRCLE;So;0;L;;;;;N;;;;;
+1D8EC;SIGNWRITING HAND-CUP INDEX THUMB;So;0;L;;;;;N;;;;;
+1D8ED;SIGNWRITING HAND-CUP INDEX THUMB OPEN;So;0;L;;;;;N;;;;;
+1D8EE;SIGNWRITING HAND-HINGE INDEX THUMB OPEN;So;0;L;;;;;N;;;;;
+1D8EF;SIGNWRITING HAND-HINGE INDEX THUMB LARGE;So;0;L;;;;;N;;;;;
+1D8F0;SIGNWRITING HAND-HINGE INDEX THUMB;So;0;L;;;;;N;;;;;
+1D8F1;SIGNWRITING HAND-HINGE INDEX THUMB SMALL;So;0;L;;;;;N;;;;;
+1D8F2;SIGNWRITING HAND-ANGLE INDEX THUMB OUT;So;0;L;;;;;N;;;;;
+1D8F3;SIGNWRITING HAND-ANGLE INDEX THUMB IN;So;0;L;;;;;N;;;;;
+1D8F4;SIGNWRITING HAND-ANGLE INDEX THUMB;So;0;L;;;;;N;;;;;
+1D8F5;SIGNWRITING HAND-FIST THUMB;So;0;L;;;;;N;;;;;
+1D8F6;SIGNWRITING HAND-FIST THUMB HEEL;So;0;L;;;;;N;;;;;
+1D8F7;SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL;So;0;L;;;;;N;;;;;
+1D8F8;SIGNWRITING HAND-FIST THUMB SIDE CONJOINED;So;0;L;;;;;N;;;;;
+1D8F9;SIGNWRITING HAND-FIST THUMB SIDE BENT;So;0;L;;;;;N;;;;;
+1D8FA;SIGNWRITING HAND-FIST THUMB FORWARD;So;0;L;;;;;N;;;;;
+1D8FB;SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE;So;0;L;;;;;N;;;;;
+1D8FC;SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING;So;0;L;;;;;N;;;;;
+1D8FD;SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE;So;0;L;;;;;N;;;;;
+1D8FE;SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS;So;0;L;;;;;N;;;;;
+1D8FF;SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS;So;0;L;;;;;N;;;;;
+1D900;SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS;So;0;L;;;;;N;;;;;
+1D901;SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS;So;0;L;;;;;N;;;;;
+1D902;SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES;So;0;L;;;;;N;;;;;
+1D903;SIGNWRITING HAND-FIST;So;0;L;;;;;N;;;;;
+1D904;SIGNWRITING HAND-FIST HEEL;So;0;L;;;;;N;;;;;
+1D905;SIGNWRITING TOUCH SINGLE;So;0;L;;;;;N;;;;;
+1D906;SIGNWRITING TOUCH MULTIPLE;So;0;L;;;;;N;;;;;
+1D907;SIGNWRITING TOUCH BETWEEN;So;0;L;;;;;N;;;;;
+1D908;SIGNWRITING GRASP SINGLE;So;0;L;;;;;N;;;;;
+1D909;SIGNWRITING GRASP MULTIPLE;So;0;L;;;;;N;;;;;
+1D90A;SIGNWRITING GRASP BETWEEN;So;0;L;;;;;N;;;;;
+1D90B;SIGNWRITING STRIKE SINGLE;So;0;L;;;;;N;;;;;
+1D90C;SIGNWRITING STRIKE MULTIPLE;So;0;L;;;;;N;;;;;
+1D90D;SIGNWRITING STRIKE BETWEEN;So;0;L;;;;;N;;;;;
+1D90E;SIGNWRITING BRUSH SINGLE;So;0;L;;;;;N;;;;;
+1D90F;SIGNWRITING BRUSH MULTIPLE;So;0;L;;;;;N;;;;;
+1D910;SIGNWRITING BRUSH BETWEEN;So;0;L;;;;;N;;;;;
+1D911;SIGNWRITING RUB SINGLE;So;0;L;;;;;N;;;;;
+1D912;SIGNWRITING RUB MULTIPLE;So;0;L;;;;;N;;;;;
+1D913;SIGNWRITING RUB BETWEEN;So;0;L;;;;;N;;;;;
+1D914;SIGNWRITING SURFACE SYMBOLS;So;0;L;;;;;N;;;;;
+1D915;SIGNWRITING SURFACE BETWEEN;So;0;L;;;;;N;;;;;
+1D916;SIGNWRITING SQUEEZE LARGE SINGLE;So;0;L;;;;;N;;;;;
+1D917;SIGNWRITING SQUEEZE SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D918;SIGNWRITING SQUEEZE LARGE MULTIPLE;So;0;L;;;;;N;;;;;
+1D919;SIGNWRITING SQUEEZE SMALL MULTIPLE;So;0;L;;;;;N;;;;;
+1D91A;SIGNWRITING SQUEEZE SEQUENTIAL;So;0;L;;;;;N;;;;;
+1D91B;SIGNWRITING FLICK LARGE SINGLE;So;0;L;;;;;N;;;;;
+1D91C;SIGNWRITING FLICK SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D91D;SIGNWRITING FLICK LARGE MULTIPLE;So;0;L;;;;;N;;;;;
+1D91E;SIGNWRITING FLICK SMALL MULTIPLE;So;0;L;;;;;N;;;;;
+1D91F;SIGNWRITING FLICK SEQUENTIAL;So;0;L;;;;;N;;;;;
+1D920;SIGNWRITING SQUEEZE FLICK ALTERNATING;So;0;L;;;;;N;;;;;
+1D921;SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE;So;0;L;;;;;N;;;;;
+1D922;SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL;So;0;L;;;;;N;;;;;
+1D923;SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL;So;0;L;;;;;N;;;;;
+1D924;SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL;So;0;L;;;;;N;;;;;
+1D925;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE;So;0;L;;;;;N;;;;;
+1D926;SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL;So;0;L;;;;;N;;;;;
+1D927;SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS;So;0;L;;;;;N;;;;;
+1D928;SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT;So;0;L;;;;;N;;;;;
+1D929;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT;So;0;L;;;;;N;;;;;
+1D92A;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;;
+1D92B;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;;
+1D92C;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;;
+1D92D;SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;;
+1D92E;SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D92F;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;;
+1D930;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D931;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;;
+1D932;SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;
+1D933;SIGNWRITING MOVEMENT-WALLPLANE CROSS;So;0;L;;;;;N;;;;;
+1D934;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;;
+1D935;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D936;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING;So;0;L;;;;;N;;;;;
+1D937;SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;
+1D938;SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL;So;0;L;;;;;N;;;;;
+1D939;SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM;So;0;L;;;;;N;;;;;
+1D93A;SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE;So;0;L;;;;;N;;;;;
+1D93B;SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL;So;0;L;;;;;N;;;;;
+1D93C;SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;;
+1D93D;SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE;So;0;L;;;;;N;;;;;
+1D93E;SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION;So;0;L;;;;;N;;;;;
+1D93F;SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL;So;0;L;;;;;N;;;;;
+1D940;SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM;So;0;L;;;;;N;;;;;
+1D941;SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE;So;0;L;;;;;N;;;;;
+1D942;SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL;So;0;L;;;;;N;;;;;
+1D943;SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM;So;0;L;;;;;N;;;;;
+1D944;SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE;So;0;L;;;;;N;;;;;
+1D945;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;;
+1D946;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;;
+1D947;SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;;
+1D948;SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL;So;0;L;;;;;N;;;;;
+1D949;SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;;
+1D94A;SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE;So;0;L;;;;;N;;;;;
+1D94B;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D94C;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D94D;SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;;
+1D94E;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D94F;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D950;SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;
+1D951;SIGNWRITING TRAVEL-WALLPLANE SHAKING;So;0;L;;;;;N;;;;;
+1D952;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE;So;0;L;;;;;N;;;;;
+1D953;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE;So;0;L;;;;;N;;;;;
+1D954;SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE;So;0;L;;;;;N;;;;;
+1D955;SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL;So;0;L;;;;;N;;;;;
+1D956;SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM;So;0;L;;;;;N;;;;;
+1D957;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE;So;0;L;;;;;N;;;;;
+1D958;SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST;So;0;L;;;;;N;;;;;
+1D959;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL;So;0;L;;;;;N;;;;;
+1D95A;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM;So;0;L;;;;;N;;;;;
+1D95B;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE;So;0;L;;;;;N;;;;;
+1D95C;SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST;So;0;L;;;;;N;;;;;
+1D95D;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL;So;0;L;;;;;N;;;;;
+1D95E;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM;So;0;L;;;;;N;;;;;
+1D95F;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE;So;0;L;;;;;N;;;;;
+1D960;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST;So;0;L;;;;;N;;;;;
+1D961;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL;So;0;L;;;;;N;;;;;
+1D962;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM;So;0;L;;;;;N;;;;;
+1D963;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE;So;0;L;;;;;N;;;;;
+1D964;SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST;So;0;L;;;;;N;;;;;
+1D965;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL;So;0;L;;;;;N;;;;;
+1D966;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM;So;0;L;;;;;N;;;;;
+1D967;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE;So;0;L;;;;;N;;;;;
+1D968;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST;So;0;L;;;;;N;;;;;
+1D969;SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D96A;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT;So;0;L;;;;;N;;;;;
+1D96B;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D96C;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING;So;0;L;;;;;N;;;;;
+1D96D;SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;
+1D96E;SIGNWRITING MOVEMENT-FLOORPLANE CROSS;So;0;L;;;;;N;;;;;
+1D96F;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT;So;0;L;;;;;N;;;;;
+1D970;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX;So;0;L;;;;;N;;;;;
+1D971;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT;So;0;L;;;;;N;;;;;
+1D972;SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX;So;0;L;;;;;N;;;;;
+1D973;SIGNWRITING MOVEMENT-FLOORPLANE BEND;So;0;L;;;;;N;;;;;
+1D974;SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL;So;0;L;;;;;N;;;;;
+1D975;SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM;So;0;L;;;;;N;;;;;
+1D976;SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE;So;0;L;;;;;N;;;;;
+1D977;SIGNWRITING MOVEMENT-FLOORPLANE CHECK;So;0;L;;;;;N;;;;;
+1D978;SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL;So;0;L;;;;;N;;;;;
+1D979;SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM;So;0;L;;;;;N;;;;;
+1D97A;SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE;So;0;L;;;;;N;;;;;
+1D97B;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL;So;0;L;;;;;N;;;;;
+1D97C;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM;So;0;L;;;;;N;;;;;
+1D97D;SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE;So;0;L;;;;;N;;;;;
+1D97E;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL;So;0;L;;;;;N;;;;;
+1D97F;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM;So;0;L;;;;;N;;;;;
+1D980;SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE;So;0;L;;;;;N;;;;;
+1D981;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D982;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D983;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;
+1D984;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D985;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D986;SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING;So;0;L;;;;;N;;;;;
+1D987;SIGNWRITING TRAVEL-FLOORPLANE SHAKING;So;0;L;;;;;N;;;;;
+1D988;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL;So;0;L;;;;;N;;;;;
+1D989;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM;So;0;L;;;;;N;;;;;
+1D98A;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE;So;0;L;;;;;N;;;;;
+1D98B;SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST;So;0;L;;;;;N;;;;;
+1D98C;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL;So;0;L;;;;;N;;;;;
+1D98D;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM;So;0;L;;;;;N;;;;;
+1D98E;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE;So;0;L;;;;;N;;;;;
+1D98F;SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST;So;0;L;;;;;N;;;;;
+1D990;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL;So;0;L;;;;;N;;;;;
+1D991;SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM;So;0;L;;;;;N;;;;;
+1D992;SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL;So;0;L;;;;;N;;;;;
+1D993;SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM;So;0;L;;;;;N;;;;;
+1D994;SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE;So;0;L;;;;;N;;;;;
+1D995;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL;So;0;L;;;;;N;;;;;
+1D996;SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM;So;0;L;;;;;N;;;;;
+1D997;SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE;So;0;L;;;;;N;;;;;
+1D998;SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D999;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL;So;0;L;;;;;N;;;;;
+1D99A;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM;So;0;L;;;;;N;;;;;
+1D99B;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE;So;0;L;;;;;N;;;;;
+1D99C;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL;So;0;L;;;;;N;;;;;
+1D99D;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM;So;0;L;;;;;N;;;;;
+1D99E;SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE;So;0;L;;;;;N;;;;;
+1D99F;SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT;So;0;L;;;;;N;;;;;
+1D9A0;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL;So;0;L;;;;;N;;;;;
+1D9A1;SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM;So;0;L;;;;;N;;;;;
+1D9A2;SIGNWRITING ROTATION-WALLPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D9A3;SIGNWRITING ROTATION-WALLPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D9A4;SIGNWRITING ROTATION-WALLPLANE ALTERNATE;So;0;L;;;;;N;;;;;
+1D9A5;SIGNWRITING MOVEMENT-WALLPLANE SHAKING;So;0;L;;;;;N;;;;;
+1D9A6;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9A7;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9A8;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9A9;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9AA;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9AB;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9AC;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL;So;0;L;;;;;N;;;;;
+1D9AD;SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9AE;SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9AF;SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9B0;SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9B1;SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9B2;SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9B3;SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST;So;0;L;;;;;N;;;;;
+1D9B4;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL;So;0;L;;;;;N;;;;;
+1D9B5;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM;So;0;L;;;;;N;;;;;
+1D9B6;SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE;So;0;L;;;;;N;;;;;
+1D9B7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;;
+1D9B8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;;
+1D9B9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9BA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;;
+1D9BB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE;So;0;L;;;;;N;;;;;
+1D9BC;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE;So;0;L;;;;;N;;;;;
+1D9BD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D9BE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE;So;0;L;;;;;N;;;;;
+1D9BF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9C0;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE;So;0;L;;;;;N;;;;;
+1D9C1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL;So;0;L;;;;;N;;;;;
+1D9C2;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE;So;0;L;;;;;N;;;;;
+1D9C3;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING;So;0;L;;;;;N;;;;;
+1D9C4;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING;So;0;L;;;;;N;;;;;
+1D9C5;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING;So;0;L;;;;;N;;;;;
+1D9C6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;;
+1D9C7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;;
+1D9C8;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9C9;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;;
+1D9CA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE;So;0;L;;;;;N;;;;;
+1D9CB;SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE;So;0;L;;;;;N;;;;;
+1D9CC;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D9CD;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE;So;0;L;;;;;N;;;;;
+1D9CE;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9CF;SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE;So;0;L;;;;;N;;;;;
+1D9D0;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL;So;0;L;;;;;N;;;;;
+1D9D1;SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE;So;0;L;;;;;N;;;;;
+1D9D2;SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR;So;0;L;;;;;N;;;;;
+1D9D3;SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR;So;0;L;;;;;N;;;;;
+1D9D4;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR;So;0;L;;;;;N;;;;;
+1D9D5;SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL;So;0;L;;;;;N;;;;;
+1D9D6;SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM;So;0;L;;;;;N;;;;;
+1D9D7;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE;So;0;L;;;;;N;;;;;
+1D9D8;SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST;So;0;L;;;;;N;;;;;
+1D9D9;SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED;So;0;L;;;;;N;;;;;
+1D9DA;SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL;So;0;L;;;;;N;;;;;
+1D9DB;SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL;So;0;L;;;;;N;;;;;
+1D9DC;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE;So;0;L;;;;;N;;;;;
+1D9DD;SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL;So;0;L;;;;;N;;;;;
+1D9DE;SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE;So;0;L;;;;;N;;;;;
+1D9DF;SIGNWRITING ROTATION-FLOORPLANE SINGLE;So;0;L;;;;;N;;;;;
+1D9E0;SIGNWRITING ROTATION-FLOORPLANE DOUBLE;So;0;L;;;;;N;;;;;
+1D9E1;SIGNWRITING ROTATION-FLOORPLANE ALTERNATING;So;0;L;;;;;N;;;;;
+1D9E2;SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL;So;0;L;;;;;N;;;;;
+1D9E3;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D9E4;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE;So;0;L;;;;;N;;;;;
+1D9E5;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9E6;SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE;So;0;L;;;;;N;;;;;
+1D9E7;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE;So;0;L;;;;;N;;;;;
+1D9E8;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE;So;0;L;;;;;N;;;;;
+1D9E9;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE;So;0;L;;;;;N;;;;;
+1D9EA;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9EB;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE;So;0;L;;;;;N;;;;;
+1D9EC;SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE;So;0;L;;;;;N;;;;;
+1D9ED;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE;So;0;L;;;;;N;;;;;
+1D9EE;SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE;So;0;L;;;;;N;;;;;
+1D9EF;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE;So;0;L;;;;;N;;;;;
+1D9F0;SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9F1;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE;So;0;L;;;;;N;;;;;
+1D9F2;SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE;So;0;L;;;;;N;;;;;
+1D9F3;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE;So;0;L;;;;;N;;;;;
+1D9F4;SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE;So;0;L;;;;;N;;;;;
+1D9F5;SIGNWRITING DYNAMIC ARROWHEAD SMALL;So;0;L;;;;;N;;;;;
+1D9F6;SIGNWRITING DYNAMIC ARROWHEAD LARGE;So;0;L;;;;;N;;;;;
+1D9F7;SIGNWRITING DYNAMIC FAST;So;0;L;;;;;N;;;;;
+1D9F8;SIGNWRITING DYNAMIC SLOW;So;0;L;;;;;N;;;;;
+1D9F9;SIGNWRITING DYNAMIC TENSE;So;0;L;;;;;N;;;;;
+1D9FA;SIGNWRITING DYNAMIC RELAXED;So;0;L;;;;;N;;;;;
+1D9FB;SIGNWRITING DYNAMIC SIMULTANEOUS;So;0;L;;;;;N;;;;;
+1D9FC;SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING;So;0;L;;;;;N;;;;;
+1D9FD;SIGNWRITING DYNAMIC EVERY OTHER TIME;So;0;L;;;;;N;;;;;
+1D9FE;SIGNWRITING DYNAMIC GRADUAL;So;0;L;;;;;N;;;;;
+1D9FF;SIGNWRITING HEAD;So;0;L;;;;;N;;;;;
+1DA00;SIGNWRITING HEAD RIM;Mn;0;NSM;;;;;N;;;;;
+1DA01;SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;
+1DA02;SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT;Mn;0;NSM;;;;;N;;;;;
+1DA03;SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;
+1DA04;SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE;Mn;0;NSM;;;;;N;;;;;
+1DA05;SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE;Mn;0;NSM;;;;;N;;;;;
+1DA06;SIGNWRITING HEAD MOVEMENT CIRCLE;Mn;0;NSM;;;;;N;;;;;
+1DA07;SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING;Mn;0;NSM;;;;;N;;;;;
+1DA08;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN;Mn;0;NSM;;;;;N;;;;;
+1DA09;SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING;Mn;0;NSM;;;;;N;;;;;
+1DA0A;SIGNWRITING EYEBROWS STRAIGHT UP;Mn;0;NSM;;;;;N;;;;;
+1DA0B;SIGNWRITING EYEBROWS STRAIGHT NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA0C;SIGNWRITING EYEBROWS STRAIGHT DOWN;Mn;0;NSM;;;;;N;;;;;
+1DA0D;SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN;Mn;0;NSM;;;;;N;;;;;
+1DA0E;SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA0F;SIGNWRITING DREAMY EYEBROWS UP NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA10;SIGNWRITING DREAMY EYEBROWS NEUTRAL UP;Mn;0;NSM;;;;;N;;;;;
+1DA11;SIGNWRITING FOREHEAD NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA12;SIGNWRITING FOREHEAD CONTACT;Mn;0;NSM;;;;;N;;;;;
+1DA13;SIGNWRITING FOREHEAD WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA14;SIGNWRITING EYES OPEN;Mn;0;NSM;;;;;N;;;;;
+1DA15;SIGNWRITING EYES SQUEEZED;Mn;0;NSM;;;;;N;;;;;
+1DA16;SIGNWRITING EYES CLOSED;Mn;0;NSM;;;;;N;;;;;
+1DA17;SIGNWRITING EYE BLINK SINGLE;Mn;0;NSM;;;;;N;;;;;
+1DA18;SIGNWRITING EYE BLINK MULTIPLE;Mn;0;NSM;;;;;N;;;;;
+1DA19;SIGNWRITING EYES HALF OPEN;Mn;0;NSM;;;;;N;;;;;
+1DA1A;SIGNWRITING EYES WIDE OPEN;Mn;0;NSM;;;;;N;;;;;
+1DA1B;SIGNWRITING EYES HALF CLOSED;Mn;0;NSM;;;;;N;;;;;
+1DA1C;SIGNWRITING EYES WIDENING MOVEMENT;Mn;0;NSM;;;;;N;;;;;
+1DA1D;SIGNWRITING EYE WINK;Mn;0;NSM;;;;;N;;;;;
+1DA1E;SIGNWRITING EYELASHES UP;Mn;0;NSM;;;;;N;;;;;
+1DA1F;SIGNWRITING EYELASHES DOWN;Mn;0;NSM;;;;;N;;;;;
+1DA20;SIGNWRITING EYELASHES FLUTTERING;Mn;0;NSM;;;;;N;;;;;
+1DA21;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;
+1DA22;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;;
+1DA23;SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;;
+1DA24;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT;Mn;0;NSM;;;;;N;;;;;
+1DA25;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE;Mn;0;NSM;;;;;N;;;;;
+1DA26;SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING;Mn;0;NSM;;;;;N;;;;;
+1DA27;SIGNWRITING EYEGAZE-WALLPLANE CURVED;Mn;0;NSM;;;;;N;;;;;
+1DA28;SIGNWRITING EYEGAZE-FLOORPLANE CURVED;Mn;0;NSM;;;;;N;;;;;
+1DA29;SIGNWRITING EYEGAZE-WALLPLANE CIRCLING;Mn;0;NSM;;;;;N;;;;;
+1DA2A;SIGNWRITING CHEEKS PUFFED;Mn;0;NSM;;;;;N;;;;;
+1DA2B;SIGNWRITING CHEEKS NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA2C;SIGNWRITING CHEEKS SUCKED;Mn;0;NSM;;;;;N;;;;;
+1DA2D;SIGNWRITING TENSE CHEEKS HIGH;Mn;0;NSM;;;;;N;;;;;
+1DA2E;SIGNWRITING TENSE CHEEKS MIDDLE;Mn;0;NSM;;;;;N;;;;;
+1DA2F;SIGNWRITING TENSE CHEEKS LOW;Mn;0;NSM;;;;;N;;;;;
+1DA30;SIGNWRITING EARS;Mn;0;NSM;;;;;N;;;;;
+1DA31;SIGNWRITING NOSE NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA32;SIGNWRITING NOSE CONTACT;Mn;0;NSM;;;;;N;;;;;
+1DA33;SIGNWRITING NOSE WRINKLES;Mn;0;NSM;;;;;N;;;;;
+1DA34;SIGNWRITING NOSE WIGGLES;Mn;0;NSM;;;;;N;;;;;
+1DA35;SIGNWRITING AIR BLOWING OUT;Mn;0;NSM;;;;;N;;;;;
+1DA36;SIGNWRITING AIR SUCKING IN;Mn;0;NSM;;;;;N;;;;;
+1DA37;SIGNWRITING AIR BLOW SMALL ROTATIONS;So;0;L;;;;;N;;;;;
+1DA38;SIGNWRITING AIR SUCK SMALL ROTATIONS;So;0;L;;;;;N;;;;;
+1DA39;SIGNWRITING BREATH INHALE;So;0;L;;;;;N;;;;;
+1DA3A;SIGNWRITING BREATH EXHALE;So;0;L;;;;;N;;;;;
+1DA3B;SIGNWRITING MOUTH CLOSED NEUTRAL;Mn;0;NSM;;;;;N;;;;;
+1DA3C;SIGNWRITING MOUTH CLOSED FORWARD;Mn;0;NSM;;;;;N;;;;;
+1DA3D;SIGNWRITING MOUTH CLOSED CONTACT;Mn;0;NSM;;;;;N;;;;;
+1DA3E;SIGNWRITING MOUTH SMILE;Mn;0;NSM;;;;;N;;;;;
+1DA3F;SIGNWRITING MOUTH SMILE WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA40;SIGNWRITING MOUTH SMILE OPEN;Mn;0;NSM;;;;;N;;;;;
+1DA41;SIGNWRITING MOUTH FROWN;Mn;0;NSM;;;;;N;;;;;
+1DA42;SIGNWRITING MOUTH FROWN WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA43;SIGNWRITING MOUTH FROWN OPEN;Mn;0;NSM;;;;;N;;;;;
+1DA44;SIGNWRITING MOUTH OPEN CIRCLE;Mn;0;NSM;;;;;N;;;;;
+1DA45;SIGNWRITING MOUTH OPEN FORWARD;Mn;0;NSM;;;;;N;;;;;
+1DA46;SIGNWRITING MOUTH OPEN WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA47;SIGNWRITING MOUTH OPEN OVAL;Mn;0;NSM;;;;;N;;;;;
+1DA48;SIGNWRITING MOUTH OPEN OVAL WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA49;SIGNWRITING MOUTH OPEN OVAL YAWN;Mn;0;NSM;;;;;N;;;;;
+1DA4A;SIGNWRITING MOUTH OPEN RECTANGLE;Mn;0;NSM;;;;;N;;;;;
+1DA4B;SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA4C;SIGNWRITING MOUTH OPEN RECTANGLE YAWN;Mn;0;NSM;;;;;N;;;;;
+1DA4D;SIGNWRITING MOUTH KISS;Mn;0;NSM;;;;;N;;;;;
+1DA4E;SIGNWRITING MOUTH KISS FORWARD;Mn;0;NSM;;;;;N;;;;;
+1DA4F;SIGNWRITING MOUTH KISS WRINKLED;Mn;0;NSM;;;;;N;;;;;
+1DA50;SIGNWRITING MOUTH TENSE;Mn;0;NSM;;;;;N;;;;;
+1DA51;SIGNWRITING MOUTH TENSE FORWARD;Mn;0;NSM;;;;;N;;;;;
+1DA52;SIGNWRITING MOUTH TENSE SUCKED;Mn;0;NSM;;;;;N;;;;;
+1DA53;SIGNWRITING LIPS PRESSED TOGETHER;Mn;0;NSM;;;;;N;;;;;
+1DA54;SIGNWRITING LIP LOWER OVER UPPER;Mn;0;NSM;;;;;N;;;;;
+1DA55;SIGNWRITING LIP UPPER OVER LOWER;Mn;0;NSM;;;;;N;;;;;
+1DA56;SIGNWRITING MOUTH CORNERS;Mn;0;NSM;;;;;N;;;;;
+1DA57;SIGNWRITING MOUTH WRINKLES SINGLE;Mn;0;NSM;;;;;N;;;;;
+1DA58;SIGNWRITING MOUTH WRINKLES DOUBLE;Mn;0;NSM;;;;;N;;;;;
+1DA59;SIGNWRITING TONGUE STICKING OUT FAR;Mn;0;NSM;;;;;N;;;;;
+1DA5A;SIGNWRITING TONGUE LICKING LIPS;Mn;0;NSM;;;;;N;;;;;
+1DA5B;SIGNWRITING TONGUE TIP BETWEEN LIPS;Mn;0;NSM;;;;;N;;;;;
+1DA5C;SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;;
+1DA5D;SIGNWRITING TONGUE INSIDE MOUTH RELAXED;Mn;0;NSM;;;;;N;;;;;
+1DA5E;SIGNWRITING TONGUE MOVES AGAINST CHEEK;Mn;0;NSM;;;;;N;;;;;
+1DA5F;SIGNWRITING TONGUE CENTRE STICKING OUT;Mn;0;NSM;;;;;N;;;;;
+1DA60;SIGNWRITING TONGUE CENTRE INSIDE MOUTH;Mn;0;NSM;;;;;N;;;;;
+1DA61;SIGNWRITING TEETH;Mn;0;NSM;;;;;N;;;;;
+1DA62;SIGNWRITING TEETH MOVEMENT;Mn;0;NSM;;;;;N;;;;;
+1DA63;SIGNWRITING TEETH ON TONGUE;Mn;0;NSM;;;;;N;;;;;
+1DA64;SIGNWRITING TEETH ON TONGUE MOVEMENT;Mn;0;NSM;;;;;N;;;;;
+1DA65;SIGNWRITING TEETH ON LIPS;Mn;0;NSM;;;;;N;;;;;
+1DA66;SIGNWRITING TEETH ON LIPS MOVEMENT;Mn;0;NSM;;;;;N;;;;;
+1DA67;SIGNWRITING TEETH BITE LIPS;Mn;0;NSM;;;;;N;;;;;
+1DA68;SIGNWRITING MOVEMENT-WALLPLANE JAW;Mn;0;NSM;;;;;N;;;;;
+1DA69;SIGNWRITING MOVEMENT-FLOORPLANE JAW;Mn;0;NSM;;;;;N;;;;;
+1DA6A;SIGNWRITING NECK;Mn;0;NSM;;;;;N;;;;;
+1DA6B;SIGNWRITING HAIR;Mn;0;NSM;;;;;N;;;;;
+1DA6C;SIGNWRITING EXCITEMENT;Mn;0;NSM;;;;;N;;;;;
+1DA6D;SIGNWRITING SHOULDER HIP SPINE;So;0;L;;;;;N;;;;;
+1DA6E;SIGNWRITING SHOULDER HIP POSITIONS;So;0;L;;;;;N;;;;;
+1DA6F;SIGNWRITING WALLPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;;
+1DA70;SIGNWRITING FLOORPLANE SHOULDER HIP MOVE;So;0;L;;;;;N;;;;;
+1DA71;SIGNWRITING SHOULDER TILTING FROM WAIST;So;0;L;;;;;N;;;;;
+1DA72;SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH;So;0;L;;;;;N;;;;;
+1DA73;SIGNWRITING TORSO-WALLPLANE CURVED BEND;So;0;L;;;;;N;;;;;
+1DA74;SIGNWRITING TORSO-FLOORPLANE TWISTING;So;0;L;;;;;N;;;;;
+1DA75;SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS;Mn;0;NSM;;;;;N;;;;;
+1DA76;SIGNWRITING LIMB COMBINATION;So;0;L;;;;;N;;;;;
+1DA77;SIGNWRITING LIMB LENGTH-1;So;0;L;;;;;N;;;;;
+1DA78;SIGNWRITING LIMB LENGTH-2;So;0;L;;;;;N;;;;;
+1DA79;SIGNWRITING LIMB LENGTH-3;So;0;L;;;;;N;;;;;
+1DA7A;SIGNWRITING LIMB LENGTH-4;So;0;L;;;;;N;;;;;
+1DA7B;SIGNWRITING LIMB LENGTH-5;So;0;L;;;;;N;;;;;
+1DA7C;SIGNWRITING LIMB LENGTH-6;So;0;L;;;;;N;;;;;
+1DA7D;SIGNWRITING LIMB LENGTH-7;So;0;L;;;;;N;;;;;
+1DA7E;SIGNWRITING FINGER;So;0;L;;;;;N;;;;;
+1DA7F;SIGNWRITING LOCATION-WALLPLANE SPACE;So;0;L;;;;;N;;;;;
+1DA80;SIGNWRITING LOCATION-FLOORPLANE SPACE;So;0;L;;;;;N;;;;;
+1DA81;SIGNWRITING LOCATION HEIGHT;So;0;L;;;;;N;;;;;
+1DA82;SIGNWRITING LOCATION WIDTH;So;0;L;;;;;N;;;;;
+1DA83;SIGNWRITING LOCATION DEPTH;So;0;L;;;;;N;;;;;
+1DA84;SIGNWRITING LOCATION HEAD NECK;Mn;0;NSM;;;;;N;;;;;
+1DA85;SIGNWRITING LOCATION TORSO;So;0;L;;;;;N;;;;;
+1DA86;SIGNWRITING LOCATION LIMBS DIGITS;So;0;L;;;;;N;;;;;
+1DA87;SIGNWRITING COMMA;Po;0;L;;;;;N;;;;;
+1DA88;SIGNWRITING FULL STOP;Po;0;L;;;;;N;;;;;
+1DA89;SIGNWRITING SEMICOLON;Po;0;L;;;;;N;;;;;
+1DA8A;SIGNWRITING COLON;Po;0;L;;;;;N;;;;;
+1DA8B;SIGNWRITING PARENTHESIS;Po;0;L;;;;;N;;;;;
+1DA9B;SIGNWRITING FILL MODIFIER-2;Mn;0;NSM;;;;;N;;;;;
+1DA9C;SIGNWRITING FILL MODIFIER-3;Mn;0;NSM;;;;;N;;;;;
+1DA9D;SIGNWRITING FILL MODIFIER-4;Mn;0;NSM;;;;;N;;;;;
+1DA9E;SIGNWRITING FILL MODIFIER-5;Mn;0;NSM;;;;;N;;;;;
+1DA9F;SIGNWRITING FILL MODIFIER-6;Mn;0;NSM;;;;;N;;;;;
+1DAA1;SIGNWRITING ROTATION MODIFIER-2;Mn;0;NSM;;;;;N;;;;;
+1DAA2;SIGNWRITING ROTATION MODIFIER-3;Mn;0;NSM;;;;;N;;;;;
+1DAA3;SIGNWRITING ROTATION MODIFIER-4;Mn;0;NSM;;;;;N;;;;;
+1DAA4;SIGNWRITING ROTATION MODIFIER-5;Mn;0;NSM;;;;;N;;;;;
+1DAA5;SIGNWRITING ROTATION MODIFIER-6;Mn;0;NSM;;;;;N;;;;;
+1DAA6;SIGNWRITING ROTATION MODIFIER-7;Mn;0;NSM;;;;;N;;;;;
+1DAA7;SIGNWRITING ROTATION MODIFIER-8;Mn;0;NSM;;;;;N;;;;;
+1DAA8;SIGNWRITING ROTATION MODIFIER-9;Mn;0;NSM;;;;;N;;;;;
+1DAA9;SIGNWRITING ROTATION MODIFIER-10;Mn;0;NSM;;;;;N;;;;;
+1DAAA;SIGNWRITING ROTATION MODIFIER-11;Mn;0;NSM;;;;;N;;;;;
+1DAAB;SIGNWRITING ROTATION MODIFIER-12;Mn;0;NSM;;;;;N;;;;;
+1DAAC;SIGNWRITING ROTATION MODIFIER-13;Mn;0;NSM;;;;;N;;;;;
+1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;;
+1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;;
+1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;;
+1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;;
+1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;;
+1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;;
+1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;;
+1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;;
+1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;;
+1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;;
+1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;;
+1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;;
+1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;;
+1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;;
+1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;;
+1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;;
+1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;;
+1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;;
+1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;;
+1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;;
+1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;;
+1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;;
+1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;;
+1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;;
+1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;;
+1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;;
+1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;;
+1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;;
+1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;;
+1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;;
+1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;;
+1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;;
+1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;;
+1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;;
+1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;;
+1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;;
+1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;;
+1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;;
+1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;;
+1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;;
+1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;;
+1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;;
+1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;;
+1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;;
+1E803;MENDE KIKAKUI SYLLABLE M065 KEE;Lo;0;R;;;;;N;;;;;
+1E804;MENDE KIKAKUI SYLLABLE M095 KE;Lo;0;R;;;;;N;;;;;
+1E805;MENDE KIKAKUI SYLLABLE M076 KOO;Lo;0;R;;;;;N;;;;;
+1E806;MENDE KIKAKUI SYLLABLE M048 KO;Lo;0;R;;;;;N;;;;;
+1E807;MENDE KIKAKUI SYLLABLE M179 KUA;Lo;0;R;;;;;N;;;;;
+1E808;MENDE KIKAKUI SYLLABLE M004 WI;Lo;0;R;;;;;N;;;;;
+1E809;MENDE KIKAKUI SYLLABLE M005 WA;Lo;0;R;;;;;N;;;;;
+1E80A;MENDE KIKAKUI SYLLABLE M006 WU;Lo;0;R;;;;;N;;;;;
+1E80B;MENDE KIKAKUI SYLLABLE M126 WEE;Lo;0;R;;;;;N;;;;;
+1E80C;MENDE KIKAKUI SYLLABLE M118 WE;Lo;0;R;;;;;N;;;;;
+1E80D;MENDE KIKAKUI SYLLABLE M114 WOO;Lo;0;R;;;;;N;;;;;
+1E80E;MENDE KIKAKUI SYLLABLE M045 WO;Lo;0;R;;;;;N;;;;;
+1E80F;MENDE KIKAKUI SYLLABLE M194 WUI;Lo;0;R;;;;;N;;;;;
+1E810;MENDE KIKAKUI SYLLABLE M143 WEI;Lo;0;R;;;;;N;;;;;
+1E811;MENDE KIKAKUI SYLLABLE M061 WVI;Lo;0;R;;;;;N;;;;;
+1E812;MENDE KIKAKUI SYLLABLE M049 WVA;Lo;0;R;;;;;N;;;;;
+1E813;MENDE KIKAKUI SYLLABLE M139 WVE;Lo;0;R;;;;;N;;;;;
+1E814;MENDE KIKAKUI SYLLABLE M007 MIN;Lo;0;R;;;;;N;;;;;
+1E815;MENDE KIKAKUI SYLLABLE M008 MAN;Lo;0;R;;;;;N;;;;;
+1E816;MENDE KIKAKUI SYLLABLE M009 MUN;Lo;0;R;;;;;N;;;;;
+1E817;MENDE KIKAKUI SYLLABLE M059 MEN;Lo;0;R;;;;;N;;;;;
+1E818;MENDE KIKAKUI SYLLABLE M094 MON;Lo;0;R;;;;;N;;;;;
+1E819;MENDE KIKAKUI SYLLABLE M154 MUAN;Lo;0;R;;;;;N;;;;;
+1E81A;MENDE KIKAKUI SYLLABLE M189 MUEN;Lo;0;R;;;;;N;;;;;
+1E81B;MENDE KIKAKUI SYLLABLE M010 BI;Lo;0;R;;;;;N;;;;;
+1E81C;MENDE KIKAKUI SYLLABLE M011 BA;Lo;0;R;;;;;N;;;;;
+1E81D;MENDE KIKAKUI SYLLABLE M012 BU;Lo;0;R;;;;;N;;;;;
+1E81E;MENDE KIKAKUI SYLLABLE M150 BEE;Lo;0;R;;;;;N;;;;;
+1E81F;MENDE KIKAKUI SYLLABLE M097 BE;Lo;0;R;;;;;N;;;;;
+1E820;MENDE KIKAKUI SYLLABLE M103 BOO;Lo;0;R;;;;;N;;;;;
+1E821;MENDE KIKAKUI SYLLABLE M138 BO;Lo;0;R;;;;;N;;;;;
+1E822;MENDE KIKAKUI SYLLABLE M013 I;Lo;0;R;;;;;N;;;;;
+1E823;MENDE KIKAKUI SYLLABLE M014 A;Lo;0;R;;;;;N;;;;;
+1E824;MENDE KIKAKUI SYLLABLE M015 U;Lo;0;R;;;;;N;;;;;
+1E825;MENDE KIKAKUI SYLLABLE M163 EE;Lo;0;R;;;;;N;;;;;
+1E826;MENDE KIKAKUI SYLLABLE M100 E;Lo;0;R;;;;;N;;;;;
+1E827;MENDE KIKAKUI SYLLABLE M165 OO;Lo;0;R;;;;;N;;;;;
+1E828;MENDE KIKAKUI SYLLABLE M147 O;Lo;0;R;;;;;N;;;;;
+1E829;MENDE KIKAKUI SYLLABLE M137 EI;Lo;0;R;;;;;N;;;;;
+1E82A;MENDE KIKAKUI SYLLABLE M131 IN;Lo;0;R;;;;;N;;;;;
+1E82B;MENDE KIKAKUI SYLLABLE M135 IN;Lo;0;R;;;;;N;;;;;
+1E82C;MENDE KIKAKUI SYLLABLE M195 AN;Lo;0;R;;;;;N;;;;;
+1E82D;MENDE KIKAKUI SYLLABLE M178 EN;Lo;0;R;;;;;N;;;;;
+1E82E;MENDE KIKAKUI SYLLABLE M019 SI;Lo;0;R;;;;;N;;;;;
+1E82F;MENDE KIKAKUI SYLLABLE M020 SA;Lo;0;R;;;;;N;;;;;
+1E830;MENDE KIKAKUI SYLLABLE M021 SU;Lo;0;R;;;;;N;;;;;
+1E831;MENDE KIKAKUI SYLLABLE M162 SEE;Lo;0;R;;;;;N;;;;;
+1E832;MENDE KIKAKUI SYLLABLE M116 SE;Lo;0;R;;;;;N;;;;;
+1E833;MENDE KIKAKUI SYLLABLE M136 SOO;Lo;0;R;;;;;N;;;;;
+1E834;MENDE KIKAKUI SYLLABLE M079 SO;Lo;0;R;;;;;N;;;;;
+1E835;MENDE KIKAKUI SYLLABLE M196 SIA;Lo;0;R;;;;;N;;;;;
+1E836;MENDE KIKAKUI SYLLABLE M025 LI;Lo;0;R;;;;;N;;;;;
+1E837;MENDE KIKAKUI SYLLABLE M026 LA;Lo;0;R;;;;;N;;;;;
+1E838;MENDE KIKAKUI SYLLABLE M027 LU;Lo;0;R;;;;;N;;;;;
+1E839;MENDE KIKAKUI SYLLABLE M084 LEE;Lo;0;R;;;;;N;;;;;
+1E83A;MENDE KIKAKUI SYLLABLE M073 LE;Lo;0;R;;;;;N;;;;;
+1E83B;MENDE KIKAKUI SYLLABLE M054 LOO;Lo;0;R;;;;;N;;;;;
+1E83C;MENDE KIKAKUI SYLLABLE M153 LO;Lo;0;R;;;;;N;;;;;
+1E83D;MENDE KIKAKUI SYLLABLE M110 LONG LE;Lo;0;R;;;;;N;;;;;
+1E83E;MENDE KIKAKUI SYLLABLE M016 DI;Lo;0;R;;;;;N;;;;;
+1E83F;MENDE KIKAKUI SYLLABLE M017 DA;Lo;0;R;;;;;N;;;;;
+1E840;MENDE KIKAKUI SYLLABLE M018 DU;Lo;0;R;;;;;N;;;;;
+1E841;MENDE KIKAKUI SYLLABLE M089 DEE;Lo;0;R;;;;;N;;;;;
+1E842;MENDE KIKAKUI SYLLABLE M180 DOO;Lo;0;R;;;;;N;;;;;
+1E843;MENDE KIKAKUI SYLLABLE M181 DO;Lo;0;R;;;;;N;;;;;
+1E844;MENDE KIKAKUI SYLLABLE M022 TI;Lo;0;R;;;;;N;;;;;
+1E845;MENDE KIKAKUI SYLLABLE M023 TA;Lo;0;R;;;;;N;;;;;
+1E846;MENDE KIKAKUI SYLLABLE M024 TU;Lo;0;R;;;;;N;;;;;
+1E847;MENDE KIKAKUI SYLLABLE M091 TEE;Lo;0;R;;;;;N;;;;;
+1E848;MENDE KIKAKUI SYLLABLE M055 TE;Lo;0;R;;;;;N;;;;;
+1E849;MENDE KIKAKUI SYLLABLE M104 TOO;Lo;0;R;;;;;N;;;;;
+1E84A;MENDE KIKAKUI SYLLABLE M069 TO;Lo;0;R;;;;;N;;;;;
+1E84B;MENDE KIKAKUI SYLLABLE M028 JI;Lo;0;R;;;;;N;;;;;
+1E84C;MENDE KIKAKUI SYLLABLE M029 JA;Lo;0;R;;;;;N;;;;;
+1E84D;MENDE KIKAKUI SYLLABLE M030 JU;Lo;0;R;;;;;N;;;;;
+1E84E;MENDE KIKAKUI SYLLABLE M157 JEE;Lo;0;R;;;;;N;;;;;
+1E84F;MENDE KIKAKUI SYLLABLE M113 JE;Lo;0;R;;;;;N;;;;;
+1E850;MENDE KIKAKUI SYLLABLE M160 JOO;Lo;0;R;;;;;N;;;;;
+1E851;MENDE KIKAKUI SYLLABLE M063 JO;Lo;0;R;;;;;N;;;;;
+1E852;MENDE KIKAKUI SYLLABLE M175 LONG JO;Lo;0;R;;;;;N;;;;;
+1E853;MENDE KIKAKUI SYLLABLE M031 YI;Lo;0;R;;;;;N;;;;;
+1E854;MENDE KIKAKUI SYLLABLE M032 YA;Lo;0;R;;;;;N;;;;;
+1E855;MENDE KIKAKUI SYLLABLE M033 YU;Lo;0;R;;;;;N;;;;;
+1E856;MENDE KIKAKUI SYLLABLE M109 YEE;Lo;0;R;;;;;N;;;;;
+1E857;MENDE KIKAKUI SYLLABLE M080 YE;Lo;0;R;;;;;N;;;;;
+1E858;MENDE KIKAKUI SYLLABLE M141 YOO;Lo;0;R;;;;;N;;;;;
+1E859;MENDE KIKAKUI SYLLABLE M121 YO;Lo;0;R;;;;;N;;;;;
+1E85A;MENDE KIKAKUI SYLLABLE M034 FI;Lo;0;R;;;;;N;;;;;
+1E85B;MENDE KIKAKUI SYLLABLE M035 FA;Lo;0;R;;;;;N;;;;;
+1E85C;MENDE KIKAKUI SYLLABLE M036 FU;Lo;0;R;;;;;N;;;;;
+1E85D;MENDE KIKAKUI SYLLABLE M078 FEE;Lo;0;R;;;;;N;;;;;
+1E85E;MENDE KIKAKUI SYLLABLE M075 FE;Lo;0;R;;;;;N;;;;;
+1E85F;MENDE KIKAKUI SYLLABLE M133 FOO;Lo;0;R;;;;;N;;;;;
+1E860;MENDE KIKAKUI SYLLABLE M088 FO;Lo;0;R;;;;;N;;;;;
+1E861;MENDE KIKAKUI SYLLABLE M197 FUA;Lo;0;R;;;;;N;;;;;
+1E862;MENDE KIKAKUI SYLLABLE M101 FAN;Lo;0;R;;;;;N;;;;;
+1E863;MENDE KIKAKUI SYLLABLE M037 NIN;Lo;0;R;;;;;N;;;;;
+1E864;MENDE KIKAKUI SYLLABLE M038 NAN;Lo;0;R;;;;;N;;;;;
+1E865;MENDE KIKAKUI SYLLABLE M039 NUN;Lo;0;R;;;;;N;;;;;
+1E866;MENDE KIKAKUI SYLLABLE M117 NEN;Lo;0;R;;;;;N;;;;;
+1E867;MENDE KIKAKUI SYLLABLE M169 NON;Lo;0;R;;;;;N;;;;;
+1E868;MENDE KIKAKUI SYLLABLE M176 HI;Lo;0;R;;;;;N;;;;;
+1E869;MENDE KIKAKUI SYLLABLE M041 HA;Lo;0;R;;;;;N;;;;;
+1E86A;MENDE KIKAKUI SYLLABLE M186 HU;Lo;0;R;;;;;N;;;;;
+1E86B;MENDE KIKAKUI SYLLABLE M040 HEE;Lo;0;R;;;;;N;;;;;
+1E86C;MENDE KIKAKUI SYLLABLE M096 HE;Lo;0;R;;;;;N;;;;;
+1E86D;MENDE KIKAKUI SYLLABLE M042 HOO;Lo;0;R;;;;;N;;;;;
+1E86E;MENDE KIKAKUI SYLLABLE M140 HO;Lo;0;R;;;;;N;;;;;
+1E86F;MENDE KIKAKUI SYLLABLE M083 HEEI;Lo;0;R;;;;;N;;;;;
+1E870;MENDE KIKAKUI SYLLABLE M128 HOOU;Lo;0;R;;;;;N;;;;;
+1E871;MENDE KIKAKUI SYLLABLE M053 HIN;Lo;0;R;;;;;N;;;;;
+1E872;MENDE KIKAKUI SYLLABLE M130 HAN;Lo;0;R;;;;;N;;;;;
+1E873;MENDE KIKAKUI SYLLABLE M087 HUN;Lo;0;R;;;;;N;;;;;
+1E874;MENDE KIKAKUI SYLLABLE M052 HEN;Lo;0;R;;;;;N;;;;;
+1E875;MENDE KIKAKUI SYLLABLE M193 HON;Lo;0;R;;;;;N;;;;;
+1E876;MENDE KIKAKUI SYLLABLE M046 HUAN;Lo;0;R;;;;;N;;;;;
+1E877;MENDE KIKAKUI SYLLABLE M090 NGGI;Lo;0;R;;;;;N;;;;;
+1E878;MENDE KIKAKUI SYLLABLE M043 NGGA;Lo;0;R;;;;;N;;;;;
+1E879;MENDE KIKAKUI SYLLABLE M082 NGGU;Lo;0;R;;;;;N;;;;;
+1E87A;MENDE KIKAKUI SYLLABLE M115 NGGEE;Lo;0;R;;;;;N;;;;;
+1E87B;MENDE KIKAKUI SYLLABLE M146 NGGE;Lo;0;R;;;;;N;;;;;
+1E87C;MENDE KIKAKUI SYLLABLE M156 NGGOO;Lo;0;R;;;;;N;;;;;
+1E87D;MENDE KIKAKUI SYLLABLE M120 NGGO;Lo;0;R;;;;;N;;;;;
+1E87E;MENDE KIKAKUI SYLLABLE M159 NGGAA;Lo;0;R;;;;;N;;;;;
+1E87F;MENDE KIKAKUI SYLLABLE M127 NGGUA;Lo;0;R;;;;;N;;;;;
+1E880;MENDE KIKAKUI SYLLABLE M086 LONG NGGE;Lo;0;R;;;;;N;;;;;
+1E881;MENDE KIKAKUI SYLLABLE M106 LONG NGGOO;Lo;0;R;;;;;N;;;;;
+1E882;MENDE KIKAKUI SYLLABLE M183 LONG NGGO;Lo;0;R;;;;;N;;;;;
+1E883;MENDE KIKAKUI SYLLABLE M155 GI;Lo;0;R;;;;;N;;;;;
+1E884;MENDE KIKAKUI SYLLABLE M111 GA;Lo;0;R;;;;;N;;;;;
+1E885;MENDE KIKAKUI SYLLABLE M168 GU;Lo;0;R;;;;;N;;;;;
+1E886;MENDE KIKAKUI SYLLABLE M190 GEE;Lo;0;R;;;;;N;;;;;
+1E887;MENDE KIKAKUI SYLLABLE M166 GUEI;Lo;0;R;;;;;N;;;;;
+1E888;MENDE KIKAKUI SYLLABLE M167 GUAN;Lo;0;R;;;;;N;;;;;
+1E889;MENDE KIKAKUI SYLLABLE M184 NGEN;Lo;0;R;;;;;N;;;;;
+1E88A;MENDE KIKAKUI SYLLABLE M057 NGON;Lo;0;R;;;;;N;;;;;
+1E88B;MENDE KIKAKUI SYLLABLE M177 NGUAN;Lo;0;R;;;;;N;;;;;
+1E88C;MENDE KIKAKUI SYLLABLE M068 PI;Lo;0;R;;;;;N;;;;;
+1E88D;MENDE KIKAKUI SYLLABLE M099 PA;Lo;0;R;;;;;N;;;;;
+1E88E;MENDE KIKAKUI SYLLABLE M050 PU;Lo;0;R;;;;;N;;;;;
+1E88F;MENDE KIKAKUI SYLLABLE M081 PEE;Lo;0;R;;;;;N;;;;;
+1E890;MENDE KIKAKUI SYLLABLE M051 PE;Lo;0;R;;;;;N;;;;;
+1E891;MENDE KIKAKUI SYLLABLE M102 POO;Lo;0;R;;;;;N;;;;;
+1E892;MENDE KIKAKUI SYLLABLE M066 PO;Lo;0;R;;;;;N;;;;;
+1E893;MENDE KIKAKUI SYLLABLE M145 MBI;Lo;0;R;;;;;N;;;;;
+1E894;MENDE KIKAKUI SYLLABLE M062 MBA;Lo;0;R;;;;;N;;;;;
+1E895;MENDE KIKAKUI SYLLABLE M122 MBU;Lo;0;R;;;;;N;;;;;
+1E896;MENDE KIKAKUI SYLLABLE M047 MBEE;Lo;0;R;;;;;N;;;;;
+1E897;MENDE KIKAKUI SYLLABLE M188 MBEE;Lo;0;R;;;;;N;;;;;
+1E898;MENDE KIKAKUI SYLLABLE M072 MBE;Lo;0;R;;;;;N;;;;;
+1E899;MENDE KIKAKUI SYLLABLE M172 MBOO;Lo;0;R;;;;;N;;;;;
+1E89A;MENDE KIKAKUI SYLLABLE M174 MBO;Lo;0;R;;;;;N;;;;;
+1E89B;MENDE KIKAKUI SYLLABLE M187 MBUU;Lo;0;R;;;;;N;;;;;
+1E89C;MENDE KIKAKUI SYLLABLE M161 LONG MBE;Lo;0;R;;;;;N;;;;;
+1E89D;MENDE KIKAKUI SYLLABLE M105 LONG MBOO;Lo;0;R;;;;;N;;;;;
+1E89E;MENDE KIKAKUI SYLLABLE M142 LONG MBO;Lo;0;R;;;;;N;;;;;
+1E89F;MENDE KIKAKUI SYLLABLE M132 KPI;Lo;0;R;;;;;N;;;;;
+1E8A0;MENDE KIKAKUI SYLLABLE M092 KPA;Lo;0;R;;;;;N;;;;;
+1E8A1;MENDE KIKAKUI SYLLABLE M074 KPU;Lo;0;R;;;;;N;;;;;
+1E8A2;MENDE KIKAKUI SYLLABLE M044 KPEE;Lo;0;R;;;;;N;;;;;
+1E8A3;MENDE KIKAKUI SYLLABLE M108 KPE;Lo;0;R;;;;;N;;;;;
+1E8A4;MENDE KIKAKUI SYLLABLE M112 KPOO;Lo;0;R;;;;;N;;;;;
+1E8A5;MENDE KIKAKUI SYLLABLE M158 KPO;Lo;0;R;;;;;N;;;;;
+1E8A6;MENDE KIKAKUI SYLLABLE M124 GBI;Lo;0;R;;;;;N;;;;;
+1E8A7;MENDE KIKAKUI SYLLABLE M056 GBA;Lo;0;R;;;;;N;;;;;
+1E8A8;MENDE KIKAKUI SYLLABLE M148 GBU;Lo;0;R;;;;;N;;;;;
+1E8A9;MENDE KIKAKUI SYLLABLE M093 GBEE;Lo;0;R;;;;;N;;;;;
+1E8AA;MENDE KIKAKUI SYLLABLE M107 GBE;Lo;0;R;;;;;N;;;;;
+1E8AB;MENDE KIKAKUI SYLLABLE M071 GBOO;Lo;0;R;;;;;N;;;;;
+1E8AC;MENDE KIKAKUI SYLLABLE M070 GBO;Lo;0;R;;;;;N;;;;;
+1E8AD;MENDE KIKAKUI SYLLABLE M171 RA;Lo;0;R;;;;;N;;;;;
+1E8AE;MENDE KIKAKUI SYLLABLE M123 NDI;Lo;0;R;;;;;N;;;;;
+1E8AF;MENDE KIKAKUI SYLLABLE M129 NDA;Lo;0;R;;;;;N;;;;;
+1E8B0;MENDE KIKAKUI SYLLABLE M125 NDU;Lo;0;R;;;;;N;;;;;
+1E8B1;MENDE KIKAKUI SYLLABLE M191 NDEE;Lo;0;R;;;;;N;;;;;
+1E8B2;MENDE KIKAKUI SYLLABLE M119 NDE;Lo;0;R;;;;;N;;;;;
+1E8B3;MENDE KIKAKUI SYLLABLE M067 NDOO;Lo;0;R;;;;;N;;;;;
+1E8B4;MENDE KIKAKUI SYLLABLE M064 NDO;Lo;0;R;;;;;N;;;;;
+1E8B5;MENDE KIKAKUI SYLLABLE M152 NJA;Lo;0;R;;;;;N;;;;;
+1E8B6;MENDE KIKAKUI SYLLABLE M192 NJU;Lo;0;R;;;;;N;;;;;
+1E8B7;MENDE KIKAKUI SYLLABLE M149 NJEE;Lo;0;R;;;;;N;;;;;
+1E8B8;MENDE KIKAKUI SYLLABLE M134 NJOO;Lo;0;R;;;;;N;;;;;
+1E8B9;MENDE KIKAKUI SYLLABLE M182 VI;Lo;0;R;;;;;N;;;;;
+1E8BA;MENDE KIKAKUI SYLLABLE M185 VA;Lo;0;R;;;;;N;;;;;
+1E8BB;MENDE KIKAKUI SYLLABLE M151 VU;Lo;0;R;;;;;N;;;;;
+1E8BC;MENDE KIKAKUI SYLLABLE M173 VEE;Lo;0;R;;;;;N;;;;;
+1E8BD;MENDE KIKAKUI SYLLABLE M085 VE;Lo;0;R;;;;;N;;;;;
+1E8BE;MENDE KIKAKUI SYLLABLE M144 VOO;Lo;0;R;;;;;N;;;;;
+1E8BF;MENDE KIKAKUI SYLLABLE M077 VO;Lo;0;R;;;;;N;;;;;
+1E8C0;MENDE KIKAKUI SYLLABLE M164 NYIN;Lo;0;R;;;;;N;;;;;
+1E8C1;MENDE KIKAKUI SYLLABLE M058 NYAN;Lo;0;R;;;;;N;;;;;
+1E8C2;MENDE KIKAKUI SYLLABLE M170 NYUN;Lo;0;R;;;;;N;;;;;
+1E8C3;MENDE KIKAKUI SYLLABLE M098 NYEN;Lo;0;R;;;;;N;;;;;
+1E8C4;MENDE KIKAKUI SYLLABLE M060 NYON;Lo;0;R;;;;;N;;;;;
+1E8C7;MENDE KIKAKUI DIGIT ONE;No;0;R;;;;1;N;;;;;
+1E8C8;MENDE KIKAKUI DIGIT TWO;No;0;R;;;;2;N;;;;;
+1E8C9;MENDE KIKAKUI DIGIT THREE;No;0;R;;;;3;N;;;;;
+1E8CA;MENDE KIKAKUI DIGIT FOUR;No;0;R;;;;4;N;;;;;
+1E8CB;MENDE KIKAKUI DIGIT FIVE;No;0;R;;;;5;N;;;;;
+1E8CC;MENDE KIKAKUI DIGIT SIX;No;0;R;;;;6;N;;;;;
+1E8CD;MENDE KIKAKUI DIGIT SEVEN;No;0;R;;;;7;N;;;;;
+1E8CE;MENDE KIKAKUI DIGIT EIGHT;No;0;R;;;;8;N;;;;;
+1E8CF;MENDE KIKAKUI DIGIT NINE;No;0;R;;;;9;N;;;;;
+1E8D0;MENDE KIKAKUI COMBINING NUMBER TEENS;Mn;220;NSM;;;;;N;;;;;
+1E8D1;MENDE KIKAKUI COMBINING NUMBER TENS;Mn;220;NSM;;;;;N;;;;;
+1E8D2;MENDE KIKAKUI COMBINING NUMBER HUNDREDS;Mn;220;NSM;;;;;N;;;;;
+1E8D3;MENDE KIKAKUI COMBINING NUMBER THOUSANDS;Mn;220;NSM;;;;;N;;;;;
+1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;;
+1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;;
+1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;;
+1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922;
+1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923;
+1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924;
+1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925;
+1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926;
+1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927;
+1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928;
+1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929;
+1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A;
+1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B;
+1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C;
+1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D;
+1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E;
+1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F;
+1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930;
+1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931;
+1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932;
+1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933;
+1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934;
+1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935;
+1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936;
+1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937;
+1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938;
+1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939;
+1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A;
+1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B;
+1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C;
+1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D;
+1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E;
+1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F;
+1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940;
+1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941;
+1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942;
+1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943;
+1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900
+1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901
+1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902
+1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903
+1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904
+1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905
+1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906
+1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907
+1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908
+1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909
+1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A
+1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B
+1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C
+1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D
+1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E
+1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F
+1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910
+1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911
+1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912
+1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913
+1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914
+1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915
+1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916
+1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917
+1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918
+1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919
+1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A
+1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B
+1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C
+1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D
+1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E
+1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F
+1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920
+1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921
+1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;;
+1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;;
+1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;
+1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;;
+1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;;
+1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;;
+1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;;
+1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;;
+1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;;
+1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;;
+1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;;
+1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;;
+1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;;
+1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;;
+1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;;
+1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;;
+1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;
+1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;;
+1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;;
+1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;
+1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
+1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EE03;ARABIC MATHEMATICAL DAL;Lo;0;AL;<font> 062F;;;;N;;;;;
+1EE05;ARABIC MATHEMATICAL WAW;Lo;0;AL;<font> 0648;;;;N;;;;;
+1EE06;ARABIC MATHEMATICAL ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;
+1EE07;ARABIC MATHEMATICAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EE08;ARABIC MATHEMATICAL TAH;Lo;0;AL;<font> 0637;;;;N;;;;;
+1EE09;ARABIC MATHEMATICAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EE0A;ARABIC MATHEMATICAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;;
+1EE0B;ARABIC MATHEMATICAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;;
+1EE0C;ARABIC MATHEMATICAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;
+1EE0D;ARABIC MATHEMATICAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EE0E;ARABIC MATHEMATICAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EE0F;ARABIC MATHEMATICAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EE10;ARABIC MATHEMATICAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;;
+1EE11;ARABIC MATHEMATICAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EE12;ARABIC MATHEMATICAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EE13;ARABIC MATHEMATICAL REH;Lo;0;AL;<font> 0631;;;;N;;;;;
+1EE14;ARABIC MATHEMATICAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EE15;ARABIC MATHEMATICAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;;
+1EE16;ARABIC MATHEMATICAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;;
+1EE17;ARABIC MATHEMATICAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EE18;ARABIC MATHEMATICAL THAL;Lo;0;AL;<font> 0630;;;;N;;;;;
+1EE19;ARABIC MATHEMATICAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EE1A;ARABIC MATHEMATICAL ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;
+1EE1B;ARABIC MATHEMATICAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EE1C;ARABIC MATHEMATICAL DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;;
+1EE1D;ARABIC MATHEMATICAL DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;;
+1EE1E;ARABIC MATHEMATICAL DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;;
+1EE1F;ARABIC MATHEMATICAL DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;;
+1EE21;ARABIC MATHEMATICAL INITIAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
+1EE22;ARABIC MATHEMATICAL INITIAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EE24;ARABIC MATHEMATICAL INITIAL HEH;Lo;0;AL;<font> 0647;;;;N;;;;;
+1EE27;ARABIC MATHEMATICAL INITIAL HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EE29;ARABIC MATHEMATICAL INITIAL YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EE2A;ARABIC MATHEMATICAL INITIAL KAF;Lo;0;AL;<font> 0643;;;;N;;;;;
+1EE2B;ARABIC MATHEMATICAL INITIAL LAM;Lo;0;AL;<font> 0644;;;;N;;;;;
+1EE2C;ARABIC MATHEMATICAL INITIAL MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;
+1EE2D;ARABIC MATHEMATICAL INITIAL NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EE2E;ARABIC MATHEMATICAL INITIAL SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EE2F;ARABIC MATHEMATICAL INITIAL AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EE30;ARABIC MATHEMATICAL INITIAL FEH;Lo;0;AL;<font> 0641;;;;N;;;;;
+1EE31;ARABIC MATHEMATICAL INITIAL SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EE32;ARABIC MATHEMATICAL INITIAL QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EE34;ARABIC MATHEMATICAL INITIAL SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EE35;ARABIC MATHEMATICAL INITIAL TEH;Lo;0;AL;<font> 062A;;;;N;;;;;
+1EE36;ARABIC MATHEMATICAL INITIAL THEH;Lo;0;AL;<font> 062B;;;;N;;;;;
+1EE37;ARABIC MATHEMATICAL INITIAL KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EE39;ARABIC MATHEMATICAL INITIAL DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EE3B;ARABIC MATHEMATICAL INITIAL GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EE42;ARABIC MATHEMATICAL TAILED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EE47;ARABIC MATHEMATICAL TAILED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EE49;ARABIC MATHEMATICAL TAILED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EE4B;ARABIC MATHEMATICAL TAILED LAM;Lo;0;AL;<font> 0644;;;;N;;;;;
+1EE4D;ARABIC MATHEMATICAL TAILED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EE4E;ARABIC MATHEMATICAL TAILED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EE4F;ARABIC MATHEMATICAL TAILED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EE51;ARABIC MATHEMATICAL TAILED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EE52;ARABIC MATHEMATICAL TAILED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EE54;ARABIC MATHEMATICAL TAILED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EE57;ARABIC MATHEMATICAL TAILED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EE59;ARABIC MATHEMATICAL TAILED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EE5B;ARABIC MATHEMATICAL TAILED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EE5D;ARABIC MATHEMATICAL TAILED DOTLESS NOON;Lo;0;AL;<font> 06BA;;;;N;;;;;
+1EE5F;ARABIC MATHEMATICAL TAILED DOTLESS QAF;Lo;0;AL;<font> 066F;;;;N;;;;;
+1EE61;ARABIC MATHEMATICAL STRETCHED BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
+1EE62;ARABIC MATHEMATICAL STRETCHED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EE64;ARABIC MATHEMATICAL STRETCHED HEH;Lo;0;AL;<font> 0647;;;;N;;;;;
+1EE67;ARABIC MATHEMATICAL STRETCHED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EE68;ARABIC MATHEMATICAL STRETCHED TAH;Lo;0;AL;<font> 0637;;;;N;;;;;
+1EE69;ARABIC MATHEMATICAL STRETCHED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EE6A;ARABIC MATHEMATICAL STRETCHED KAF;Lo;0;AL;<font> 0643;;;;N;;;;;
+1EE6C;ARABIC MATHEMATICAL STRETCHED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;
+1EE6D;ARABIC MATHEMATICAL STRETCHED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EE6E;ARABIC MATHEMATICAL STRETCHED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EE6F;ARABIC MATHEMATICAL STRETCHED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EE70;ARABIC MATHEMATICAL STRETCHED FEH;Lo;0;AL;<font> 0641;;;;N;;;;;
+1EE71;ARABIC MATHEMATICAL STRETCHED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EE72;ARABIC MATHEMATICAL STRETCHED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EE74;ARABIC MATHEMATICAL STRETCHED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EE75;ARABIC MATHEMATICAL STRETCHED TEH;Lo;0;AL;<font> 062A;;;;N;;;;;
+1EE76;ARABIC MATHEMATICAL STRETCHED THEH;Lo;0;AL;<font> 062B;;;;N;;;;;
+1EE77;ARABIC MATHEMATICAL STRETCHED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EE79;ARABIC MATHEMATICAL STRETCHED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EE7A;ARABIC MATHEMATICAL STRETCHED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;
+1EE7B;ARABIC MATHEMATICAL STRETCHED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EE7C;ARABIC MATHEMATICAL STRETCHED DOTLESS BEH;Lo;0;AL;<font> 066E;;;;N;;;;;
+1EE7E;ARABIC MATHEMATICAL STRETCHED DOTLESS FEH;Lo;0;AL;<font> 06A1;;;;N;;;;;
+1EE80;ARABIC MATHEMATICAL LOOPED ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;
+1EE81;ARABIC MATHEMATICAL LOOPED BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
+1EE82;ARABIC MATHEMATICAL LOOPED JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EE83;ARABIC MATHEMATICAL LOOPED DAL;Lo;0;AL;<font> 062F;;;;N;;;;;
+1EE84;ARABIC MATHEMATICAL LOOPED HEH;Lo;0;AL;<font> 0647;;;;N;;;;;
+1EE85;ARABIC MATHEMATICAL LOOPED WAW;Lo;0;AL;<font> 0648;;;;N;;;;;
+1EE86;ARABIC MATHEMATICAL LOOPED ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;
+1EE87;ARABIC MATHEMATICAL LOOPED HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EE88;ARABIC MATHEMATICAL LOOPED TAH;Lo;0;AL;<font> 0637;;;;N;;;;;
+1EE89;ARABIC MATHEMATICAL LOOPED YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EE8B;ARABIC MATHEMATICAL LOOPED LAM;Lo;0;AL;<font> 0644;;;;N;;;;;
+1EE8C;ARABIC MATHEMATICAL LOOPED MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;
+1EE8D;ARABIC MATHEMATICAL LOOPED NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EE8E;ARABIC MATHEMATICAL LOOPED SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EE8F;ARABIC MATHEMATICAL LOOPED AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EE90;ARABIC MATHEMATICAL LOOPED FEH;Lo;0;AL;<font> 0641;;;;N;;;;;
+1EE91;ARABIC MATHEMATICAL LOOPED SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EE92;ARABIC MATHEMATICAL LOOPED QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EE93;ARABIC MATHEMATICAL LOOPED REH;Lo;0;AL;<font> 0631;;;;N;;;;;
+1EE94;ARABIC MATHEMATICAL LOOPED SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EE95;ARABIC MATHEMATICAL LOOPED TEH;Lo;0;AL;<font> 062A;;;;N;;;;;
+1EE96;ARABIC MATHEMATICAL LOOPED THEH;Lo;0;AL;<font> 062B;;;;N;;;;;
+1EE97;ARABIC MATHEMATICAL LOOPED KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EE98;ARABIC MATHEMATICAL LOOPED THAL;Lo;0;AL;<font> 0630;;;;N;;;;;
+1EE99;ARABIC MATHEMATICAL LOOPED DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EE9A;ARABIC MATHEMATICAL LOOPED ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;
+1EE9B;ARABIC MATHEMATICAL LOOPED GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EEA1;ARABIC MATHEMATICAL DOUBLE-STRUCK BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
+1EEA2;ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
+1EEA3;ARABIC MATHEMATICAL DOUBLE-STRUCK DAL;Lo;0;AL;<font> 062F;;;;N;;;;;
+1EEA5;ARABIC MATHEMATICAL DOUBLE-STRUCK WAW;Lo;0;AL;<font> 0648;;;;N;;;;;
+1EEA6;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN;Lo;0;AL;<font> 0632;;;;N;;;;;
+1EEA7;ARABIC MATHEMATICAL DOUBLE-STRUCK HAH;Lo;0;AL;<font> 062D;;;;N;;;;;
+1EEA8;ARABIC MATHEMATICAL DOUBLE-STRUCK TAH;Lo;0;AL;<font> 0637;;;;N;;;;;
+1EEA9;ARABIC MATHEMATICAL DOUBLE-STRUCK YEH;Lo;0;AL;<font> 064A;;;;N;;;;;
+1EEAB;ARABIC MATHEMATICAL DOUBLE-STRUCK LAM;Lo;0;AL;<font> 0644;;;;N;;;;;
+1EEAC;ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM;Lo;0;AL;<font> 0645;;;;N;;;;;
+1EEAD;ARABIC MATHEMATICAL DOUBLE-STRUCK NOON;Lo;0;AL;<font> 0646;;;;N;;;;;
+1EEAE;ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN;Lo;0;AL;<font> 0633;;;;N;;;;;
+1EEAF;ARABIC MATHEMATICAL DOUBLE-STRUCK AIN;Lo;0;AL;<font> 0639;;;;N;;;;;
+1EEB0;ARABIC MATHEMATICAL DOUBLE-STRUCK FEH;Lo;0;AL;<font> 0641;;;;N;;;;;
+1EEB1;ARABIC MATHEMATICAL DOUBLE-STRUCK SAD;Lo;0;AL;<font> 0635;;;;N;;;;;
+1EEB2;ARABIC MATHEMATICAL DOUBLE-STRUCK QAF;Lo;0;AL;<font> 0642;;;;N;;;;;
+1EEB3;ARABIC MATHEMATICAL DOUBLE-STRUCK REH;Lo;0;AL;<font> 0631;;;;N;;;;;
+1EEB4;ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN;Lo;0;AL;<font> 0634;;;;N;;;;;
+1EEB5;ARABIC MATHEMATICAL DOUBLE-STRUCK TEH;Lo;0;AL;<font> 062A;;;;N;;;;;
+1EEB6;ARABIC MATHEMATICAL DOUBLE-STRUCK THEH;Lo;0;AL;<font> 062B;;;;N;;;;;
+1EEB7;ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH;Lo;0;AL;<font> 062E;;;;N;;;;;
+1EEB8;ARABIC MATHEMATICAL DOUBLE-STRUCK THAL;Lo;0;AL;<font> 0630;;;;N;;;;;
+1EEB9;ARABIC MATHEMATICAL DOUBLE-STRUCK DAD;Lo;0;AL;<font> 0636;;;;N;;;;;
+1EEBA;ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH;Lo;0;AL;<font> 0638;;;;N;;;;;
+1EEBB;ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN;Lo;0;AL;<font> 063A;;;;N;;;;;
+1EEF0;ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL;Sm;0;ON;;;;;N;;;;;
+1EEF1;ARABIC MATHEMATICAL OPERATOR HAH WITH DAL;Sm;0;ON;;;;;N;;;;;
+1F000;MAHJONG TILE EAST WIND;So;0;ON;;;;;N;;;;;
+1F001;MAHJONG TILE SOUTH WIND;So;0;ON;;;;;N;;;;;
+1F002;MAHJONG TILE WEST WIND;So;0;ON;;;;;N;;;;;
+1F003;MAHJONG TILE NORTH WIND;So;0;ON;;;;;N;;;;;
+1F004;MAHJONG TILE RED DRAGON;So;0;ON;;;;;N;;;;;
+1F005;MAHJONG TILE GREEN DRAGON;So;0;ON;;;;;N;;;;;
+1F006;MAHJONG TILE WHITE DRAGON;So;0;ON;;;;;N;;;;;
+1F007;MAHJONG TILE ONE OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F008;MAHJONG TILE TWO OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F009;MAHJONG TILE THREE OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00A;MAHJONG TILE FOUR OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00B;MAHJONG TILE FIVE OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00C;MAHJONG TILE SIX OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00D;MAHJONG TILE SEVEN OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00E;MAHJONG TILE EIGHT OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F00F;MAHJONG TILE NINE OF CHARACTERS;So;0;ON;;;;;N;;;;;
+1F010;MAHJONG TILE ONE OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F011;MAHJONG TILE TWO OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F012;MAHJONG TILE THREE OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F013;MAHJONG TILE FOUR OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F014;MAHJONG TILE FIVE OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F015;MAHJONG TILE SIX OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F016;MAHJONG TILE SEVEN OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F017;MAHJONG TILE EIGHT OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F018;MAHJONG TILE NINE OF BAMBOOS;So;0;ON;;;;;N;;;;;
+1F019;MAHJONG TILE ONE OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01A;MAHJONG TILE TWO OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01B;MAHJONG TILE THREE OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01C;MAHJONG TILE FOUR OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01D;MAHJONG TILE FIVE OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01E;MAHJONG TILE SIX OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F01F;MAHJONG TILE SEVEN OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F020;MAHJONG TILE EIGHT OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F021;MAHJONG TILE NINE OF CIRCLES;So;0;ON;;;;;N;;;;;
+1F022;MAHJONG TILE PLUM;So;0;ON;;;;;N;;;;;
+1F023;MAHJONG TILE ORCHID;So;0;ON;;;;;N;;;;;
+1F024;MAHJONG TILE BAMBOO;So;0;ON;;;;;N;;;;;
+1F025;MAHJONG TILE CHRYSANTHEMUM;So;0;ON;;;;;N;;;;;
+1F026;MAHJONG TILE SPRING;So;0;ON;;;;;N;;;;;
+1F027;MAHJONG TILE SUMMER;So;0;ON;;;;;N;;;;;
+1F028;MAHJONG TILE AUTUMN;So;0;ON;;;;;N;;;;;
+1F029;MAHJONG TILE WINTER;So;0;ON;;;;;N;;;;;
+1F02A;MAHJONG TILE JOKER;So;0;ON;;;;;N;;;;;
+1F02B;MAHJONG TILE BACK;So;0;ON;;;;;N;;;;;
+1F030;DOMINO TILE HORIZONTAL BACK;So;0;ON;;;;;N;;;;;
+1F031;DOMINO TILE HORIZONTAL-00-00;So;0;ON;;;;;N;;;;;
+1F032;DOMINO TILE HORIZONTAL-00-01;So;0;ON;;;;;N;;;;;
+1F033;DOMINO TILE HORIZONTAL-00-02;So;0;ON;;;;;N;;;;;
+1F034;DOMINO TILE HORIZONTAL-00-03;So;0;ON;;;;;N;;;;;
+1F035;DOMINO TILE HORIZONTAL-00-04;So;0;ON;;;;;N;;;;;
+1F036;DOMINO TILE HORIZONTAL-00-05;So;0;ON;;;;;N;;;;;
+1F037;DOMINO TILE HORIZONTAL-00-06;So;0;ON;;;;;N;;;;;
+1F038;DOMINO TILE HORIZONTAL-01-00;So;0;ON;;;;;N;;;;;
+1F039;DOMINO TILE HORIZONTAL-01-01;So;0;ON;;;;;N;;;;;
+1F03A;DOMINO TILE HORIZONTAL-01-02;So;0;ON;;;;;N;;;;;
+1F03B;DOMINO TILE HORIZONTAL-01-03;So;0;ON;;;;;N;;;;;
+1F03C;DOMINO TILE HORIZONTAL-01-04;So;0;ON;;;;;N;;;;;
+1F03D;DOMINO TILE HORIZONTAL-01-05;So;0;ON;;;;;N;;;;;
+1F03E;DOMINO TILE HORIZONTAL-01-06;So;0;ON;;;;;N;;;;;
+1F03F;DOMINO TILE HORIZONTAL-02-00;So;0;ON;;;;;N;;;;;
+1F040;DOMINO TILE HORIZONTAL-02-01;So;0;ON;;;;;N;;;;;
+1F041;DOMINO TILE HORIZONTAL-02-02;So;0;ON;;;;;N;;;;;
+1F042;DOMINO TILE HORIZONTAL-02-03;So;0;ON;;;;;N;;;;;
+1F043;DOMINO TILE HORIZONTAL-02-04;So;0;ON;;;;;N;;;;;
+1F044;DOMINO TILE HORIZONTAL-02-05;So;0;ON;;;;;N;;;;;
+1F045;DOMINO TILE HORIZONTAL-02-06;So;0;ON;;;;;N;;;;;
+1F046;DOMINO TILE HORIZONTAL-03-00;So;0;ON;;;;;N;;;;;
+1F047;DOMINO TILE HORIZONTAL-03-01;So;0;ON;;;;;N;;;;;
+1F048;DOMINO TILE HORIZONTAL-03-02;So;0;ON;;;;;N;;;;;
+1F049;DOMINO TILE HORIZONTAL-03-03;So;0;ON;;;;;N;;;;;
+1F04A;DOMINO TILE HORIZONTAL-03-04;So;0;ON;;;;;N;;;;;
+1F04B;DOMINO TILE HORIZONTAL-03-05;So;0;ON;;;;;N;;;;;
+1F04C;DOMINO TILE HORIZONTAL-03-06;So;0;ON;;;;;N;;;;;
+1F04D;DOMINO TILE HORIZONTAL-04-00;So;0;ON;;;;;N;;;;;
+1F04E;DOMINO TILE HORIZONTAL-04-01;So;0;ON;;;;;N;;;;;
+1F04F;DOMINO TILE HORIZONTAL-04-02;So;0;ON;;;;;N;;;;;
+1F050;DOMINO TILE HORIZONTAL-04-03;So;0;ON;;;;;N;;;;;
+1F051;DOMINO TILE HORIZONTAL-04-04;So;0;ON;;;;;N;;;;;
+1F052;DOMINO TILE HORIZONTAL-04-05;So;0;ON;;;;;N;;;;;
+1F053;DOMINO TILE HORIZONTAL-04-06;So;0;ON;;;;;N;;;;;
+1F054;DOMINO TILE HORIZONTAL-05-00;So;0;ON;;;;;N;;;;;
+1F055;DOMINO TILE HORIZONTAL-05-01;So;0;ON;;;;;N;;;;;
+1F056;DOMINO TILE HORIZONTAL-05-02;So;0;ON;;;;;N;;;;;
+1F057;DOMINO TILE HORIZONTAL-05-03;So;0;ON;;;;;N;;;;;
+1F058;DOMINO TILE HORIZONTAL-05-04;So;0;ON;;;;;N;;;;;
+1F059;DOMINO TILE HORIZONTAL-05-05;So;0;ON;;;;;N;;;;;
+1F05A;DOMINO TILE HORIZONTAL-05-06;So;0;ON;;;;;N;;;;;
+1F05B;DOMINO TILE HORIZONTAL-06-00;So;0;ON;;;;;N;;;;;
+1F05C;DOMINO TILE HORIZONTAL-06-01;So;0;ON;;;;;N;;;;;
+1F05D;DOMINO TILE HORIZONTAL-06-02;So;0;ON;;;;;N;;;;;
+1F05E;DOMINO TILE HORIZONTAL-06-03;So;0;ON;;;;;N;;;;;
+1F05F;DOMINO TILE HORIZONTAL-06-04;So;0;ON;;;;;N;;;;;
+1F060;DOMINO TILE HORIZONTAL-06-05;So;0;ON;;;;;N;;;;;
+1F061;DOMINO TILE HORIZONTAL-06-06;So;0;ON;;;;;N;;;;;
+1F062;DOMINO TILE VERTICAL BACK;So;0;ON;;;;;N;;;;;
+1F063;DOMINO TILE VERTICAL-00-00;So;0;ON;;;;;N;;;;;
+1F064;DOMINO TILE VERTICAL-00-01;So;0;ON;;;;;N;;;;;
+1F065;DOMINO TILE VERTICAL-00-02;So;0;ON;;;;;N;;;;;
+1F066;DOMINO TILE VERTICAL-00-03;So;0;ON;;;;;N;;;;;
+1F067;DOMINO TILE VERTICAL-00-04;So;0;ON;;;;;N;;;;;
+1F068;DOMINO TILE VERTICAL-00-05;So;0;ON;;;;;N;;;;;
+1F069;DOMINO TILE VERTICAL-00-06;So;0;ON;;;;;N;;;;;
+1F06A;DOMINO TILE VERTICAL-01-00;So;0;ON;;;;;N;;;;;
+1F06B;DOMINO TILE VERTICAL-01-01;So;0;ON;;;;;N;;;;;
+1F06C;DOMINO TILE VERTICAL-01-02;So;0;ON;;;;;N;;;;;
+1F06D;DOMINO TILE VERTICAL-01-03;So;0;ON;;;;;N;;;;;
+1F06E;DOMINO TILE VERTICAL-01-04;So;0;ON;;;;;N;;;;;
+1F06F;DOMINO TILE VERTICAL-01-05;So;0;ON;;;;;N;;;;;
+1F070;DOMINO TILE VERTICAL-01-06;So;0;ON;;;;;N;;;;;
+1F071;DOMINO TILE VERTICAL-02-00;So;0;ON;;;;;N;;;;;
+1F072;DOMINO TILE VERTICAL-02-01;So;0;ON;;;;;N;;;;;
+1F073;DOMINO TILE VERTICAL-02-02;So;0;ON;;;;;N;;;;;
+1F074;DOMINO TILE VERTICAL-02-03;So;0;ON;;;;;N;;;;;
+1F075;DOMINO TILE VERTICAL-02-04;So;0;ON;;;;;N;;;;;
+1F076;DOMINO TILE VERTICAL-02-05;So;0;ON;;;;;N;;;;;
+1F077;DOMINO TILE VERTICAL-02-06;So;0;ON;;;;;N;;;;;
+1F078;DOMINO TILE VERTICAL-03-00;So;0;ON;;;;;N;;;;;
+1F079;DOMINO TILE VERTICAL-03-01;So;0;ON;;;;;N;;;;;
+1F07A;DOMINO TILE VERTICAL-03-02;So;0;ON;;;;;N;;;;;
+1F07B;DOMINO TILE VERTICAL-03-03;So;0;ON;;;;;N;;;;;
+1F07C;DOMINO TILE VERTICAL-03-04;So;0;ON;;;;;N;;;;;
+1F07D;DOMINO TILE VERTICAL-03-05;So;0;ON;;;;;N;;;;;
+1F07E;DOMINO TILE VERTICAL-03-06;So;0;ON;;;;;N;;;;;
+1F07F;DOMINO TILE VERTICAL-04-00;So;0;ON;;;;;N;;;;;
+1F080;DOMINO TILE VERTICAL-04-01;So;0;ON;;;;;N;;;;;
+1F081;DOMINO TILE VERTICAL-04-02;So;0;ON;;;;;N;;;;;
+1F082;DOMINO TILE VERTICAL-04-03;So;0;ON;;;;;N;;;;;
+1F083;DOMINO TILE VERTICAL-04-04;So;0;ON;;;;;N;;;;;
+1F084;DOMINO TILE VERTICAL-04-05;So;0;ON;;;;;N;;;;;
+1F085;DOMINO TILE VERTICAL-04-06;So;0;ON;;;;;N;;;;;
+1F086;DOMINO TILE VERTICAL-05-00;So;0;ON;;;;;N;;;;;
+1F087;DOMINO TILE VERTICAL-05-01;So;0;ON;;;;;N;;;;;
+1F088;DOMINO TILE VERTICAL-05-02;So;0;ON;;;;;N;;;;;
+1F089;DOMINO TILE VERTICAL-05-03;So;0;ON;;;;;N;;;;;
+1F08A;DOMINO TILE VERTICAL-05-04;So;0;ON;;;;;N;;;;;
+1F08B;DOMINO TILE VERTICAL-05-05;So;0;ON;;;;;N;;;;;
+1F08C;DOMINO TILE VERTICAL-05-06;So;0;ON;;;;;N;;;;;
+1F08D;DOMINO TILE VERTICAL-06-00;So;0;ON;;;;;N;;;;;
+1F08E;DOMINO TILE VERTICAL-06-01;So;0;ON;;;;;N;;;;;
+1F08F;DOMINO TILE VERTICAL-06-02;So;0;ON;;;;;N;;;;;
+1F090;DOMINO TILE VERTICAL-06-03;So;0;ON;;;;;N;;;;;
+1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;;
+1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;;
+1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;;
+1F0A0;PLAYING CARD BACK;So;0;ON;;;;;N;;;;;
+1F0A1;PLAYING CARD ACE OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A2;PLAYING CARD TWO OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A3;PLAYING CARD THREE OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A4;PLAYING CARD FOUR OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A5;PLAYING CARD FIVE OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A6;PLAYING CARD SIX OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A7;PLAYING CARD SEVEN OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A8;PLAYING CARD EIGHT OF SPADES;So;0;ON;;;;;N;;;;;
+1F0A9;PLAYING CARD NINE OF SPADES;So;0;ON;;;;;N;;;;;
+1F0AA;PLAYING CARD TEN OF SPADES;So;0;ON;;;;;N;;;;;
+1F0AB;PLAYING CARD JACK OF SPADES;So;0;ON;;;;;N;;;;;
+1F0AC;PLAYING CARD KNIGHT OF SPADES;So;0;ON;;;;;N;;;;;
+1F0AD;PLAYING CARD QUEEN OF SPADES;So;0;ON;;;;;N;;;;;
+1F0AE;PLAYING CARD KING OF SPADES;So;0;ON;;;;;N;;;;;
+1F0B1;PLAYING CARD ACE OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B2;PLAYING CARD TWO OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B3;PLAYING CARD THREE OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B4;PLAYING CARD FOUR OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B5;PLAYING CARD FIVE OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B6;PLAYING CARD SIX OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B7;PLAYING CARD SEVEN OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B8;PLAYING CARD EIGHT OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0B9;PLAYING CARD NINE OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BA;PLAYING CARD TEN OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BB;PLAYING CARD JACK OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;;
+1F0BF;PLAYING CARD RED JOKER;So;0;ON;;;;;N;;;;;
+1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C4;PLAYING CARD FOUR OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C5;PLAYING CARD FIVE OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C6;PLAYING CARD SIX OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C7;PLAYING CARD SEVEN OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C8;PLAYING CARD EIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0C9;PLAYING CARD NINE OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CA;PLAYING CARD TEN OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CB;PLAYING CARD JACK OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CC;PLAYING CARD KNIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CD;PLAYING CARD QUEEN OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CE;PLAYING CARD KING OF DIAMONDS;So;0;ON;;;;;N;;;;;
+1F0CF;PLAYING CARD BLACK JOKER;So;0;ON;;;;;N;;;;;
+1F0D1;PLAYING CARD ACE OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D2;PLAYING CARD TWO OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D3;PLAYING CARD THREE OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D4;PLAYING CARD FOUR OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D5;PLAYING CARD FIVE OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D6;PLAYING CARD SIX OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D7;PLAYING CARD SEVEN OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D8;PLAYING CARD EIGHT OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0D9;PLAYING CARD NINE OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DA;PLAYING CARD TEN OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DB;PLAYING CARD JACK OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DC;PLAYING CARD KNIGHT OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;;
+1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;;
+1F0E0;PLAYING CARD FOOL;So;0;ON;;;;;N;;;;;
+1F0E1;PLAYING CARD TRUMP-1;So;0;ON;;;;;N;;;;;
+1F0E2;PLAYING CARD TRUMP-2;So;0;ON;;;;;N;;;;;
+1F0E3;PLAYING CARD TRUMP-3;So;0;ON;;;;;N;;;;;
+1F0E4;PLAYING CARD TRUMP-4;So;0;ON;;;;;N;;;;;
+1F0E5;PLAYING CARD TRUMP-5;So;0;ON;;;;;N;;;;;
+1F0E6;PLAYING CARD TRUMP-6;So;0;ON;;;;;N;;;;;
+1F0E7;PLAYING CARD TRUMP-7;So;0;ON;;;;;N;;;;;
+1F0E8;PLAYING CARD TRUMP-8;So;0;ON;;;;;N;;;;;
+1F0E9;PLAYING CARD TRUMP-9;So;0;ON;;;;;N;;;;;
+1F0EA;PLAYING CARD TRUMP-10;So;0;ON;;;;;N;;;;;
+1F0EB;PLAYING CARD TRUMP-11;So;0;ON;;;;;N;;;;;
+1F0EC;PLAYING CARD TRUMP-12;So;0;ON;;;;;N;;;;;
+1F0ED;PLAYING CARD TRUMP-13;So;0;ON;;;;;N;;;;;
+1F0EE;PLAYING CARD TRUMP-14;So;0;ON;;;;;N;;;;;
+1F0EF;PLAYING CARD TRUMP-15;So;0;ON;;;;;N;;;;;
+1F0F0;PLAYING CARD TRUMP-16;So;0;ON;;;;;N;;;;;
+1F0F1;PLAYING CARD TRUMP-17;So;0;ON;;;;;N;;;;;
+1F0F2;PLAYING CARD TRUMP-18;So;0;ON;;;;;N;;;;;
+1F0F3;PLAYING CARD TRUMP-19;So;0;ON;;;;;N;;;;;
+1F0F4;PLAYING CARD TRUMP-20;So;0;ON;;;;;N;;;;;
+1F0F5;PLAYING CARD TRUMP-21;So;0;ON;;;;;N;;;;;
+1F100;DIGIT ZERO FULL STOP;No;0;EN;<compat> 0030 002E;;0;0;N;;;;;
+1F101;DIGIT ZERO COMMA;No;0;EN;<compat> 0030 002C;;0;0;N;;;;;
+1F102;DIGIT ONE COMMA;No;0;EN;<compat> 0031 002C;;1;1;N;;;;;
+1F103;DIGIT TWO COMMA;No;0;EN;<compat> 0032 002C;;2;2;N;;;;;
+1F104;DIGIT THREE COMMA;No;0;EN;<compat> 0033 002C;;3;3;N;;;;;
+1F105;DIGIT FOUR COMMA;No;0;EN;<compat> 0034 002C;;4;4;N;;;;;
+1F106;DIGIT FIVE COMMA;No;0;EN;<compat> 0035 002C;;5;5;N;;;;;
+1F107;DIGIT SIX COMMA;No;0;EN;<compat> 0036 002C;;6;6;N;;;;;
+1F108;DIGIT SEVEN COMMA;No;0;EN;<compat> 0037 002C;;7;7;N;;;;;
+1F109;DIGIT EIGHT COMMA;No;0;EN;<compat> 0038 002C;;8;8;N;;;;;
+1F10A;DIGIT NINE COMMA;No;0;EN;<compat> 0039 002C;;9;9;N;;;;;
+1F10B;DINGBAT CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;
+1F10C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO;No;0;ON;;;;0;N;;;;;
+1F110;PARENTHESIZED LATIN CAPITAL LETTER A;So;0;L;<compat> 0028 0041 0029;;;;N;;;;;
+1F111;PARENTHESIZED LATIN CAPITAL LETTER B;So;0;L;<compat> 0028 0042 0029;;;;N;;;;;
+1F112;PARENTHESIZED LATIN CAPITAL LETTER C;So;0;L;<compat> 0028 0043 0029;;;;N;;;;;
+1F113;PARENTHESIZED LATIN CAPITAL LETTER D;So;0;L;<compat> 0028 0044 0029;;;;N;;;;;
+1F114;PARENTHESIZED LATIN CAPITAL LETTER E;So;0;L;<compat> 0028 0045 0029;;;;N;;;;;
+1F115;PARENTHESIZED LATIN CAPITAL LETTER F;So;0;L;<compat> 0028 0046 0029;;;;N;;;;;
+1F116;PARENTHESIZED LATIN CAPITAL LETTER G;So;0;L;<compat> 0028 0047 0029;;;;N;;;;;
+1F117;PARENTHESIZED LATIN CAPITAL LETTER H;So;0;L;<compat> 0028 0048 0029;;;;N;;;;;
+1F118;PARENTHESIZED LATIN CAPITAL LETTER I;So;0;L;<compat> 0028 0049 0029;;;;N;;;;;
+1F119;PARENTHESIZED LATIN CAPITAL LETTER J;So;0;L;<compat> 0028 004A 0029;;;;N;;;;;
+1F11A;PARENTHESIZED LATIN CAPITAL LETTER K;So;0;L;<compat> 0028 004B 0029;;;;N;;;;;
+1F11B;PARENTHESIZED LATIN CAPITAL LETTER L;So;0;L;<compat> 0028 004C 0029;;;;N;;;;;
+1F11C;PARENTHESIZED LATIN CAPITAL LETTER M;So;0;L;<compat> 0028 004D 0029;;;;N;;;;;
+1F11D;PARENTHESIZED LATIN CAPITAL LETTER N;So;0;L;<compat> 0028 004E 0029;;;;N;;;;;
+1F11E;PARENTHESIZED LATIN CAPITAL LETTER O;So;0;L;<compat> 0028 004F 0029;;;;N;;;;;
+1F11F;PARENTHESIZED LATIN CAPITAL LETTER P;So;0;L;<compat> 0028 0050 0029;;;;N;;;;;
+1F120;PARENTHESIZED LATIN CAPITAL LETTER Q;So;0;L;<compat> 0028 0051 0029;;;;N;;;;;
+1F121;PARENTHESIZED LATIN CAPITAL LETTER R;So;0;L;<compat> 0028 0052 0029;;;;N;;;;;
+1F122;PARENTHESIZED LATIN CAPITAL LETTER S;So;0;L;<compat> 0028 0053 0029;;;;N;;;;;
+1F123;PARENTHESIZED LATIN CAPITAL LETTER T;So;0;L;<compat> 0028 0054 0029;;;;N;;;;;
+1F124;PARENTHESIZED LATIN CAPITAL LETTER U;So;0;L;<compat> 0028 0055 0029;;;;N;;;;;
+1F125;PARENTHESIZED LATIN CAPITAL LETTER V;So;0;L;<compat> 0028 0056 0029;;;;N;;;;;
+1F126;PARENTHESIZED LATIN CAPITAL LETTER W;So;0;L;<compat> 0028 0057 0029;;;;N;;;;;
+1F127;PARENTHESIZED LATIN CAPITAL LETTER X;So;0;L;<compat> 0028 0058 0029;;;;N;;;;;
+1F128;PARENTHESIZED LATIN CAPITAL LETTER Y;So;0;L;<compat> 0028 0059 0029;;;;N;;;;;
+1F129;PARENTHESIZED LATIN CAPITAL LETTER Z;So;0;L;<compat> 0028 005A 0029;;;;N;;;;;
+1F12A;TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S;So;0;L;<compat> 3014 0053 3015;;;;N;;;;;
+1F12B;CIRCLED ITALIC LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;;
+1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;;
+1F12D;CIRCLED CD;So;0;L;<circle> 0043 0044;;;;N;;;;;
+1F12E;CIRCLED WZ;So;0;L;<circle> 0057 005A;;;;N;;;;;
+1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L;<square> 0041;;;;N;;;;;
+1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L;<square> 0042;;;;N;;;;;
+1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L;<square> 0043;;;;N;;;;;
+1F133;SQUARED LATIN CAPITAL LETTER D;So;0;L;<square> 0044;;;;N;;;;;
+1F134;SQUARED LATIN CAPITAL LETTER E;So;0;L;<square> 0045;;;;N;;;;;
+1F135;SQUARED LATIN CAPITAL LETTER F;So;0;L;<square> 0046;;;;N;;;;;
+1F136;SQUARED LATIN CAPITAL LETTER G;So;0;L;<square> 0047;;;;N;;;;;
+1F137;SQUARED LATIN CAPITAL LETTER H;So;0;L;<square> 0048;;;;N;;;;;
+1F138;SQUARED LATIN CAPITAL LETTER I;So;0;L;<square> 0049;;;;N;;;;;
+1F139;SQUARED LATIN CAPITAL LETTER J;So;0;L;<square> 004A;;;;N;;;;;
+1F13A;SQUARED LATIN CAPITAL LETTER K;So;0;L;<square> 004B;;;;N;;;;;
+1F13B;SQUARED LATIN CAPITAL LETTER L;So;0;L;<square> 004C;;;;N;;;;;
+1F13C;SQUARED LATIN CAPITAL LETTER M;So;0;L;<square> 004D;;;;N;;;;;
+1F13D;SQUARED LATIN CAPITAL LETTER N;So;0;L;<square> 004E;;;;N;;;;;
+1F13E;SQUARED LATIN CAPITAL LETTER O;So;0;L;<square> 004F;;;;N;;;;;
+1F13F;SQUARED LATIN CAPITAL LETTER P;So;0;L;<square> 0050;;;;N;;;;;
+1F140;SQUARED LATIN CAPITAL LETTER Q;So;0;L;<square> 0051;;;;N;;;;;
+1F141;SQUARED LATIN CAPITAL LETTER R;So;0;L;<square> 0052;;;;N;;;;;
+1F142;SQUARED LATIN CAPITAL LETTER S;So;0;L;<square> 0053;;;;N;;;;;
+1F143;SQUARED LATIN CAPITAL LETTER T;So;0;L;<square> 0054;;;;N;;;;;
+1F144;SQUARED LATIN CAPITAL LETTER U;So;0;L;<square> 0055;;;;N;;;;;
+1F145;SQUARED LATIN CAPITAL LETTER V;So;0;L;<square> 0056;;;;N;;;;;
+1F146;SQUARED LATIN CAPITAL LETTER W;So;0;L;<square> 0057;;;;N;;;;;
+1F147;SQUARED LATIN CAPITAL LETTER X;So;0;L;<square> 0058;;;;N;;;;;
+1F148;SQUARED LATIN CAPITAL LETTER Y;So;0;L;<square> 0059;;;;N;;;;;
+1F149;SQUARED LATIN CAPITAL LETTER Z;So;0;L;<square> 005A;;;;N;;;;;
+1F14A;SQUARED HV;So;0;L;<square> 0048 0056;;;;N;;;;;
+1F14B;SQUARED MV;So;0;L;<square> 004D 0056;;;;N;;;;;
+1F14C;SQUARED SD;So;0;L;<square> 0053 0044;;;;N;;;;;
+1F14D;SQUARED SS;So;0;L;<square> 0053 0053;;;;N;;;;;
+1F14E;SQUARED PPV;So;0;L;<square> 0050 0050 0056;;;;N;;;;;
+1F14F;SQUARED WC;So;0;L;<square> 0057 0043;;;;N;;;;;
+1F150;NEGATIVE CIRCLED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;;
+1F151;NEGATIVE CIRCLED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;;
+1F152;NEGATIVE CIRCLED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;;
+1F153;NEGATIVE CIRCLED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;;
+1F154;NEGATIVE CIRCLED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;;
+1F155;NEGATIVE CIRCLED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;;
+1F156;NEGATIVE CIRCLED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;;
+1F157;NEGATIVE CIRCLED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;;
+1F158;NEGATIVE CIRCLED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;;
+1F159;NEGATIVE CIRCLED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;;
+1F15A;NEGATIVE CIRCLED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;;
+1F15B;NEGATIVE CIRCLED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;;
+1F15C;NEGATIVE CIRCLED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;;
+1F15D;NEGATIVE CIRCLED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;;
+1F15E;NEGATIVE CIRCLED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;;
+1F15F;NEGATIVE CIRCLED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;
+1F160;NEGATIVE CIRCLED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;;
+1F161;NEGATIVE CIRCLED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;;
+1F162;NEGATIVE CIRCLED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;;
+1F163;NEGATIVE CIRCLED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;;
+1F164;NEGATIVE CIRCLED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;;
+1F165;NEGATIVE CIRCLED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;;
+1F166;NEGATIVE CIRCLED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;;
+1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;;
+1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;;
+1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;;
+1F16A;RAISED MC SIGN;So;0;ON;<super> 004D 0043;;;;N;;;;;
+1F16B;RAISED MD SIGN;So;0;ON;<super> 004D 0044;;;;N;;;;;
+1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;;
+1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;;
+1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;;
+1F173;NEGATIVE SQUARED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;;
+1F174;NEGATIVE SQUARED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;;
+1F175;NEGATIVE SQUARED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;;
+1F176;NEGATIVE SQUARED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;;
+1F177;NEGATIVE SQUARED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;;
+1F178;NEGATIVE SQUARED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;;
+1F179;NEGATIVE SQUARED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;;
+1F17A;NEGATIVE SQUARED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;;
+1F17B;NEGATIVE SQUARED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;;
+1F17C;NEGATIVE SQUARED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;;
+1F17D;NEGATIVE SQUARED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;;
+1F17E;NEGATIVE SQUARED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;;
+1F17F;NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;
+1F180;NEGATIVE SQUARED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;;
+1F181;NEGATIVE SQUARED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;;
+1F182;NEGATIVE SQUARED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;;
+1F183;NEGATIVE SQUARED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;;
+1F184;NEGATIVE SQUARED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;;
+1F185;NEGATIVE SQUARED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;;
+1F186;NEGATIVE SQUARED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;;
+1F187;NEGATIVE SQUARED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;;
+1F188;NEGATIVE SQUARED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;;
+1F189;NEGATIVE SQUARED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;;
+1F18A;CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;;
+1F18B;NEGATIVE SQUARED IC;So;0;L;;;;;N;;;;;
+1F18C;NEGATIVE SQUARED PA;So;0;L;;;;;N;;;;;
+1F18D;NEGATIVE SQUARED SA;So;0;L;;;;;N;;;;;
+1F18E;NEGATIVE SQUARED AB;So;0;L;;;;;N;;;;;
+1F18F;NEGATIVE SQUARED WC;So;0;L;;;;;N;;;;;
+1F190;SQUARE DJ;So;0;L;<square> 0044 004A;;;;N;;;;;
+1F191;SQUARED CL;So;0;L;;;;;N;;;;;
+1F192;SQUARED COOL;So;0;L;;;;;N;;;;;
+1F193;SQUARED FREE;So;0;L;;;;;N;;;;;
+1F194;SQUARED ID;So;0;L;;;;;N;;;;;
+1F195;SQUARED NEW;So;0;L;;;;;N;;;;;
+1F196;SQUARED NG;So;0;L;;;;;N;;;;;
+1F197;SQUARED OK;So;0;L;;;;;N;;;;;
+1F198;SQUARED SOS;So;0;L;;;;;N;;;;;
+1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;;
+1F19A;SQUARED VS;So;0;L;;;;;N;;;;;
+1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;;
+1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;;
+1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;;
+1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;;
+1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;;
+1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;;
+1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;;
+1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;;
+1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;;
+1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;;
+1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;;
+1F1A6;SQUARED HC;So;0;L;;;;;N;;;;;
+1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;;
+1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;;
+1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;;
+1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;;
+1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;;
+1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;;
+1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;;
+1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;;
+1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;;
+1F1E9;REGIONAL INDICATOR SYMBOL LETTER D;So;0;L;;;;;N;;;;;
+1F1EA;REGIONAL INDICATOR SYMBOL LETTER E;So;0;L;;;;;N;;;;;
+1F1EB;REGIONAL INDICATOR SYMBOL LETTER F;So;0;L;;;;;N;;;;;
+1F1EC;REGIONAL INDICATOR SYMBOL LETTER G;So;0;L;;;;;N;;;;;
+1F1ED;REGIONAL INDICATOR SYMBOL LETTER H;So;0;L;;;;;N;;;;;
+1F1EE;REGIONAL INDICATOR SYMBOL LETTER I;So;0;L;;;;;N;;;;;
+1F1EF;REGIONAL INDICATOR SYMBOL LETTER J;So;0;L;;;;;N;;;;;
+1F1F0;REGIONAL INDICATOR SYMBOL LETTER K;So;0;L;;;;;N;;;;;
+1F1F1;REGIONAL INDICATOR SYMBOL LETTER L;So;0;L;;;;;N;;;;;
+1F1F2;REGIONAL INDICATOR SYMBOL LETTER M;So;0;L;;;;;N;;;;;
+1F1F3;REGIONAL INDICATOR SYMBOL LETTER N;So;0;L;;;;;N;;;;;
+1F1F4;REGIONAL INDICATOR SYMBOL LETTER O;So;0;L;;;;;N;;;;;
+1F1F5;REGIONAL INDICATOR SYMBOL LETTER P;So;0;L;;;;;N;;;;;
+1F1F6;REGIONAL INDICATOR SYMBOL LETTER Q;So;0;L;;;;;N;;;;;
+1F1F7;REGIONAL INDICATOR SYMBOL LETTER R;So;0;L;;;;;N;;;;;
+1F1F8;REGIONAL INDICATOR SYMBOL LETTER S;So;0;L;;;;;N;;;;;
+1F1F9;REGIONAL INDICATOR SYMBOL LETTER T;So;0;L;;;;;N;;;;;
+1F1FA;REGIONAL INDICATOR SYMBOL LETTER U;So;0;L;;;;;N;;;;;
+1F1FB;REGIONAL INDICATOR SYMBOL LETTER V;So;0;L;;;;;N;;;;;
+1F1FC;REGIONAL INDICATOR SYMBOL LETTER W;So;0;L;;;;;N;;;;;
+1F1FD;REGIONAL INDICATOR SYMBOL LETTER X;So;0;L;;;;;N;;;;;
+1F1FE;REGIONAL INDICATOR SYMBOL LETTER Y;So;0;L;;;;;N;;;;;
+1F1FF;REGIONAL INDICATOR SYMBOL LETTER Z;So;0;L;;;;;N;;;;;
+1F200;SQUARE HIRAGANA HOKA;So;0;L;<square> 307B 304B;;;;N;;;;;
+1F201;SQUARED KATAKANA KOKO;So;0;L;<square> 30B3 30B3;;;;N;;;;;
+1F202;SQUARED KATAKANA SA;So;0;L;<square> 30B5;;;;N;;;;;
+1F210;SQUARED CJK UNIFIED IDEOGRAPH-624B;So;0;L;<square> 624B;;;;N;;;;;
+1F211;SQUARED CJK UNIFIED IDEOGRAPH-5B57;So;0;L;<square> 5B57;;;;N;;;;;
+1F212;SQUARED CJK UNIFIED IDEOGRAPH-53CC;So;0;L;<square> 53CC;;;;N;;;;;
+1F213;SQUARED KATAKANA DE;So;0;L;<square> 30C7;;;;N;;;;;
+1F214;SQUARED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<square> 4E8C;;;;N;;;;;
+1F215;SQUARED CJK UNIFIED IDEOGRAPH-591A;So;0;L;<square> 591A;;;;N;;;;;
+1F216;SQUARED CJK UNIFIED IDEOGRAPH-89E3;So;0;L;<square> 89E3;;;;N;;;;;
+1F217;SQUARED CJK UNIFIED IDEOGRAPH-5929;So;0;L;<square> 5929;;;;N;;;;;
+1F218;SQUARED CJK UNIFIED IDEOGRAPH-4EA4;So;0;L;<square> 4EA4;;;;N;;;;;
+1F219;SQUARED CJK UNIFIED IDEOGRAPH-6620;So;0;L;<square> 6620;;;;N;;;;;
+1F21A;SQUARED CJK UNIFIED IDEOGRAPH-7121;So;0;L;<square> 7121;;;;N;;;;;
+1F21B;SQUARED CJK UNIFIED IDEOGRAPH-6599;So;0;L;<square> 6599;;;;N;;;;;
+1F21C;SQUARED CJK UNIFIED IDEOGRAPH-524D;So;0;L;<square> 524D;;;;N;;;;;
+1F21D;SQUARED CJK UNIFIED IDEOGRAPH-5F8C;So;0;L;<square> 5F8C;;;;N;;;;;
+1F21E;SQUARED CJK UNIFIED IDEOGRAPH-518D;So;0;L;<square> 518D;;;;N;;;;;
+1F21F;SQUARED CJK UNIFIED IDEOGRAPH-65B0;So;0;L;<square> 65B0;;;;N;;;;;
+1F220;SQUARED CJK UNIFIED IDEOGRAPH-521D;So;0;L;<square> 521D;;;;N;;;;;
+1F221;SQUARED CJK UNIFIED IDEOGRAPH-7D42;So;0;L;<square> 7D42;;;;N;;;;;
+1F222;SQUARED CJK UNIFIED IDEOGRAPH-751F;So;0;L;<square> 751F;;;;N;;;;;
+1F223;SQUARED CJK UNIFIED IDEOGRAPH-8CA9;So;0;L;<square> 8CA9;;;;N;;;;;
+1F224;SQUARED CJK UNIFIED IDEOGRAPH-58F0;So;0;L;<square> 58F0;;;;N;;;;;
+1F225;SQUARED CJK UNIFIED IDEOGRAPH-5439;So;0;L;<square> 5439;;;;N;;;;;
+1F226;SQUARED CJK UNIFIED IDEOGRAPH-6F14;So;0;L;<square> 6F14;;;;N;;;;;
+1F227;SQUARED CJK UNIFIED IDEOGRAPH-6295;So;0;L;<square> 6295;;;;N;;;;;
+1F228;SQUARED CJK UNIFIED IDEOGRAPH-6355;So;0;L;<square> 6355;;;;N;;;;;
+1F229;SQUARED CJK UNIFIED IDEOGRAPH-4E00;So;0;L;<square> 4E00;;;;N;;;;;
+1F22A;SQUARED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<square> 4E09;;;;N;;;;;
+1F22B;SQUARED CJK UNIFIED IDEOGRAPH-904A;So;0;L;<square> 904A;;;;N;;;;;
+1F22C;SQUARED CJK UNIFIED IDEOGRAPH-5DE6;So;0;L;<square> 5DE6;;;;N;;;;;
+1F22D;SQUARED CJK UNIFIED IDEOGRAPH-4E2D;So;0;L;<square> 4E2D;;;;N;;;;;
+1F22E;SQUARED CJK UNIFIED IDEOGRAPH-53F3;So;0;L;<square> 53F3;;;;N;;;;;
+1F22F;SQUARED CJK UNIFIED IDEOGRAPH-6307;So;0;L;<square> 6307;;;;N;;;;;
+1F230;SQUARED CJK UNIFIED IDEOGRAPH-8D70;So;0;L;<square> 8D70;;;;N;;;;;
+1F231;SQUARED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<square> 6253;;;;N;;;;;
+1F232;SQUARED CJK UNIFIED IDEOGRAPH-7981;So;0;L;<square> 7981;;;;N;;;;;
+1F233;SQUARED CJK UNIFIED IDEOGRAPH-7A7A;So;0;L;<square> 7A7A;;;;N;;;;;
+1F234;SQUARED CJK UNIFIED IDEOGRAPH-5408;So;0;L;<square> 5408;;;;N;;;;;
+1F235;SQUARED CJK UNIFIED IDEOGRAPH-6E80;So;0;L;<square> 6E80;;;;N;;;;;
+1F236;SQUARED CJK UNIFIED IDEOGRAPH-6709;So;0;L;<square> 6709;;;;N;;;;;
+1F237;SQUARED CJK UNIFIED IDEOGRAPH-6708;So;0;L;<square> 6708;;;;N;;;;;
+1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L;<square> 7533;;;;N;;;;;
+1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L;<square> 5272;;;;N;;;;;
+1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L;<square> 55B6;;;;N;;;;;
+1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L;<square> 914D;;;;N;;;;;
+1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L;<compat> 3014 672C 3015;;;;N;;;;;
+1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<compat> 3014 4E09 3015;;;;N;;;;;
+1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<compat> 3014 4E8C 3015;;;;N;;;;;
+1F243;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89;So;0;L;<compat> 3014 5B89 3015;;;;N;;;;;
+1F244;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9;So;0;L;<compat> 3014 70B9 3015;;;;N;;;;;
+1F245;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253;So;0;L;<compat> 3014 6253 3015;;;;N;;;;;
+1F246;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7;So;0;L;<compat> 3014 76D7 3015;;;;N;;;;;
+1F247;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD;So;0;L;<compat> 3014 52DD 3015;;;;N;;;;;
+1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L;<compat> 3014 6557 3015;;;;N;;;;;
+1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L;<circle> 5F97;;;;N;;;;;
+1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L;<circle> 53EF;;;;N;;;;;
+1F300;CYCLONE;So;0;ON;;;;;N;;;;;
+1F301;FOGGY;So;0;ON;;;;;N;;;;;
+1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;;
+1F303;NIGHT WITH STARS;So;0;ON;;;;;N;;;;;
+1F304;SUNRISE OVER MOUNTAINS;So;0;ON;;;;;N;;;;;
+1F305;SUNRISE;So;0;ON;;;;;N;;;;;
+1F306;CITYSCAPE AT DUSK;So;0;ON;;;;;N;;;;;
+1F307;SUNSET OVER BUILDINGS;So;0;ON;;;;;N;;;;;
+1F308;RAINBOW;So;0;ON;;;;;N;;;;;
+1F309;BRIDGE AT NIGHT;So;0;ON;;;;;N;;;;;
+1F30A;WATER WAVE;So;0;ON;;;;;N;;;;;
+1F30B;VOLCANO;So;0;ON;;;;;N;;;;;
+1F30C;MILKY WAY;So;0;ON;;;;;N;;;;;
+1F30D;EARTH GLOBE EUROPE-AFRICA;So;0;ON;;;;;N;;;;;
+1F30E;EARTH GLOBE AMERICAS;So;0;ON;;;;;N;;;;;
+1F30F;EARTH GLOBE ASIA-AUSTRALIA;So;0;ON;;;;;N;;;;;
+1F310;GLOBE WITH MERIDIANS;So;0;ON;;;;;N;;;;;
+1F311;NEW MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F312;WAXING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F313;FIRST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F314;WAXING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F315;FULL MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F316;WANING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F317;LAST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F318;WANING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;;
+1F319;CRESCENT MOON;So;0;ON;;;;;N;;;;;
+1F31A;NEW MOON WITH FACE;So;0;ON;;;;;N;;;;;
+1F31B;FIRST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;;
+1F31C;LAST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;;
+1F31D;FULL MOON WITH FACE;So;0;ON;;;;;N;;;;;
+1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;;
+1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;;
+1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;;
+1F321;THERMOMETER;So;0;ON;;;;;N;;;;;
+1F322;BLACK DROPLET;So;0;ON;;;;;N;;;;;
+1F323;WHITE SUN;So;0;ON;;;;;N;;;;;
+1F324;WHITE SUN WITH SMALL CLOUD;So;0;ON;;;;;N;;;;;
+1F325;WHITE SUN BEHIND CLOUD;So;0;ON;;;;;N;;;;;
+1F326;WHITE SUN BEHIND CLOUD WITH RAIN;So;0;ON;;;;;N;;;;;
+1F327;CLOUD WITH RAIN;So;0;ON;;;;;N;;;;;
+1F328;CLOUD WITH SNOW;So;0;ON;;;;;N;;;;;
+1F329;CLOUD WITH LIGHTNING;So;0;ON;;;;;N;;;;;
+1F32A;CLOUD WITH TORNADO;So;0;ON;;;;;N;;;;;
+1F32B;FOG;So;0;ON;;;;;N;;;;;
+1F32C;WIND BLOWING FACE;So;0;ON;;;;;N;;;;;
+1F32D;HOT DOG;So;0;ON;;;;;N;;;;;
+1F32E;TACO;So;0;ON;;;;;N;;;;;
+1F32F;BURRITO;So;0;ON;;;;;N;;;;;
+1F330;CHESTNUT;So;0;ON;;;;;N;;;;;
+1F331;SEEDLING;So;0;ON;;;;;N;;;;;
+1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;;
+1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;;
+1F334;PALM TREE;So;0;ON;;;;;N;;;;;
+1F335;CACTUS;So;0;ON;;;;;N;;;;;
+1F336;HOT PEPPER;So;0;ON;;;;;N;;;;;
+1F337;TULIP;So;0;ON;;;;;N;;;;;
+1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;;
+1F339;ROSE;So;0;ON;;;;;N;;;;;
+1F33A;HIBISCUS;So;0;ON;;;;;N;;;;;
+1F33B;SUNFLOWER;So;0;ON;;;;;N;;;;;
+1F33C;BLOSSOM;So;0;ON;;;;;N;;;;;
+1F33D;EAR OF MAIZE;So;0;ON;;;;;N;;;;;
+1F33E;EAR OF RICE;So;0;ON;;;;;N;;;;;
+1F33F;HERB;So;0;ON;;;;;N;;;;;
+1F340;FOUR LEAF CLOVER;So;0;ON;;;;;N;;;;;
+1F341;MAPLE LEAF;So;0;ON;;;;;N;;;;;
+1F342;FALLEN LEAF;So;0;ON;;;;;N;;;;;
+1F343;LEAF FLUTTERING IN WIND;So;0;ON;;;;;N;;;;;
+1F344;MUSHROOM;So;0;ON;;;;;N;;;;;
+1F345;TOMATO;So;0;ON;;;;;N;;;;;
+1F346;AUBERGINE;So;0;ON;;;;;N;;;;;
+1F347;GRAPES;So;0;ON;;;;;N;;;;;
+1F348;MELON;So;0;ON;;;;;N;;;;;
+1F349;WATERMELON;So;0;ON;;;;;N;;;;;
+1F34A;TANGERINE;So;0;ON;;;;;N;;;;;
+1F34B;LEMON;So;0;ON;;;;;N;;;;;
+1F34C;BANANA;So;0;ON;;;;;N;;;;;
+1F34D;PINEAPPLE;So;0;ON;;;;;N;;;;;
+1F34E;RED APPLE;So;0;ON;;;;;N;;;;;
+1F34F;GREEN APPLE;So;0;ON;;;;;N;;;;;
+1F350;PEAR;So;0;ON;;;;;N;;;;;
+1F351;PEACH;So;0;ON;;;;;N;;;;;
+1F352;CHERRIES;So;0;ON;;;;;N;;;;;
+1F353;STRAWBERRY;So;0;ON;;;;;N;;;;;
+1F354;HAMBURGER;So;0;ON;;;;;N;;;;;
+1F355;SLICE OF PIZZA;So;0;ON;;;;;N;;;;;
+1F356;MEAT ON BONE;So;0;ON;;;;;N;;;;;
+1F357;POULTRY LEG;So;0;ON;;;;;N;;;;;
+1F358;RICE CRACKER;So;0;ON;;;;;N;;;;;
+1F359;RICE BALL;So;0;ON;;;;;N;;;;;
+1F35A;COOKED RICE;So;0;ON;;;;;N;;;;;
+1F35B;CURRY AND RICE;So;0;ON;;;;;N;;;;;
+1F35C;STEAMING BOWL;So;0;ON;;;;;N;;;;;
+1F35D;SPAGHETTI;So;0;ON;;;;;N;;;;;
+1F35E;BREAD;So;0;ON;;;;;N;;;;;
+1F35F;FRENCH FRIES;So;0;ON;;;;;N;;;;;
+1F360;ROASTED SWEET POTATO;So;0;ON;;;;;N;;;;;
+1F361;DANGO;So;0;ON;;;;;N;;;;;
+1F362;ODEN;So;0;ON;;;;;N;;;;;
+1F363;SUSHI;So;0;ON;;;;;N;;;;;
+1F364;FRIED SHRIMP;So;0;ON;;;;;N;;;;;
+1F365;FISH CAKE WITH SWIRL DESIGN;So;0;ON;;;;;N;;;;;
+1F366;SOFT ICE CREAM;So;0;ON;;;;;N;;;;;
+1F367;SHAVED ICE;So;0;ON;;;;;N;;;;;
+1F368;ICE CREAM;So;0;ON;;;;;N;;;;;
+1F369;DOUGHNUT;So;0;ON;;;;;N;;;;;
+1F36A;COOKIE;So;0;ON;;;;;N;;;;;
+1F36B;CHOCOLATE BAR;So;0;ON;;;;;N;;;;;
+1F36C;CANDY;So;0;ON;;;;;N;;;;;
+1F36D;LOLLIPOP;So;0;ON;;;;;N;;;;;
+1F36E;CUSTARD;So;0;ON;;;;;N;;;;;
+1F36F;HONEY POT;So;0;ON;;;;;N;;;;;
+1F370;SHORTCAKE;So;0;ON;;;;;N;;;;;
+1F371;BENTO BOX;So;0;ON;;;;;N;;;;;
+1F372;POT OF FOOD;So;0;ON;;;;;N;;;;;
+1F373;COOKING;So;0;ON;;;;;N;;;;;
+1F374;FORK AND KNIFE;So;0;ON;;;;;N;;;;;
+1F375;TEACUP WITHOUT HANDLE;So;0;ON;;;;;N;;;;;
+1F376;SAKE BOTTLE AND CUP;So;0;ON;;;;;N;;;;;
+1F377;WINE GLASS;So;0;ON;;;;;N;;;;;
+1F378;COCKTAIL GLASS;So;0;ON;;;;;N;;;;;
+1F379;TROPICAL DRINK;So;0;ON;;;;;N;;;;;
+1F37A;BEER MUG;So;0;ON;;;;;N;;;;;
+1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;;
+1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;;
+1F37D;FORK AND KNIFE WITH PLATE;So;0;ON;;;;;N;;;;;
+1F37E;BOTTLE WITH POPPING CORK;So;0;ON;;;;;N;;;;;
+1F37F;POPCORN;So;0;ON;;;;;N;;;;;
+1F380;RIBBON;So;0;ON;;;;;N;;;;;
+1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;;
+1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;;
+1F383;JACK-O-LANTERN;So;0;ON;;;;;N;;;;;
+1F384;CHRISTMAS TREE;So;0;ON;;;;;N;;;;;
+1F385;FATHER CHRISTMAS;So;0;ON;;;;;N;;;;;
+1F386;FIREWORKS;So;0;ON;;;;;N;;;;;
+1F387;FIREWORK SPARKLER;So;0;ON;;;;;N;;;;;
+1F388;BALLOON;So;0;ON;;;;;N;;;;;
+1F389;PARTY POPPER;So;0;ON;;;;;N;;;;;
+1F38A;CONFETTI BALL;So;0;ON;;;;;N;;;;;
+1F38B;TANABATA TREE;So;0;ON;;;;;N;;;;;
+1F38C;CROSSED FLAGS;So;0;ON;;;;;N;;;;;
+1F38D;PINE DECORATION;So;0;ON;;;;;N;;;;;
+1F38E;JAPANESE DOLLS;So;0;ON;;;;;N;;;;;
+1F38F;CARP STREAMER;So;0;ON;;;;;N;;;;;
+1F390;WIND CHIME;So;0;ON;;;;;N;;;;;
+1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;;
+1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;;
+1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;;
+1F394;HEART WITH TIP ON THE LEFT;So;0;ON;;;;;N;;;;;
+1F395;BOUQUET OF FLOWERS;So;0;ON;;;;;N;;;;;
+1F396;MILITARY MEDAL;So;0;ON;;;;;N;;;;;
+1F397;REMINDER RIBBON;So;0;ON;;;;;N;;;;;
+1F398;MUSICAL KEYBOARD WITH JACKS;So;0;ON;;;;;N;;;;;
+1F399;STUDIO MICROPHONE;So;0;ON;;;;;N;;;;;
+1F39A;LEVEL SLIDER;So;0;ON;;;;;N;;;;;
+1F39B;CONTROL KNOBS;So;0;ON;;;;;N;;;;;
+1F39C;BEAMED ASCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;;
+1F39D;BEAMED DESCENDING MUSICAL NOTES;So;0;ON;;;;;N;;;;;
+1F39E;FILM FRAMES;So;0;ON;;;;;N;;;;;
+1F39F;ADMISSION TICKETS;So;0;ON;;;;;N;;;;;
+1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;;
+1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;;
+1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;;
+1F3A3;FISHING POLE AND FISH;So;0;ON;;;;;N;;;;;
+1F3A4;MICROPHONE;So;0;ON;;;;;N;;;;;
+1F3A5;MOVIE CAMERA;So;0;ON;;;;;N;;;;;
+1F3A6;CINEMA;So;0;ON;;;;;N;;;;;
+1F3A7;HEADPHONE;So;0;ON;;;;;N;;;;;
+1F3A8;ARTIST PALETTE;So;0;ON;;;;;N;;;;;
+1F3A9;TOP HAT;So;0;ON;;;;;N;;;;;
+1F3AA;CIRCUS TENT;So;0;ON;;;;;N;;;;;
+1F3AB;TICKET;So;0;ON;;;;;N;;;;;
+1F3AC;CLAPPER BOARD;So;0;ON;;;;;N;;;;;
+1F3AD;PERFORMING ARTS;So;0;ON;;;;;N;;;;;
+1F3AE;VIDEO GAME;So;0;ON;;;;;N;;;;;
+1F3AF;DIRECT HIT;So;0;ON;;;;;N;;;;;
+1F3B0;SLOT MACHINE;So;0;ON;;;;;N;;;;;
+1F3B1;BILLIARDS;So;0;ON;;;;;N;;;;;
+1F3B2;GAME DIE;So;0;ON;;;;;N;;;;;
+1F3B3;BOWLING;So;0;ON;;;;;N;;;;;
+1F3B4;FLOWER PLAYING CARDS;So;0;ON;;;;;N;;;;;
+1F3B5;MUSICAL NOTE;So;0;ON;;;;;N;;;;;
+1F3B6;MULTIPLE MUSICAL NOTES;So;0;ON;;;;;N;;;;;
+1F3B7;SAXOPHONE;So;0;ON;;;;;N;;;;;
+1F3B8;GUITAR;So;0;ON;;;;;N;;;;;
+1F3B9;MUSICAL KEYBOARD;So;0;ON;;;;;N;;;;;
+1F3BA;TRUMPET;So;0;ON;;;;;N;;;;;
+1F3BB;VIOLIN;So;0;ON;;;;;N;;;;;
+1F3BC;MUSICAL SCORE;So;0;ON;;;;;N;;;;;
+1F3BD;RUNNING SHIRT WITH SASH;So;0;ON;;;;;N;;;;;
+1F3BE;TENNIS RACQUET AND BALL;So;0;ON;;;;;N;;;;;
+1F3BF;SKI AND SKI BOOT;So;0;ON;;;;;N;;;;;
+1F3C0;BASKETBALL AND HOOP;So;0;ON;;;;;N;;;;;
+1F3C1;CHEQUERED FLAG;So;0;ON;;;;;N;;;;;
+1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;;
+1F3C3;RUNNER;So;0;ON;;;;;N;;;;;
+1F3C4;SURFER;So;0;ON;;;;;N;;;;;
+1F3C5;SPORTS MEDAL;So;0;ON;;;;;N;;;;;
+1F3C6;TROPHY;So;0;ON;;;;;N;;;;;
+1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;;
+1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;;
+1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;;
+1F3CA;SWIMMER;So;0;ON;;;;;N;;;;;
+1F3CB;WEIGHT LIFTER;So;0;ON;;;;;N;;;;;
+1F3CC;GOLFER;So;0;ON;;;;;N;;;;;
+1F3CD;RACING MOTORCYCLE;So;0;ON;;;;;N;;;;;
+1F3CE;RACING CAR;So;0;ON;;;;;N;;;;;
+1F3CF;CRICKET BAT AND BALL;So;0;ON;;;;;N;;;;;
+1F3D0;VOLLEYBALL;So;0;ON;;;;;N;;;;;
+1F3D1;FIELD HOCKEY STICK AND BALL;So;0;ON;;;;;N;;;;;
+1F3D2;ICE HOCKEY STICK AND PUCK;So;0;ON;;;;;N;;;;;
+1F3D3;TABLE TENNIS PADDLE AND BALL;So;0;ON;;;;;N;;;;;
+1F3D4;SNOW CAPPED MOUNTAIN;So;0;ON;;;;;N;;;;;
+1F3D5;CAMPING;So;0;ON;;;;;N;;;;;
+1F3D6;BEACH WITH UMBRELLA;So;0;ON;;;;;N;;;;;
+1F3D7;BUILDING CONSTRUCTION;So;0;ON;;;;;N;;;;;
+1F3D8;HOUSE BUILDINGS;So;0;ON;;;;;N;;;;;
+1F3D9;CITYSCAPE;So;0;ON;;;;;N;;;;;
+1F3DA;DERELICT HOUSE BUILDING;So;0;ON;;;;;N;;;;;
+1F3DB;CLASSICAL BUILDING;So;0;ON;;;;;N;;;;;
+1F3DC;DESERT;So;0;ON;;;;;N;;;;;
+1F3DD;DESERT ISLAND;So;0;ON;;;;;N;;;;;
+1F3DE;NATIONAL PARK;So;0;ON;;;;;N;;;;;
+1F3DF;STADIUM;So;0;ON;;;;;N;;;;;
+1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;;
+1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;;
+1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;;
+1F3E3;JAPANESE POST OFFICE;So;0;ON;;;;;N;;;;;
+1F3E4;EUROPEAN POST OFFICE;So;0;ON;;;;;N;;;;;
+1F3E5;HOSPITAL;So;0;ON;;;;;N;;;;;
+1F3E6;BANK;So;0;ON;;;;;N;;;;;
+1F3E7;AUTOMATED TELLER MACHINE;So;0;ON;;;;;N;;;;;
+1F3E8;HOTEL;So;0;ON;;;;;N;;;;;
+1F3E9;LOVE HOTEL;So;0;ON;;;;;N;;;;;
+1F3EA;CONVENIENCE STORE;So;0;ON;;;;;N;;;;;
+1F3EB;SCHOOL;So;0;ON;;;;;N;;;;;
+1F3EC;DEPARTMENT STORE;So;0;ON;;;;;N;;;;;
+1F3ED;FACTORY;So;0;ON;;;;;N;;;;;
+1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;;
+1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;;
+1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;;
+1F3F1;WHITE PENNANT;So;0;ON;;;;;N;;;;;
+1F3F2;BLACK PENNANT;So;0;ON;;;;;N;;;;;
+1F3F3;WAVING WHITE FLAG;So;0;ON;;;;;N;;;;;
+1F3F4;WAVING BLACK FLAG;So;0;ON;;;;;N;;;;;
+1F3F5;ROSETTE;So;0;ON;;;;;N;;;;;
+1F3F6;BLACK ROSETTE;So;0;ON;;;;;N;;;;;
+1F3F7;LABEL;So;0;ON;;;;;N;;;;;
+1F3F8;BADMINTON RACQUET AND SHUTTLECOCK;So;0;ON;;;;;N;;;;;
+1F3F9;BOW AND ARROW;So;0;ON;;;;;N;;;;;
+1F3FA;AMPHORA;So;0;ON;;;;;N;;;;;
+1F3FB;EMOJI MODIFIER FITZPATRICK TYPE-1-2;Sk;0;ON;;;;;N;;;;;
+1F3FC;EMOJI MODIFIER FITZPATRICK TYPE-3;Sk;0;ON;;;;;N;;;;;
+1F3FD;EMOJI MODIFIER FITZPATRICK TYPE-4;Sk;0;ON;;;;;N;;;;;
+1F3FE;EMOJI MODIFIER FITZPATRICK TYPE-5;Sk;0;ON;;;;;N;;;;;
+1F3FF;EMOJI MODIFIER FITZPATRICK TYPE-6;Sk;0;ON;;;;;N;;;;;
+1F400;RAT;So;0;ON;;;;;N;;;;;
+1F401;MOUSE;So;0;ON;;;;;N;;;;;
+1F402;OX;So;0;ON;;;;;N;;;;;
+1F403;WATER BUFFALO;So;0;ON;;;;;N;;;;;
+1F404;COW;So;0;ON;;;;;N;;;;;
+1F405;TIGER;So;0;ON;;;;;N;;;;;
+1F406;LEOPARD;So;0;ON;;;;;N;;;;;
+1F407;RABBIT;So;0;ON;;;;;N;;;;;
+1F408;CAT;So;0;ON;;;;;N;;;;;
+1F409;DRAGON;So;0;ON;;;;;N;;;;;
+1F40A;CROCODILE;So;0;ON;;;;;N;;;;;
+1F40B;WHALE;So;0;ON;;;;;N;;;;;
+1F40C;SNAIL;So;0;ON;;;;;N;;;;;
+1F40D;SNAKE;So;0;ON;;;;;N;;;;;
+1F40E;HORSE;So;0;ON;;;;;N;;;;;
+1F40F;RAM;So;0;ON;;;;;N;;;;;
+1F410;GOAT;So;0;ON;;;;;N;;;;;
+1F411;SHEEP;So;0;ON;;;;;N;;;;;
+1F412;MONKEY;So;0;ON;;;;;N;;;;;
+1F413;ROOSTER;So;0;ON;;;;;N;;;;;
+1F414;CHICKEN;So;0;ON;;;;;N;;;;;
+1F415;DOG;So;0;ON;;;;;N;;;;;
+1F416;PIG;So;0;ON;;;;;N;;;;;
+1F417;BOAR;So;0;ON;;;;;N;;;;;
+1F418;ELEPHANT;So;0;ON;;;;;N;;;;;
+1F419;OCTOPUS;So;0;ON;;;;;N;;;;;
+1F41A;SPIRAL SHELL;So;0;ON;;;;;N;;;;;
+1F41B;BUG;So;0;ON;;;;;N;;;;;
+1F41C;ANT;So;0;ON;;;;;N;;;;;
+1F41D;HONEYBEE;So;0;ON;;;;;N;;;;;
+1F41E;LADY BEETLE;So;0;ON;;;;;N;;;;;
+1F41F;FISH;So;0;ON;;;;;N;;;;;
+1F420;TROPICAL FISH;So;0;ON;;;;;N;;;;;
+1F421;BLOWFISH;So;0;ON;;;;;N;;;;;
+1F422;TURTLE;So;0;ON;;;;;N;;;;;
+1F423;HATCHING CHICK;So;0;ON;;;;;N;;;;;
+1F424;BABY CHICK;So;0;ON;;;;;N;;;;;
+1F425;FRONT-FACING BABY CHICK;So;0;ON;;;;;N;;;;;
+1F426;BIRD;So;0;ON;;;;;N;;;;;
+1F427;PENGUIN;So;0;ON;;;;;N;;;;;
+1F428;KOALA;So;0;ON;;;;;N;;;;;
+1F429;POODLE;So;0;ON;;;;;N;;;;;
+1F42A;DROMEDARY CAMEL;So;0;ON;;;;;N;;;;;
+1F42B;BACTRIAN CAMEL;So;0;ON;;;;;N;;;;;
+1F42C;DOLPHIN;So;0;ON;;;;;N;;;;;
+1F42D;MOUSE FACE;So;0;ON;;;;;N;;;;;
+1F42E;COW FACE;So;0;ON;;;;;N;;;;;
+1F42F;TIGER FACE;So;0;ON;;;;;N;;;;;
+1F430;RABBIT FACE;So;0;ON;;;;;N;;;;;
+1F431;CAT FACE;So;0;ON;;;;;N;;;;;
+1F432;DRAGON FACE;So;0;ON;;;;;N;;;;;
+1F433;SPOUTING WHALE;So;0;ON;;;;;N;;;;;
+1F434;HORSE FACE;So;0;ON;;;;;N;;;;;
+1F435;MONKEY FACE;So;0;ON;;;;;N;;;;;
+1F436;DOG FACE;So;0;ON;;;;;N;;;;;
+1F437;PIG FACE;So;0;ON;;;;;N;;;;;
+1F438;FROG FACE;So;0;ON;;;;;N;;;;;
+1F439;HAMSTER FACE;So;0;ON;;;;;N;;;;;
+1F43A;WOLF FACE;So;0;ON;;;;;N;;;;;
+1F43B;BEAR FACE;So;0;ON;;;;;N;;;;;
+1F43C;PANDA FACE;So;0;ON;;;;;N;;;;;
+1F43D;PIG NOSE;So;0;ON;;;;;N;;;;;
+1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;;
+1F43F;CHIPMUNK;So;0;ON;;;;;N;;;;;
+1F440;EYES;So;0;ON;;;;;N;;;;;
+1F441;EYE;So;0;ON;;;;;N;;;;;
+1F442;EAR;So;0;ON;;;;;N;;;;;
+1F443;NOSE;So;0;ON;;;;;N;;;;;
+1F444;MOUTH;So;0;ON;;;;;N;;;;;
+1F445;TONGUE;So;0;ON;;;;;N;;;;;
+1F446;WHITE UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F447;WHITE DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F448;WHITE LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F449;WHITE RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F44A;FISTED HAND SIGN;So;0;ON;;;;;N;;;;;
+1F44B;WAVING HAND SIGN;So;0;ON;;;;;N;;;;;
+1F44C;OK HAND SIGN;So;0;ON;;;;;N;;;;;
+1F44D;THUMBS UP SIGN;So;0;ON;;;;;N;;;;;
+1F44E;THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;;
+1F44F;CLAPPING HANDS SIGN;So;0;ON;;;;;N;;;;;
+1F450;OPEN HANDS SIGN;So;0;ON;;;;;N;;;;;
+1F451;CROWN;So;0;ON;;;;;N;;;;;
+1F452;WOMANS HAT;So;0;ON;;;;;N;;;;;
+1F453;EYEGLASSES;So;0;ON;;;;;N;;;;;
+1F454;NECKTIE;So;0;ON;;;;;N;;;;;
+1F455;T-SHIRT;So;0;ON;;;;;N;;;;;
+1F456;JEANS;So;0;ON;;;;;N;;;;;
+1F457;DRESS;So;0;ON;;;;;N;;;;;
+1F458;KIMONO;So;0;ON;;;;;N;;;;;
+1F459;BIKINI;So;0;ON;;;;;N;;;;;
+1F45A;WOMANS CLOTHES;So;0;ON;;;;;N;;;;;
+1F45B;PURSE;So;0;ON;;;;;N;;;;;
+1F45C;HANDBAG;So;0;ON;;;;;N;;;;;
+1F45D;POUCH;So;0;ON;;;;;N;;;;;
+1F45E;MANS SHOE;So;0;ON;;;;;N;;;;;
+1F45F;ATHLETIC SHOE;So;0;ON;;;;;N;;;;;
+1F460;HIGH-HEELED SHOE;So;0;ON;;;;;N;;;;;
+1F461;WOMANS SANDAL;So;0;ON;;;;;N;;;;;
+1F462;WOMANS BOOTS;So;0;ON;;;;;N;;;;;
+1F463;FOOTPRINTS;So;0;ON;;;;;N;;;;;
+1F464;BUST IN SILHOUETTE;So;0;ON;;;;;N;;;;;
+1F465;BUSTS IN SILHOUETTE;So;0;ON;;;;;N;;;;;
+1F466;BOY;So;0;ON;;;;;N;;;;;
+1F467;GIRL;So;0;ON;;;;;N;;;;;
+1F468;MAN;So;0;ON;;;;;N;;;;;
+1F469;WOMAN;So;0;ON;;;;;N;;;;;
+1F46A;FAMILY;So;0;ON;;;;;N;;;;;
+1F46B;MAN AND WOMAN HOLDING HANDS;So;0;ON;;;;;N;;;;;
+1F46C;TWO MEN HOLDING HANDS;So;0;ON;;;;;N;;;;;
+1F46D;TWO WOMEN HOLDING HANDS;So;0;ON;;;;;N;;;;;
+1F46E;POLICE OFFICER;So;0;ON;;;;;N;;;;;
+1F46F;WOMAN WITH BUNNY EARS;So;0;ON;;;;;N;;;;;
+1F470;BRIDE WITH VEIL;So;0;ON;;;;;N;;;;;
+1F471;PERSON WITH BLOND HAIR;So;0;ON;;;;;N;;;;;
+1F472;MAN WITH GUA PI MAO;So;0;ON;;;;;N;;;;;
+1F473;MAN WITH TURBAN;So;0;ON;;;;;N;;;;;
+1F474;OLDER MAN;So;0;ON;;;;;N;;;;;
+1F475;OLDER WOMAN;So;0;ON;;;;;N;;;;;
+1F476;BABY;So;0;ON;;;;;N;;;;;
+1F477;CONSTRUCTION WORKER;So;0;ON;;;;;N;;;;;
+1F478;PRINCESS;So;0;ON;;;;;N;;;;;
+1F479;JAPANESE OGRE;So;0;ON;;;;;N;;;;;
+1F47A;JAPANESE GOBLIN;So;0;ON;;;;;N;;;;;
+1F47B;GHOST;So;0;ON;;;;;N;;;;;
+1F47C;BABY ANGEL;So;0;ON;;;;;N;;;;;
+1F47D;EXTRATERRESTRIAL ALIEN;So;0;ON;;;;;N;;;;;
+1F47E;ALIEN MONSTER;So;0;ON;;;;;N;;;;;
+1F47F;IMP;So;0;ON;;;;;N;;;;;
+1F480;SKULL;So;0;ON;;;;;N;;;;;
+1F481;INFORMATION DESK PERSON;So;0;ON;;;;;N;;;;;
+1F482;GUARDSMAN;So;0;ON;;;;;N;;;;;
+1F483;DANCER;So;0;ON;;;;;N;;;;;
+1F484;LIPSTICK;So;0;ON;;;;;N;;;;;
+1F485;NAIL POLISH;So;0;ON;;;;;N;;;;;
+1F486;FACE MASSAGE;So;0;ON;;;;;N;;;;;
+1F487;HAIRCUT;So;0;ON;;;;;N;;;;;
+1F488;BARBER POLE;So;0;ON;;;;;N;;;;;
+1F489;SYRINGE;So;0;ON;;;;;N;;;;;
+1F48A;PILL;So;0;ON;;;;;N;;;;;
+1F48B;KISS MARK;So;0;ON;;;;;N;;;;;
+1F48C;LOVE LETTER;So;0;ON;;;;;N;;;;;
+1F48D;RING;So;0;ON;;;;;N;;;;;
+1F48E;GEM STONE;So;0;ON;;;;;N;;;;;
+1F48F;KISS;So;0;ON;;;;;N;;;;;
+1F490;BOUQUET;So;0;ON;;;;;N;;;;;
+1F491;COUPLE WITH HEART;So;0;ON;;;;;N;;;;;
+1F492;WEDDING;So;0;ON;;;;;N;;;;;
+1F493;BEATING HEART;So;0;ON;;;;;N;;;;;
+1F494;BROKEN HEART;So;0;ON;;;;;N;;;;;
+1F495;TWO HEARTS;So;0;ON;;;;;N;;;;;
+1F496;SPARKLING HEART;So;0;ON;;;;;N;;;;;
+1F497;GROWING HEART;So;0;ON;;;;;N;;;;;
+1F498;HEART WITH ARROW;So;0;ON;;;;;N;;;;;
+1F499;BLUE HEART;So;0;ON;;;;;N;;;;;
+1F49A;GREEN HEART;So;0;ON;;;;;N;;;;;
+1F49B;YELLOW HEART;So;0;ON;;;;;N;;;;;
+1F49C;PURPLE HEART;So;0;ON;;;;;N;;;;;
+1F49D;HEART WITH RIBBON;So;0;ON;;;;;N;;;;;
+1F49E;REVOLVING HEARTS;So;0;ON;;;;;N;;;;;
+1F49F;HEART DECORATION;So;0;ON;;;;;N;;;;;
+1F4A0;DIAMOND SHAPE WITH A DOT INSIDE;So;0;ON;;;;;N;;;;;
+1F4A1;ELECTRIC LIGHT BULB;So;0;ON;;;;;N;;;;;
+1F4A2;ANGER SYMBOL;So;0;ON;;;;;N;;;;;
+1F4A3;BOMB;So;0;ON;;;;;N;;;;;
+1F4A4;SLEEPING SYMBOL;So;0;ON;;;;;N;;;;;
+1F4A5;COLLISION SYMBOL;So;0;ON;;;;;N;;;;;
+1F4A6;SPLASHING SWEAT SYMBOL;So;0;ON;;;;;N;;;;;
+1F4A7;DROPLET;So;0;ON;;;;;N;;;;;
+1F4A8;DASH SYMBOL;So;0;ON;;;;;N;;;;;
+1F4A9;PILE OF POO;So;0;ON;;;;;N;;;;;
+1F4AA;FLEXED BICEPS;So;0;ON;;;;;N;;;;;
+1F4AB;DIZZY SYMBOL;So;0;ON;;;;;N;;;;;
+1F4AC;SPEECH BALLOON;So;0;ON;;;;;N;;;;;
+1F4AD;THOUGHT BALLOON;So;0;ON;;;;;N;;;;;
+1F4AE;WHITE FLOWER;So;0;ON;;;;;N;;;;;
+1F4AF;HUNDRED POINTS SYMBOL;So;0;ON;;;;;N;;;;;
+1F4B0;MONEY BAG;So;0;ON;;;;;N;;;;;
+1F4B1;CURRENCY EXCHANGE;So;0;ON;;;;;N;;;;;
+1F4B2;HEAVY DOLLAR SIGN;So;0;ON;;;;;N;;;;;
+1F4B3;CREDIT CARD;So;0;ON;;;;;N;;;;;
+1F4B4;BANKNOTE WITH YEN SIGN;So;0;ON;;;;;N;;;;;
+1F4B5;BANKNOTE WITH DOLLAR SIGN;So;0;ON;;;;;N;;;;;
+1F4B6;BANKNOTE WITH EURO SIGN;So;0;ON;;;;;N;;;;;
+1F4B7;BANKNOTE WITH POUND SIGN;So;0;ON;;;;;N;;;;;
+1F4B8;MONEY WITH WINGS;So;0;ON;;;;;N;;;;;
+1F4B9;CHART WITH UPWARDS TREND AND YEN SIGN;So;0;ON;;;;;N;;;;;
+1F4BA;SEAT;So;0;ON;;;;;N;;;;;
+1F4BB;PERSONAL COMPUTER;So;0;ON;;;;;N;;;;;
+1F4BC;BRIEFCASE;So;0;ON;;;;;N;;;;;
+1F4BD;MINIDISC;So;0;ON;;;;;N;;;;;
+1F4BE;FLOPPY DISK;So;0;ON;;;;;N;;;;;
+1F4BF;OPTICAL DISC;So;0;ON;;;;;N;;;;;
+1F4C0;DVD;So;0;ON;;;;;N;;;;;
+1F4C1;FILE FOLDER;So;0;ON;;;;;N;;;;;
+1F4C2;OPEN FILE FOLDER;So;0;ON;;;;;N;;;;;
+1F4C3;PAGE WITH CURL;So;0;ON;;;;;N;;;;;
+1F4C4;PAGE FACING UP;So;0;ON;;;;;N;;;;;
+1F4C5;CALENDAR;So;0;ON;;;;;N;;;;;
+1F4C6;TEAR-OFF CALENDAR;So;0;ON;;;;;N;;;;;
+1F4C7;CARD INDEX;So;0;ON;;;;;N;;;;;
+1F4C8;CHART WITH UPWARDS TREND;So;0;ON;;;;;N;;;;;
+1F4C9;CHART WITH DOWNWARDS TREND;So;0;ON;;;;;N;;;;;
+1F4CA;BAR CHART;So;0;ON;;;;;N;;;;;
+1F4CB;CLIPBOARD;So;0;ON;;;;;N;;;;;
+1F4CC;PUSHPIN;So;0;ON;;;;;N;;;;;
+1F4CD;ROUND PUSHPIN;So;0;ON;;;;;N;;;;;
+1F4CE;PAPERCLIP;So;0;ON;;;;;N;;;;;
+1F4CF;STRAIGHT RULER;So;0;ON;;;;;N;;;;;
+1F4D0;TRIANGULAR RULER;So;0;ON;;;;;N;;;;;
+1F4D1;BOOKMARK TABS;So;0;ON;;;;;N;;;;;
+1F4D2;LEDGER;So;0;ON;;;;;N;;;;;
+1F4D3;NOTEBOOK;So;0;ON;;;;;N;;;;;
+1F4D4;NOTEBOOK WITH DECORATIVE COVER;So;0;ON;;;;;N;;;;;
+1F4D5;CLOSED BOOK;So;0;ON;;;;;N;;;;;
+1F4D6;OPEN BOOK;So;0;ON;;;;;N;;;;;
+1F4D7;GREEN BOOK;So;0;ON;;;;;N;;;;;
+1F4D8;BLUE BOOK;So;0;ON;;;;;N;;;;;
+1F4D9;ORANGE BOOK;So;0;ON;;;;;N;;;;;
+1F4DA;BOOKS;So;0;ON;;;;;N;;;;;
+1F4DB;NAME BADGE;So;0;ON;;;;;N;;;;;
+1F4DC;SCROLL;So;0;ON;;;;;N;;;;;
+1F4DD;MEMO;So;0;ON;;;;;N;;;;;
+1F4DE;TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;
+1F4DF;PAGER;So;0;ON;;;;;N;;;;;
+1F4E0;FAX MACHINE;So;0;ON;;;;;N;;;;;
+1F4E1;SATELLITE ANTENNA;So;0;ON;;;;;N;;;;;
+1F4E2;PUBLIC ADDRESS LOUDSPEAKER;So;0;ON;;;;;N;;;;;
+1F4E3;CHEERING MEGAPHONE;So;0;ON;;;;;N;;;;;
+1F4E4;OUTBOX TRAY;So;0;ON;;;;;N;;;;;
+1F4E5;INBOX TRAY;So;0;ON;;;;;N;;;;;
+1F4E6;PACKAGE;So;0;ON;;;;;N;;;;;
+1F4E7;E-MAIL SYMBOL;So;0;ON;;;;;N;;;;;
+1F4E8;INCOMING ENVELOPE;So;0;ON;;;;;N;;;;;
+1F4E9;ENVELOPE WITH DOWNWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F4EA;CLOSED MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;;
+1F4EB;CLOSED MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;;
+1F4EC;OPEN MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;;
+1F4ED;OPEN MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;;
+1F4EE;POSTBOX;So;0;ON;;;;;N;;;;;
+1F4EF;POSTAL HORN;So;0;ON;;;;;N;;;;;
+1F4F0;NEWSPAPER;So;0;ON;;;;;N;;;;;
+1F4F1;MOBILE PHONE;So;0;ON;;;;;N;;;;;
+1F4F2;MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT;So;0;ON;;;;;N;;;;;
+1F4F3;VIBRATION MODE;So;0;ON;;;;;N;;;;;
+1F4F4;MOBILE PHONE OFF;So;0;ON;;;;;N;;;;;
+1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;;
+1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;;
+1F4F7;CAMERA;So;0;ON;;;;;N;;;;;
+1F4F8;CAMERA WITH FLASH;So;0;ON;;;;;N;;;;;
+1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;;
+1F4FA;TELEVISION;So;0;ON;;;;;N;;;;;
+1F4FB;RADIO;So;0;ON;;;;;N;;;;;
+1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;;
+1F4FD;FILM PROJECTOR;So;0;ON;;;;;N;;;;;
+1F4FE;PORTABLE STEREO;So;0;ON;;;;;N;;;;;
+1F4FF;PRAYER BEADS;So;0;ON;;;;;N;;;;;
+1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;;
+1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;
+1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;;
+1F503;CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;
+1F504;ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;;
+1F505;LOW BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;;
+1F506;HIGH BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;;
+1F507;SPEAKER WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;;
+1F508;SPEAKER;So;0;ON;;;;;N;;;;;
+1F509;SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;;
+1F50A;SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;;
+1F50B;BATTERY;So;0;ON;;;;;N;;;;;
+1F50C;ELECTRIC PLUG;So;0;ON;;;;;N;;;;;
+1F50D;LEFT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;;
+1F50E;RIGHT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;;
+1F50F;LOCK WITH INK PEN;So;0;ON;;;;;N;;;;;
+1F510;CLOSED LOCK WITH KEY;So;0;ON;;;;;N;;;;;
+1F511;KEY;So;0;ON;;;;;N;;;;;
+1F512;LOCK;So;0;ON;;;;;N;;;;;
+1F513;OPEN LOCK;So;0;ON;;;;;N;;;;;
+1F514;BELL;So;0;ON;;;;;N;;;;;
+1F515;BELL WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;;
+1F516;BOOKMARK;So;0;ON;;;;;N;;;;;
+1F517;LINK SYMBOL;So;0;ON;;;;;N;;;;;
+1F518;RADIO BUTTON;So;0;ON;;;;;N;;;;;
+1F519;BACK WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F51A;END WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F51B;ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F51C;SOON WITH RIGHTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F51D;TOP WITH UPWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;;
+1F51E;NO ONE UNDER EIGHTEEN SYMBOL;So;0;ON;;;;;N;;;;;
+1F51F;KEYCAP TEN;So;0;ON;;;;;N;;;;;
+1F520;INPUT SYMBOL FOR LATIN CAPITAL LETTERS;So;0;ON;;;;;N;;;;;
+1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;;
+1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;;
+1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;;
+1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;ON;;;;;N;;;;;
+1F525;FIRE;So;0;ON;;;;;N;;;;;
+1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;;
+1F527;WRENCH;So;0;ON;;;;;N;;;;;
+1F528;HAMMER;So;0;ON;;;;;N;;;;;
+1F529;NUT AND BOLT;So;0;ON;;;;;N;;;;;
+1F52A;HOCHO;So;0;ON;;;;;N;;;;;
+1F52B;PISTOL;So;0;ON;;;;;N;;;;;
+1F52C;MICROSCOPE;So;0;ON;;;;;N;;;;;
+1F52D;TELESCOPE;So;0;ON;;;;;N;;;;;
+1F52E;CRYSTAL BALL;So;0;ON;;;;;N;;;;;
+1F52F;SIX POINTED STAR WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;
+1F530;JAPANESE SYMBOL FOR BEGINNER;So;0;ON;;;;;N;;;;;
+1F531;TRIDENT EMBLEM;So;0;ON;;;;;N;;;;;
+1F532;BLACK SQUARE BUTTON;So;0;ON;;;;;N;;;;;
+1F533;WHITE SQUARE BUTTON;So;0;ON;;;;;N;;;;;
+1F534;LARGE RED CIRCLE;So;0;ON;;;;;N;;;;;
+1F535;LARGE BLUE CIRCLE;So;0;ON;;;;;N;;;;;
+1F536;LARGE ORANGE DIAMOND;So;0;ON;;;;;N;;;;;
+1F537;LARGE BLUE DIAMOND;So;0;ON;;;;;N;;;;;
+1F538;SMALL ORANGE DIAMOND;So;0;ON;;;;;N;;;;;
+1F539;SMALL BLUE DIAMOND;So;0;ON;;;;;N;;;;;
+1F53A;UP-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F53E;LOWER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F53F;UPPER RIGHT SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F540;CIRCLED CROSS POMMEE;So;0;ON;;;;;N;;;;;
+1F541;CROSS POMMEE WITH HALF-CIRCLE BELOW;So;0;ON;;;;;N;;;;;
+1F542;CROSS POMMEE;So;0;ON;;;;;N;;;;;
+1F543;NOTCHED LEFT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;
+1F544;NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;;
+1F545;SYMBOL FOR MARKS CHAPTER;So;0;ON;;;;;N;;;;;
+1F546;WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;
+1F547;HEAVY LATIN CROSS;So;0;ON;;;;;N;;;;;
+1F548;CELTIC CROSS;So;0;ON;;;;;N;;;;;
+1F549;OM SYMBOL;So;0;ON;;;;;N;;;;;
+1F54A;DOVE OF PEACE;So;0;ON;;;;;N;;;;;
+1F54B;KAABA;So;0;ON;;;;;N;;;;;
+1F54C;MOSQUE;So;0;ON;;;;;N;;;;;
+1F54D;SYNAGOGUE;So;0;ON;;;;;N;;;;;
+1F54E;MENORAH WITH NINE BRANCHES;So;0;ON;;;;;N;;;;;
+1F54F;BOWL OF HYGIEIA;So;0;ON;;;;;N;;;;;
+1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;;
+1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;;
+1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;;
+1F553;CLOCK FACE FOUR OCLOCK;So;0;ON;;;;;N;;;;;
+1F554;CLOCK FACE FIVE OCLOCK;So;0;ON;;;;;N;;;;;
+1F555;CLOCK FACE SIX OCLOCK;So;0;ON;;;;;N;;;;;
+1F556;CLOCK FACE SEVEN OCLOCK;So;0;ON;;;;;N;;;;;
+1F557;CLOCK FACE EIGHT OCLOCK;So;0;ON;;;;;N;;;;;
+1F558;CLOCK FACE NINE OCLOCK;So;0;ON;;;;;N;;;;;
+1F559;CLOCK FACE TEN OCLOCK;So;0;ON;;;;;N;;;;;
+1F55A;CLOCK FACE ELEVEN OCLOCK;So;0;ON;;;;;N;;;;;
+1F55B;CLOCK FACE TWELVE OCLOCK;So;0;ON;;;;;N;;;;;
+1F55C;CLOCK FACE ONE-THIRTY;So;0;ON;;;;;N;;;;;
+1F55D;CLOCK FACE TWO-THIRTY;So;0;ON;;;;;N;;;;;
+1F55E;CLOCK FACE THREE-THIRTY;So;0;ON;;;;;N;;;;;
+1F55F;CLOCK FACE FOUR-THIRTY;So;0;ON;;;;;N;;;;;
+1F560;CLOCK FACE FIVE-THIRTY;So;0;ON;;;;;N;;;;;
+1F561;CLOCK FACE SIX-THIRTY;So;0;ON;;;;;N;;;;;
+1F562;CLOCK FACE SEVEN-THIRTY;So;0;ON;;;;;N;;;;;
+1F563;CLOCK FACE EIGHT-THIRTY;So;0;ON;;;;;N;;;;;
+1F564;CLOCK FACE NINE-THIRTY;So;0;ON;;;;;N;;;;;
+1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;;
+1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;;
+1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;;
+1F568;RIGHT SPEAKER;So;0;ON;;;;;N;;;;;
+1F569;RIGHT SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;;
+1F56A;RIGHT SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;;
+1F56B;BULLHORN;So;0;ON;;;;;N;;;;;
+1F56C;BULLHORN WITH SOUND WAVES;So;0;ON;;;;;N;;;;;
+1F56D;RINGING BELL;So;0;ON;;;;;N;;;;;
+1F56E;BOOK;So;0;ON;;;;;N;;;;;
+1F56F;CANDLE;So;0;ON;;;;;N;;;;;
+1F570;MANTELPIECE CLOCK;So;0;ON;;;;;N;;;;;
+1F571;BLACK SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;
+1F572;NO PIRACY;So;0;ON;;;;;N;;;;;
+1F573;HOLE;So;0;ON;;;;;N;;;;;
+1F574;MAN IN BUSINESS SUIT LEVITATING;So;0;ON;;;;;N;;;;;
+1F575;SLEUTH OR SPY;So;0;ON;;;;;N;;;;;
+1F576;DARK SUNGLASSES;So;0;ON;;;;;N;;;;;
+1F577;SPIDER;So;0;ON;;;;;N;;;;;
+1F578;SPIDER WEB;So;0;ON;;;;;N;;;;;
+1F579;JOYSTICK;So;0;ON;;;;;N;;;;;
+1F57A;MAN DANCING;So;0;ON;;;;;N;;;;;
+1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;
+1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;;
+1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;;
+1F57E;WHITE TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;;
+1F57F;BLACK TOUCHTONE TELEPHONE;So;0;ON;;;;;N;;;;;
+1F580;TELEPHONE ON TOP OF MODEM;So;0;ON;;;;;N;;;;;
+1F581;CLAMSHELL MOBILE PHONE;So;0;ON;;;;;N;;;;;
+1F582;BACK OF ENVELOPE;So;0;ON;;;;;N;;;;;
+1F583;STAMPED ENVELOPE;So;0;ON;;;;;N;;;;;
+1F584;ENVELOPE WITH LIGHTNING;So;0;ON;;;;;N;;;;;
+1F585;FLYING ENVELOPE;So;0;ON;;;;;N;;;;;
+1F586;PEN OVER STAMPED ENVELOPE;So;0;ON;;;;;N;;;;;
+1F587;LINKED PAPERCLIPS;So;0;ON;;;;;N;;;;;
+1F588;BLACK PUSHPIN;So;0;ON;;;;;N;;;;;
+1F589;LOWER LEFT PENCIL;So;0;ON;;;;;N;;;;;
+1F58A;LOWER LEFT BALLPOINT PEN;So;0;ON;;;;;N;;;;;
+1F58B;LOWER LEFT FOUNTAIN PEN;So;0;ON;;;;;N;;;;;
+1F58C;LOWER LEFT PAINTBRUSH;So;0;ON;;;;;N;;;;;
+1F58D;LOWER LEFT CRAYON;So;0;ON;;;;;N;;;;;
+1F58E;LEFT WRITING HAND;So;0;ON;;;;;N;;;;;
+1F58F;TURNED OK HAND SIGN;So;0;ON;;;;;N;;;;;
+1F590;RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;;
+1F591;REVERSED RAISED HAND WITH FINGERS SPLAYED;So;0;ON;;;;;N;;;;;
+1F592;REVERSED THUMBS UP SIGN;So;0;ON;;;;;N;;;;;
+1F593;REVERSED THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;;
+1F594;REVERSED VICTORY HAND;So;0;ON;;;;;N;;;;;
+1F595;REVERSED HAND WITH MIDDLE FINGER EXTENDED;So;0;ON;;;;;N;;;;;
+1F596;RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS;So;0;ON;;;;;N;;;;;
+1F597;WHITE DOWN POINTING LEFT HAND INDEX;So;0;ON;;;;;N;;;;;
+1F598;SIDEWAYS WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F599;SIDEWAYS WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F59A;SIDEWAYS BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F59B;SIDEWAYS BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F59C;BLACK LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F59D;BLACK RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F59E;SIDEWAYS WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F59F;SIDEWAYS WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F5A0;SIDEWAYS BLACK UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;;
+1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;;
+1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;;
+1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;;
+1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;;
+1F5A8;PRINTER;So;0;ON;;;;;N;;;;;
+1F5A9;POCKET CALCULATOR;So;0;ON;;;;;N;;;;;
+1F5AA;BLACK HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;
+1F5AB;WHITE HARD SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;
+1F5AC;SOFT SHELL FLOPPY DISK;So;0;ON;;;;;N;;;;;
+1F5AD;TAPE CARTRIDGE;So;0;ON;;;;;N;;;;;
+1F5AE;WIRED KEYBOARD;So;0;ON;;;;;N;;;;;
+1F5AF;ONE BUTTON MOUSE;So;0;ON;;;;;N;;;;;
+1F5B0;TWO BUTTON MOUSE;So;0;ON;;;;;N;;;;;
+1F5B1;THREE BUTTON MOUSE;So;0;ON;;;;;N;;;;;
+1F5B2;TRACKBALL;So;0;ON;;;;;N;;;;;
+1F5B3;OLD PERSONAL COMPUTER;So;0;ON;;;;;N;;;;;
+1F5B4;HARD DISK;So;0;ON;;;;;N;;;;;
+1F5B5;SCREEN;So;0;ON;;;;;N;;;;;
+1F5B6;PRINTER ICON;So;0;ON;;;;;N;;;;;
+1F5B7;FAX ICON;So;0;ON;;;;;N;;;;;
+1F5B8;OPTICAL DISC ICON;So;0;ON;;;;;N;;;;;
+1F5B9;DOCUMENT WITH TEXT;So;0;ON;;;;;N;;;;;
+1F5BA;DOCUMENT WITH TEXT AND PICTURE;So;0;ON;;;;;N;;;;;
+1F5BB;DOCUMENT WITH PICTURE;So;0;ON;;;;;N;;;;;
+1F5BC;FRAME WITH PICTURE;So;0;ON;;;;;N;;;;;
+1F5BD;FRAME WITH TILES;So;0;ON;;;;;N;;;;;
+1F5BE;FRAME WITH AN X;So;0;ON;;;;;N;;;;;
+1F5BF;BLACK FOLDER;So;0;ON;;;;;N;;;;;
+1F5C0;FOLDER;So;0;ON;;;;;N;;;;;
+1F5C1;OPEN FOLDER;So;0;ON;;;;;N;;;;;
+1F5C2;CARD INDEX DIVIDERS;So;0;ON;;;;;N;;;;;
+1F5C3;CARD FILE BOX;So;0;ON;;;;;N;;;;;
+1F5C4;FILE CABINET;So;0;ON;;;;;N;;;;;
+1F5C5;EMPTY NOTE;So;0;ON;;;;;N;;;;;
+1F5C6;EMPTY NOTE PAGE;So;0;ON;;;;;N;;;;;
+1F5C7;EMPTY NOTE PAD;So;0;ON;;;;;N;;;;;
+1F5C8;NOTE;So;0;ON;;;;;N;;;;;
+1F5C9;NOTE PAGE;So;0;ON;;;;;N;;;;;
+1F5CA;NOTE PAD;So;0;ON;;;;;N;;;;;
+1F5CB;EMPTY DOCUMENT;So;0;ON;;;;;N;;;;;
+1F5CC;EMPTY PAGE;So;0;ON;;;;;N;;;;;
+1F5CD;EMPTY PAGES;So;0;ON;;;;;N;;;;;
+1F5CE;DOCUMENT;So;0;ON;;;;;N;;;;;
+1F5CF;PAGE;So;0;ON;;;;;N;;;;;
+1F5D0;PAGES;So;0;ON;;;;;N;;;;;
+1F5D1;WASTEBASKET;So;0;ON;;;;;N;;;;;
+1F5D2;SPIRAL NOTE PAD;So;0;ON;;;;;N;;;;;
+1F5D3;SPIRAL CALENDAR PAD;So;0;ON;;;;;N;;;;;
+1F5D4;DESKTOP WINDOW;So;0;ON;;;;;N;;;;;
+1F5D5;MINIMIZE;So;0;ON;;;;;N;;;;;
+1F5D6;MAXIMIZE;So;0;ON;;;;;N;;;;;
+1F5D7;OVERLAP;So;0;ON;;;;;N;;;;;
+1F5D8;CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS;So;0;ON;;;;;N;;;;;
+1F5D9;CANCELLATION X;So;0;ON;;;;;N;;;;;
+1F5DA;INCREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;;
+1F5DB;DECREASE FONT SIZE SYMBOL;So;0;ON;;;;;N;;;;;
+1F5DC;COMPRESSION;So;0;ON;;;;;N;;;;;
+1F5DD;OLD KEY;So;0;ON;;;;;N;;;;;
+1F5DE;ROLLED-UP NEWSPAPER;So;0;ON;;;;;N;;;;;
+1F5DF;PAGE WITH CIRCLED TEXT;So;0;ON;;;;;N;;;;;
+1F5E0;STOCK CHART;So;0;ON;;;;;N;;;;;
+1F5E1;DAGGER KNIFE;So;0;ON;;;;;N;;;;;
+1F5E2;LIPS;So;0;ON;;;;;N;;;;;
+1F5E3;SPEAKING HEAD IN SILHOUETTE;So;0;ON;;;;;N;;;;;
+1F5E4;THREE RAYS ABOVE;So;0;ON;;;;;N;;;;;
+1F5E5;THREE RAYS BELOW;So;0;ON;;;;;N;;;;;
+1F5E6;THREE RAYS LEFT;So;0;ON;;;;;N;;;;;
+1F5E7;THREE RAYS RIGHT;So;0;ON;;;;;N;;;;;
+1F5E8;LEFT SPEECH BUBBLE;So;0;ON;;;;;N;;;;;
+1F5E9;RIGHT SPEECH BUBBLE;So;0;ON;;;;;N;;;;;
+1F5EA;TWO SPEECH BUBBLES;So;0;ON;;;;;N;;;;;
+1F5EB;THREE SPEECH BUBBLES;So;0;ON;;;;;N;;;;;
+1F5EC;LEFT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;;
+1F5ED;RIGHT THOUGHT BUBBLE;So;0;ON;;;;;N;;;;;
+1F5EE;LEFT ANGER BUBBLE;So;0;ON;;;;;N;;;;;
+1F5EF;RIGHT ANGER BUBBLE;So;0;ON;;;;;N;;;;;
+1F5F0;MOOD BUBBLE;So;0;ON;;;;;N;;;;;
+1F5F1;LIGHTNING MOOD BUBBLE;So;0;ON;;;;;N;;;;;
+1F5F2;LIGHTNING MOOD;So;0;ON;;;;;N;;;;;
+1F5F3;BALLOT BOX WITH BALLOT;So;0;ON;;;;;N;;;;;
+1F5F4;BALLOT SCRIPT X;So;0;ON;;;;;N;;;;;
+1F5F5;BALLOT BOX WITH SCRIPT X;So;0;ON;;;;;N;;;;;
+1F5F6;BALLOT BOLD SCRIPT X;So;0;ON;;;;;N;;;;;
+1F5F7;BALLOT BOX WITH BOLD SCRIPT X;So;0;ON;;;;;N;;;;;
+1F5F8;LIGHT CHECK MARK;So;0;ON;;;;;N;;;;;
+1F5F9;BALLOT BOX WITH BOLD CHECK;So;0;ON;;;;;N;;;;;
+1F5FA;WORLD MAP;So;0;ON;;;;;N;;;;;
+1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;;
+1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;;
+1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;;
+1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;;
+1F5FF;MOYAI;So;0;ON;;;;;N;;;;;
+1F600;GRINNING FACE;So;0;ON;;;;;N;;;;;
+1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;
+1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;;
+1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;
+1F604;SMILING FACE WITH OPEN MOUTH AND SMILING EYES;So;0;ON;;;;;N;;;;;
+1F605;SMILING FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;;
+1F606;SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;;
+1F607;SMILING FACE WITH HALO;So;0;ON;;;;;N;;;;;
+1F608;SMILING FACE WITH HORNS;So;0;ON;;;;;N;;;;;
+1F609;WINKING FACE;So;0;ON;;;;;N;;;;;
+1F60A;SMILING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;
+1F60B;FACE SAVOURING DELICIOUS FOOD;So;0;ON;;;;;N;;;;;
+1F60C;RELIEVED FACE;So;0;ON;;;;;N;;;;;
+1F60D;SMILING FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;;
+1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;;
+1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;;
+1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;;
+1F611;EXPRESSIONLESS FACE;So;0;ON;;;;;N;;;;;
+1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;;
+1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;;
+1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;;
+1F615;CONFUSED FACE;So;0;ON;;;;;N;;;;;
+1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;;
+1F617;KISSING FACE;So;0;ON;;;;;N;;;;;
+1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;;
+1F619;KISSING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;
+1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;
+1F61B;FACE WITH STUCK-OUT TONGUE;So;0;ON;;;;;N;;;;;
+1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;;
+1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;;
+1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;;
+1F61F;WORRIED FACE;So;0;ON;;;;;N;;;;;
+1F620;ANGRY FACE;So;0;ON;;;;;N;;;;;
+1F621;POUTING FACE;So;0;ON;;;;;N;;;;;
+1F622;CRYING FACE;So;0;ON;;;;;N;;;;;
+1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;;
+1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;;
+1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;;
+1F626;FROWNING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;
+1F627;ANGUISHED FACE;So;0;ON;;;;;N;;;;;
+1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;;
+1F629;WEARY FACE;So;0;ON;;;;;N;;;;;
+1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;;
+1F62B;TIRED FACE;So;0;ON;;;;;N;;;;;
+1F62C;GRIMACING FACE;So;0;ON;;;;;N;;;;;
+1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;;
+1F62E;FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;
+1F62F;HUSHED FACE;So;0;ON;;;;;N;;;;;
+1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;;
+1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;;
+1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;;
+1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;;
+1F634;SLEEPING FACE;So;0;ON;;;;;N;;;;;
+1F635;DIZZY FACE;So;0;ON;;;;;N;;;;;
+1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;;
+1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;;
+1F638;GRINNING CAT FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;;
+1F639;CAT FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;;
+1F63A;SMILING CAT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;;
+1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;;
+1F63C;CAT FACE WITH WRY SMILE;So;0;ON;;;;;N;;;;;
+1F63D;KISSING CAT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;;
+1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;;
+1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;;
+1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;;
+1F641;SLIGHTLY FROWNING FACE;So;0;ON;;;;;N;;;;;
+1F642;SLIGHTLY SMILING FACE;So;0;ON;;;;;N;;;;;
+1F643;UPSIDE-DOWN FACE;So;0;ON;;;;;N;;;;;
+1F644;FACE WITH ROLLING EYES;So;0;ON;;;;;N;;;;;
+1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;;
+1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;;
+1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;;
+1F648;SEE-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;
+1F649;HEAR-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;
+1F64A;SPEAK-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;;
+1F64B;HAPPY PERSON RAISING ONE HAND;So;0;ON;;;;;N;;;;;
+1F64C;PERSON RAISING BOTH HANDS IN CELEBRATION;So;0;ON;;;;;N;;;;;
+1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;;
+1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;;
+1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;;
+1F650;NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F651;SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F652;NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F653;SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F654;TURNED NORTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F655;TURNED SOUTH WEST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F656;TURNED NORTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F657;TURNED SOUTH EAST POINTING LEAF;So;0;ON;;;;;N;;;;;
+1F658;NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F659;SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65A;NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65B;SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65C;HEAVY NORTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65D;HEAVY SOUTH WEST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65E;HEAVY NORTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F65F;HEAVY SOUTH EAST POINTING VINE LEAF;So;0;ON;;;;;N;;;;;
+1F660;NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F661;SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F662;NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F663;SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F664;HEAVY NORTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F665;HEAVY SOUTH WEST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F666;HEAVY NORTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F667;HEAVY SOUTH EAST POINTING BUD;So;0;ON;;;;;N;;;;;
+1F668;HOLLOW QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;;
+1F669;HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;;
+1F66A;SOLID QUILT SQUARE ORNAMENT;So;0;ON;;;;;N;;;;;
+1F66B;SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE;So;0;ON;;;;;N;;;;;
+1F66C;LEFTWARDS ROCKET;So;0;ON;;;;;N;;;;;
+1F66D;UPWARDS ROCKET;So;0;ON;;;;;N;;;;;
+1F66E;RIGHTWARDS ROCKET;So;0;ON;;;;;N;;;;;
+1F66F;DOWNWARDS ROCKET;So;0;ON;;;;;N;;;;;
+1F670;SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;;
+1F671;HEAVY SCRIPT LIGATURE ET ORNAMENT;So;0;ON;;;;;N;;;;;
+1F672;LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;;
+1F673;HEAVY LIGATURE OPEN ET ORNAMENT;So;0;ON;;;;;N;;;;;
+1F674;HEAVY AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;;
+1F675;SWASH AMPERSAND ORNAMENT;So;0;ON;;;;;N;;;;;
+1F676;SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+1F677;SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+1F678;SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+1F679;HEAVY INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;
+1F67A;SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;
+1F67B;HEAVY SANS-SERIF INTERROBANG ORNAMENT;So;0;ON;;;;;N;;;;;
+1F67C;VERY HEAVY SOLIDUS;So;0;ON;;;;;N;;;;;
+1F67D;VERY HEAVY REVERSE SOLIDUS;So;0;ON;;;;;N;;;;;
+1F67E;CHECKER BOARD;So;0;ON;;;;;N;;;;;
+1F67F;REVERSE CHECKER BOARD;So;0;ON;;;;;N;;;;;
+1F680;ROCKET;So;0;ON;;;;;N;;;;;
+1F681;HELICOPTER;So;0;ON;;;;;N;;;;;
+1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;;
+1F683;RAILWAY CAR;So;0;ON;;;;;N;;;;;
+1F684;HIGH-SPEED TRAIN;So;0;ON;;;;;N;;;;;
+1F685;HIGH-SPEED TRAIN WITH BULLET NOSE;So;0;ON;;;;;N;;;;;
+1F686;TRAIN;So;0;ON;;;;;N;;;;;
+1F687;METRO;So;0;ON;;;;;N;;;;;
+1F688;LIGHT RAIL;So;0;ON;;;;;N;;;;;
+1F689;STATION;So;0;ON;;;;;N;;;;;
+1F68A;TRAM;So;0;ON;;;;;N;;;;;
+1F68B;TRAM CAR;So;0;ON;;;;;N;;;;;
+1F68C;BUS;So;0;ON;;;;;N;;;;;
+1F68D;ONCOMING BUS;So;0;ON;;;;;N;;;;;
+1F68E;TROLLEYBUS;So;0;ON;;;;;N;;;;;
+1F68F;BUS STOP;So;0;ON;;;;;N;;;;;
+1F690;MINIBUS;So;0;ON;;;;;N;;;;;
+1F691;AMBULANCE;So;0;ON;;;;;N;;;;;
+1F692;FIRE ENGINE;So;0;ON;;;;;N;;;;;
+1F693;POLICE CAR;So;0;ON;;;;;N;;;;;
+1F694;ONCOMING POLICE CAR;So;0;ON;;;;;N;;;;;
+1F695;TAXI;So;0;ON;;;;;N;;;;;
+1F696;ONCOMING TAXI;So;0;ON;;;;;N;;;;;
+1F697;AUTOMOBILE;So;0;ON;;;;;N;;;;;
+1F698;ONCOMING AUTOMOBILE;So;0;ON;;;;;N;;;;;
+1F699;RECREATIONAL VEHICLE;So;0;ON;;;;;N;;;;;
+1F69A;DELIVERY TRUCK;So;0;ON;;;;;N;;;;;
+1F69B;ARTICULATED LORRY;So;0;ON;;;;;N;;;;;
+1F69C;TRACTOR;So;0;ON;;;;;N;;;;;
+1F69D;MONORAIL;So;0;ON;;;;;N;;;;;
+1F69E;MOUNTAIN RAILWAY;So;0;ON;;;;;N;;;;;
+1F69F;SUSPENSION RAILWAY;So;0;ON;;;;;N;;;;;
+1F6A0;MOUNTAIN CABLEWAY;So;0;ON;;;;;N;;;;;
+1F6A1;AERIAL TRAMWAY;So;0;ON;;;;;N;;;;;
+1F6A2;SHIP;So;0;ON;;;;;N;;;;;
+1F6A3;ROWBOAT;So;0;ON;;;;;N;;;;;
+1F6A4;SPEEDBOAT;So;0;ON;;;;;N;;;;;
+1F6A5;HORIZONTAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;;
+1F6A6;VERTICAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;;
+1F6A7;CONSTRUCTION SIGN;So;0;ON;;;;;N;;;;;
+1F6A8;POLICE CARS REVOLVING LIGHT;So;0;ON;;;;;N;;;;;
+1F6A9;TRIANGULAR FLAG ON POST;So;0;ON;;;;;N;;;;;
+1F6AA;DOOR;So;0;ON;;;;;N;;;;;
+1F6AB;NO ENTRY SIGN;So;0;ON;;;;;N;;;;;
+1F6AC;SMOKING SYMBOL;So;0;ON;;;;;N;;;;;
+1F6AD;NO SMOKING SYMBOL;So;0;ON;;;;;N;;;;;
+1F6AE;PUT LITTER IN ITS PLACE SYMBOL;So;0;ON;;;;;N;;;;;
+1F6AF;DO NOT LITTER SYMBOL;So;0;ON;;;;;N;;;;;
+1F6B0;POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;;
+1F6B1;NON-POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;;
+1F6B2;BICYCLE;So;0;ON;;;;;N;;;;;
+1F6B3;NO BICYCLES;So;0;ON;;;;;N;;;;;
+1F6B4;BICYCLIST;So;0;ON;;;;;N;;;;;
+1F6B5;MOUNTAIN BICYCLIST;So;0;ON;;;;;N;;;;;
+1F6B6;PEDESTRIAN;So;0;ON;;;;;N;;;;;
+1F6B7;NO PEDESTRIANS;So;0;ON;;;;;N;;;;;
+1F6B8;CHILDREN CROSSING;So;0;ON;;;;;N;;;;;
+1F6B9;MENS SYMBOL;So;0;ON;;;;;N;;;;;
+1F6BA;WOMENS SYMBOL;So;0;ON;;;;;N;;;;;
+1F6BB;RESTROOM;So;0;ON;;;;;N;;;;;
+1F6BC;BABY SYMBOL;So;0;ON;;;;;N;;;;;
+1F6BD;TOILET;So;0;ON;;;;;N;;;;;
+1F6BE;WATER CLOSET;So;0;ON;;;;;N;;;;;
+1F6BF;SHOWER;So;0;ON;;;;;N;;;;;
+1F6C0;BATH;So;0;ON;;;;;N;;;;;
+1F6C1;BATHTUB;So;0;ON;;;;;N;;;;;
+1F6C2;PASSPORT CONTROL;So;0;ON;;;;;N;;;;;
+1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;;
+1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;;
+1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;;
+1F6C6;TRIANGLE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+1F6C7;PROHIBITED SIGN;So;0;ON;;;;;N;;;;;
+1F6C8;CIRCLED INFORMATION SOURCE;So;0;ON;;;;;N;;;;;
+1F6C9;BOYS SYMBOL;So;0;ON;;;;;N;;;;;
+1F6CA;GIRLS SYMBOL;So;0;ON;;;;;N;;;;;
+1F6CB;COUCH AND LAMP;So;0;ON;;;;;N;;;;;
+1F6CC;SLEEPING ACCOMMODATION;So;0;ON;;;;;N;;;;;
+1F6CD;SHOPPING BAGS;So;0;ON;;;;;N;;;;;
+1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;;
+1F6CF;BED;So;0;ON;;;;;N;;;;;
+1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;;
+1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;;
+1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;;
+1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;;
+1F6E1;SHIELD;So;0;ON;;;;;N;;;;;
+1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;;
+1F6E3;MOTORWAY;So;0;ON;;;;;N;;;;;
+1F6E4;RAILWAY TRACK;So;0;ON;;;;;N;;;;;
+1F6E5;MOTOR BOAT;So;0;ON;;;;;N;;;;;
+1F6E6;UP-POINTING MILITARY AIRPLANE;So;0;ON;;;;;N;;;;;
+1F6E7;UP-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;
+1F6E8;UP-POINTING SMALL AIRPLANE;So;0;ON;;;;;N;;;;;
+1F6E9;SMALL AIRPLANE;So;0;ON;;;;;N;;;;;
+1F6EA;NORTHEAST-POINTING AIRPLANE;So;0;ON;;;;;N;;;;;
+1F6EB;AIRPLANE DEPARTURE;So;0;ON;;;;;N;;;;;
+1F6EC;AIRPLANE ARRIVING;So;0;ON;;;;;N;;;;;
+1F6F0;SATELLITE;So;0;ON;;;;;N;;;;;
+1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;;
+1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;;
+1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;;
+1F6F4;SCOOTER;So;0;ON;;;;;N;;;;;
+1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;;
+1F6F6;CANOE;So;0;ON;;;;;N;;;;;
+1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;;
+1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;;
+1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;;
+1F703;ALCHEMICAL SYMBOL FOR EARTH;So;0;ON;;;;;N;;;;;
+1F704;ALCHEMICAL SYMBOL FOR WATER;So;0;ON;;;;;N;;;;;
+1F705;ALCHEMICAL SYMBOL FOR AQUAFORTIS;So;0;ON;;;;;N;;;;;
+1F706;ALCHEMICAL SYMBOL FOR AQUA REGIA;So;0;ON;;;;;N;;;;;
+1F707;ALCHEMICAL SYMBOL FOR AQUA REGIA-2;So;0;ON;;;;;N;;;;;
+1F708;ALCHEMICAL SYMBOL FOR AQUA VITAE;So;0;ON;;;;;N;;;;;
+1F709;ALCHEMICAL SYMBOL FOR AQUA VITAE-2;So;0;ON;;;;;N;;;;;
+1F70A;ALCHEMICAL SYMBOL FOR VINEGAR;So;0;ON;;;;;N;;;;;
+1F70B;ALCHEMICAL SYMBOL FOR VINEGAR-2;So;0;ON;;;;;N;;;;;
+1F70C;ALCHEMICAL SYMBOL FOR VINEGAR-3;So;0;ON;;;;;N;;;;;
+1F70D;ALCHEMICAL SYMBOL FOR SULFUR;So;0;ON;;;;;N;;;;;
+1F70E;ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR;So;0;ON;;;;;N;;;;;
+1F70F;ALCHEMICAL SYMBOL FOR BLACK SULFUR;So;0;ON;;;;;N;;;;;
+1F710;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE;So;0;ON;;;;;N;;;;;
+1F711;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2;So;0;ON;;;;;N;;;;;
+1F712;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3;So;0;ON;;;;;N;;;;;
+1F713;ALCHEMICAL SYMBOL FOR CINNABAR;So;0;ON;;;;;N;;;;;
+1F714;ALCHEMICAL SYMBOL FOR SALT;So;0;ON;;;;;N;;;;;
+1F715;ALCHEMICAL SYMBOL FOR NITRE;So;0;ON;;;;;N;;;;;
+1F716;ALCHEMICAL SYMBOL FOR VITRIOL;So;0;ON;;;;;N;;;;;
+1F717;ALCHEMICAL SYMBOL FOR VITRIOL-2;So;0;ON;;;;;N;;;;;
+1F718;ALCHEMICAL SYMBOL FOR ROCK SALT;So;0;ON;;;;;N;;;;;
+1F719;ALCHEMICAL SYMBOL FOR ROCK SALT-2;So;0;ON;;;;;N;;;;;
+1F71A;ALCHEMICAL SYMBOL FOR GOLD;So;0;ON;;;;;N;;;;;
+1F71B;ALCHEMICAL SYMBOL FOR SILVER;So;0;ON;;;;;N;;;;;
+1F71C;ALCHEMICAL SYMBOL FOR IRON ORE;So;0;ON;;;;;N;;;;;
+1F71D;ALCHEMICAL SYMBOL FOR IRON ORE-2;So;0;ON;;;;;N;;;;;
+1F71E;ALCHEMICAL SYMBOL FOR CROCUS OF IRON;So;0;ON;;;;;N;;;;;
+1F71F;ALCHEMICAL SYMBOL FOR REGULUS OF IRON;So;0;ON;;;;;N;;;;;
+1F720;ALCHEMICAL SYMBOL FOR COPPER ORE;So;0;ON;;;;;N;;;;;
+1F721;ALCHEMICAL SYMBOL FOR IRON-COPPER ORE;So;0;ON;;;;;N;;;;;
+1F722;ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER;So;0;ON;;;;;N;;;;;
+1F723;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER;So;0;ON;;;;;N;;;;;
+1F724;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2;So;0;ON;;;;;N;;;;;
+1F725;ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;;
+1F726;ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;;
+1F727;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER;So;0;ON;;;;;N;;;;;
+1F728;ALCHEMICAL SYMBOL FOR VERDIGRIS;So;0;ON;;;;;N;;;;;
+1F729;ALCHEMICAL SYMBOL FOR TIN ORE;So;0;ON;;;;;N;;;;;
+1F72A;ALCHEMICAL SYMBOL FOR LEAD ORE;So;0;ON;;;;;N;;;;;
+1F72B;ALCHEMICAL SYMBOL FOR ANTIMONY ORE;So;0;ON;;;;;N;;;;;
+1F72C;ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY;So;0;ON;;;;;N;;;;;
+1F72D;ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY;So;0;ON;;;;;N;;;;;
+1F72E;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY;So;0;ON;;;;;N;;;;;
+1F72F;ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY;So;0;ON;;;;;N;;;;;
+1F730;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY;So;0;ON;;;;;N;;;;;
+1F731;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2;So;0;ON;;;;;N;;;;;
+1F732;ALCHEMICAL SYMBOL FOR REGULUS;So;0;ON;;;;;N;;;;;
+1F733;ALCHEMICAL SYMBOL FOR REGULUS-2;So;0;ON;;;;;N;;;;;
+1F734;ALCHEMICAL SYMBOL FOR REGULUS-3;So;0;ON;;;;;N;;;;;
+1F735;ALCHEMICAL SYMBOL FOR REGULUS-4;So;0;ON;;;;;N;;;;;
+1F736;ALCHEMICAL SYMBOL FOR ALKALI;So;0;ON;;;;;N;;;;;
+1F737;ALCHEMICAL SYMBOL FOR ALKALI-2;So;0;ON;;;;;N;;;;;
+1F738;ALCHEMICAL SYMBOL FOR MARCASITE;So;0;ON;;;;;N;;;;;
+1F739;ALCHEMICAL SYMBOL FOR SAL-AMMONIAC;So;0;ON;;;;;N;;;;;
+1F73A;ALCHEMICAL SYMBOL FOR ARSENIC;So;0;ON;;;;;N;;;;;
+1F73B;ALCHEMICAL SYMBOL FOR REALGAR;So;0;ON;;;;;N;;;;;
+1F73C;ALCHEMICAL SYMBOL FOR REALGAR-2;So;0;ON;;;;;N;;;;;
+1F73D;ALCHEMICAL SYMBOL FOR AURIPIGMENT;So;0;ON;;;;;N;;;;;
+1F73E;ALCHEMICAL SYMBOL FOR BISMUTH ORE;So;0;ON;;;;;N;;;;;
+1F73F;ALCHEMICAL SYMBOL FOR TARTAR;So;0;ON;;;;;N;;;;;
+1F740;ALCHEMICAL SYMBOL FOR TARTAR-2;So;0;ON;;;;;N;;;;;
+1F741;ALCHEMICAL SYMBOL FOR QUICK LIME;So;0;ON;;;;;N;;;;;
+1F742;ALCHEMICAL SYMBOL FOR BORAX;So;0;ON;;;;;N;;;;;
+1F743;ALCHEMICAL SYMBOL FOR BORAX-2;So;0;ON;;;;;N;;;;;
+1F744;ALCHEMICAL SYMBOL FOR BORAX-3;So;0;ON;;;;;N;;;;;
+1F745;ALCHEMICAL SYMBOL FOR ALUM;So;0;ON;;;;;N;;;;;
+1F746;ALCHEMICAL SYMBOL FOR OIL;So;0;ON;;;;;N;;;;;
+1F747;ALCHEMICAL SYMBOL FOR SPIRIT;So;0;ON;;;;;N;;;;;
+1F748;ALCHEMICAL SYMBOL FOR TINCTURE;So;0;ON;;;;;N;;;;;
+1F749;ALCHEMICAL SYMBOL FOR GUM;So;0;ON;;;;;N;;;;;
+1F74A;ALCHEMICAL SYMBOL FOR WAX;So;0;ON;;;;;N;;;;;
+1F74B;ALCHEMICAL SYMBOL FOR POWDER;So;0;ON;;;;;N;;;;;
+1F74C;ALCHEMICAL SYMBOL FOR CALX;So;0;ON;;;;;N;;;;;
+1F74D;ALCHEMICAL SYMBOL FOR TUTTY;So;0;ON;;;;;N;;;;;
+1F74E;ALCHEMICAL SYMBOL FOR CAPUT MORTUUM;So;0;ON;;;;;N;;;;;
+1F74F;ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE;So;0;ON;;;;;N;;;;;
+1F750;ALCHEMICAL SYMBOL FOR CADUCEUS;So;0;ON;;;;;N;;;;;
+1F751;ALCHEMICAL SYMBOL FOR TRIDENT;So;0;ON;;;;;N;;;;;
+1F752;ALCHEMICAL SYMBOL FOR STARRED TRIDENT;So;0;ON;;;;;N;;;;;
+1F753;ALCHEMICAL SYMBOL FOR LODESTONE;So;0;ON;;;;;N;;;;;
+1F754;ALCHEMICAL SYMBOL FOR SOAP;So;0;ON;;;;;N;;;;;
+1F755;ALCHEMICAL SYMBOL FOR URINE;So;0;ON;;;;;N;;;;;
+1F756;ALCHEMICAL SYMBOL FOR HORSE DUNG;So;0;ON;;;;;N;;;;;
+1F757;ALCHEMICAL SYMBOL FOR ASHES;So;0;ON;;;;;N;;;;;
+1F758;ALCHEMICAL SYMBOL FOR POT ASHES;So;0;ON;;;;;N;;;;;
+1F759;ALCHEMICAL SYMBOL FOR BRICK;So;0;ON;;;;;N;;;;;
+1F75A;ALCHEMICAL SYMBOL FOR POWDERED BRICK;So;0;ON;;;;;N;;;;;
+1F75B;ALCHEMICAL SYMBOL FOR AMALGAM;So;0;ON;;;;;N;;;;;
+1F75C;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM;So;0;ON;;;;;N;;;;;
+1F75D;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2;So;0;ON;;;;;N;;;;;
+1F75E;ALCHEMICAL SYMBOL FOR SUBLIMATION;So;0;ON;;;;;N;;;;;
+1F75F;ALCHEMICAL SYMBOL FOR PRECIPITATE;So;0;ON;;;;;N;;;;;
+1F760;ALCHEMICAL SYMBOL FOR DISTILL;So;0;ON;;;;;N;;;;;
+1F761;ALCHEMICAL SYMBOL FOR DISSOLVE;So;0;ON;;;;;N;;;;;
+1F762;ALCHEMICAL SYMBOL FOR DISSOLVE-2;So;0;ON;;;;;N;;;;;
+1F763;ALCHEMICAL SYMBOL FOR PURIFY;So;0;ON;;;;;N;;;;;
+1F764;ALCHEMICAL SYMBOL FOR PUTREFACTION;So;0;ON;;;;;N;;;;;
+1F765;ALCHEMICAL SYMBOL FOR CRUCIBLE;So;0;ON;;;;;N;;;;;
+1F766;ALCHEMICAL SYMBOL FOR CRUCIBLE-2;So;0;ON;;;;;N;;;;;
+1F767;ALCHEMICAL SYMBOL FOR CRUCIBLE-3;So;0;ON;;;;;N;;;;;
+1F768;ALCHEMICAL SYMBOL FOR CRUCIBLE-4;So;0;ON;;;;;N;;;;;
+1F769;ALCHEMICAL SYMBOL FOR CRUCIBLE-5;So;0;ON;;;;;N;;;;;
+1F76A;ALCHEMICAL SYMBOL FOR ALEMBIC;So;0;ON;;;;;N;;;;;
+1F76B;ALCHEMICAL SYMBOL FOR BATH OF MARY;So;0;ON;;;;;N;;;;;
+1F76C;ALCHEMICAL SYMBOL FOR BATH OF VAPOURS;So;0;ON;;;;;N;;;;;
+1F76D;ALCHEMICAL SYMBOL FOR RETORT;So;0;ON;;;;;N;;;;;
+1F76E;ALCHEMICAL SYMBOL FOR HOUR;So;0;ON;;;;;N;;;;;
+1F76F;ALCHEMICAL SYMBOL FOR NIGHT;So;0;ON;;;;;N;;;;;
+1F770;ALCHEMICAL SYMBOL FOR DAY-NIGHT;So;0;ON;;;;;N;;;;;
+1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;;
+1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;;
+1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;;
+1F780;BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+1F781;BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+1F782;BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+1F783;BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+1F784;BLACK SLIGHTLY SMALL CIRCLE;So;0;ON;;;;;N;;;;;
+1F785;MEDIUM BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F786;BOLD WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F787;HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F788;VERY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F789;EXTREMELY HEAVY WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+1F78A;WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE;So;0;ON;;;;;N;;;;;
+1F78B;ROUND TARGET;So;0;ON;;;;;N;;;;;
+1F78C;BLACK TINY SQUARE;So;0;ON;;;;;N;;;;;
+1F78D;BLACK SLIGHTLY SMALL SQUARE;So;0;ON;;;;;N;;;;;
+1F78E;LIGHT WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F78F;MEDIUM WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F790;BOLD WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F791;HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F792;VERY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F793;EXTREMELY HEAVY WHITE SQUARE;So;0;ON;;;;;N;;;;;
+1F794;WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE;So;0;ON;;;;;N;;;;;
+1F795;WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE;So;0;ON;;;;;N;;;;;
+1F796;SQUARE TARGET;So;0;ON;;;;;N;;;;;
+1F797;BLACK TINY DIAMOND;So;0;ON;;;;;N;;;;;
+1F798;BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+1F799;BLACK MEDIUM SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+1F79A;WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+1F79B;WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND;So;0;ON;;;;;N;;;;;
+1F79C;DIAMOND TARGET;So;0;ON;;;;;N;;;;;
+1F79D;BLACK TINY LOZENGE;So;0;ON;;;;;N;;;;;
+1F79E;BLACK VERY SMALL LOZENGE;So;0;ON;;;;;N;;;;;
+1F79F;BLACK MEDIUM SMALL LOZENGE;So;0;ON;;;;;N;;;;;
+1F7A0;WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE;So;0;ON;;;;;N;;;;;
+1F7A1;THIN GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A2;LIGHT GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A3;MEDIUM GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A4;BOLD GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A5;VERY BOLD GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A6;VERY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A7;EXTREMELY HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+1F7A8;THIN SALTIRE;So;0;ON;;;;;N;;;;;
+1F7A9;LIGHT SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AA;MEDIUM SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AB;BOLD SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AC;HEAVY SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AD;VERY HEAVY SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AE;EXTREMELY HEAVY SALTIRE;So;0;ON;;;;;N;;;;;
+1F7AF;LIGHT FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B0;MEDIUM FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B1;BOLD FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B2;HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B3;VERY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B4;EXTREMELY HEAVY FIVE SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B5;LIGHT SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B6;MEDIUM SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B7;BOLD SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B8;HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7B9;VERY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BA;EXTREMELY HEAVY SIX SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BB;LIGHT EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BC;MEDIUM EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BD;BOLD EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BE;HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7BF;VERY HEAVY EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+1F7C0;LIGHT THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C1;MEDIUM THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C2;THREE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C3;MEDIUM THREE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7C4;LIGHT FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C5;MEDIUM FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C6;FOUR POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7C7;MEDIUM FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7C8;REVERSE LIGHT FOUR POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7C9;LIGHT FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7CA;HEAVY FIVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7CB;MEDIUM SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7CC;HEAVY SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7CD;SIX POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7CE;MEDIUM EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7CF;HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7D0;VERY HEAVY EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7D1;HEAVY EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F803;DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F804;LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F805;UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F806;RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F807;DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F808;LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F809;UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F80A;RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F80B;DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F810;LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F811;UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F812;RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F813;DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F814;LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F815;UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F816;RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F817;DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F818;HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F819;HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81A;HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81B;HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81C;HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81D;HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81E;HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F81F;HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F820;LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;
+1F821;UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;
+1F822;RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;
+1F823;DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT;So;0;ON;;;;;N;;;;;
+1F824;LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;
+1F825;UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;
+1F826;RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;
+1F827;DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT;So;0;ON;;;;;N;;;;;
+1F828;LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;
+1F829;UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;
+1F82A;RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;
+1F82B;DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT;So;0;ON;;;;;N;;;;;
+1F82C;LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F82D;UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F82E;RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F82F;DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F830;LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F831;UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F832;RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F833;DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT;So;0;ON;;;;;N;;;;;
+1F834;LEFTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;
+1F835;UPWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;
+1F836;RIGHTWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;
+1F837;DOWNWARDS FINGER-POST ARROW;So;0;ON;;;;;N;;;;;
+1F838;LEFTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;
+1F839;UPWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;
+1F83A;RIGHTWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;
+1F83B;DOWNWARDS SQUARED ARROW;So;0;ON;;;;;N;;;;;
+1F83C;LEFTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F83D;UPWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F83E;RIGHTWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F83F;DOWNWARDS COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F840;LEFTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F841;UPWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F842;RIGHTWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F843;DOWNWARDS HEAVY COMPRESSED ARROW;So;0;ON;;;;;N;;;;;
+1F844;LEFTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;
+1F845;UPWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;
+1F846;RIGHTWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;
+1F847;DOWNWARDS HEAVY ARROW;So;0;ON;;;;;N;;;;;
+1F850;LEFTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F851;UPWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F852;RIGHTWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F853;DOWNWARDS SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F854;NORTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F855;NORTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F856;SOUTH EAST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F857;SOUTH WEST SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F858;LEFT RIGHT SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F859;UP DOWN SANS-SERIF ARROW;So;0;ON;;;;;N;;;;;
+1F860;WIDE-HEADED LEFTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F861;WIDE-HEADED UPWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F862;WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F863;WIDE-HEADED DOWNWARDS LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F864;WIDE-HEADED NORTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F865;WIDE-HEADED NORTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F866;WIDE-HEADED SOUTH EAST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F867;WIDE-HEADED SOUTH WEST LIGHT BARB ARROW;So;0;ON;;;;;N;;;;;
+1F868;WIDE-HEADED LEFTWARDS BARB ARROW;So;0;ON;;;;;N;;;;;
+1F869;WIDE-HEADED UPWARDS BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86A;WIDE-HEADED RIGHTWARDS BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86B;WIDE-HEADED DOWNWARDS BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86C;WIDE-HEADED NORTH WEST BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86D;WIDE-HEADED NORTH EAST BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86E;WIDE-HEADED SOUTH EAST BARB ARROW;So;0;ON;;;;;N;;;;;
+1F86F;WIDE-HEADED SOUTH WEST BARB ARROW;So;0;ON;;;;;N;;;;;
+1F870;WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F871;WIDE-HEADED UPWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F872;WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F873;WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F874;WIDE-HEADED NORTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F875;WIDE-HEADED NORTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F876;WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F877;WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW;So;0;ON;;;;;N;;;;;
+1F878;WIDE-HEADED LEFTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F879;WIDE-HEADED UPWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87A;WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87B;WIDE-HEADED DOWNWARDS HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87C;WIDE-HEADED NORTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87D;WIDE-HEADED NORTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87E;WIDE-HEADED SOUTH EAST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F87F;WIDE-HEADED SOUTH WEST HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F880;WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F881;WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F882;WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F883;WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F884;WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F885;WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F886;WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F887;WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW;So;0;ON;;;;;N;;;;;
+1F890;LEFTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F891;UPWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F892;RIGHTWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F893;DOWNWARDS TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F894;LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F895;UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F896;RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F897;DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
+1F898;LEFTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;
+1F899;UPWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;
+1F89A;RIGHTWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;
+1F89B;DOWNWARDS ARROW WITH NOTCHED TAIL;So;0;ON;;;;;N;;;;;
+1F89C;HEAVY ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;
+1F89D;HEAVY ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;
+1F89E;HEAVY ARROW SHAFT WIDTH ONE HALF;So;0;ON;;;;;N;;;;;
+1F89F;HEAVY ARROW SHAFT WIDTH ONE THIRD;So;0;ON;;;;;N;;;;;
+1F8A0;LEFTWARDS BOTTOM-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A1;RIGHTWARDS BOTTOM SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A2;LEFTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A3;RIGHTWARDS TOP SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A4;LEFTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A5;RIGHTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A6;LEFTWARDS RIGHT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A7;RIGHTWARDS LEFT-SHADED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A8;LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8A9;RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8AA;LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;;
+1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;;
+1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;;
+1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;;
+1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;;
+1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;;
+1F913;NERD FACE;So;0;ON;;;;;N;;;;;
+1F914;THINKING FACE;So;0;ON;;;;;N;;;;;
+1F915;FACE WITH HEAD-BANDAGE;So;0;ON;;;;;N;;;;;
+1F916;ROBOT FACE;So;0;ON;;;;;N;;;;;
+1F917;HUGGING FACE;So;0;ON;;;;;N;;;;;
+1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;;
+1F919;CALL ME HAND;So;0;ON;;;;;N;;;;;
+1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;;
+1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;;
+1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;;
+1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;;
+1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;;
+1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;;
+1F921;CLOWN FACE;So;0;ON;;;;;N;;;;;
+1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;;
+1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;;
+1F924;DROOLING FACE;So;0;ON;;;;;N;;;;;
+1F925;LYING FACE;So;0;ON;;;;;N;;;;;
+1F926;FACE PALM;So;0;ON;;;;;N;;;;;
+1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;;
+1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;;
+1F933;SELFIE;So;0;ON;;;;;N;;;;;
+1F934;PRINCE;So;0;ON;;;;;N;;;;;
+1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;;
+1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;;
+1F937;SHRUG;So;0;ON;;;;;N;;;;;
+1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;;
+1F939;JUGGLING;So;0;ON;;;;;N;;;;;
+1F93A;FENCER;So;0;ON;;;;;N;;;;;
+1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;;
+1F93C;WRESTLERS;So;0;ON;;;;;N;;;;;
+1F93D;WATER POLO;So;0;ON;;;;;N;;;;;
+1F93E;HANDBALL;So;0;ON;;;;;N;;;;;
+1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;;
+1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;;
+1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;;
+1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;;
+1F944;SPOON;So;0;ON;;;;;N;;;;;
+1F945;GOAL NET;So;0;ON;;;;;N;;;;;
+1F946;RIFLE;So;0;ON;;;;;N;;;;;
+1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;;
+1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;;
+1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;;
+1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;;
+1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;;
+1F950;CROISSANT;So;0;ON;;;;;N;;;;;
+1F951;AVOCADO;So;0;ON;;;;;N;;;;;
+1F952;CUCUMBER;So;0;ON;;;;;N;;;;;
+1F953;BACON;So;0;ON;;;;;N;;;;;
+1F954;POTATO;So;0;ON;;;;;N;;;;;
+1F955;CARROT;So;0;ON;;;;;N;;;;;
+1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;;
+1F957;GREEN SALAD;So;0;ON;;;;;N;;;;;
+1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;;
+1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;;
+1F95A;EGG;So;0;ON;;;;;N;;;;;
+1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;;
+1F95C;PEANUTS;So;0;ON;;;;;N;;;;;
+1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;;
+1F95E;PANCAKES;So;0;ON;;;;;N;;;;;
+1F980;CRAB;So;0;ON;;;;;N;;;;;
+1F981;LION FACE;So;0;ON;;;;;N;;;;;
+1F982;SCORPION;So;0;ON;;;;;N;;;;;
+1F983;TURKEY;So;0;ON;;;;;N;;;;;
+1F984;UNICORN FACE;So;0;ON;;;;;N;;;;;
+1F985;EAGLE;So;0;ON;;;;;N;;;;;
+1F986;DUCK;So;0;ON;;;;;N;;;;;
+1F987;BAT;So;0;ON;;;;;N;;;;;
+1F988;SHARK;So;0;ON;;;;;N;;;;;
+1F989;OWL;So;0;ON;;;;;N;;;;;
+1F98A;FOX FACE;So;0;ON;;;;;N;;;;;
+1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;;
+1F98C;DEER;So;0;ON;;;;;N;;;;;
+1F98D;GORILLA;So;0;ON;;;;;N;;;;;
+1F98E;LIZARD;So;0;ON;;;;;N;;;;;
+1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;;
+1F990;SHRIMP;So;0;ON;;;;;N;;;;;
+1F991;SQUID;So;0;ON;;;;;N;;;;;
+1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;;
+20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
+2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
+2B734;<CJK Ideograph Extension C, Last>;Lo;0;L;;;;;N;;;;;
+2B740;<CJK Ideograph Extension D, First>;Lo;0;L;;;;;N;;;;;
+2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;;
+2B820;<CJK Ideograph Extension E, First>;Lo;0;L;;;;;N;;;;;
+2CEA1;<CJK Ideograph Extension E, Last>;Lo;0;L;;;;;N;;;;;
+2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;
+2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;
+2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;
+2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;;
+2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;;
+2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;;
+2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;;
+2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;;
+2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;;
+2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;;
+2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;;
+2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;;
+2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;;
+2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;;
+2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;;
+2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;;
+2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;;
+2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;;
+2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;;
+2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;;
+2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;;
+2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;;
+2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;;
+2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;;
+2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;;
+2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;;
+2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;;
+2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;;
+2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;;
+2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;;
+2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;;
+2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;;
+2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;;
+2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;;
+2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;;
+2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;;
+2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;;
+2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;;
+2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;;
+2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;;
+2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;;
+2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;;
+2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;;
+2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;;
+2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;;
+2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;;
+2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;;
+2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;;
+2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;;
+2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;;
+2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;;
+2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;;
+2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;;
+2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;;
+2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;;
+2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;;
+2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;;
+2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;;
+2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;;
+2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;;
+2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;;
+2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;;
+2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;;
+2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;;
+2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;;
+2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;;
+2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;;
+2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;;
+2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;;
+2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;;
+2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;;
+2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;;
+2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;;
+2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;;
+2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;;
+2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;;
+2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;;
+2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;;
+2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;;
+2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;;
+2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;;
+2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;;
+2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;;
+2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;;
+2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;;
+2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;;
+2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;;
+2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;;
+2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;;
+2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;;
+2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;;
+2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;;
+2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;;
+2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;;
+2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;;
+2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;;
+2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;;
+2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;;
+2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;;
+2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;;
+2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;;
+2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;;
+2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;;
+2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;;
+2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;;
+2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;;
+2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;;
+2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;;
+2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;;
+2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;;
+2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;;
+2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;;
+2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;;
+2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;;
+2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;;
+2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;;
+2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;;
+2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;;
+2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;;
+2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;;
+2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;;
+2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;;
+2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;;
+2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;;
+2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;;
+2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;;
+2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;;
+2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;;
+2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;;
+2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;;
+2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;;
+2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;;
+2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;;
+2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;;
+2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;;
+2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;;
+2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;;
+2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;;
+2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;;
+2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;;
+2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;;
+2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;;
+2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;;
+2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;;
+2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;9;N;;;;;
+2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;;
+2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;;
+2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;;
+2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;;
+2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;;
+2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;;
+2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;;
+2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;;
+2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;;
+2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;;
+2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;;
+2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;;
+2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;;
+2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;;
+2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;;
+2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;;
+2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;;
+2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;;
+2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;;
+2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;;
+2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;;
+2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;;
+2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;;
+2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;;
+2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;;
+2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;;
+2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;;
+2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;;
+2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;;
+2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;;
+2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;;
+2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;;
+2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;;
+2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;;
+2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;;
+2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;;
+2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;;
+2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;;
+2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;;
+2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;;
+2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;;
+2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;;
+2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;;
+2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;;
+2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;;
+2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;;
+2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;;
+2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;;
+2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;;
+2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;;
+2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;;
+2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;;
+2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;;
+2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;;
+2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;;
+2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;;
+2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;;
+2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;;
+2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;;
+2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;;
+2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;;
+2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;;
+2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;;
+2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;;
+2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;;
+2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;;
+2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;;
+2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;;
+2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;;
+2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;;
+2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;;
+2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;;
+2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;;
+2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;;
+2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;;
+2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;;
+2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;;
+2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;;
+2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;;
+2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;;
+2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;;
+2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;;
+2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;;
+2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;;
+2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;;
+2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;;
+2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;;
+2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;;
+2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;;
+2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;;
+2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;;
+2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;;
+2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;;
+2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;;
+2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;;
+2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;;
+2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;;
+2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;;
+2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;;
+2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;;
+2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;;
+2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;;
+2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;;
+2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;;
+2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;;
+2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;;
+2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;;
+2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;;
+2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;;
+2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;;
+2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;;
+2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;;
+2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;;
+2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;;
+2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;;
+2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;;
+2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;;
+2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;;
+2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;;
+2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;;
+2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;;
+2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;;
+2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;;
+2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;;
+2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;;
+2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;;
+2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;;
+2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;;
+2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;;
+2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;;
+2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;;
+2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;;
+2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;;
+2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;;
+2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;;
+2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;;
+2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;;
+2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;;
+2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;;
+2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;;
+2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;;
+2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;;
+2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;;
+2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;;
+2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;;
+2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;;
+2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;;
+2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;;
+2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;;
+2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;;
+2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;;
+2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;;
+2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;;
+2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;;
+2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;;
+2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;;
+2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;;
+2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;;
+2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;;
+2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;;
+2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;;
+2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;;
+2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;;
+2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;;
+2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;;
+2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;;
+2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;;
+2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;;
+2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;;
+2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;;
+2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;;
+2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;;
+2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;;
+2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;;
+2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;;
+2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;;
+2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;;
+2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;;
+2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;;
+2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;;
+2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;;
+2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;;
+2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;;
+2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;;
+2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;;
+2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;;
+2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;;
+2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;;
+2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;;
+2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;;
+2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;;
+2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;;
+2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;;
+2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;;
+2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;;
+2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;;
+2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;;
+2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;;
+2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;;
+2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;;
+2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;;
+2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;;
+2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;;
+2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;;
+2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;;
+2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;;
+2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;;
+2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;;
+2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;;
+2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;;
+2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;;
+2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;;
+2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;;
+2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;;
+2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;;
+2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;;
+2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;;
+2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;;
+2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;;
+2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;;
+2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;;
+2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;;
+2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;;
+2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;;
+2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;;
+2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;;
+2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;;
+2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;;
+2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;;
+2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;;
+2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;;
+2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;;
+2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;;
+2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;;
+2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;;
+2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;;
+2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;;
+2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;;
+2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;;
+2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;;
+2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;;
+2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;;
+2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;;
+2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;;
+2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;;
+2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;;
+2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;;
+2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;;
+2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;;
+2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;;
+2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;;
+2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;;
+2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;;
+2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;;
+2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;;
+2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;;
+2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;;
+2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;;
+2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;;
+2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;;
+2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;;
+2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;;
+2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;;
+2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;;
+2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;;
+2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;;
+2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;;
+2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;;
+2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;;
+2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;;
+2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;;
+2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;;
+2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;;
+2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;;
+2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;;
+2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;;
+2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;;
+2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;;
+2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;;
+2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;;
+2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;;
+2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;;
+2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;;
+2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;;
+2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;;
+2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;;
+2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;;
+2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;;
+2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;;
+2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;;
+2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;;
+2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;;
+2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;;
+2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;;
+2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;;
+2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;;
+2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;;
+2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;;
+2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;;
+2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;;
+2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;;
+2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;;
+2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;;
+2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;;
+2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;;
+2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;;
+2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;;
+2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;;
+2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;;
+2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;;
+2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;;
+2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;;
+2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;;
+2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;;
+2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;;
+2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;;
+2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;;
+2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;;
+2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;;
+2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;;
+2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;;
+2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;;
+2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;;
+2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;;
+2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;;
+2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;;
+2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;;
+2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;;
+2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;;
+2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;;
+2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;;
+2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;;
+2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;;
+2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;;
+2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;;
+2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;;
+2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;;
+2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;;
+2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;;
+2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;;
+2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;;
+2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;;
+2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;;
+2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;;
+2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;;
+2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;;
+2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;;
+2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;;
+2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;;
+2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;;
+2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;;
+2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;;
+2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;;
+2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;;
+2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;;
+2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;;
+2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;;
+2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;;
+2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;;
+2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;;
+2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;;
+2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;;
+2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;;
+2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;;
+2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;;
+2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;;
+2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;;
+2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;;
+2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;;
+2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;;
+2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;;
+2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;;
+2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;;
+2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;;
+2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;;
+2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;;
+2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;;
+2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;;
+2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;;
+2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;;
+2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;;
+2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;;
+2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;;
+2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;;
+2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;;
+2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;;
+2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;;
+2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;;
+2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;;
+2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;;
+2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;;
+2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;;
+2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;;
+2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;;
+2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;
+2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;
+2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;
+E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
+E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
+E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
+E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;;
+E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;;
+E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;;
+E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;;
+E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;;
+E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;;
+E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;;
+E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;;
+E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;;
+E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;;
+E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;;
+E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;;
+E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;;
+E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;;
+E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;;
+E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;;
+E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;;
+E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;;
+E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;;
+E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;;
+E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;;
+E003A;TAG COLON;Cf;0;BN;;;;;N;;;;;
+E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;;
+E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;;
+E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;;
+E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;;
+E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;;
+E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;;
+E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;;
+E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;;
+E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;;
+E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;;
+E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;;
+E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;;
+E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;;
+E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;;
+E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;;
+E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;;
+E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;;
+E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;;
+E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;;
+E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;;
+E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;;
+E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;;
+E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;;
+E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;;
+E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;;
+E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;;
+E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;;
+E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;;
+E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;;
+E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;;
+E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;;
+E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;;
+E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;;
+E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;;
+E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;;
+E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;;
+E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;;
+E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;;
+E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;;
+E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;;
+E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;;
+E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;;
+E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;;
+E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;;
+E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;;
+E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;;
+E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;;
+E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;;
+E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;;
+E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;;
+E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;;
+E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;;
+E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;;
+E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;;
+E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;;
+E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;;
+E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;;
+E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;;
+E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;;
+E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;;
+E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;;
+E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;;
+E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;;
+E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;;
+E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;;
+E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;;
+E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;;
+E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;;
+E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;;
+E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;;
+E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;;
+E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;;
+E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;;
+E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;;
+E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;;
+E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;;
+E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;;
+E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;;
+E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;;
+E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;;
+E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;;
+E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;;
+E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;;
+E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;;
+E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;;
+E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;;
+E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;;
+E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;;
+E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;;
+E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;;
+E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;;
+E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;;
+E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;;
+E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;;
+E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;;
+E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;;
+E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;;
+E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;;
+E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;;
+E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;;
+E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;;
+E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;;
+E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;;
+E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;;
+E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;;
+E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;;
+E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;;
+E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;;
+E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;;
+E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;;
+E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;;
+E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;;
+E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;;
+E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;;
+E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;;
+E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;;
+E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;;
+E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;;
+E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;;
+E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;;
+E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;;
+E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;;
+E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;;
+E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;;
+E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;;
+E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;;
+E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;;
+E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;;
+E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;;
+E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;;
+E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;;
+E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;;
+E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;;
+E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;;
+E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;;
+E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;;
+E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;;
+E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;;
+E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;;
+E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;;
+E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;;
+E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;;
+E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;;
+E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;;
+E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;;
+E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;;
+E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;;
+E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;;
+E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;;
+E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;;
+E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;;
+E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;;
+E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;;
+E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;;
+E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;;
+E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;;
+E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;;
+E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;;
+E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;;
+E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;;
+E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;;
+E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;;
+E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;;
+E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;;
+E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;;
+E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;;
+E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;;
+E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;;
+E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;;
+E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;;
+E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;;
+E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;;
+E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;;
+E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;;
+E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;;
+E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;;
+E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;;
+E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;;
+E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;;
+E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;;
+E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;;
+E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;;
+E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;;
+E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;;
+E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;;
+E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;;
+E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;;
+E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;;
+E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;;
+E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;;
+E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;;
+E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;;
+E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;;
+E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;;
+E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;;
+E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;;
+E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;;
+E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;;
+E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;;
+E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;;
+E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;;
+E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;;
+E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;;
+E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;;
+E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;;
+E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;;
+E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;;
+E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;;
+E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;;
+E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;;
+E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;;
+E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;;
+E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;;
+E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;;
+E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;;
+E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;;
+E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;;
+E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;;
+E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;;
+E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;;
+E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;;
+E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;;
+E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;;
+E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;;
+E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;;
+E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;;
+E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;;
+E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;;
+E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;;
+E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;;
+E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;;
+E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;;
+E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;;
+E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;;
+E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;;
+E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;;
+E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;;
+E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;;
+E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;;
+E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;;
+E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;;
+E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;;
+E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;;
+E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;;
+E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;;
+E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;;
+E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;;
+E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;;
+E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;;
+E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;;
+E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;;
+E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;;
+E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;;
+E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;;
+E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;;
+E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;;
+E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;;
+E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;;
+E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;;
+E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;;
+E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;;
+E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;;
+F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;;
+FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;;
+100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;;
+10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;;
diff --git a/js/src/vm/UnicodeNonBMP.h b/js/src/vm/UnicodeNonBMP.h
new file mode 100644
index 000000000..6cc64cde4
--- /dev/null
+++ b/js/src/vm/UnicodeNonBMP.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Generated by make_unicode.py DO NOT MODIFY */
+/* Unicode version: 9.0.0 */
+
+#ifndef vm_UnicodeNonBMP_h
+#define vm_UnicodeNonBMP_h
+
+#define FOR_EACH_NON_BMP_LOWERCASE(macro) \
+ macro(0x10400, 0x10427, 0xd801, 0xdc00, 0xdc27, 40) \
+ macro(0x104b0, 0x104d3, 0xd801, 0xdcb0, 0xdcd3, 40) \
+ macro(0x10c80, 0x10cb2, 0xd803, 0xdc80, 0xdcb2, 64) \
+ macro(0x118a0, 0x118bf, 0xd806, 0xdca0, 0xdcbf, 32) \
+ macro(0x1e900, 0x1e921, 0xd83a, 0xdd00, 0xdd21, 34)
+
+#define FOR_EACH_NON_BMP_UPPERCASE(macro) \
+ macro(0x10428, 0x1044f, 0xd801, 0xdc28, 0xdc4f, -40) \
+ macro(0x104d8, 0x104fb, 0xd801, 0xdcd8, 0xdcfb, -40) \
+ macro(0x10cc0, 0x10cf2, 0xd803, 0xdcc0, 0xdcf2, -64) \
+ macro(0x118c0, 0x118df, 0xd806, 0xdcc0, 0xdcdf, -32) \
+ macro(0x1e922, 0x1e943, 0xd83a, 0xdd22, 0xdd43, -34)
+
+#define FOR_EACH_NON_BMP_CASE_FOLDING(macro) \
+ macro(0x10400, 0x10427, 0xd801, 0xdc00, 0xdc27, 40) \
+ macro(0x104b0, 0x104d3, 0xd801, 0xdcb0, 0xdcd3, 40) \
+ macro(0x10c80, 0x10cb2, 0xd803, 0xdc80, 0xdcb2, 64) \
+ macro(0x118a0, 0x118bf, 0xd806, 0xdca0, 0xdcbf, 32) \
+ macro(0x1e900, 0x1e921, 0xd83a, 0xdd00, 0xdd21, 34)
+
+#define FOR_EACH_NON_BMP_REV_CASE_FOLDING(macro) \
+ macro(0x10428, 0x1044f, 0xd801, 0xdc28, 0xdc4f, -40) \
+ macro(0x104d8, 0x104fb, 0xd801, 0xdcd8, 0xdcfb, -40) \
+ macro(0x10cc0, 0x10cf2, 0xd803, 0xdcc0, 0xdcf2, -64) \
+ macro(0x118c0, 0x118df, 0xd806, 0xdcc0, 0xdcdf, -32) \
+ macro(0x1e922, 0x1e943, 0xd83a, 0xdd22, 0xdd43, -34)
+
+#endif /* vm_UnicodeNonBMP_h */
diff --git a/js/src/vm/Value.cpp b/js/src/vm/Value.cpp
new file mode 100644
index 000000000..bdd5b56b5
--- /dev/null
+++ b/js/src/vm/Value.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/Value.h"
+
+static const JS::Value JSVAL_NULL = JS::Value::fromTagAndPayload(JSVAL_TAG_NULL, 0);
+static const JS::Value JSVAL_FALSE = JS::Value::fromTagAndPayload(JSVAL_TAG_BOOLEAN, false);
+static const JS::Value JSVAL_TRUE = JS::Value::fromTagAndPayload(JSVAL_TAG_BOOLEAN, true);
+static const JS::Value JSVAL_VOID = JS::Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0);
+
+namespace JS {
+
+const HandleValue NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
+const HandleValue UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
+const HandleValue TrueHandleValue = HandleValue::fromMarkedLocation(&JSVAL_TRUE);
+const HandleValue FalseHandleValue = HandleValue::fromMarkedLocation(&JSVAL_FALSE);
+
+} // namespace JS
diff --git a/js/src/vm/WeakMapPtr.cpp b/js/src/vm/WeakMapPtr.cpp
new file mode 100644
index 000000000..628a08ede
--- /dev/null
+++ b/js/src/vm/WeakMapPtr.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "js/WeakMapPtr.h"
+
+#include "jsweakmap.h"
+
+//
+// Machinery for the externally-linkable JS::WeakMapPtr, which wraps js::WeakMap
+// for a few public data types.
+//
+
+using namespace js;
+
+namespace details {
+
+template<typename T>
+struct DataType
+{
+};
+
+template<>
+struct DataType<JSObject*>
+{
+ using BarrieredType = HeapPtr<JSObject*>;
+ using HasherType = MovableCellHasher<BarrieredType>;
+ static JSObject* NullValue() { return nullptr; }
+};
+
+template<>
+struct DataType<JS::Value>
+{
+ using BarrieredType = HeapPtr<Value>;
+ static JS::Value NullValue() { return JS::UndefinedValue(); }
+};
+
+template <typename K, typename V>
+struct Utils
+{
+ typedef typename DataType<K>::BarrieredType KeyType;
+ typedef typename DataType<K>::HasherType HasherType;
+ typedef typename DataType<V>::BarrieredType ValueType;
+ typedef WeakMap<KeyType, ValueType, HasherType> Type;
+ typedef Type* PtrType;
+ static PtrType cast(void* ptr) { return static_cast<PtrType>(ptr); }
+};
+
+} /* namespace */
+
+template <typename K, typename V>
+void
+JS::WeakMapPtr<K, V>::destroy()
+{
+ MOZ_ASSERT(initialized());
+ js_delete(details::Utils<K, V>::cast(ptr));
+ ptr = nullptr;
+}
+
+template <typename K, typename V>
+bool
+JS::WeakMapPtr<K, V>::init(JSContext* cx)
+{
+ MOZ_ASSERT(!initialized());
+ typename details::Utils<K, V>::PtrType map = cx->runtime()->new_<typename details::Utils<K,V>::Type>(cx);
+ if (!map || !map->init())
+ return false;
+ ptr = map;
+ return true;
+}
+
+template <typename K, typename V>
+void
+JS::WeakMapPtr<K, V>::trace(JSTracer* trc)
+{
+ MOZ_ASSERT(initialized());
+ return details::Utils<K, V>::cast(ptr)->trace(trc);
+}
+
+template <typename K, typename V>
+V
+JS::WeakMapPtr<K, V>::lookup(const K& key)
+{
+ MOZ_ASSERT(initialized());
+ typename details::Utils<K, V>::Type::Ptr result = details::Utils<K, V>::cast(ptr)->lookup(key);
+ if (!result)
+ return details::DataType<V>::NullValue();
+ return result->value();
+}
+
+template <typename K, typename V>
+bool
+JS::WeakMapPtr<K, V>::put(JSContext* cx, const K& key, const V& value)
+{
+ MOZ_ASSERT(initialized());
+ return details::Utils<K, V>::cast(ptr)->put(key, value);
+}
+
+//
+// Supported specializations of JS::WeakMap:
+//
+
+template class JS_PUBLIC_API(JS::WeakMapPtr)<JSObject*, JSObject*>;
+
+#ifdef DEBUG
+// Nobody's using this at the moment, but we want to make sure it compiles.
+template class JS_PUBLIC_API(JS::WeakMapPtr)<JSObject*, JS::Value>;
+#endif
diff --git a/js/src/vm/WrapperObject.h b/js/src/vm/WrapperObject.h
new file mode 100644
index 000000000..7ce402e80
--- /dev/null
+++ b/js/src/vm/WrapperObject.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_WrapperObject_h
+#define vm_WrapperObject_h
+
+#include "jsobj.h"
+#include "jswrapper.h"
+
+#include "vm/ProxyObject.h"
+
+namespace js {
+
+// Proxy family for wrappers.
+// This variable exists solely to provide a unique address for use as an identifier.
+extern const char sWrapperFamily;
+
+class WrapperObject : public ProxyObject
+{
+};
+
+class CrossCompartmentWrapperObject : public WrapperObject
+{
+};
+
+} // namespace js
+
+template<>
+inline bool
+JSObject::is<js::WrapperObject>() const
+{
+ return js::IsWrapper(const_cast<JSObject*>(this));
+}
+
+template<>
+inline bool
+JSObject::is<js::CrossCompartmentWrapperObject>() const
+{
+ return js::IsCrossCompartmentWrapper(const_cast<JSObject*>(this));
+}
+
+#endif /* vm_WrapperObject_h */
diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp
new file mode 100644
index 000000000..7f1012d86
--- /dev/null
+++ b/js/src/vm/Xdr.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/Xdr.h"
+
+#include "mozilla/PodOperations.h"
+
+#include <string.h>
+
+#include "jsapi.h"
+#include "jsscript.h"
+
+#include "vm/Debugger.h"
+#include "vm/EnvironmentObject.h"
+
+using namespace js;
+using mozilla::PodEqual;
+
+template<XDRMode mode>
+void
+XDRState<mode>::postProcessContextErrors(JSContext* cx)
+{
+ if (cx->isExceptionPending()) {
+ MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok);
+ resultCode_ = JS::TranscodeResult_Throw;
+ }
+}
+
+template<XDRMode mode>
+bool
+XDRState<mode>::codeChars(const Latin1Char* chars, size_t nchars)
+{
+ static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
+
+ MOZ_ASSERT(mode == XDR_ENCODE);
+
+ if (nchars == 0)
+ return true;
+ uint8_t* ptr = buf.write(nchars);
+ if (!ptr)
+ return false;
+
+ mozilla::PodCopy(ptr, chars, nchars);
+ return true;
+}
+
+template<XDRMode mode>
+bool
+XDRState<mode>::codeChars(char16_t* chars, size_t nchars)
+{
+ if (nchars == 0)
+ return true;
+ size_t nbytes = nchars * sizeof(char16_t);
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(nbytes);
+ if (!ptr)
+ return false;
+ mozilla::NativeEndian::copyAndSwapToLittleEndian(ptr, chars, nchars);
+ } else {
+ const uint8_t* ptr = buf.read(nbytes);
+ mozilla::NativeEndian::copyAndSwapFromLittleEndian(chars, ptr, nchars);
+ }
+ return true;
+}
+
+template<XDRMode mode>
+static bool
+VersionCheck(XDRState<mode>* xdr)
+{
+ JS::BuildIdCharVector buildId;
+ if (!xdr->cx()->buildIdOp() || !xdr->cx()->buildIdOp()(&buildId)) {
+ JS_ReportErrorNumberASCII(xdr->cx(), GetErrorMessage, nullptr,
+ JSMSG_BUILD_ID_NOT_AVAILABLE);
+ return false;
+ }
+ MOZ_ASSERT(!buildId.empty());
+
+ uint32_t buildIdLength;
+ if (mode == XDR_ENCODE)
+ buildIdLength = buildId.length();
+
+ if (!xdr->codeUint32(&buildIdLength))
+ return false;
+
+ if (mode == XDR_DECODE && buildIdLength != buildId.length())
+ return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
+
+ if (mode == XDR_ENCODE) {
+ if (!xdr->codeBytes(buildId.begin(), buildIdLength))
+ return false;
+ } else {
+ JS::BuildIdCharVector decodedBuildId;
+
+ // buildIdLength is already checked against the length of current
+ // buildId.
+ if (!decodedBuildId.resize(buildIdLength)) {
+ ReportOutOfMemory(xdr->cx());
+ return false;
+ }
+
+ if (!xdr->codeBytes(decodedBuildId.begin(), buildIdLength))
+ return false;
+
+ // We do not provide binary compatibility with older scripts.
+ if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength))
+ return xdr->fail(JS::TranscodeResult_Failure_BadBuildId);
+ }
+
+ return true;
+}
+
+template<XDRMode mode>
+bool
+XDRState<mode>::codeFunction(MutableHandleFunction funp)
+{
+ if (mode == XDR_DECODE)
+ funp.set(nullptr);
+ else
+ MOZ_ASSERT(funp->nonLazyScript()->enclosingScope()->is<GlobalScope>());
+
+ if (!VersionCheck(this)) {
+ postProcessContextErrors(cx());
+ return false;
+ }
+
+ RootedScope scope(cx(), &cx()->global()->emptyGlobalScope());
+ if (!XDRInterpretedFunction(this, scope, nullptr, funp)) {
+ postProcessContextErrors(cx());
+ funp.set(nullptr);
+ return false;
+ }
+
+ return true;
+}
+
+template<XDRMode mode>
+bool
+XDRState<mode>::codeScript(MutableHandleScript scriptp)
+{
+ if (mode == XDR_DECODE)
+ scriptp.set(nullptr);
+ else
+ MOZ_ASSERT(!scriptp->enclosingScope());
+
+ if (!VersionCheck(this)) {
+ postProcessContextErrors(cx());
+ return false;
+ }
+
+ if (!XDRScript(this, nullptr, nullptr, nullptr, scriptp)) {
+ postProcessContextErrors(cx());
+ scriptp.set(nullptr);
+ return false;
+ }
+
+ return true;
+}
+
+template<XDRMode mode>
+bool
+XDRState<mode>::codeConstValue(MutableHandleValue vp)
+{
+ return XDRScriptConst(this, vp);
+}
+
+template class js::XDRState<XDR_ENCODE>;
+template class js::XDRState<XDR_DECODE>;
diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h
new file mode 100644
index 000000000..8e8c5bf17
--- /dev/null
+++ b/js/src/vm/Xdr.h
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Xdr_h
+#define vm_Xdr_h
+
+#include "mozilla/EndianUtils.h"
+#include "mozilla/TypeTraits.h"
+
+#include "jsatom.h"
+#include "jsfriendapi.h"
+
+namespace js {
+
+class XDRBuffer {
+ public:
+ XDRBuffer(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
+ : context_(cx), buffer_(buffer), cursor_(cursor) { }
+
+ JSContext* cx() const {
+ return context_;
+ }
+
+ const uint8_t* read(size_t n) {
+ MOZ_ASSERT(cursor_ < buffer_.length());
+ uint8_t* ptr = &buffer_[cursor_];
+ cursor_ += n;
+ return ptr;
+ }
+
+ const char* readCString() {
+ char* ptr = reinterpret_cast<char*>(&buffer_[cursor_]);
+ uint8_t* end = reinterpret_cast<uint8_t*>(strchr(ptr, '\0')) + 1;
+ MOZ_ASSERT(buffer_.begin() < end);
+ MOZ_ASSERT(end <= buffer_.end());
+ cursor_ = end - buffer_.begin();
+ return ptr;
+ }
+
+ uint8_t* write(size_t n) {
+ MOZ_ASSERT(n != 0);
+ if (!buffer_.growByUninitialized(n)) {
+ JS_ReportOutOfMemory(cx());
+ return nullptr;
+ }
+ uint8_t* ptr = &buffer_[cursor_];
+ cursor_ += n;
+ return ptr;
+ }
+
+ private:
+ JSContext* const context_;
+ JS::TranscodeBuffer& buffer_;
+ size_t cursor_;
+};
+
+/*
+ * XDR serialization state. All data is encoded in little endian.
+ */
+template <XDRMode mode>
+class XDRState {
+ public:
+ XDRBuffer buf;
+ JS::TranscodeResult resultCode_;
+
+ XDRState(JSContext* cx, JS::TranscodeBuffer& buffer, size_t cursor = 0)
+ : buf(cx, buffer, cursor), resultCode_(JS::TranscodeResult_Ok) { }
+
+ JSContext* cx() const {
+ return buf.cx();
+ }
+
+ // Record logical failures of XDR.
+ void postProcessContextErrors(JSContext* cx);
+ JS::TranscodeResult resultCode() const {
+ return resultCode_;
+ }
+ bool fail(JS::TranscodeResult code) {
+ MOZ_ASSERT(resultCode_ == JS::TranscodeResult_Ok);
+ resultCode_ = code;
+ return false;
+ }
+
+ bool codeUint8(uint8_t* n) {
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(sizeof(*n));
+ if (!ptr)
+ return false;
+ *ptr = *n;
+ } else {
+ *n = *buf.read(sizeof(*n));
+ }
+ return true;
+ }
+
+ bool codeUint16(uint16_t* n) {
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(sizeof(*n));
+ if (!ptr)
+ return false;
+ mozilla::LittleEndian::writeUint16(ptr, *n);
+ } else {
+ const uint8_t* ptr = buf.read(sizeof(*n));
+ *n = mozilla::LittleEndian::readUint16(ptr);
+ }
+ return true;
+ }
+
+ bool codeUint32(uint32_t* n) {
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(sizeof(*n));
+ if (!ptr)
+ return false;
+ mozilla::LittleEndian::writeUint32(ptr, *n);
+ } else {
+ const uint8_t* ptr = buf.read(sizeof(*n));
+ *n = mozilla::LittleEndian::readUint32(ptr);
+ }
+ return true;
+ }
+
+ bool codeUint64(uint64_t* n) {
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(sizeof(*n));
+ if (!ptr)
+ return false;
+ mozilla::LittleEndian::writeUint64(ptr, *n);
+ } else {
+ const uint8_t* ptr = buf.read(sizeof(*n));
+ *n = mozilla::LittleEndian::readUint64(ptr);
+ }
+ return true;
+ }
+
+ /*
+ * Use SFINAE to refuse any specialization which is not an enum. Uses of
+ * this function do not have to specialize the type of the enumerated field
+ * as C++ will extract the parameterized from the argument list.
+ */
+ template <typename T>
+ bool codeEnum32(T* val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
+ {
+ uint32_t tmp;
+ if (mode == XDR_ENCODE)
+ tmp = uint32_t(*val);
+ if (!codeUint32(&tmp))
+ return false;
+ if (mode == XDR_DECODE)
+ *val = T(tmp);
+ return true;
+ }
+
+ bool codeDouble(double* dp) {
+ union DoublePun {
+ double d;
+ uint64_t u;
+ } pun;
+ if (mode == XDR_ENCODE)
+ pun.d = *dp;
+ if (!codeUint64(&pun.u))
+ return false;
+ if (mode == XDR_DECODE)
+ *dp = pun.d;
+ return true;
+ }
+
+ bool codeBytes(void* bytes, size_t len) {
+ if (len == 0)
+ return true;
+ if (mode == XDR_ENCODE) {
+ uint8_t* ptr = buf.write(len);
+ if (!ptr)
+ return false;
+ memcpy(ptr, bytes, len);
+ } else {
+ memcpy(bytes, buf.read(len), len);
+ }
+ return true;
+ }
+
+ /*
+ * During encoding the string is written into the buffer together with its
+ * terminating '\0'. During decoding the method returns a pointer into the
+ * decoding buffer and the caller must copy the string if it will outlive
+ * the decoding buffer.
+ */
+ bool codeCString(const char** sp) {
+ if (mode == XDR_ENCODE) {
+ size_t n = strlen(*sp) + 1;
+ uint8_t* ptr = buf.write(n);
+ if (!ptr)
+ return false;
+ memcpy(ptr, *sp, n);
+ } else {
+ *sp = buf.readCString();
+ }
+ return true;
+ }
+
+ bool codeChars(const JS::Latin1Char* chars, size_t nchars);
+ bool codeChars(char16_t* chars, size_t nchars);
+
+ bool codeFunction(JS::MutableHandleFunction objp);
+ bool codeScript(MutableHandleScript scriptp);
+ bool codeConstValue(MutableHandleValue vp);
+};
+
+using XDREncoder = XDRState<XDR_ENCODE>;
+using XDRDecoder = XDRState<XDR_DECODE>;
+
+} /* namespace js */
+
+#endif /* vm_Xdr_h */
diff --git a/js/src/vm/make_opcode_doc.py b/js/src/vm/make_opcode_doc.py
new file mode 100755
index 000000000..454d8b8d5
--- /dev/null
+++ b/js/src/vm/make_opcode_doc.py
@@ -0,0 +1,369 @@
+#!/usr/bin/python -B
+
+""" Usage: make_opcode_doc.py PATH_TO_MOZILLA_CENTRAL
+
+ This script generates SpiderMonkey bytecode documentation
+ from js/src/vm/Opcodes.h.
+
+ Output is written to stdout and should be pasted into the following
+ MDN page:
+ https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
+"""
+
+from __future__ import print_function
+import re
+import sys
+from xml.sax.saxutils import escape
+
+SOURCE_BASE = 'http://dxr.mozilla.org/mozilla-central/source'
+
+def error(message):
+ print("Error: {message}".format(message=message), file=sys.stderr)
+ sys.exit(1)
+
+quoted_pat = re.compile(r"([^A-Za-z0-9]|^)'([^']+)'")
+js_pat = re.compile(r"([^A-Za-z0-9]|^)(JS[A-Z0-9_\*]+)")
+def codify(text):
+ text = re.sub(quoted_pat, '\\1<code>\\2</code>', text)
+ text = re.sub(js_pat, '\\1<code>\\2</code>', text)
+
+ return text
+
+space_star_space_pat = re.compile('^\s*\* ?', re.M)
+def get_comment_body(comment):
+ return re.sub(space_star_space_pat, '', comment).split('\n')
+
+def parse_index(comment):
+ index = []
+ current_types = None
+ category_name = ''
+ category_pat = re.compile('\[([^\]]+)\]')
+ for line in get_comment_body(comment):
+ m = category_pat.search(line)
+ if m:
+ category_name = m.group(1)
+ if category_name == 'Index':
+ continue
+ current_types = []
+ index.append((category_name, current_types))
+ else:
+ type_name = line.strip()
+ if type_name and current_types is not None:
+ current_types.append((type_name, []))
+
+ return index
+
+class OpcodeInfo:
+ def __init__(self):
+ self.name = ''
+ self.value = ''
+ self.length = ''
+ self.length_override = ''
+ self.nuses = ''
+ self.nuses_override = ''
+ self.ndefs = ''
+ self.ndefs_override = ''
+ self.flags = ''
+ self.operands = ''
+ self.stack_uses = ''
+ self.stack_defs = ''
+
+ self.desc = ''
+
+ self.category_name = ''
+ self.type_name = ''
+
+ self.group = []
+ self.sort_key = ''
+
+def find_by_name(list, name):
+ for (n, body) in list:
+ if n == name:
+ return body
+
+ return None
+
+def add_to_index(index, opcode):
+ types = find_by_name(index, opcode.category_name)
+ if types is None:
+ error("Category is not listed in index: "
+ "{name}".format(name=opcode.category_name))
+ opcodes = find_by_name(types, opcode.type_name)
+ if opcodes is None:
+ if opcode.type_name:
+ error("Type is not listed in {category}: "
+ "{name}".format(category=opcode.category_name,
+ name=opcode.type_name))
+ types.append((opcode.type_name, [opcode]))
+ return
+
+ opcodes.append(opcode)
+
+def format_desc(descs):
+ current_type = ''
+ desc = ''
+ for (type, line) in descs:
+ if type != current_type:
+ if current_type:
+ desc += '</{name}>\n'.format(name=current_type)
+ current_type = type
+ if type:
+ desc += '<{name}>'.format(name=current_type)
+ if current_type:
+ desc += line + "\n"
+ if current_type:
+ desc += '</{name}>'.format(name=current_type)
+
+ return desc
+
+tag_pat = re.compile('^\s*[A-Za-z]+:\s*|\s*$')
+def get_tag_value(line):
+ return re.sub(tag_pat, '', line)
+
+def get_opcodes(dir):
+ iter_pat = re.compile(r"/\*(.*?)\*/" # either a documentation comment...
+ r"|"
+ r"macro\(" # or a macro(...) call
+ r"([^,]+),\s*" # op
+ r"([0-9]+),\s*" # val
+ r"[^,]+,\s*" # name
+ r"[^,]+,\s*" # image
+ r"([0-9\-]+),\s*" # length
+ r"([0-9\-]+),\s*" # nuses
+ r"([0-9\-]+),\s*" # ndefs
+ r"([^\)]+)" # format
+ r"\)", re.S)
+ stack_pat = re.compile('^(.*?)\s*=>\s*(.*?)$')
+
+ index = []
+
+ opcode = OpcodeInfo()
+ merged = opcode
+
+ with open('{dir}/js/src/vm/Opcodes.h'.format(dir=dir), 'r') as f:
+ data = f.read()
+
+ for m in re.finditer(iter_pat, data):
+ comment = m.group(1)
+ name = m.group(2)
+
+ if comment:
+ if '[Index]' in comment:
+ index = parse_index(comment)
+ continue
+
+ if 'Operands:' not in comment:
+ continue
+
+ state = 'desc'
+ stack = ''
+ descs = []
+
+ for line in get_comment_body(comment):
+ if line.startswith(' Category:'):
+ state = 'category'
+ opcode.category_name = get_tag_value(line)
+ elif line.startswith(' Type:'):
+ state = 'type'
+ opcode.type_name = get_tag_value(line)
+ elif line.startswith(' Operands:'):
+ state = 'operands'
+ opcode.operands = get_tag_value(line)
+ elif line.startswith(' Stack:'):
+ state = 'stack'
+ stack = get_tag_value(line)
+ elif line.startswith(' len:'):
+ state = 'len'
+ opcode.length_override = get_tag_value(line)
+ elif line.startswith(' nuses:'):
+ state = 'nuses'
+ opcode.nuses_override = get_tag_value(line)
+ elif line.startswith(' ndefs:'):
+ state = 'ndefs'
+ opcode.ndefs_override = get_tag_value(line)
+ elif state == 'desc':
+ if line.startswith(' '):
+ descs.append(('pre', escape(line[1:])))
+ else:
+ line = line.strip()
+ if line == '':
+ descs.append(('', line))
+ else:
+ descs.append(('p', codify(escape(line))))
+ elif line.startswith(' '):
+ if state == 'operands':
+ opcode.operands += line.strip()
+ elif state == 'stack':
+ stack += line.strip()
+ elif state == 'len':
+ opcode.length_override += line.strip()
+ elif state == 'nuses':
+ opcode.nuses_override += line.strip()
+ elif state == 'ndefs':
+ opcode.ndefs_override += line.strip()
+
+ opcode.desc = format_desc(descs)
+
+ m2 = stack_pat.search(stack)
+ if m2:
+ opcode.stack_uses = m2.group(1)
+ opcode.stack_defs = m2.group(2)
+
+ merged = opcode
+ elif name and not name.startswith('JSOP_UNUSED'):
+ opcode.name = name
+ opcode.value = int(m.group(3))
+ opcode.length = m.group(4)
+ opcode.nuses = m.group(5)
+ opcode.ndefs = m.group(6)
+
+ flags = []
+ for flag in m.group(7).split('|'):
+ if flag != 'JOF_BYTE':
+ flags.append(flag.replace('JOF_', ''))
+ opcode.flags = ', '.join(flags)
+
+ if merged == opcode:
+ opcode.sort_key = opcode.name
+ if opcode.category_name == '':
+ error("Category is not specified for "
+ "{name}".format(name=opcode.name))
+ add_to_index(index, opcode)
+ else:
+ if merged.length != opcode.length:
+ error("length should be same for merged section: "
+ "{value1}({name1}) != "
+ "{value2}({name2})".format(name1=merged.name,
+ value1=merged.length,
+ name2=opcode.name,
+ value2=opcode.length))
+ if merged.nuses != opcode.nuses:
+ error("nuses should be same for merged section: "
+ "{value1}({name1}) != "
+ "{value2}({name2})".format(name1=merged.name,
+ value1=merged.nuses,
+ name2=opcode.name,
+ value2=opcode.nuses))
+ if merged.ndefs != opcode.ndefs:
+ error("ndefs should be same for merged section: "
+ "{value1}({name1}) != "
+ "{value2}({name2})".format(name1=merged.name,
+ value1=merged.ndefs,
+ name2=opcode.name,
+ value2=opcode.ndefs))
+ merged.group.append(opcode)
+ if opcode.name < merged.name:
+ merged.sort_key = opcode.name
+
+ opcode = OpcodeInfo()
+
+ return index
+
+def override(value, override_value):
+ if override_value != '':
+ return override_value
+
+ return value
+
+def format_flags(flags):
+ if flags == '':
+ return ''
+
+ return ' ({flags})'.format(flags=flags)
+
+def print_opcode(opcode):
+ names_template = '{name} [-{nuses}, +{ndefs}]{flags}'
+ opcodes = sorted([opcode] + opcode.group,
+ key=lambda opcode: opcode.name)
+ names = map(lambda code: names_template.format(name=escape(code.name),
+ nuses=override(code.nuses,
+ opcode.nuses_override),
+ ndefs=override(code.ndefs,
+ opcode.ndefs_override),
+ flags=format_flags(code.flags)),
+ opcodes)
+ if len(opcodes) == 1:
+ values = ['{value} (0x{value:02x})'.format(value=opcode.value)]
+ else:
+ values_template = '{name}: {value} (0x{value:02x})'
+ values = map(lambda code: values_template.format(name=escape(code.name),
+ value=code.value),
+ opcodes)
+
+ print("""<dt id="{id}">{names}</dt>
+<dd>
+<table class="standard-table">
+<tbody>
+<tr><th>Value</th><td><code>{values}</code></td></tr>
+<tr><th>Operands</th><td><code>{operands}</code></td></tr>
+<tr><th>Length</th><td><code>{length}</code></td></tr>
+<tr><th>Stack Uses</th><td><code>{stack_uses}</code></td></tr>
+<tr><th>Stack Defs</th><td><code>{stack_defs}</code></td></tr>
+</tbody>
+</table>
+
+{desc}
+</dd>
+""".format(id=opcodes[0].name,
+ names='<br>'.join(names),
+ values='<br>'.join(values),
+ operands=escape(opcode.operands) or "&nbsp;",
+ length=escape(override(opcode.length,
+ opcode.length_override)),
+ stack_uses=escape(opcode.stack_uses) or "&nbsp;",
+ stack_defs=escape(opcode.stack_defs) or "&nbsp;",
+ desc=opcode.desc)) # desc is already escaped
+
+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(index):
+ print("""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
+
+<h2 id="Bytecode_Listing">Bytecode Listing</h2>
+
+<p>This document is automatically generated from
+<a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> by
+<a href="{source_base}/js/src/vm/make_opcode_doc.py">make_opcode_doc.py</a>.</p>
+""".format(source_base=SOURCE_BASE))
+
+ for (category_name, types) in index:
+ print('<h3 id="{id}">{name}</h3>'.format(name=category_name,
+ id=make_element_id(category_name)))
+ for (type_name, opcodes) in types:
+ if type_name:
+ print('<h4 id="{id}">{name}</h4>'.format(name=type_name,
+ id=make_element_id(category_name, type_name)))
+ print('<dl>')
+ for opcode in sorted(opcodes,
+ key=lambda opcode: opcode.sort_key):
+ print_opcode(opcode)
+ print('</dl>')
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("Usage: make_opcode_doc.py PATH_TO_MOZILLA_CENTRAL",
+ file=sys.stderr)
+ sys.exit(1)
+ dir = sys.argv[1]
+ index = get_opcodes(dir)
+ print_doc(index)
diff --git a/js/src/vm/make_unicode.py b/js/src/vm/make_unicode.py
new file mode 100755
index 000000000..5565d7d14
--- /dev/null
+++ b/js/src/vm/make_unicode.py
@@ -0,0 +1,836 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Based upon makeunicodedata.py
+# (http://hg.python.org/cpython/file/c8192197d23d/Tools/unicode/makeunicodedata.py)
+# written by Fredrik Lundh (fredrik@pythonware.com)
+#
+# Copyright (C) 2011 Tom Schuster <evilpies@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+import csv
+import io
+import re
+import os
+import sys
+from contextlib import closing
+
+# ECMAScript 2016
+# §11.2 White Space
+whitespace = [
+ # python doesn't support using control character names :(
+ 0x9, # CHARACTER TABULATION
+ 0xb, # LINE TABULATION
+ 0xc, # FORM FEED
+ ord(u'\N{SPACE}'),
+ ord(u'\N{NO-BREAK SPACE}'),
+ ord(u'\N{ZERO WIDTH NO-BREAK SPACE}'), # also BOM
+]
+
+# §11.3 Line Terminators
+line_terminator = [
+ 0xa, # LINE FEED
+ 0xd, # CARRIAGE RETURN
+ ord(u'\N{LINE SEPARATOR}'),
+ ord(u'\N{PARAGRAPH SEPARATOR}'),
+]
+
+# These are also part of IdentifierPart §11.6 Names and Keywords
+compatibility_identifier_part = [
+ ord(u'\N{ZERO WIDTH NON-JOINER}'),
+ ord(u'\N{ZERO WIDTH JOINER}'),
+]
+
+FLAG_SPACE = 1 << 0
+FLAG_UNICODE_ID_START = 1 << 1
+FLAG_UNICODE_ID_CONTINUE_ONLY = 1 << 2
+
+MAX_BMP = 0xffff
+
+public_domain = """
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+"""
+
+mpl_license = """\
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"""
+
+warning_message = """\
+/* Generated by make_unicode.py DO NOT MODIFY */
+"""
+
+unicode_version_message = """\
+/* Unicode version: {0} */
+"""
+
+def read_unicode_data(unicode_data):
+ """
+ If you want to understand how this wonderful file format works checkout
+ Unicode Standard Annex #44 - Unicode Character Database
+ http://www.unicode.org/reports/tr44/
+ """
+
+ reader = csv.reader(unicode_data, delimiter=';')
+
+ while True:
+ row = reader.next()
+ name = row[1]
+
+ # We need to expand the UAX #44 4.2.3 Code Point Range
+ if name.startswith('<') and name.endswith('First>'):
+ next_row = reader.next()
+
+ for i in range(int(row[0], 16), int(next_row[0], 16) + 1):
+ row[0] = i
+ row[1] = name[1:-8]
+
+ yield row
+ else:
+ row[0] = int(row[0], 16)
+ yield row
+
+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 read_derived_core_properties(derived_core_properties):
+ for line in derived_core_properties:
+ if line == '\n' or line.startswith('#'):
+ continue
+ row = line.split('#')[0].split(';')
+ char_range = row[0].strip()
+ char_property = row[1].strip()
+ if '..' not in char_range:
+ yield (int(char_range, 16), char_property)
+ else:
+ [start, end] = char_range.split('..')
+ for char in range(int(start, 16), int(end, 16) + 1):
+ yield (char, char_property)
+
+def utf16_encode(code):
+ NonBMPMin = 0x10000
+ LeadSurrogateMin = 0xD800
+ TrailSurrogateMin = 0xDC00
+
+ lead = (code - NonBMPMin) / 1024 + LeadSurrogateMin
+ trail = ((code - NonBMPMin) % 1024) + TrailSurrogateMin
+
+ return lead, trail
+
+def make_non_bmp_convert_macro(out_file, name, convert_map):
+ convert_list = []
+ entry = None
+ for code in sorted(convert_map.keys()):
+ converted = convert_map[code]
+ diff = converted - code
+
+ if entry and code == entry['code'] + entry['length'] and diff == entry['diff']:
+ entry['length'] += 1
+ continue
+
+ entry = { 'code': code, 'diff': diff, 'length': 1 }
+ convert_list.append(entry)
+
+ lines = []
+ for entry in convert_list:
+ from_code = entry['code']
+ to_code = entry['code'] + entry['length'] - 1
+ diff = entry['diff']
+
+ from_lead, from_trail = utf16_encode(from_code)
+ to_lead, to_trail = utf16_encode(to_code)
+
+ assert from_lead == to_lead
+
+ lines.append(' macro(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, {:d})'.format(
+ from_code, to_code, from_lead, from_trail, to_trail, diff))
+
+ out_file.write('#define FOR_EACH_NON_BMP_{}(macro) \\\n'.format(name))
+ out_file.write(' \\\n'.join(lines))
+ out_file.write('\n')
+
+def process_derived_core_properties(derived_core_properties):
+ id_start = set()
+ id_continue = set()
+
+ for (char, prop) in read_derived_core_properties(derived_core_properties):
+ if prop == 'ID_Start':
+ id_start.add(char)
+ if prop == 'ID_Continue':
+ id_continue.add(char)
+
+ return (id_start, id_continue)
+
+def process_unicode_data(unicode_data, derived_core_properties):
+ dummy = (0, 0, 0)
+ table = [dummy]
+ cache = {dummy: 0}
+ index = [0] * (MAX_BMP + 1)
+ same_upper_map = {}
+ same_upper_dummy = (0, 0, 0)
+ same_upper_table = [same_upper_dummy]
+ same_upper_cache = {same_upper_dummy: 0}
+ same_upper_index = [0] * (MAX_BMP + 1)
+
+ test_table = {}
+ test_space_table = []
+
+ non_bmp_lower_map = {}
+ non_bmp_upper_map = {}
+
+ (id_start, id_continue) = process_derived_core_properties(derived_core_properties)
+
+ for row in read_unicode_data(unicode_data):
+ code = row[0]
+ name = row[1]
+ category = row[2]
+ alias = row[-5]
+ uppercase = row[-3]
+ lowercase = row[-2]
+ flags = 0
+
+ if uppercase:
+ upper = int(uppercase, 16)
+
+ if upper not in same_upper_map:
+ same_upper_map[upper] = [code]
+ else:
+ same_upper_map[upper].append(code)
+ else:
+ upper = code
+
+ if lowercase:
+ lower = int(lowercase, 16)
+ else:
+ lower = code
+
+ if code > MAX_BMP:
+ if code != lower:
+ non_bmp_lower_map[code] = lower
+ if code != upper:
+ non_bmp_upper_map[code] = upper
+ continue
+
+ # we combine whitespace and lineterminators because in pratice we don't need them separated
+ if category == 'Zs' or code in whitespace or code in line_terminator:
+ flags |= FLAG_SPACE
+ test_space_table.append(code)
+
+ # §11.6 (IdentifierStart)
+ if code in id_start:
+ flags |= FLAG_UNICODE_ID_START
+
+ # §11.6 (IdentifierPart)
+ elif code in id_continue or code in compatibility_identifier_part:
+ flags |= FLAG_UNICODE_ID_CONTINUE_ONLY
+
+ test_table[code] = (upper, lower, name, alias)
+
+ up_d = upper - code
+ low_d = lower - code
+
+ assert up_d > -65535 and up_d < 65535
+ assert low_d > -65535 and low_d < 65535
+
+ upper = up_d & 0xffff
+ lower = low_d & 0xffff
+
+ item = (upper, lower, flags)
+
+ i = cache.get(item)
+ if i is None:
+ assert item not in table
+ cache[item] = i = len(table)
+ table.append(item)
+ index[code] = i
+
+ for code in range(0, MAX_BMP + 1):
+ entry = test_table.get(code)
+
+ if not entry:
+ continue
+
+ (upper, lower, name, alias) = entry
+
+ if upper not in same_upper_map:
+ continue
+
+ same_upper_ds = [v - code for v in same_upper_map[upper]]
+
+ assert len(same_upper_ds) <= 3
+ assert all([v > -65535 and v < 65535 for v in same_upper_ds])
+
+ same_upper = [v & 0xffff for v in same_upper_ds]
+ same_upper_0 = same_upper[0] if len(same_upper) >= 1 else 0
+ same_upper_1 = same_upper[1] if len(same_upper) >= 2 else 0
+ same_upper_2 = same_upper[2] if len(same_upper) >= 3 else 0
+
+ item = (same_upper_0, same_upper_1, same_upper_2)
+
+ i = same_upper_cache.get(item)
+ if i is None:
+ assert item not in same_upper_table
+ same_upper_cache[item] = i = len(same_upper_table)
+ same_upper_table.append(item)
+ same_upper_index[code] = i
+
+ return (
+ table, index,
+ same_upper_table, same_upper_index,
+ non_bmp_lower_map, non_bmp_upper_map,
+ test_table, test_space_table,
+ )
+
+def process_case_folding(case_folding):
+ folding_map = {}
+ rev_folding_map = {}
+ folding_dummy = (0, 0, 0, 0)
+ folding_table = [folding_dummy]
+ folding_cache = {folding_dummy: 0}
+ folding_index = [0] * (MAX_BMP + 1)
+
+ folding_tests = []
+ folding_codes = set()
+
+ non_bmp_folding_map = {}
+ non_bmp_rev_folding_map = {}
+
+ for row in read_case_folding(case_folding):
+ code = row[0]
+ mapping = row[2]
+ folding_map[code] = mapping
+
+ if code > MAX_BMP:
+ non_bmp_folding_map[code] = mapping
+ non_bmp_rev_folding_map[mapping] = code
+
+ 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_BMP:
+ 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
+ return (
+ folding_table, folding_index,
+ non_bmp_folding_map, non_bmp_rev_folding_map,
+ folding_tests
+ )
+
+def make_non_bmp_file(version,
+ non_bmp_lower_map, non_bmp_upper_map,
+ non_bmp_folding_map, non_bmp_rev_folding_map):
+ file_name = 'UnicodeNonBMP.h';
+ with io.open(file_name, mode='wb') as non_bmp_file:
+ non_bmp_file.write(mpl_license)
+ non_bmp_file.write('\n')
+ non_bmp_file.write(warning_message)
+ non_bmp_file.write(unicode_version_message.format(version))
+ non_bmp_file.write("""
+#ifndef vm_UnicodeNonBMP_h
+#define vm_UnicodeNonBMP_h
+
+""")
+
+ make_non_bmp_convert_macro(non_bmp_file, 'LOWERCASE', non_bmp_lower_map)
+ non_bmp_file.write('\n')
+ make_non_bmp_convert_macro(non_bmp_file, 'UPPERCASE', non_bmp_upper_map)
+ non_bmp_file.write('\n')
+ make_non_bmp_convert_macro(non_bmp_file, 'CASE_FOLDING', non_bmp_folding_map)
+ non_bmp_file.write('\n')
+ make_non_bmp_convert_macro(non_bmp_file, 'REV_CASE_FOLDING', non_bmp_rev_folding_map)
+
+ non_bmp_file.write("""
+#endif /* vm_UnicodeNonBMP_h */
+""")
+
+def make_bmp_mapping_test(version, test_table):
+ file_name = '../tests/ecma_5/String/string-upper-lower-mapping.js'
+ with io.open(file_name, mode='wb') as test_mapping:
+ test_mapping.write(warning_message)
+ test_mapping.write(unicode_version_message.format(version))
+ test_mapping.write(public_domain)
+ test_mapping.write('var mapping = [\n')
+ for code in range(0, MAX_BMP + 1):
+ entry = test_table.get(code)
+
+ if entry:
+ (upper, lower, name, alias) = entry
+ test_mapping.write(' [' + hex(upper) + ', ' + hex(lower) + '], /* ' +
+ name + (' (' + alias + ')' if alias else '') + ' */\n')
+ else:
+ test_mapping.write(' [' + hex(code) + ', ' + hex(code) + '],\n')
+ test_mapping.write('];')
+ test_mapping.write("""
+assertEq(mapping.length, 0x10000);
+for (var i = 0; i <= 0xffff; i++) {
+ var char = String.fromCharCode(i);
+ var info = mapping[i];
+
+ assertEq(char.toUpperCase().charCodeAt(0), info[0]);
+ assertEq(char.toLowerCase().charCodeAt(0), info[1]);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+""")
+
+def make_non_bmp_mapping_test(version, non_bmp_upper_map, non_bmp_lower_map):
+ file_name = '../tests/ecma_6/String/string-code-point-upper-lower-mapping.js'
+ with io.open(file_name, mode='wb') as test_non_bmp_mapping:
+ test_non_bmp_mapping.write(warning_message)
+ test_non_bmp_mapping.write(unicode_version_message.format(version))
+ test_non_bmp_mapping.write(public_domain)
+ for code in sorted(non_bmp_upper_map.keys()):
+ test_non_bmp_mapping.write("""\
+assertEq(String.fromCodePoint(0x{:x}).toUpperCase().codePointAt(0), 0x{:x});
+""".format(code, non_bmp_upper_map[code]))
+ for code in sorted(non_bmp_lower_map.keys()):
+ test_non_bmp_mapping.write("""\
+assertEq(String.fromCodePoint(0x{:x}).toLowerCase().codePointAt(0), 0x{:x});
+""".format(code, non_bmp_lower_map[code]))
+
+ test_non_bmp_mapping.write("""
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+""")
+
+def make_space_test(version, test_space_table):
+ file_name = '../tests/ecma_5/String/string-space-trim.js'
+ with io.open(file_name, mode='wb') as test_space:
+ test_space.write(warning_message)
+ test_space.write(unicode_version_message.format(version))
+ test_space.write(public_domain)
+ test_space.write('var onlySpace = String.fromCharCode(' +
+ ', '.join(map(lambda c: hex(c), test_space_table)) + ');\n')
+ test_space.write("""
+assertEq(onlySpace.trim(), "");
+assertEq((onlySpace + 'aaaa').trim(), 'aaaa');
+assertEq(('aaaa' + onlySpace).trim(), 'aaaa');
+assertEq((onlySpace + 'aaaa' + onlySpace).trim(), 'aaaa');
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+""")
+
+def make_icase_test(version, folding_tests):
+ file_name = '../tests/ecma_6/RegExp/unicode-ignoreCase.js'
+ with io.open(file_name, mode='wb') as test_icase:
+ test_icase.write(warning_message)
+ test_icase.write(unicode_version_message.format(version))
+ 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);
+""")
+
+def make_unicode_file(version,
+ table, index,
+ same_upper_table, same_upper_index,
+ folding_table, folding_index):
+ index1, index2, shift = splitbins(index)
+
+ # Don't forget to update CharInfo in Unicode.h if you need to change this
+ assert shift == 6
+
+ same_upper_index1, same_upper_index2, same_upper_shift = splitbins(same_upper_index)
+
+ # Don't forget to update CodepointsWithSameUpperCaseInfo in Unicode.h if you need to change this
+ assert same_upper_shift == 6
+
+ folding_index1, folding_index2, folding_shift = splitbins(folding_index)
+
+ # Don't forget to update CaseFoldInfo in Unicode.h if you need to change this
+ assert folding_shift == 6
+
+ # verify correctness
+ for char in index:
+ test = table[index[char]]
+
+ idx = index1[char >> shift]
+ idx = index2[(idx << shift) + (char & ((1 << shift) - 1))]
+
+ assert test == table[idx]
+
+ # verify correctness
+ for char in same_upper_index:
+ test = same_upper_table[same_upper_index[char]]
+
+ idx = same_upper_index1[char >> same_upper_shift]
+ idx = same_upper_index2[(idx << same_upper_shift) + (char & ((1 << same_upper_shift) - 1))]
+
+ assert test == same_upper_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 = """
+/*
+ * So how does indexing work?
+ * First let's have a look at a char16_t, 16-bits:
+ * [................]
+ * Step 1:
+ * Extracting the upper 11 bits from the char16_t.
+ * upper = char >> 5 ([***********.....])
+ * Step 2:
+ * Using these bits to get an reduced index from index1.
+ * index = index1[upper]
+ * Step 3:
+ * Combining the index and the bottom 5 bits of the original char16_t.
+ * real_index = index2[(index << 5) + (char & ((1 << 5) - 1))] ([...********+++++])
+ *
+ * The advantage here is that the biggest number in index1 doesn't need 10 bits,
+ * but 7 and we save some memory.
+ *
+ * Step 4:
+ * Get the character informations by looking up real_index in js_charinfo.
+ *
+ * Pseudocode of generation:
+ *
+ * let table be the mapping of char16_t => js_charinfo_index
+ * let index1 be an empty array
+ * let index2 be an empty array
+ * let cache be a hash map
+ *
+ * while shift is less then maximal amount you can shift 0xffff before it's 0
+ * let chunks be table split in chunks of size 2**shift
+ *
+ * for every chunk in chunks
+ * if chunk is in cache
+ * let index be cache[chunk]
+ * else
+ * let index be the max key of index2 + 1
+ * for element in chunk
+ * push element to index2
+ * put index as chunk in cache
+ *
+ * push index >> shift to index1
+ *
+ * increase shift
+ * stop if you found the best shift
+ */
+"""
+ def dump(data, name, file):
+ file.write('const uint8_t unicode::' + name + '[] = {\n')
+
+ line = pad = ' ' * 4
+ lines = []
+ for entry in data:
+ assert entry < 256
+ s = str(entry)
+ s = s.rjust(3)
+
+ if len(line + s) + 5 > 99:
+ lines.append(line.rstrip())
+ line = pad + s + ', '
+ else:
+ line = line + s + ', '
+ lines.append(line.rstrip())
+
+ file.write('\n'.join(lines))
+ file.write('\n};\n')
+
+ file_name = 'Unicode.cpp'
+ with io.open(file_name, 'wb') as data_file:
+ data_file.write(warning_message)
+ data_file.write(unicode_version_message.format(version))
+ data_file.write(public_domain)
+ data_file.write('#include "vm/Unicode.h"\n\n')
+ data_file.write('using namespace js;\n')
+ data_file.write('using namespace js::unicode;\n')
+ data_file.write(comment)
+ data_file.write('const CharacterInfo unicode::js_charinfo[] = {\n')
+ for d in 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(index1, 'index1', data_file)
+ data_file.write('\n')
+ dump(index2, 'index2', data_file)
+ data_file.write('\n')
+
+ data_file.write('const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {\n')
+ for d in same_upper_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(same_upper_index1, 'codepoints_with_same_upper_index1', data_file)
+ data_file.write('\n')
+ dump(same_upper_index2, 'codepoints_with_same_upper_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')
+
+def getsize(data):
+ """ return smallest possible integer size for the given array """
+ maxdata = max(data)
+ assert maxdata < 2**32
+
+ if maxdata < 256:
+ return 1
+ elif maxdata < 65536:
+ return 2
+ else:
+ return 4
+
+def splitbins(t):
+ """t -> (t1, t2, shift). Split a table to save space.
+
+ t is a sequence of ints. This function can be useful to save space if
+ many of the ints are the same. t1 and t2 are lists of ints, and shift
+ is an int, chosen to minimize the combined size of t1 and t2 (in C
+ code), and where for each i in range(len(t)),
+ t[i] == t2[(t1[i >> shift] << shift) + (i & mask)]
+ where mask is a bitmask isolating the last "shift" bits.
+ """
+
+ def dump(t1, t2, shift, bytes):
+ print("%d+%d bins at shift %d; %d bytes" % (
+ len(t1), len(t2), shift, bytes), file=sys.stderr)
+ print("Size of original table:", len(t)*getsize(t), \
+ "bytes", file=sys.stderr)
+ n = len(t)-1 # last valid index
+ maxshift = 0 # the most we can shift n and still have something left
+ if n > 0:
+ while n >> 1:
+ n >>= 1
+ maxshift += 1
+ del n
+ bytes = sys.maxsize # smallest total size so far
+ t = tuple(t) # so slices can be dict keys
+ for shift in range(maxshift + 1):
+ t1 = []
+ t2 = []
+ size = 2**shift
+ bincache = {}
+
+ for i in range(0, len(t), size):
+ bin = t[i:i + size]
+
+ index = bincache.get(bin)
+ if index is None:
+ index = len(t2)
+ bincache[bin] = index
+ t2.extend(bin)
+ t1.append(index >> shift)
+
+ # determine memory size
+ b = len(t1) * getsize(t1) + len(t2) * getsize(t2)
+ if b < bytes:
+ best = t1, t2, shift
+ bytes = b
+ t1, t2, shift = best
+
+ print("Best:", end=' ', file=sys.stderr)
+ dump(t1, t2, shift, bytes)
+
+ # exhaustively verify that the decomposition is correct
+ mask = 2**shift - 1
+ for i in range(len(t)):
+ assert t[i] == t2[(t1[i >> shift] << shift) + (i & mask)]
+ return best
+
+def update_unicode(args):
+ import urllib2
+
+ version = args.version
+ if version is not None:
+ baseurl = 'http://unicode.org/Public'
+ if version == 'UNIDATA':
+ url = '%s/%s' % (baseurl, version)
+ else:
+ url = '%s/%s/ucd' % (baseurl, version)
+
+ print('Arguments:')
+ if version is not None:
+ print('\tVersion: %s' % version)
+ print('\tDownload url: %s' % url)
+ else:
+ print('\tUsing local files.')
+ print('\tAlways make sure you have the newest Unicode files!')
+ print('')
+
+ def download_or_open(fname):
+ tfile_path = os.path.join(os.getcwd(), fname)
+ if version is not None:
+ print('Downloading %s...' % fname)
+ unicode_data_url = '%s/%s' % (url, fname)
+ with closing(urllib2.urlopen(unicode_data_url)) as reader:
+ data = reader.read()
+ tfile = io.open(tfile_path, 'w+b')
+ tfile.write(data)
+ tfile.flush()
+ tfile.seek(0)
+ else:
+ if not os.path.isfile(tfile_path):
+ raise RuntimeError('File not found: %s' % tfile_path)
+ tfile = io.open(tfile_path, 'rb');
+ return tfile
+
+ def version_from_file(f, fname):
+ pat_version = re.compile(r"# %s-(?P<version>\d+\.\d+\.\d+).txt" % fname)
+ return pat_version.match(f.readline()).group("version")
+
+ with download_or_open('UnicodeData.txt') as unicode_data, \
+ download_or_open('CaseFolding.txt') as case_folding, \
+ download_or_open('DerivedCoreProperties.txt') as derived_core_properties:
+ unicode_version = version_from_file(derived_core_properties, 'DerivedCoreProperties')
+
+ print('Processing...')
+ (
+ table, index,
+ same_upper_table, same_upper_index,
+ non_bmp_lower_map, non_bmp_upper_map,
+ test_table, test_space_table
+ ) = process_unicode_data(unicode_data, derived_core_properties)
+ (
+ folding_table, folding_index,
+ non_bmp_folding_map, non_bmp_rev_folding_map,
+ folding_tests
+ ) = process_case_folding(case_folding)
+
+ print('Generating...')
+ make_unicode_file(unicode_version,
+ table, index,
+ same_upper_table, same_upper_index,
+ folding_table, folding_index)
+ make_non_bmp_file(unicode_version,
+ non_bmp_lower_map, non_bmp_upper_map,
+ non_bmp_folding_map, non_bmp_rev_folding_map)
+
+ make_bmp_mapping_test(unicode_version, test_table)
+ make_non_bmp_mapping_test(unicode_version, non_bmp_upper_map, non_bmp_lower_map)
+ make_space_test(unicode_version, test_space_table)
+ make_icase_test(unicode_version, folding_tests)
+
+if __name__ == '__main__':
+ import argparse
+
+ # This script must be run from js/src/vm to work correctly.
+ if '/'.join(os.path.normpath(os.getcwd()).split(os.sep)[-3:]) != 'js/src/vm':
+ raise RuntimeError('%s must be run from js/src/vm' % sys.argv[0])
+
+ parser = argparse.ArgumentParser(description='Update Unicode data.')
+
+ parser.add_argument('--version',
+ help='Optional Unicode version number. If specified, downloads the\
+ selected version from <http://unicode.org/Public>. If not specified\
+ uses the existing local files to generate the Unicode data. The\
+ number must match a published Unicode version, e.g. use\
+ "--version=8.0.0" to download Unicode 8 files. Alternatively use\
+ "--version=UNIDATA" to download the latest published version.')
+
+ parser.set_defaults(func=update_unicode)
+
+ args = parser.parse_args()
+ args.func(args)