From: Ryan Hyun Choi Date: Thu, 4 Nov 2021 02:25:21 +0000 (+0900) Subject: LWNode_Release_211104_926ca98 X-Git-Tag: submit/tizen/20211104.035646^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F05%2F266005%2F1;p=platform%2Fframework%2Fweb%2Flwnode.git LWNode_Release_211104_926ca98 Change-Id: I1809355761778188f1141c15e3be139d30adef4d Signed-off-by: Ryan Choi --- diff --git a/README.md b/README.md index 6331ee0..ea36b20 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,16 @@ git submodule update --init --recursive sudo apt-get install -y build-essential cmake clang libicu-dev ``` -### Compile -1. Generate build config files and build node.js +### How to build and run ``` ./lwnode/build.sh -./lwnode/build-cctest.sh +./out/linux/Release/lwnode ./test/message/hello_world.js ``` -### How to run +### How to run testcases ``` -./node ./test/message/hello_world.js +./lwnode/build-cctest.sh +./cctest ``` ## How to Compile: Tizen @@ -47,5 +47,8 @@ Build Options * --define 'build_profile `none|tv|kiosk|soundbar`': default is `none` * --define 'build_mode `release|debug`': default is `release` +### Installing lwnode executable +Install `lwnode-devel.rpm` to get the `lwnode` executable. + ## Maintainers A list of maintainers can be found in [MAINTAINERS.md](MAINTAINERS.md). diff --git a/common.gypi b/common.gypi index 2ef53fd..a9496c7 100644 --- a/common.gypi +++ b/common.gypi @@ -388,6 +388,15 @@ }], ], 'conditions': [ + [ 'lwnode=="true"', { + 'cflags': [ + '-fdata-sections', # for gc-sections + '-ffunction-sections', # for gc-sections + ], + 'ldflags': [ + '-Wl,--gc-sections', + ], + }], [ 'target_arch=="ia32"', { 'cflags': [ '-m32' ], 'ldflags': [ '-m32' ], diff --git a/configure.py b/configure.py index 20a451d..074fdec 100755 --- a/configure.py +++ b/configure.py @@ -92,12 +92,18 @@ lwnode_optgroup.add_option('--profile', default='common', help='Build profile: common | tv | kiosk') -lwnode_optgroup.add_option('--enable-external-builtin-scripts', +lwnode_optgroup.add_option('--enable-external-builtin-script', action='store_true', - dest='enable_external_builtin_scripts', + dest='enable_external_builtin_script', default=False, help='Store builtin scripts outside of executable') +lwnode_optgroup.add_option('--enable-reload-script', + action='store_true', + dest='enable_reload_script', + default=False, + help='Reload scripts on demand') + lwnode_optgroup.add_option('--static-escargot', action='store_true', dest='static_escargot', @@ -124,10 +130,15 @@ def get_lwnode_gyp_options(): lwnode_jsengine_path = 'lwnode/code/escargotshim' args += ['-Dlwnode_jsengine_path='+ lwnode_jsengine_path] - if options.enable_external_builtin_scripts: - args += ['-Denable_external_builtin_scripts=true'] + if options.enable_external_builtin_script: + args += ['-Denable_external_builtin_script=true'] + else: + args += ['-Denable_external_builtin_script=false'] + + if options.enable_reload_script: + args += ['-Denable_reload_script=true'] else: - args += ['-Denable_external_builtin_scripts=false'] + args += ['-Denable_reload_script=false'] else: args += ['-Dlwnode='+ 'false'] diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 223c6b2..d47a330 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1087,7 +1087,19 @@ Module._extensions['.js'] = function(module, filename) { content = cached.source; cached.source = undefined; } else { - content = fs.readFileSync(filename, 'utf8'); + // @lwnode + let reloadableContent; + + if (process.lwnode && process.lwnode.isReloadScriptEnabled()) { + reloadableContent = + process.lwnode.CreateReloadableSourceFromFile(filename); + } + + if (reloadableContent) { + content = reloadableContent; + } else { + content = fs.readFileSync(filename, "utf8"); + } } module._compile(content, filename); }; diff --git a/lib/internal/process/per_thread.js b/lib/internal/process/per_thread.js index c4f1e2c..4fa7167 100644 --- a/lib/internal/process/per_thread.js +++ b/lib/internal/process/per_thread.js @@ -262,6 +262,14 @@ function wrapProcessMethods(binding) { return binding.MemSnapshot.apply(null, args); } }, + isReloadScriptEnabled: () => { + return !!(binding.CreateReloadableSourceFromFile); + }, + CreateReloadableSourceFromFile: (...args) => { + if (binding.CreateReloadableSourceFromFile) { + return binding.CreateReloadableSourceFromFile.apply(null, args); + } + }, }; return { diff --git a/lwnode/build.sh b/lwnode/build.sh index 5b6686d..a248671 100755 --- a/lwnode/build.sh +++ b/lwnode/build.sh @@ -18,7 +18,7 @@ set -e CONFIG="--without-npm --without-bundled-v8 \ --without-inspector --without-node-code-cache --without-node-snapshot \ - --with-intl none --shared-openssl --shared-zlib \ + --with-intl none --shared-zlib \ --dest-os linux --dest-cpu x64 \ --engine escargot --escargot-threading \ --ninja" @@ -26,8 +26,8 @@ CONFIG="--without-npm --without-bundled-v8 \ if [[ $1 =~ ^"-d" ]]; then ! [[ $1 =~ .*"b" ]] && ./configure $CONFIG --debug --debug-node ninja -v -C out/linux/Debug lwnode |& lwnode/tools/colorize.sh - else ./configure $CONFIG ninja -v -C out/linux/Release lwnode |& lwnode/tools/colorize.sh fi + diff --git a/lwnode/code/escargotshim/common.gypi b/lwnode/code/escargotshim/common.gypi index 5f64ff6..f7e074e 100755 --- a/lwnode/code/escargotshim/common.gypi +++ b/lwnode/code/escargotshim/common.gypi @@ -16,6 +16,11 @@ '-Wno-unused-but-set-variable', '-fPIC', '-ggdb', # all builds include debug symbols, which will be stripped before packaging + '-fdata-sections', # for gc-sections + '-ffunction-sections', # for gc-sections + ], + 'ldflags': [ + '-Wl,--gc-sections', ], 'link_settings': { 'libraries': [ '-ldl', '-lrt' ], diff --git a/lwnode/code/escargotshim/deps/escargot/Jenkinsfile b/lwnode/code/escargotshim/deps/escargot/Jenkinsfile index 1256dc4..4f4f1f2 100644 --- a/lwnode/code/escargotshim/deps/escargot/Jenkinsfile +++ b/lwnode/code/escargotshim/deps/escargot/Jenkinsfile @@ -35,10 +35,6 @@ def isPr() { } } - stage('Check tidy') { - sh 'python tools/check_tidy.py' - } - stage('Submodule update') { sh 'git submodule update --init test third_party/GCutil' } diff --git a/lwnode/code/escargotshim/deps/escargot/docs/Debugger.md b/lwnode/code/escargotshim/deps/escargot/docs/Debugger.md new file mode 100644 index 0000000..a22bfef --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/docs/Debugger.md @@ -0,0 +1,64 @@ +# Internal operation of the Debugger + +The debugger uses a client server model where the server is the Escargot engine. +The connection between the client and server must be bi-directional and reliable. + +The debugger protocol uses packets, although the connection layer can split +these packets into smaller ones if needed. The maximum packet length is defined by +the connection layer. For example, it is 125 for the websockets layer. When a +message is longer than the maximum packet size, it is split into a sequence of +packets. The type of the last packet has an `_END` prefix. The following +example shows the transmission of strings: + +Characters of a string can be 8 or 16 bit long. When a string is transmitted, +it is split into a sequence of packets, and the type of these packets is either +`ESCARGOT_MESSAGE_STRING_8BIT` or `ESCARGOT_MESSAGE_STRING_16BIT`, except +the last one which type is either `ESCARGOT_MESSAGE_STRING_8BIT_END` +or `ESCARGOT_MESSAGE_STRING_16BIT_END`. If a string fits into a single packet, +only the type ending with `_END` is used. + +## Debugger modes + +The message types which can be transmitted depends on the current mode. These are +the current modes: + +* Free running mode: Escargot executes ECMAScript code. The engine may stop at +a breakpoint and notify the client. The client can also request an execution stop. + +* Parsing mode: when Escargot parses an ECMAScript code, it produces several +messages which follows the parsing process. For example, Escargot notifies the +client when it starts parsing a new nested function, or the breakpoint list is +available for a function. This reduces the memory consumption, since the data +is collected until the parsing ends. The debugger client sets up its internal +data about the structure of the ECMAScript code based on these messages. + +* Breakpoint mode: when Escargot stops at a breakpoint, the client can request +information about the execution status such as backtrace or lexical environment. +The objects and their properties can be enumerated as well. Escargot maintains +a reference to all objects which properties are enumerated until the execution +resumes. Therefore the properties of temporary objects (e.g. the result of a +getter) can be inspected later. These temporary objects may increase the memory +consumption. + +* Source sending mode: the client can send multiple source files to Escargot +in this mode, and the engine executes them. Escargot enters this mode when +the user instructs it or it has no code to execute. + +## Evaluating code + +In breakpoint mode, the client can evaluate ECMAScript code. After the evaluation +is completed, the client receives the string represenation of the result, if the +evaluation is successful, or the string representation of the exception otherwise. +These evaluations can have side effects, e.g. variables or properties can be created, +changed, or deleted. The engine does not maintain a separate environment for +executing code, the side effects remain after the execution resumes. Furthermore +the engine ignores all breakpoints during the evaluation, so infinite loops +will never stop. + +## Breakpoints + +The Escargot debugger emits disabled breakpoint instructions into the byte code +stream. The debugger client receives the offset of these instructions with their +corresponding line info. Using these offsets the client can request the server +to enable or disable breakpoints by changing the opcode to enabled or disabled +state. Escargot always stops when an enabled breakpoint is executed. diff --git a/lwnode/code/escargotshim/deps/escargot/src/Escargot.h b/lwnode/code/escargotshim/deps/escargot/src/Escargot.h index 77974ef..657b182 100755 --- a/lwnode/code/escargotshim/deps/escargot/src/Escargot.h +++ b/lwnode/code/escargotshim/deps/escargot/src/Escargot.h @@ -260,6 +260,10 @@ typedef unsigned char LChar; #include // for Intl #include // for Intl #include // for Intl +#include // for Intl +#include // for Intl +#include // for Intl +#include // for Intl // FIXME replace these vzone decl into include // I declare vzone api because there is no header file in include folder diff --git a/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp b/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp index 7e3c1c2..1bb2310 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp @@ -370,19 +370,69 @@ size_t Memory::totalSize() return GC_get_total_bytes(); } -static Memory::OnGCEventListener g_gcEventListener; -static void gcEventListener(GC_EventType evtType, void*) -{ - if (GC_EVENT_RECLAIM_END == evtType && g_gcEventListener) { - g_gcEventListener(); +void Memory::addGCEventListener(GCEventType type, OnGCEventListener l, void* data) +{ + GCEventListenerSet& list = ThreadLocal::gcEventListenerSet(); + GCEventListenerSet::EventListenerVector* listeners = nullptr; + + switch (type) { + case MARK_START: + listeners = list.ensureMarkStartListeners(); + break; + case MARK_END: + listeners = list.ensureMarkEndListeners(); + break; + case RECLAIM_START: + listeners = list.ensureReclaimStartListeners(); + break; + case RECLAIM_END: + listeners = list.ensureReclaimEndListeners(); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + +#ifndef NDEBUG + auto iter = std::find(listeners->begin(), listeners->end(), std::make_pair(l, data)); + ASSERT(iter == listeners->end()); +#endif + + listeners->push_back(std::make_pair(l, data)); +} + +bool Memory::removeGCEventListener(GCEventType type, OnGCEventListener l, void* data) +{ + GCEventListenerSet& list = ThreadLocal::gcEventListenerSet(); + Optional listeners; + + switch (type) { + case MARK_START: + listeners = list.markStartListeners(); + break; + case MARK_END: + listeners = list.markEndListeners(); + break; + case RECLAIM_START: + listeners = list.reclaimStartListeners(); + break; + case RECLAIM_END: + listeners = list.reclaimEndListeners(); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + if (listeners) { + auto iter = std::find(listeners->begin(), listeners->end(), std::make_pair(l, data)); + if (iter != listeners->end()) { + listeners->erase(iter); + return true; + } } -} -void Memory::setGCEventListener(OnGCEventListener l) -{ - g_gcEventListener = l; - GC_remove_event_callback(gcEventListener, nullptr); - GC_add_event_callback(gcEventListener, nullptr); + return false; } // I store ref count as EncodedValue. this can prevent what bdwgc can see ref count as address (EncodedValue store integer value as odd) @@ -1019,17 +1069,31 @@ void VMInstanceRef::setOnVMInstanceDelete(OnVMInstanceDelete cb) { toImpl(this)->setOnDestroyCallback([](VMInstance* instance, void* data) { if (data) { - ((OnVMInstanceDelete)data)(toRef(instance)); + (reinterpret_cast(data))(toRef(instance)); } }, (void*)cb); } +void VMInstanceRef::registerErrorCreationCallback(ErrorCreationCallback cb) +{ + toImpl(this)->registerErrorCreationCallback([](ExecutionState& state, ErrorObject* err, void* cb) -> void { + ASSERT(!!cb); + (reinterpret_cast(cb))(toRef(&state), toRef(err)); + }, + (void*)cb); +} + +void VMInstanceRef::unregisterErrorCreationCallback() +{ + toImpl(this)->unregisterErrorCreationCallback(); +} + void VMInstanceRef::registerPromiseHook(PromiseHook promiseHook) { toImpl(this)->registerPromiseHook([](ExecutionState& state, VMInstance::PromiseHookType type, PromiseObject* promise, const Value& parent, void* hook) -> void { ASSERT(!!hook); - ((PromiseHook)hook)(toRef(&state), (PromiseHookType)type, toRef(promise), toRef(parent)); + (reinterpret_cast(hook))(toRef(&state), (PromiseHookType)type, toRef(promise), toRef(parent)); }, (void*)promiseHook); } @@ -2047,6 +2111,22 @@ FunctionObjectRef* FunctionObjectRef::createBuiltinFunction(ExecutionStateRef* s return createFunction(state, info, true); } +FunctionObjectRef* FunctionObjectRef::create(ExecutionStateRef* stateRef, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body) +{ + ExecutionState& state = *toImpl(stateRef); + Value* newArgv = ALLOCA(sizeof(Value) * argumentCount, Value, state); + for (size_t i = 0; i < argumentCount; i++) { + newArgv[i] = toImpl(argumentNameArray[i]); + } + + auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, toImpl(functionName), argumentCount, newArgv, toImpl(body), false, false, false, false); + + Object* proto = state.context()->globalObject()->functionPrototype(); + ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false, false); + + return toRef(result); +} + ValueRef* FunctionObjectRef::getFunctionPrototype(ExecutionStateRef* state) { FunctionObject* o = toImpl(this); @@ -2238,6 +2318,21 @@ GlobalObjectRef* ExecutionStateRef::resolveCallerLexicalGlobalObject() return toRef(ctx->globalObject()); } +bool ExecutionStateRef::onTry() +{ + return toImpl(this)->onTry(); +} + +bool ExecutionStateRef::onCatch() +{ + return toImpl(this)->onCatch(); +} + +bool ExecutionStateRef::onFinally() +{ + return toImpl(this)->onFinally(); +} + void ExecutionStateRef::throwException(ValueRef* value) { ExecutionState* imp = toImpl(this); @@ -2635,14 +2730,39 @@ bool ValueRef::instanceOf(ExecutionStateRef* state, const ValueRef* other) const return toImpl(this).instanceOf(*toImpl(state), toImpl(other)); } -IteratorObjectRef* IteratorObjectRef::create(ExecutionStateRef* state) +ValueRef* IteratorObjectRef::next(ExecutionStateRef* state) { - return toRef(new IteratorObject(*toImpl(state))); + return toRef(toImpl(this)->next(*toImpl(state))); } -ValueRef* IteratorObjectRef::next(ExecutionStateRef* state) +class GenericIteratorObject : public IteratorObject { +public: + GenericIteratorObject(ExecutionState& state, GenericIteratorObjectRef::GenericIteratorObjectRefCallback callback, void* callbackData) + : IteratorObject(state, state.context()->globalObject()->genericIteratorPrototype()) + , m_callback(callback) + , m_callbackData(callbackData) + { + } + + virtual bool isGenericIteratorObject() const override + { + return true; + } + + virtual std::pair advance(ExecutionState& state) override + { + auto ret = m_callback(toRef(&state), m_callbackData); + return std::make_pair(toImpl(ret.first), ret.second); + } + +private: + GenericIteratorObjectRef::GenericIteratorObjectRefCallback m_callback; + void* m_callbackData; +}; + +GenericIteratorObjectRef* GenericIteratorObjectRef::create(ExecutionStateRef* state, GenericIteratorObjectRefCallback callback, void* callbackData) { - return toRef(toImpl(this)->next(*toImpl(state))); + return toRef(new GenericIteratorObject(*toImpl(state), callback, callbackData)); } ArrayObjectRef* ArrayObjectRef::create(ExecutionStateRef* state) @@ -2853,16 +2973,37 @@ RegExpObjectRef::RegExpObjectOption RegExpObjectRef::option() return (RegExpObjectRef::RegExpObjectOption)toImpl(this)->option(); } -BackingStoreRef* BackingStoreRef::create(size_t byteLength) +BackingStoreRef* BackingStoreRef::createDefaultNonSharedBackingStore(size_t byteLength) { - return toRef(new BackingStore(byteLength)); + return toRef(BackingStore::createDefaultNonSharedBackingStore(byteLength)); } -BackingStoreRef* BackingStoreRef::create(void* data, size_t byteLength, BackingStoreRef::BackingStoreRefDeleterCallback callback, void* callbackData) +BackingStoreRef* BackingStoreRef::createNonSharedBackingStore(void* data, size_t byteLength, BackingStoreRef::BackingStoreRefDeleterCallback callback, void* callbackData) { - return toRef(new BackingStore(data, byteLength, (BackingStoreDeleterCallback)callback, callbackData)); + return toRef(BackingStore::createNonSharedBackingStore(data, byteLength, (BackingStoreDeleterCallback)callback, callbackData)); } +#if defined(ENABLE_THREADING) +BackingStoreRef* BackingStoreRef::createDefaultSharedBackingStore(size_t byteLength) +{ + return toRef(BackingStore::createDefaultSharedBackingStore(byteLength)); +} + +BackingStoreRef* BackingStoreRef::createSharedBackingStore(BackingStoreRef* backingStore) +{ + return toRef(BackingStore::createSharedBackingStore(toImpl(backingStore)->sharedDataBlockInfo())); +} +#else +BackingStoreRef* BackingStoreRef::createDefaultSharedBackingStore(size_t byteLength) +{ + RELEASE_ASSERT_NOT_REACHED(); +} +BackingStoreRef* BackingStoreRef::createSharedBackingStore(BackingStoreRef* backingStore) +{ + RELEASE_ASSERT_NOT_REACHED(); +} +#endif + void* BackingStoreRef::data() { return toImpl(this)->data(); @@ -2931,11 +3072,21 @@ SharedArrayBufferObjectRef* SharedArrayBufferObjectRef::create(ExecutionStateRef { return toRef(new SharedArrayBufferObject(*toImpl(state), toImpl(state)->context()->globalObject()->sharedArrayBufferPrototype(), byteLength)); } + +SharedArrayBufferObjectRef* SharedArrayBufferObjectRef::create(ExecutionStateRef* state, BackingStoreRef* backingStore) +{ + return toRef(new SharedArrayBufferObject(*toImpl(state), toImpl(state)->context()->globalObject()->sharedArrayBufferPrototype(), toImpl(backingStore))); +} #else SharedArrayBufferObjectRef* SharedArrayBufferObjectRef::create(ExecutionStateRef* state, size_t byteLength) { RELEASE_ASSERT_NOT_REACHED(); } + +SharedArrayBufferObjectRef* SharedArrayBufferObjectRef::create(ExecutionStateRef* state, BackingStoreRef* backingStore) +{ + RELEASE_ASSERT_NOT_REACHED(); +} #endif ArrayBufferRef* ArrayBufferViewRef::buffer() diff --git a/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.h b/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.h index 2014b38..c0d35a8 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.h +++ b/lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.h @@ -57,6 +57,7 @@ F(ErrorObject) \ F(FinalizationRegistryObject) \ F(FunctionObject) \ + F(GenericIteratorObject) \ F(GlobalObject) \ F(GlobalObjectProxyObject) \ F(IteratorObject) \ @@ -170,8 +171,17 @@ public: static size_t heapSize(); // Return the number of bytes in the heap. Excludes bdwgc private data structures. Excludes the unmapped memory static size_t totalSize(); // Return the total number of bytes allocated in this process - typedef void (*OnGCEventListener)(); - static void setGCEventListener(OnGCEventListener l); + enum GCEventType { + MARK_START, + MARK_END, + RECLAIM_START, + RECLAIM_END, + }; + // pointer `data` is not a GC object + typedef void (*OnGCEventListener)(void* data); + static void addGCEventListener(GCEventType type, OnGCEventListener l, void* data); + static bool removeGCEventListener(GCEventType type, OnGCEventListener l, void* data); + // NOTE bdwgc(c/c++ gc library escargot use) allocate at least N/GC_free_space_divisor bytes between collections // (Allocated memory by GC x 2) / (Frequency parameter value) // Increasing this value may use less space but there is more collection event @@ -603,6 +613,10 @@ public: GCManagedVector resolveCallstack(); // resolve list of callee GlobalObjectRef* resolveCallerLexicalGlobalObject(); // resolve caller's lexical global object + bool onTry(); + bool onCatch(); + bool onFinally(); + void throwException(ValueRef* value); GCManagedVector computeStackTraceData(); @@ -621,6 +635,12 @@ public: typedef void (*OnVMInstanceDelete)(VMInstanceRef* instance); void setOnVMInstanceDelete(OnVMInstanceDelete cb); + // register ErrorCreationCallback which is triggered when each Error constructor (e.g. new TypeError()) invoked + // parameter `err` is newly created ErrorObject + typedef void (*ErrorCreationCallback)(ExecutionStateRef* state, ErrorObjectRef* err); + void registerErrorCreationCallback(ErrorCreationCallback cb); + void unregisterErrorCreationCallback(); + enum PromiseHookType { Init, Resolve, @@ -834,26 +854,26 @@ public: { return createFromASCII(str, N - 1); } - static StringRef* createFromASCII(const char* s, size_t len); + static StringRef* createFromASCII(const char* s, size_t stringLength); template static StringRef* createFromUTF8(const char (&str)[N]) { return createFromUTF8(str, N - 1); } - static StringRef* createFromUTF8(const char* s, size_t len, bool maybeASCII = true); - static StringRef* createFromUTF16(const char16_t* s, size_t len); - static StringRef* createFromLatin1(const unsigned char* s, size_t len); + static StringRef* createFromUTF8(const char* s, size_t byteLength, bool maybeASCII = true); + static StringRef* createFromUTF16(const char16_t* s, size_t stringLength); + static StringRef* createFromLatin1(const unsigned char* s, size_t stringLength); - static StringRef* createExternalFromASCII(const char* s, size_t len); - static StringRef* createExternalFromLatin1(const unsigned char* s, size_t len); - static StringRef* createExternalFromUTF16(const char16_t* s, size_t len); + static StringRef* createExternalFromASCII(const char* s, size_t stringLength); + static StringRef* createExternalFromLatin1(const unsigned char* s, size_t stringLength); + static StringRef* createExternalFromUTF16(const char16_t* s, size_t stringLength); // you can use these functions only if you enabled string compression static bool isCompressibleStringEnabled(); - static StringRef* createFromUTF8ToCompressibleString(VMInstanceRef* instance, const char* s, size_t len, bool maybeASCII = true); - static StringRef* createFromUTF16ToCompressibleString(VMInstanceRef* instance, const char16_t* s, size_t len); - static StringRef* createFromASCIIToCompressibleString(VMInstanceRef* instance, const char* s, size_t len); - static StringRef* createFromLatin1ToCompressibleString(VMInstanceRef* instance, const unsigned char* s, size_t len); + static StringRef* createFromUTF8ToCompressibleString(VMInstanceRef* instance, const char* s, size_t byteLength, bool maybeASCII = true); + static StringRef* createFromUTF16ToCompressibleString(VMInstanceRef* instance, const char16_t* s, size_t stringLength); + static StringRef* createFromASCIIToCompressibleString(VMInstanceRef* instance, const char* s, size_t stringLength); + static StringRef* createFromLatin1ToCompressibleString(VMInstanceRef* instance, const unsigned char* s, size_t stringLength); static void* allocateStringDataBufferForCompressibleString(size_t byteLength); static void deallocateStringDataBufferForCompressibleString(void* ptr, size_t byteLength); static StringRef* createFromAlreadyAllocatedBufferToCompressibleString(VMInstanceRef* instance, void* buffer, size_t stringLen, bool is8Bit /* is ASCII or Latin1 */); @@ -861,7 +881,7 @@ public: // you can use these functions only if you enabled reloadable string static bool isReloadableStringEnabled(); static StringRef* createReloadableString(VMInstanceRef* instance, - bool is8BitString, size_t len, void* callbackData, + bool is8BitString, size_t stringLength, void* callbackData, void* (*loadCallback)(void* callbackData), // you should returns string buffer void (*unloadCallback)(void* memoryPtr, void* callbackData)); // you should free memoryPtr @@ -879,7 +899,7 @@ public: RopeStringRef* asRopeString(); bool equals(StringRef* src); - bool equalsWithASCIIString(const char* buf, size_t len); + bool equalsWithASCIIString(const char* buf, size_t stringLength); StringRef* substring(size_t from, size_t to); @@ -1313,6 +1333,7 @@ public: static FunctionObjectRef* create(ExecutionStateRef* state, NativeFunctionInfo info); static FunctionObjectRef* createBuiltinFunction(ExecutionStateRef* state, NativeFunctionInfo info); // protoype of builtin function is non-writable + static FunctionObjectRef* create(ExecutionStateRef* state, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body); // get prototype property of constructible function(not [[prototype]]) // this property is used for new object construction. see https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarycreatefromconstructor @@ -1328,10 +1349,17 @@ public: class ESCARGOT_EXPORT IteratorObjectRef : public ObjectRef { public: - static IteratorObjectRef* create(ExecutionStateRef* state); ValueRef* next(ExecutionStateRef* state); }; +class ESCARGOT_EXPORT GenericIteratorObjectRef : public IteratorObjectRef { +public: + // returns result and done pair + typedef std::pair (*GenericIteratorObjectRefCallback)(ExecutionStateRef* state, void* data); + + static GenericIteratorObjectRef* create(ExecutionStateRef* state, GenericIteratorObjectRefCallback callback, void* callbackData); +}; + class ESCARGOT_EXPORT ArrayObjectRef : public ObjectRef { public: static ArrayObjectRef* create(ExecutionStateRef* state); @@ -1351,7 +1379,8 @@ public: SyntaxError, RangeError, URIError, - EvalError + EvalError, + AggregateError, }; static ErrorObjectRef* create(ExecutionStateRef* state, ErrorObjectRef::Code code, StringRef* errorMessage); }; @@ -1474,14 +1503,24 @@ class ESCARGOT_EXPORT BackingStoreRef { friend class ArrayBufferObject; public: - static BackingStoreRef* create(size_t byteLength); typedef void (*BackingStoreRefDeleterCallback)(void* data, size_t length, void* deleterData); - static BackingStoreRef* create(void* data, size_t byteLength, BackingStoreRefDeleterCallback callback, void* callbackData); + + // create default NonSharedBackingStore allocated by platform allocator + static BackingStoreRef* createDefaultNonSharedBackingStore(size_t byteLength); + // create customized NonSharedBackingStore allocated by other allocator + static BackingStoreRef* createNonSharedBackingStore(void* data, size_t byteLength, BackingStoreRefDeleterCallback callback, void* callbackData); + + // Note) SharedBackingStore is allocated for each worker(thread) and its internal data block is actually shared among workers. + // Also, SharedBackingStore's internal data block is allocated only by platform allocator now. + // create default SharedBackingStore allocated by platform allocator + static BackingStoreRef* createDefaultSharedBackingStore(size_t byteLength); + // create SharedBackingStore by sharing with already created one + static BackingStoreRef* createSharedBackingStore(BackingStoreRef* backingStore); void* data(); size_t byteLength(); - // Indicates whether the backing store is Shared Data Block (for SharedArrayBuffer) + // Indicates whether the backing store is SharedDataBlock(for SharedArrayBuffer) bool isShared(); void reallocate(size_t newByteLength); }; @@ -1505,6 +1544,7 @@ public: class ESCARGOT_EXPORT SharedArrayBufferObjectRef : public ArrayBufferRef { public: static SharedArrayBufferObjectRef* create(ExecutionStateRef* state, size_t bytelength); + static SharedArrayBufferObjectRef* create(ExecutionStateRef* state, BackingStoreRef* backingStore); }; class ESCARGOT_EXPORT ArrayBufferViewRef : public ObjectRef { diff --git a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAtomics.cpp b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAtomics.cpp index 4018e7e..9845f1a 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAtomics.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAtomics.cpp @@ -603,7 +603,7 @@ static Value builtinAtomicsIsLockFree(ExecutionState& state, Value thisValue, si return Value(false); #else // spec want to do toInteger operation - size; + UNUSED_VARIABLE(size); return Value(false); #endif } diff --git a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinError.cpp b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinError.cpp index 3558c7c..3745b8e 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinError.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinError.cpp @@ -20,6 +20,7 @@ #include "Escargot.h" #include "runtime/GlobalObject.h" #include "runtime/Context.h" +#include "runtime/VMInstance.h" #include "runtime/ErrorObject.h" #include "runtime/NativeFunctionObject.h" #include "runtime/ToStringRecursionPreventer.h" @@ -61,6 +62,11 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz Value options = argc > 1 ? argv[1] : Value(); installErrorCause(state, obj, options); + + if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) { + state.context()->vmInstance()->triggerErrorCreationCallback(state, obj); + } + return obj; } @@ -81,6 +87,9 @@ static Value builtinErrorConstructor(ExecutionState& state, Value thisValue, siz } \ Value options = argc > 1 ? argv[1] : Value(); \ installErrorCause(state, obj, options); \ + if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) { \ + state.context()->vmInstance()->triggerErrorCreationCallback(state, obj); \ + } \ return obj; \ } @@ -121,6 +130,11 @@ static Value builtinAggregateErrorConstructor(ExecutionState& state, Value thisV // Perform ! DefinePropertyOrThrow(O, "errors", PropertyDescriptor { [[Configurable]]: true, [[Enumerable]]: false, [[Writable]]: true, [[Value]]: ! CreateArrayFromList(errorsList) }). O->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, String::fromASCII("errors")), ObjectPropertyDescriptor(Value(Object::createArrayFromList(state, errorsList.size(), errorsList.data())), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectStructurePropertyDescriptor::ConfigurablePresent))); + + if (UNLIKELY(state.context()->vmInstance()->isErrorCreationCallbackRegistered())) { + state.context()->vmInstance()->triggerErrorCreationCallback(state, O); + } + // Return O. return O; } diff --git a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinIntl.cpp b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinIntl.cpp index e114ca7..38b7fe9 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinIntl.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinIntl.cpp @@ -58,6 +58,8 @@ #include "intl/IntlPluralRules.h" #include "intl/IntlLocale.h" #include "intl/IntlRelativeTimeFormat.h" +#include "intl/IntlDisplayNames.h" +#include "intl/IntlListFormat.h" namespace Escargot { @@ -246,10 +248,8 @@ static Value builtinIntlDateTimeFormatFormatToParts(ExecutionState& state, Value return dtf->formatToParts(state, x); } -static void setFormatOpt(ExecutionState& state, Object* internalSlot, Object* result, const char* pName) +static void setFormatOpt(ExecutionState& state, Object* internalSlot, Object* result, String* prop) { - String* prop = String::fromASCII(pName); - ObjectGetResult r; r = internalSlot->get(state, ObjectPropertyName(state, prop)); @@ -391,23 +391,23 @@ static Value builtinIntlNumberFormatResolvedOptions(ExecutionState& state, Value Object* internalSlot = thisValue.asObject()->internalSlot(); Object* result = new Object(state); - setFormatOpt(state, internalSlot, result, "locale"); - setFormatOpt(state, internalSlot, result, "numberingSystem"); - setFormatOpt(state, internalSlot, result, "style"); - setFormatOpt(state, internalSlot, result, "currency"); - setFormatOpt(state, internalSlot, result, "currencyDisplay"); - setFormatOpt(state, internalSlot, result, "currencySign"); - setFormatOpt(state, internalSlot, result, "unit"); - setFormatOpt(state, internalSlot, result, "unitDisplay"); - setFormatOpt(state, internalSlot, result, "minimumIntegerDigits"); - setFormatOpt(state, internalSlot, result, "minimumFractionDigits"); - setFormatOpt(state, internalSlot, result, "maximumFractionDigits"); - setFormatOpt(state, internalSlot, result, "minimumSignificantDigits"); - setFormatOpt(state, internalSlot, result, "maximumSignificantDigits"); - setFormatOpt(state, internalSlot, result, "useGrouping"); - setFormatOpt(state, internalSlot, result, "notation"); - setFormatOpt(state, internalSlot, result, "compactDisplay"); - setFormatOpt(state, internalSlot, result, "signDisplay"); + setFormatOpt(state, internalSlot, result, String::fromASCII("locale")); + setFormatOpt(state, internalSlot, result, String::fromASCII("numberingSystem")); + setFormatOpt(state, internalSlot, result, String::fromASCII("style")); + setFormatOpt(state, internalSlot, result, String::fromASCII("currency")); + setFormatOpt(state, internalSlot, result, String::fromASCII("currencyDisplay")); + setFormatOpt(state, internalSlot, result, String::fromASCII("currencySign")); + setFormatOpt(state, internalSlot, result, String::fromASCII("unit")); + setFormatOpt(state, internalSlot, result, String::fromASCII("unitDisplay")); + setFormatOpt(state, internalSlot, result, String::fromASCII("minimumIntegerDigits")); + setFormatOpt(state, internalSlot, result, String::fromASCII("minimumFractionDigits")); + setFormatOpt(state, internalSlot, result, String::fromASCII("maximumFractionDigits")); + setFormatOpt(state, internalSlot, result, String::fromASCII("minimumSignificantDigits")); + setFormatOpt(state, internalSlot, result, String::fromASCII("maximumSignificantDigits")); + setFormatOpt(state, internalSlot, result, String::fromASCII("useGrouping")); + setFormatOpt(state, internalSlot, result, String::fromASCII("notation")); + setFormatOpt(state, internalSlot, result, String::fromASCII("compactDisplay")); + setFormatOpt(state, internalSlot, result, String::fromASCII("signDisplay")); return result; } @@ -840,6 +840,62 @@ static Value builtinIntlLocaleMinimize(ExecutionState& state, Value thisValue, s return new IntlLocaleObject(state, sb.finalize(), nullptr); } +static Value builtinIntlLocaleCalendarsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->calendars(state); +} + +static Value builtinIntlLocaleCollationsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->collations(state); +} + +static Value builtinIntlLocaleHourCyclesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->hourCycles(state); +} + +static Value builtinIntlLocaleNumberingSystemsGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->numberingSystems(state); +} + +static Value builtinIntlLocaleTextInfoGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->textInfo(state); +} + +static Value builtinIntlLocaleWeekInfoGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->weekInfo(state); +} + +static Value builtinIntlLocaleTimeZonesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlLocaleObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + return thisValue.asObject()->asIntlLocaleObject()->timeZones(state); +} + static Value builtinIntlRelativeTimeFormatConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) { // If NewTarget is undefined, throw a TypeError exception. @@ -931,6 +987,117 @@ static Value builtinIntlRelativeTimeFormatFormatToParts(ExecutionState& state, V return thisValue.asObject()->asIntlRelativeTimeFormatObject()->formatToParts(state, value, unit); } +static Value builtinIntlDisplayNamesConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + // https://402.ecma-international.org/8.0/#sec-Intl.DisplayNames + // If NewTarget is undefined, throw a TypeError exception. + if (!newTarget) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew); + } + + Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* realm) -> Object* { + return realm->globalObject()->intlDisplayNamesPrototype(); + }); + return new IntlDisplayNamesObject(state, proto, argv[0], argv[1]); +} + +static Value builtinIntlDisplayNamesOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlDisplayNamesObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + + IntlDisplayNamesObject* r = thisValue.asObject()->asIntlDisplayNamesObject(); + return r->of(state, argv[0]); +} + +static Value builtinIntlDisplayNamesResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlDisplayNamesObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + + IntlDisplayNamesObject* r = thisValue.asObject()->asIntlDisplayNamesObject(); + + Object* options = new Object(state); + + auto& staticStrings = state.context()->staticStrings(); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazySmallLetterLocale()), ObjectPropertyDescriptor(r->locale(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyStyle()), ObjectPropertyDescriptor(r->style(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyType()), ObjectPropertyDescriptor(r->type(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyFallback()), ObjectPropertyDescriptor(r->fallback(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyLanguageDisplay()), ObjectPropertyDescriptor(r->languageDisplay(), ObjectPropertyDescriptor::AllPresent)); + return options; +} + +static Value builtinIntlListFormatConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + // If NewTarget is undefined, throw a TypeError exception. + if (!newTarget) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, ErrorObject::Messages::GlobalObject_ConstructorRequiresNew); + } + + Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* realm) -> Object* { + return realm->globalObject()->intlListFormatPrototype(); + }); + if (argc >= 2) { + return new IntlListFormatObject(state, proto, argv[0], argv[1]); + } else if (argc >= 1) { + return new IntlListFormatObject(state, proto, argv[0], Value()); + } else { + return new IntlListFormatObject(state, proto, Value(), Value()); + } +} + +static Value builtinIntlListFormatSupportedLocalesOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + Value locales = argv[0]; + Value options; + if (argc >= 2) { + options = argv[1]; + } + const auto& availableLocales = state.context()->vmInstance()->intlListFormatAvailableLocales(); + ValueVector requestedLocales = Intl::canonicalizeLocaleList(state, locales); + return Intl::supportedLocales(state, availableLocales, requestedLocales, options); +} + +static Value builtinIntlListFormatResolvedOptions(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + + IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject(); + + Object* options = new Object(state); + + auto& staticStrings = state.context()->staticStrings(); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazySmallLetterLocale()), ObjectPropertyDescriptor(r->locale(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyType()), ObjectPropertyDescriptor(r->type(), ObjectPropertyDescriptor::AllPresent)); + options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyStyle()), ObjectPropertyDescriptor(r->style(), ObjectPropertyDescriptor::AllPresent)); + return options; +} + +static Value builtinIntlListFormatFormat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + + IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject(); + return r->format(state, argv[0]); +} + +static Value builtinIntlListFormatFormatToParts(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + if (!thisValue.isObject() || !thisValue.asObject()->isIntlListFormatObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Method called on incompatible receiver"); + } + + IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject(); + return r->formatToParts(state, argv[0]); +} + static Value builtinIntlGetCanonicalLocales(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) { // Let ll be ? CanonicalizeLocaleList(locales). @@ -956,7 +1123,7 @@ void GlobalObject::installIntl(ExecutionState& state) m_intl = new Object(state); m_intl->setGlobalIntrinsicObject(state); - const StaticStrings* strings = &state.context()->staticStrings(); + StaticStrings* strings = &state.context()->staticStrings(); redefineOwnProperty(state, ObjectPropertyName(strings->Intl), ObjectPropertyDescriptor(m_intl, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); @@ -1032,7 +1199,7 @@ void GlobalObject::installIntl(ExecutionState& state) ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->resolvedOptions, builtinIntlPluralRulesResolvedOptions, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); m_intlPluralRulesPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag), - ObjectPropertyDescriptor(Value(state.context()->staticStrings().Object.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent))); + ObjectPropertyDescriptor(Value(state.context()->staticStrings().intlDotPluralRules.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent))); m_intlPluralRules->defineOwnProperty(state, state.context()->staticStrings().supportedLocalesOf, ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->supportedLocalesOf, builtinIntlPluralRulesSupportedLocalesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); @@ -1126,6 +1293,55 @@ void GlobalObject::installIntl(ExecutionState& state) m_intlLocalePrototype->defineOwnProperty(state, state.context()->staticStrings().minimize, ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->minimize, builtinIntlLocaleMinimize, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getCalendars, builtinIntlLocaleCalendarsGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyCalendars()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getCollations, builtinIntlLocaleCollationsGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyCollations()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getHourCycles, builtinIntlLocaleHourCyclesGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyHourCycles()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getNumberingSystems, builtinIntlLocaleNumberingSystemsGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyNumberingSystems()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getTextInfo, builtinIntlLocaleTextInfoGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyTextInfo()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getWeekInfo, builtinIntlLocaleWeekInfoGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyWeekInfo()), desc); + } + + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getTimeZones, builtinIntlLocaleTimeZonesGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyTimeZones()), desc); + } + m_intlRelativeTimeFormat = new NativeFunctionObject(state, NativeFunctionInfo(strings->RelativeTimeFormat, builtinIntlRelativeTimeFormatConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__); m_intlRelativeTimeFormat->setGlobalIntrinsicObject(state); @@ -1147,6 +1363,45 @@ void GlobalObject::installIntl(ExecutionState& state) m_intlRelativeTimeFormat->defineOwnProperty(state, state.context()->staticStrings().supportedLocalesOf, ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->supportedLocalesOf, builtinIntlRelativeTimeFormatSupportedLocalesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + m_intlDisplayNames = new NativeFunctionObject(state, NativeFunctionInfo(strings->DisplayNames, builtinIntlDisplayNamesConstructor, 2), NativeFunctionObject::__ForBuiltinConstructor__); + m_intlDisplayNames->setGlobalIntrinsicObject(state); + + m_intlDisplayNamesPrototype = m_intlDisplayNames->getFunctionPrototype(state).asObject(); + m_intlDisplayNamesPrototype->setGlobalIntrinsicObject(state, true); + + m_intlDisplayNamesPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag), + ObjectPropertyDescriptor(Value(strings->intlDotDisplayNames.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent))); + + m_intlDisplayNamesPrototype->defineOwnProperty(state, state.context()->staticStrings().of, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->of, builtinIntlDisplayNamesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlDisplayNamesPrototype->defineOwnProperty(state, state.context()->staticStrings().resolvedOptions, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->resolvedOptions, builtinIntlDisplayNamesResolvedOptions, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlListFormat = new NativeFunctionObject(state, NativeFunctionInfo(strings->ListFormat, builtinIntlListFormatConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__); + m_intlListFormat->setGlobalIntrinsicObject(state); + + m_intlListFormat->defineOwnProperty(state, state.context()->staticStrings().supportedLocalesOf, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->supportedLocalesOf, builtinIntlListFormatSupportedLocalesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlListFormatPrototype = m_intlListFormat->getFunctionPrototype(state).asObject(); + m_intlListFormatPrototype->setGlobalIntrinsicObject(state, true); + + m_intlListFormatPrototype->defineOwnProperty(state, state.context()->staticStrings().resolvedOptions, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->resolvedOptions, builtinIntlListFormatResolvedOptions, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlListFormatPrototype->defineOwnProperty(state, state.context()->staticStrings().format, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->format, builtinIntlListFormatFormat, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlListFormatPrototype->defineOwnProperty(state, state.context()->staticStrings().formatToParts, + ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->formatToParts, builtinIntlListFormatFormatToParts, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent))); + + m_intlListFormatPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag), + ObjectPropertyDescriptor(Value(strings->intlDotListFormat.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent))); + + m_intl->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag), + ObjectPropertyDescriptor(Value(state.context()->staticStrings().Intl.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent))); + m_intl->defineOwnProperty(state, ObjectPropertyName(strings->Collator), ObjectPropertyDescriptor(m_intlCollator, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); @@ -1165,6 +1420,12 @@ void GlobalObject::installIntl(ExecutionState& state) m_intl->defineOwnProperty(state, ObjectPropertyName(strings->RelativeTimeFormat), ObjectPropertyDescriptor(m_intlRelativeTimeFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); + m_intl->defineOwnProperty(state, ObjectPropertyName(strings->DisplayNames), + ObjectPropertyDescriptor(m_intlDisplayNames, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); + + m_intl->defineOwnProperty(state, ObjectPropertyName(strings->ListFormat), + ObjectPropertyDescriptor(m_intlListFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); + FunctionObject* getCanonicalLocales = new NativeFunctionObject(state, NativeFunctionInfo(strings->getCanonicalLocales, builtinIntlGetCanonicalLocales, 1, NativeFunctionInfo::Strict)); m_intl->defineOwnProperty(state, ObjectPropertyName(strings->getCanonicalLocales), ObjectPropertyDescriptor(getCanonicalLocales, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); diff --git a/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.cpp b/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.cpp index acdbff5..07daaf2 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.cpp @@ -290,9 +290,20 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m { SandBox::StackTraceDataVector stackTraceData; - SandBox::createStackTraceData(stackTraceData, *state); + bool hasSavedStackTrace = SandBox::createStackTraceData(stackTraceData, *state, true); - uint32_t total = (uint32_t)stackTraceData.size(); + uint32_t size = (uint32_t)stackTraceData.size(); + uint32_t total = 0; + + for (uint32_t i = 0; i < size; i++) { + if ((size_t)stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) { + total++; + } + } + + if (hasSavedStackTrace) { + total += (uint32_t)m_activeSavedStackTrace->size(); + } if (getTotal && !send(ESCARGOT_MESSAGE_BACKTRACE_TOTAL, &total, sizeof(uint32_t))) { return; @@ -307,33 +318,63 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m } ByteCodeLOCDataMap locMap; - for (uint32_t i = minDepth; i < maxDepth; i++) { - if ((size_t)stackTraceData[i].second.loc.index == SIZE_MAX && (size_t)stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) { + uint32_t counter = 0; + + for (uint32_t i = 0; i < size && counter < maxDepth; i++) { + if ((size_t)stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) { + if (++counter <= minDepth) { + continue; + } + ByteCodeBlock* byteCodeBlock = stackTraceData[i].second.loc.actualCodeBlock; - size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition; + uint32_t line, column; + + if ((size_t)stackTraceData[i].second.loc.index == SIZE_MAX) { + size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition; + + ByteCodeLOCData* locData; + auto iterMap = locMap.find(byteCodeBlock); + if (iterMap == locMap.end()) { + locData = new ByteCodeLOCData(); + locMap.insert(std::make_pair(byteCodeBlock, locData)); + } else { + locData = iterMap->second; + } - ByteCodeLOCData* locData; - auto iterMap = locMap.find(byteCodeBlock); - if (iterMap == locMap.end()) { - locData = new ByteCodeLOCData(); - locMap.insert(std::make_pair(byteCodeBlock, locData)); + ExtendedNodeLOC loc = byteCodeBlock->computeNodeLOCFromByteCode(state->context(), byteCodePosition, byteCodeBlock->m_codeBlock, locData); + line = (uint32_t)loc.line; + column = (uint32_t)loc.column; } else { - locData = iterMap->second; + line = (uint32_t)stackTraceData[i].second.loc.line; + column = (uint32_t)stackTraceData[i].second.loc.column; } - ExtendedNodeLOC loc = byteCodeBlock->computeNodeLOCFromByteCode(state->context(), byteCodePosition, byteCodeBlock->m_codeBlock, locData); - - sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, byteCodeBlock, (uint32_t)loc.line, (uint32_t)loc.column, (uint32_t)stackTraceData[i].second.executionStateDepth); + sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, byteCodeBlock, line, column, (uint32_t)stackTraceData[i].second.executionStateDepth); if (!enabled()) { return; } } } + for (auto iter = locMap.begin(); iter != locMap.end(); iter++) { delete iter->second; } + if (hasSavedStackTrace) { + SavedStackTraceData* savedStackTracePtr = m_activeSavedStackTrace->begin(); + SavedStackTraceData* savedStackTraceEnd = m_activeSavedStackTrace->end(); + + while (counter < maxDepth && savedStackTracePtr < savedStackTraceEnd) { + if (++counter <= minDepth) { + continue; + } + + sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, savedStackTracePtr->byteCodeBlock, savedStackTracePtr->line, savedStackTracePtr->column, UINT32_MAX); + savedStackTracePtr++; + } + } + sendType(ESCARGOT_MESSAGE_BACKTRACE_END); } @@ -826,6 +867,67 @@ void Debugger::waitForResolvingPendingBreakpoints() } } +Debugger::SavedStackTraceDataVector* Debugger::saveStackTrace(ExecutionState& state) +{ + SavedStackTraceDataVector* savedStackTrace = new SavedStackTraceDataVector(); + SandBox::StackTraceDataVector stackTraceData; + ByteCodeLOCDataMap locMap; + uint32_t counter = 0; + + bool hasSavedStackTrace = SandBox::createStackTraceData(stackTraceData, state, true); + uint32_t total = (uint32_t)stackTraceData.size(); + + for (uint32_t i = 0; i < total && counter < ESCARGOT_DEBUGGER_MAX_STACK_TRACE_LENGTH; i++) { + if ((size_t)stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) { + ByteCodeBlock* byteCodeBlock = stackTraceData[i].second.loc.actualCodeBlock; + uint32_t line, column; + + counter++; + + if ((size_t)stackTraceData[i].second.loc.index == SIZE_MAX) { + size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition; + + ByteCodeLOCData* locData; + auto iterMap = locMap.find(byteCodeBlock); + if (iterMap == locMap.end()) { + locData = new ByteCodeLOCData(); + locMap.insert(std::make_pair(byteCodeBlock, locData)); + } else { + locData = iterMap->second; + } + + ExtendedNodeLOC loc = byteCodeBlock->computeNodeLOCFromByteCode(state.context(), byteCodePosition, byteCodeBlock->m_codeBlock, locData); + + line = (uint32_t)loc.line; + column = (uint32_t)loc.column; + } else { + line = (uint32_t)stackTraceData[i].second.loc.line; + column = (uint32_t)stackTraceData[i].second.loc.column; + } + + savedStackTrace->push_back(SavedStackTraceData(byteCodeBlock, line, column)); + } + } + + for (auto iter = locMap.begin(); iter != locMap.end(); iter++) { + delete iter->second; + } + + if (hasSavedStackTrace) { + Debugger* debugger = state.context()->debugger(); + SavedStackTraceData* savedStackTracePtr = debugger->activeSavedStackTrace()->begin(); + SavedStackTraceData* savedStackTraceEnd = debugger->activeSavedStackTrace()->end(); + + while (counter < ESCARGOT_DEBUGGER_MAX_STACK_TRACE_LENGTH && savedStackTracePtr < savedStackTraceEnd) { + savedStackTrace->push_back(SavedStackTraceData(savedStackTracePtr->byteCodeBlock, savedStackTracePtr->line, savedStackTracePtr->column)); + savedStackTracePtr++; + counter++; + } + } + + return savedStackTrace; +} + Debugger* createDebugger(const char* options, bool* debuggerEnabled) { Debugger* debugger = new DebuggerTcp(); diff --git a/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.h b/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.h index 7618ff6..be824cb 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.h +++ b/lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.h @@ -25,13 +25,16 @@ #ifdef ESCARGOT_DEBUGGER namespace Escargot { +#define ESCARGOT_DEBUGGER_MAX_STACK_TRACE_LENGTH 8 + /* WebSocket max length encoded in one byte. */ #define ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH 125 #define ESCARGOT_DEBUGGER_VERSION 1 #define ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY 10 #define ESCARGOT_DEBUGGER_IN_WAIT_MODE (nullptr) -#define ESCARGOT_DEBUGGER_IN_EVAL_MODE ((ExecutionState*)0x1) -#define ESCARGOT_DEBUGGER_ALWAYS_STOP ((ExecutionState*)0x2) +#define ESCARGOT_DEBUGGER_IN_EVAL_MODE (reinterpret_cast(0x1)) +#define ESCARGOT_DEBUGGER_ALWAYS_STOP (reinterpret_cast(0x2)) +#define ESCARGOT_DEBUGGER_NO_STACK_TRACE_RESTORE (reinterpret_cast(0x1)) #define ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH 128 class Object; @@ -168,11 +171,36 @@ public: uint32_t offset; }; + struct SavedStackTraceData : public gc { + ByteCodeBlock* byteCodeBlock; + uint32_t line; + uint32_t column; + + SavedStackTraceData(ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column) + : byteCodeBlock(byteCodeBlock) + , line(line) + , column(column) + { + } + }; + + typedef Vector> SavedStackTraceDataVector; + bool enabled() { return m_enabled; } + bool parsingEnabled() + { + return m_parsingEnabled; + } + + void setParsingEnabled(bool value) + { + m_parsingEnabled = value; + } + bool pendingWait(void) { return m_pendingWait; @@ -192,6 +220,22 @@ public: } } + void setActiveSavedStackTrace(ExecutionState* state, SavedStackTraceDataVector* trace) + { + m_activeSavedStackTraceExecutionState = state; + m_activeSavedStackTrace = trace; + } + + ExecutionState* activeSavedStackTraceExecutionState() + { + return m_activeSavedStackTraceExecutionState; + } + + SavedStackTraceDataVector* activeSavedStackTrace() + { + return m_activeSavedStackTrace; + } + static inline void updateStopState(Debugger* debugger, ExecutionState* state, ExecutionState* newState) { if (debugger != nullptr && debugger->m_stopState == state) { @@ -212,10 +256,12 @@ public: void releaseFunction(const void* ptr); String* getClientSource(String** sourceName); void waitForResolvingPendingBreakpoints(); + static SavedStackTraceDataVector* saveStackTrace(ExecutionState& state); protected: Debugger() : m_enabled(false) + , m_parsingEnabled(false) , m_debuggerEnabled(nullptr) , m_delay(ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY) , m_pendingWait(false) @@ -223,6 +269,8 @@ protected: , m_stopState(ESCARGOT_DEBUGGER_ALWAYS_STOP) , m_clientSourceData(nullptr) , m_clientSourceName(nullptr) + , m_activeSavedStackTraceExecutionState(nullptr) + , m_activeSavedStackTrace(nullptr) { } @@ -232,6 +280,7 @@ protected: virtual void close(void) = 0; bool m_enabled; + bool m_parsingEnabled; bool* m_debuggerEnabled; private: @@ -285,6 +334,8 @@ private: String* m_clientSourceName; Vector> m_releasedFunctions; Vector> m_activeObjects; + ExecutionState* m_activeSavedStackTraceExecutionState; + SavedStackTraceDataVector* m_activeSavedStackTrace; }; Debugger* createDebugger(const char* options, bool* debuggerEnabled); diff --git a/lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.cpp b/lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.cpp index 1a498b4..39de349 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.cpp @@ -372,6 +372,7 @@ bool DebuggerTcp::init(const char*) } m_enabled = true; + m_parsingEnabled = true; m_receiveBufferFill = 0; m_messageLength = 0; return true; diff --git a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.cpp b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.cpp index 27ee6be..f82d1b6 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.cpp @@ -101,7 +101,12 @@ size_t ByteCodeGenerateContext::calculateBreakpointLineOffset(size_t index, Exte size_t lastLineOffset = m_breakpointContext->m_lastBreakpointLineOffset; index -= sourceElementStart.index; - ASSERT(index >= m_breakpointContext->m_lastBreakpointIndexOffset); + // if cache is invalid, we should recalulate {index, lineOffset} from begin + if (UNLIKELY(index < m_breakpointContext->m_lastBreakpointIndexOffset)) { + m_breakpointContext->m_lastBreakpointLineOffset = m_breakpointContext->m_lastBreakpointIndexOffset = 0; + lastLineOffset = 0; + } + for (size_t i = m_breakpointContext->m_lastBreakpointIndexOffset; i < index; i++) { char16_t c = src.charAt(i); if (EscargotLexer::isLineTerminator(c)) { @@ -135,8 +140,10 @@ void ByteCodeGenerateContext::insertBreakpoint(size_t index, Node* node) void ByteCodeGenerateContext::insertBreakpointAt(size_t line, Node* node) { - m_breakpointContext->m_breakpointLocations.push_back(Debugger::BreakpointLocation(line, (uint32_t)m_byteCodeBlock->currentCodeSize())); - m_byteCodeBlock->pushCode(BreakpointDisabled(ByteCodeLOC(node->loc().index)), this, node); + if (m_breakpointContext->m_parsingEnabled) { + m_breakpointContext->m_breakpointLocations.push_back(Debugger::BreakpointLocation(line, (uint32_t)m_byteCodeBlock->currentCodeSize())); + m_byteCodeBlock->pushCode(BreakpointDisabled(ByteCodeLOC(node->loc().index)), this, node); + } } #endif /* ESCARGOT_DEBUGGER */ @@ -183,38 +190,18 @@ ByteCodeBlock* ByteCodeGenerator::generateByteCode(Context* context, Interpreted ByteCodeGenerateContext ctx(codeBlock, block, codeBlock->isGlobalScope(), codeBlock->isEvalCode(), inWithFromRuntime || codeBlock->inWith(), nData); #ifdef ESCARGOT_DEBUGGER - ByteCodeBreakpointContext breakpointContext; + ByteCodeBreakpointContext breakpointContext(context->debugger() && context->debugger()->parsingEnabled()); ctx.m_breakpointContext = &breakpointContext; #endif /* ESCARGOT_DEBUGGER */ - // generate common codes - { - AtomicString name = codeBlock->functionName(); - if (name.string()->length()) { - if (UNLIKELY(codeBlock->isFunctionNameExplicitlyDeclared())) { - if (codeBlock->canUseIndexedVariableStorage()) { - if (!codeBlock->isFunctionNameSaveOnHeap()) { - auto r = ctx.getRegister(); - block->pushCode(LoadLiteral(ByteCodeLOC(0), r, Value()), &ctx, nullptr); - block->pushCode(Move(ByteCodeLOC(0), r, REGULAR_REGISTER_LIMIT + 1), &ctx, nullptr); - ctx.giveUpRegister(); - } - } - } else if (UNLIKELY(codeBlock->isFunctionNameSaveOnHeap() && !name.string()->equals("arguments"))) { - ctx.m_isVarDeclaredBindingInitialization = true; - IdentifierNode* id = new (alloca(sizeof(IdentifierNode))) IdentifierNode(codeBlock->functionName()); - id->generateStoreByteCode(block, &ctx, REGULAR_REGISTER_LIMIT + 1, true); - } - } - - ast->generateStatementByteCode(block, &ctx); + // generate bytecode + ast->generateStatementByteCode(block, &ctx); #ifdef ESCARGOT_DEBUGGER - if (context->debugger() && context->debugger()->enabled()) { - context->debugger()->sendBreakpointLocations(breakpointContext.m_breakpointLocations); - } -#endif /* ESCARGOT_DEBUGGER */ + if (context->debugger() && context->debugger()->enabled() && breakpointContext.m_parsingEnabled) { + context->debugger()->sendBreakpointLocations(breakpointContext.m_breakpointLocations); } +#endif /* ESCARGOT_DEBUGGER */ if (ctx.m_keepNumberalLiteralsInRegisterFile) { block->m_numeralLiteralData.resizeWithUninitializedValues(nData->size()); @@ -279,7 +266,7 @@ void ByteCodeGenerator::collectByteCodeLOCData(Context* context, InterpretedCode ctx.m_locData = locData; #ifdef ESCARGOT_DEBUGGER - ByteCodeBreakpointContext breakpointContext; + ByteCodeBreakpointContext breakpointContext(context->debugger() && context->debugger()->parsingEnabled()); ctx.m_breakpointContext = &breakpointContext; #endif /* ESCARGOT_DEBUGGER */ diff --git a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.h b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.h index bfbea0a..ab3a412 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.h +++ b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.h @@ -54,12 +54,14 @@ struct ClassContextInformation { #ifdef ESCARGOT_DEBUGGER struct ByteCodeBreakpointContext { + bool m_parsingEnabled; size_t m_lastBreakpointLineOffset; size_t m_lastBreakpointIndexOffset; std::vector m_breakpointLocations; - ByteCodeBreakpointContext() - : m_lastBreakpointLineOffset(0) + ByteCodeBreakpointContext(bool parsingEnabled) + : m_parsingEnabled(parsingEnabled) + , m_lastBreakpointLineOffset(0) , m_lastBreakpointIndexOffset(0) { } diff --git a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.cpp b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.cpp index 38feaa9..8677775 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.cpp @@ -83,6 +83,25 @@ private: size_t* m_oldAddress; }; +template +class ExecutionStateVariableChanger { +public: + ExecutionStateVariableChanger(ExecutionState& state, T changer) + : m_state(state) + , m_changer(changer) + { + m_changer(m_state, true); + } + ~ExecutionStateVariableChanger() + { + m_changer(m_state, false); + } + +private: + ExecutionState& m_state; + T m_changer; +}; + Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteCodeBlock, size_t programCounter, Value* registerFile) { #if defined(COMPILER_GCC) || defined(COMPILER_CLANG) @@ -2585,6 +2604,10 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz if (LIKELY(!code->m_isCatchResumeProcess && !code->m_isFinallyResumeProcess)) { try { + ExecutionStateVariableChanger changer(*state, [](ExecutionState& state, bool in) { + state.m_onTry = in; + }); + size_t newPc = programCounter + sizeof(TryOperation); interpret(newState, byteCodeBlock, resolveProgramCounter(codeBuffer, newPc), registerFile); if (newState->inExecutionStopState()) { @@ -2633,6 +2656,9 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz stackTraceData.clear(); registerFile[code->m_catchedValueRegisterIndex] = val; try { + ExecutionStateVariableChanger changer(*state, [](ExecutionState& state, bool in) { + state.m_onCatch = in; + }); interpret(newState, byteCodeBlock, code->m_catchPosition, registerFile); if (newState->inExecutionStopState()) { return Value(); @@ -2645,6 +2671,9 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz } } else if (code->m_isCatchResumeProcess) { try { + ExecutionStateVariableChanger changer(*state, [](ExecutionState& state, bool in) { + state.m_onCatch = in; + }); interpret(newState, byteCodeBlock, resolveProgramCounter(codeBuffer, programCounter + sizeof(TryOperation)), registerFile); if (UNLIKELY(newState->inExecutionStopState() || newState->parent()->inExecutionStopState())) { return Value(); @@ -2659,6 +2688,9 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz } if (code->m_isFinallyResumeProcess) { + ExecutionStateVariableChanger changer(*state, [](ExecutionState& state, bool in) { + state.m_onFinally = in; + }); interpret(newState, byteCodeBlock, resolveProgramCounter(codeBuffer, programCounter + sizeof(TryOperation)), registerFile); if (newState->inExecutionStopState() || newState->parent()->inExecutionStopState()) { return Value(); @@ -2675,7 +2707,9 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz newState = new ExecutionState(state, state->lexicalEnvironment(), state->inStrictMode()); newState->ensureRareData()->m_controlFlowRecord = state->rareData()->m_controlFlowRecord; } - + ExecutionStateVariableChanger changer(*state, [](ExecutionState& state, bool in) { + state.m_onFinally = in; + }); interpret(newState, byteCodeBlock, code->m_tryCatchEndPosition, registerFile); if (newState->inExecutionStopState()) { return Value(); @@ -2787,7 +2821,7 @@ NEVER_INLINE void ByteCodeInterpreter::initializeClassOperation(ExecutionState& } else { if (!heritagePresent) { Value argv[] = { String::emptyString, String::emptyString }; - auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, false); + auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, false, false); functionSource.codeBlock->setAsClassConstructor(); constructor = new ScriptClassConstructorFunctionObject(state, constructorParent.asObject(), functionSource.codeBlock, functionSource.outerEnvironment, proto, @@ -2795,7 +2829,7 @@ NEVER_INLINE void ByteCodeInterpreter::initializeClassOperation(ExecutionState& } else { Value argv[] = { state.context()->staticStrings().lazyDotDotDotArgs().string(), state.context()->staticStrings().lazySuperDotDotDotArgs().string() }; - auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, true); + auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, true, false); functionSource.codeBlock->setAsClassConstructor(); functionSource.codeBlock->setAsDerivedClassConstructor(); constructor = new ScriptClassConstructorFunctionObject(state, constructorParent.asObject(), diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.cpp b/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.cpp index fda957f..f48f1eb 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.cpp @@ -1317,6 +1317,32 @@ String* Intl::icuLocaleToBCP47Tag(String* string) return sb.finalize(); } +std::string Intl::convertICUCalendarKeywordToBCP47KeywordIfNeeds(const std::string& icuCalendar) +{ + if (icuCalendar == std::string("gregorian")) { + return "gregory"; + } else if (icuCalendar == std::string("islamic-civil")) { + return "islamicc"; + } else if (icuCalendar == std::string("ethiopic-amete-alem")) { + return "ethioaa"; + } + return icuCalendar; +} + +std::string Intl::convertICUCollationKeywordToBCP47KeywordIfNeeds(const std::string& icuCollation) +{ + if (icuCollation == std::string("dictionary")) { + return "dict"; + } else if (icuCollation == std::string("gb2312han")) { + return "gb2312"; + } else if (icuCollation == std::string("phonebook")) { + return "phonebk"; + } else if (icuCollation == std::string("traditional")) { + return "trad"; + } + return icuCollation; +} + static String* defaultLocale(ExecutionState& state) { String* localeString = String::fromUTF8(state.context()->vmInstance()->locale().data(), state.context()->vmInstance()->locale().length()); @@ -1988,13 +2014,19 @@ static bool is38Alphanum(const std::string& str) return false; } -static bool is38AlphanumList(const std::string& str) +static bool is38AlphanumList(const std::string& str, bool allowUnderScore = false) { std::size_t found = str.find("-"); if (found == std::string::npos) { + if (allowUnderScore) { + found = str.find("_"); + if (found != std::string::npos) { + return is38Alphanum(str.substr(0, found)) && is38AlphanumList(str.substr(found + 1), allowUnderScore); + } + } return is38Alphanum(str); } - return is38Alphanum(str.substr(0, found)) && is38AlphanumList(str.substr(found + 1)); + return is38Alphanum(str.substr(0, found)) && is38AlphanumList(str.substr(found + 1), allowUnderScore); } bool Intl::isValidUnicodeLocaleIdentifierTypeNonterminalOrTypeSequence(String* value) @@ -2002,6 +2034,11 @@ bool Intl::isValidUnicodeLocaleIdentifierTypeNonterminalOrTypeSequence(String* v return is38AlphanumList(value->toNonGCUTF8StringData()); } +bool Intl::isValidUnicodeLocaleIdentifier(String* value) +{ + return is38AlphanumList(value->toNonGCUTF8StringData(), true); +} + void Intl::convertICUNumberFieldToEcmaNumberField(std::vector& fields, double x, const UTF16StringDataNonGCStd& resultString) { // we need to divide integer field diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.h b/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.h index 020d2e1..5841bb3 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.h +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/Intl.h @@ -51,6 +51,8 @@ public: static T getNumberOption(ExecutionState& state, Object* options, String* property, double minimum, double maximum, const T& fallback); static std::string preferredLanguage(const std::string& language); static String* icuLocaleToBCP47Tag(String* string); + static std::string convertICUCalendarKeywordToBCP47KeywordIfNeeds(const std::string& icuCalendar); + static std::string convertICUCollationKeywordToBCP47KeywordIfNeeds(const std::string& icuCollation); static std::vector calendarsForLocale(String* locale); static std::vector numberingSystemsForLocale(String* locale); struct CanonicalizedLangunageTag { @@ -72,6 +74,7 @@ public: static CanonicalizedLangunageTag isStructurallyValidLanguageTagAndCanonicalizeLanguageTag(const std::string& locale); static String* getLocaleForStringLocaleConvertCase(ExecutionState& state, Value locales); + static bool isValidUnicodeLocaleIdentifier(String* value); // test string is `(3*8alphanum) *("-" (3*8alphanum))` sequence static bool isValidUnicodeLocaleIdentifierTypeNonterminalOrTypeSequence(String* value); @@ -82,6 +85,42 @@ public: }; static void convertICUNumberFieldToEcmaNumberField(std::vector& fields, double x, const UTF16StringDataNonGCStd& resultString); static String* icuNumberFieldToString(ExecutionState& state, int32_t fieldName, double d); + +#define INTL_ICU_STRING_BUFFER_OPERATION(icuFnName, ...) \ + ([&]() -> std::pair { \ + UTF16StringDataNonGCStd output; \ + UErrorCode status = U_ZERO_ERROR; \ + const size_t defaultStringBufferSize = 32; \ + output.resize(defaultStringBufferSize); \ + status = U_ZERO_ERROR; \ + auto resultLength = icuFnName(__VA_ARGS__, (UChar*)output.data(), defaultStringBufferSize, &status); \ + if (U_SUCCESS(status)) { \ + output.resize(resultLength); \ + } else if (status == U_BUFFER_OVERFLOW_ERROR) { \ + status = U_ZERO_ERROR; \ + output.resize(resultLength); \ + icuFnName(__VA_ARGS__, (UChar*)output.data(), resultLength, &status); \ + } \ + return std::make_pair(status, output); \ + })() + +#define INTL_ICU_STRING_BUFFER_OPERATION_COMPLEX(icuFnName, extra, ...) \ + ([&]() -> std::pair { \ + UTF16StringDataNonGCStd output; \ + UErrorCode status = U_ZERO_ERROR; \ + const size_t defaultStringBufferSize = 32; \ + output.resize(defaultStringBufferSize); \ + status = U_ZERO_ERROR; \ + auto resultLength = icuFnName(__VA_ARGS__, (UChar*)output.data(), defaultStringBufferSize, extra, &status); \ + if (U_SUCCESS(status)) { \ + output.resize(resultLength); \ + } else if (status == U_BUFFER_OVERFLOW_ERROR) { \ + status = U_ZERO_ERROR; \ + output.resize(resultLength); \ + icuFnName(__VA_ARGS__, (UChar*)output.data(), resultLength, extra, &status); \ + } \ + return std::make_pair(status, output); \ + })() }; } // namespace Escargot diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlCollator.cpp b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlCollator.cpp index 2cf2a9a..3e31750 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlCollator.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlCollator.cpp @@ -80,16 +80,7 @@ static std::vector sortLocaleData(String* locale, size_t keyIndex) continue; // Map keyword values to BCP 47 equivalents. - if (!strcmp(collation, "dictionary")) - collation = "dict"; - else if (!strcmp(collation, "gb2312han")) - collation = "gb2312"; - else if (!strcmp(collation, "phonebook")) - collation = "phonebk"; - else if (!strcmp(collation, "traditional")) - collation = "trad"; - - keyLocaleData.push_back(std::string(collation)); + keyLocaleData.push_back(Intl::convertICUCollationKeywordToBCP47KeywordIfNeeds(collation)); } uenum_close(enumeration); } diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.cpp b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.cpp index 0551119..0c6af5d 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.cpp +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.cpp @@ -61,7 +61,6 @@ static const size_t indexOfExtensionKeyCa = 0; static const size_t indexOfExtensionKeyNu = 1; static const size_t indexOfExtensionKeyHc = 2; static const double minECMAScriptTime = -8.64E15; -static const size_t defaultStringBufferSize = 32; std::vector Intl::calendarsForLocale(String* locale) { @@ -76,16 +75,7 @@ std::vector Intl::calendarsForLocale(String* locale) ASSERT(U_SUCCESS(status)); status = U_ZERO_ERROR; std::string calendar = std::string(availableName, nameLength); - // Ensure aliases used in language tag are allowed. - if (calendar == std::string("gregorian")) { - keyLocaleData.push_back(std::string("gregory")); - } else if (calendar == std::string("islamic-civil")) { - keyLocaleData.push_back(std::string("islamicc")); - } else if (calendar == std::string("ethiopic-amete-alem")) { - keyLocaleData.push_back(std::string("ethioaa")); - } else { - keyLocaleData.push_back(calendar); - } + keyLocaleData.push_back(Intl::convertICUCalendarKeywordToBCP47KeywordIfNeeds(calendar)); } uenum_close(calendars); @@ -197,7 +187,7 @@ static String* defaultTimeZone(ExecutionState& state) return String::fromUTF8(state.context()->vmInstance()->timezoneID().data(), state.context()->vmInstance()->timezoneID().length()); } -static std::string readHourCycleFromPattern(const UTF16StringDataNonGCStd& patternString) +std::string IntlDateTimeFormatObject::readHourCycleFromPattern(const UTF16StringDataNonGCStd& patternString) { bool inQuote = false; for (size_t i = 0; i < patternString.length(); i++) { @@ -671,16 +661,9 @@ IntlDateTimeFormatObject::IntlDateTimeFormatObject(ExecutionState& state, Object return; } - patternBuffer.resize(defaultStringBufferSize); - status = U_ZERO_ERROR; - auto patternLength = udat_toPattern(dateFormatFromStyle.get(), false, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - patternBuffer.resize(patternLength); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - patternBuffer.resize(patternLength); - udat_toPattern(dateFormatFromStyle.get(), false, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - } - if (U_FAILURE(status)) { + auto toPatternResult = INTL_ICU_STRING_BUFFER_OPERATION(udat_toPattern, dateFormatFromStyle.get(), false); + patternBuffer = std::move(toPatternResult.second); + if (U_FAILURE(toPatternResult.first)) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "failed to initialize DateTimeFormat"); return; } @@ -706,21 +689,13 @@ IntlDateTimeFormatObject::IntlDateTimeFormatObject(ExecutionState& state, Object } std::string extractedHourCycle = readHourCycleFromPattern(patternBuffer); if (extractedHourCycle.size() && (extractedHourCycle == "h11" || extractedHourCycle == "h12") != specifiedHour12) { - UTF16StringDataNonGCStd skeleton; - skeleton.resize(defaultStringBufferSize); - status = U_ZERO_ERROR; - auto resultLength = udatpg_getSkeleton(nullptr, (UChar*)patternBuffer.data(), patternBuffer.size(), (UChar*)skeleton.data(), skeleton.size(), &status); - skeleton.resize(resultLength); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - skeleton.resize(resultLength); - udatpg_getSkeleton(nullptr, (UChar*)patternBuffer.data(), patternBuffer.size(), (UChar*)skeleton.data(), skeleton.size(), &status); - } - if (U_FAILURE(status)) { + auto getSkeletonResult = INTL_ICU_STRING_BUFFER_OPERATION(udatpg_getSkeleton, nullptr, (UChar*)patternBuffer.data(), patternBuffer.size()); + if (U_FAILURE(getSkeletonResult.first)) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "failed to initialize DateTimeFormat"); return; } + UTF16StringDataNonGCStd skeleton = std::move(getSkeletonResult.second); for (size_t i = 0; i < skeleton.size(); i++) { auto ch = skeleton[i]; if (ch == 'h' || ch == 'H' || ch == 'j') { @@ -732,19 +707,12 @@ IntlDateTimeFormatObject::IntlDateTimeFormatObject(ExecutionState& state, Object } } - patternBuffer.resize(defaultStringBufferSize); - status = U_ZERO_ERROR; - auto patternLength = udatpg_getBestPatternWithOptions(generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - patternBuffer.resize(patternLength); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - patternBuffer.resize(patternLength); - udatpg_getBestPatternWithOptions(generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - } - if (U_FAILURE(status)) { + auto getBestPatternWithOptionsResult = INTL_ICU_STRING_BUFFER_OPERATION(udatpg_getBestPatternWithOptions, generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH); + if (U_FAILURE(getBestPatternWithOptionsResult.first)) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "failed to initialize DateTimeFormat"); return; } + patternBuffer = std::move(getBestPatternWithOptionsResult.second); } } @@ -756,19 +724,12 @@ IntlDateTimeFormatObject::IntlDateTimeFormatObject(ExecutionState& state, Object // Else, // Let bestFormat be BestFitFormatMatcher(opt, formats). skeleton = skeletonBuilder.finalize()->toUTF16StringData(); - patternBuffer.resize(defaultStringBufferSize); - status = U_ZERO_ERROR; - auto patternLength = udatpg_getBestPatternWithOptions(generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - patternBuffer.resize(patternLength); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - patternBuffer.resize(patternLength); - udatpg_getBestPatternWithOptions(generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, (UChar*)patternBuffer.data(), patternBuffer.size(), &status); - } - if (U_FAILURE(status)) { + auto getBestPatternWithOptionsResult = INTL_ICU_STRING_BUFFER_OPERATION(udatpg_getBestPatternWithOptions, generator.get(), (UChar*)skeleton.data(), skeleton.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH); + if (U_FAILURE(getBestPatternWithOptionsResult.first)) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "failed to initialize DateTimeFormat"); return; } + patternBuffer = std::move(getBestPatternWithOptionsResult.second); } // If dateTimeFormat.[[Hour]] is not undefined, then @@ -776,16 +737,9 @@ IntlDateTimeFormatObject::IntlDateTimeFormatObject(ExecutionState& state, Object if (hasHourOption) { // Let hcDefault be dataLocaleData.[[hourCycle]]. UTF16StringDataNonGCStd patternBuffer; - patternBuffer.resize(defaultStringBufferSize); - status = U_ZERO_ERROR; - auto patternLength = udatpg_getBestPattern(generator.get(), u"jjmm", 4, (UChar*)patternBuffer.data(), patternBuffer.length(), &status); - patternBuffer.resize(patternLength); - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - patternBuffer.resize(patternLength); - udatpg_getBestPattern(generator.get(), u"jjmm", 4, (UChar*)patternBuffer.data(), patternLength, &status); - } - ASSERT(U_SUCCESS(status)); + auto getBestPatternResult = INTL_ICU_STRING_BUFFER_OPERATION(udatpg_getBestPattern, generator.get(), u"jjmm", 4); + ASSERT(U_SUCCESS(getBestPatternResult.first)); + patternBuffer = std::move(getBestPatternResult.second); auto hcDefault = readHourCycleFromPattern(patternBuffer); // Let hc be dateTimeFormat.[[HourCycle]]. auto hc = m_hourCycle; @@ -1007,24 +961,13 @@ UTF16StringDataNonGCStd IntlDateTimeFormatObject::format(ExecutionState& state, x = Value(x).toInteger(state); - UDateFormat* udat = (UDateFormat*)m_icuDateFormat; - // Delegate remaining steps to ICU. - UErrorCode status = U_ZERO_ERROR; - UTF16StringDataNonGCStd result; - result.resize(defaultStringBufferSize); - auto resultLength = udat_format(udat, x, (UChar*)result.data(), result.size(), nullptr, &status); - result.resize(resultLength); - - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - udat_format(udat, x, (UChar*)result.data(), resultLength, nullptr, &status); - } - if (U_FAILURE(status)) { + auto formatResult = INTL_ICU_STRING_BUFFER_OPERATION_COMPLEX(udat_format, nullptr, m_icuDateFormat, x); + if (U_FAILURE(formatResult.first)) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "failed to format date value"); } - return result; + return formatResult.second; } ArrayObject* IntlDateTimeFormatObject::formatToParts(ExecutionState& state, double x) @@ -1040,23 +983,14 @@ ArrayObject* IntlDateTimeFormatObject::formatToParts(ExecutionState& state, doub ArrayObject* result = new ArrayObject(state); - UDateFormat* udat = (UDateFormat*)m_icuDateFormat; - UErrorCode status = U_ZERO_ERROR; UFieldPositionIterator* fpositer; fpositer = ufieldpositer_open(&status); ASSERT(U_SUCCESS(status)); - UTF16StringDataNonGCStd resultString; - resultString.resize(defaultStringBufferSize); - auto resultLength = udat_formatForFields(udat, x, (UChar*)resultString.data(), resultString.size(), fpositer, &status); - resultString.resize(resultLength); - - if (status == U_BUFFER_OVERFLOW_ERROR) { - status = U_ZERO_ERROR; - udat_formatForFields(udat, x, (UChar*)resultString.data(), resultLength, fpositer, &status); - } + auto formatResult = INTL_ICU_STRING_BUFFER_OPERATION_COMPLEX(udat_formatForFields, fpositer, m_icuDateFormat, x); + UTF16StringDataNonGCStd resultString = std::move(formatResult.second); struct FieldItem { int32_t start; diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.h b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.h index 940a2f4..bee40fa 100644 --- a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.h +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.h @@ -39,7 +39,7 @@ public: UTF16StringDataNonGCStd format(ExecutionState& state, double x); ArrayObject* formatToParts(ExecutionState& state, double x); static Value toDateTimeOptions(ExecutionState& state, Value options, Value required, Value defaults); - + static std::string readHourCycleFromPattern(const UTF16StringDataNonGCStd& patternString); String* locale() const { return m_locale; diff --git a/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDisplayNames.cpp b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDisplayNames.cpp new file mode 100644 index 0000000..0b1b322 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/src/intl/IntlDisplayNames.cpp @@ -0,0 +1,369 @@ +#if defined(ENABLE_ICU) && defined(ENABLE_INTL) +/* + * Copyright (c) 2021-present Samsung Electronics Co., Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "Escargot.h" +#include "runtime/Context.h" +#include "runtime/ExecutionState.h" +#include "runtime/Value.h" +#include "runtime/VMInstance.h" +#include "Intl.h" +#include "IntlDisplayNames.h" + +namespace Escargot { + +IntlDisplayNamesObject::IntlDisplayNamesObject(ExecutionState& state, Object* proto, Value locales, Value options) + : Object(state, proto) +{ +#if defined(ENABLE_RUNTIME_ICU_BINDER) + UVersionInfo versionArray; + u_getVersion(versionArray); + if (versionArray[0] < 62) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "Intl.DisplayNames needs 61+ version of ICU"); + } +#endif + // https://402.ecma-international.org/8.0/#sec-Intl.DisplayNames + // + https://tc39.es/intl-displaynames-v2/ + auto& staticStrings = state.context()->staticStrings(); + + // Let displayNames be ? OrdinaryCreateFromConstructor(NewTarget, "%DisplayNames.prototype%", « [[InitializedDisplayNames]], [[Locale]], [[Style]], [[Type]], [[Fallback]], [[Fields]] »). + // Let requestedLocales be ? CanonicalizeLocaleList(locales). + ValueVector requestedLocales = Intl::canonicalizeLocaleList(state, locales); + // If options is undefined, throw a TypeError exception. + // Let options be ? GetOptionsObject(options). + if (!options.isObject()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "options must be object"); + } + Object* optionsObject = options.asObject(); + // Let opt be a new Record. + StringMap opt; + // Let localeData be %DisplayNames%.[[LocaleData]]. + // Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). + Value matcherValues[2] = { staticStrings.lazyLookup().string(), staticStrings.lazyBestFit().string() }; + Value matcher = Intl::getOption(state, optionsObject, staticStrings.lazyLocaleMatcher().string(), Intl::StringValue, matcherValues, 2, matcherValues[1]); + // Set opt.[[localeMatcher]] to matcher. + opt.insert(std::make_pair("localeMatcher", matcher.asString())); + // Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]). + const auto& availableLocales = state.context()->vmInstance()->intlDisplayNamesAvailableLocales(); + StringMap r = Intl::resolveLocale(state, availableLocales, requestedLocales, opt, nullptr, 0, nullptr); + + // Let style be ? GetOption(options, "style", "string", « "narrow", "short", "long" », "long"). + Value styleValues[] = { staticStrings.lazyNarrow().string(), staticStrings.lazyShort().string(), staticStrings.lazyLong().string() }; + Value style = Intl::getOption(state, optionsObject, staticStrings.lazyStyle().string(), Intl::StringValue, styleValues, 3, styleValues[2]); + // Set displayNames.[[Style]] to style. + m_style = style.asString(); + // Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency", "calendar", "dateTimeField" », undefined). + Value typeValues[] = { staticStrings.language.string(), staticStrings.region.string(), + staticStrings.script.string(), staticStrings.lazyCurrency().string(), staticStrings.calendar.string(), staticStrings.lazyDateTimeField().string() }; + Value type = Intl::getOption(state, optionsObject, staticStrings.lazyType().string(), Intl::StringValue, typeValues, 6, Value()); + // If type is undefined, throw a TypeError exception. + if (type.isUndefined()) { + ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "type of options is required"); + } + // Set displayNames.[[Type]] to type. + m_type = type.asString(); + // Let fallback be ? GetOption(options, "fallback", "string", « "code", "none" », "code"). + Value fallbackValues[2] = { staticStrings.lazyCode().string(), staticStrings.lazyNone().string() }; + Value fallback = Intl::getOption(state, optionsObject, staticStrings.lazyFallback().string(), Intl::StringValue, fallbackValues, 2, fallbackValues[0]); + // Set displayNames.[[Fallback]] to fallback. + m_fallback = fallback.asString(); + // Set displayNames.[[Locale]] to the value of r.[[Locale]]. + m_locale = r.at("locale"); + // Let dataLocale be r.[[dataLocale]]. + // Let dataLocaleData be localeData.[[]]. + // Let types be dataLocaleData.[[types]]. + // Assert: types is a Record (see 12.3.3). + // Let typeFields be types.[[]]. + // Assert: typeFields is a Record (see 12.3.3). + // Let languageDisplay be ? GetOption(options, "languageDisplay", "string", « "dialect", "standard" », "dialect"). + Value languageDisplayValues[] = { staticStrings.lazyDialect().string(), staticStrings.lazyStandard().string() }; + Value languageDisplay = Intl::getOption(state, optionsObject, staticStrings.lazyLanguageDisplay().string(), Intl::StringValue, + languageDisplayValues, 2, languageDisplayValues[0]); + // If type is "language", then + // Set displayNames.[[LanguageDisplay]] to languageDisplay. + m_languageDisplay = languageDisplay.asString(); + // Let typeFields be typeFields.[[]]. + // Assert: typeFields is a Record (see 1.4.3). + + // Let styleFields be typeFields.[[